diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,674 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
+ 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 <https://www.gnu.org/licenses/>.
+
+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:
+
+    <program>  Copyright (C) <year>  <name of author>
+    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
+<https://www.gnu.org/licenses/>.
+
+  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
+<https://www.gnu.org/licenses/why-not-lgpl.html>.
diff --git a/README.md b/README.md
new file mode 100644
--- /dev/null
+++ b/README.md
@@ -0,0 +1,6 @@
+# tidal-link
+
+Ableton Link integration for Tidal
+
+Requires fixes to GHC on Windows (see https://gitlab.haskell.org/ghc/ghc/-/issues/20918)
+which are available from GHC 9.2.4.
diff --git a/link/examples/linkaudio/AudioEngine.hpp b/link/examples/linkaudio/AudioEngine.hpp
new file mode 100644
--- /dev/null
+++ b/link/examples/linkaudio/AudioEngine.hpp
@@ -0,0 +1,81 @@
+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.
+ *
+ *  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 2 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 <http://www.gnu.org/licenses/>.
+ *
+ *  If you would like to incorporate Link into a proprietary software application,
+ *  please contact <link-devs@ableton.com>.
+ */
+
+#pragma once
+
+// Make sure to define this before <cmath> is included for Windows
+#define _USE_MATH_DEFINES
+#include <ableton/Link.hpp>
+#include <atomic>
+#include <mutex>
+
+namespace ableton
+{
+namespace linkaudio
+{
+
+class AudioEngine
+{
+public:
+  AudioEngine(Link& link);
+  void startPlaying();
+  void stopPlaying();
+  bool isPlaying() const;
+  double beatTime() const;
+  void setTempo(double tempo);
+  double quantum() const;
+  void setQuantum(double quantum);
+  bool isStartStopSyncEnabled() const;
+  void setStartStopSyncEnabled(bool enabled);
+
+private:
+  struct EngineData
+  {
+    double requestedTempo;
+    bool requestStart;
+    bool requestStop;
+    double quantum;
+    bool startStopSyncOn;
+  };
+
+  void setBufferSize(std::size_t size);
+  void setSampleRate(double sampleRate);
+  EngineData pullEngineData();
+  void renderMetronomeIntoBuffer(Link::SessionState sessionState,
+    double quantum,
+    std::chrono::microseconds beginHostTime,
+    std::size_t numSamples);
+  void audioCallback(const std::chrono::microseconds hostTime, std::size_t numSamples);
+
+  Link& mLink;
+  double mSampleRate;
+  std::atomic<std::chrono::microseconds> mOutputLatency;
+  std::vector<double> mBuffer;
+  EngineData mSharedEngineData;
+  EngineData mLockfreeEngineData;
+  std::chrono::microseconds mTimeAtLastClick;
+  bool mIsPlaying;
+  std::mutex mEngineDataGuard;
+
+  friend class AudioPlatform;
+};
+
+
+} // namespace linkaudio
+} // namespace ableton
diff --git a/link/examples/linkaudio/AudioPlatform.hpp b/link/examples/linkaudio/AudioPlatform.hpp
new file mode 100644
--- /dev/null
+++ b/link/examples/linkaudio/AudioPlatform.hpp
@@ -0,0 +1,44 @@
+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.
+ *
+ *  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 2 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 <http://www.gnu.org/licenses/>.
+ *
+ *  If you would like to incorporate Link into a proprietary software application,
+ *  please contact <link-devs@ableton.com>.
+ */
+
+#pragma once
+
+#if defined(LINKHUT_AUDIO_PLATFORM_ASIO)
+#include "AudioPlatform_Asio.hpp"
+#endif
+
+#if defined(LINKHUT_AUDIO_PLATFORM_COREAUDIO)
+#include "AudioPlatform_CoreAudio.hpp"
+#endif
+
+#if defined(LINKHUT_AUDIO_PLATFORM_DUMMY)
+#include "AudioPlatform_Dummy.hpp"
+#endif
+
+#if defined(LINKHUT_AUDIO_PLATFORM_JACK)
+#include "AudioPlatform_Jack.hpp"
+#endif
+
+#if defined(LINKHUT_AUDIO_PLATFORM_PORTAUDIO)
+#include "AudioPlatform_Portaudio.hpp"
+#endif
+
+#if defined(LINKHUT_AUDIO_PLATFORM_WASAPI)
+#include "AudioPlatform_Wasapi.hpp"
+#endif
diff --git a/link/examples/linkaudio/AudioPlatform_Asio.hpp b/link/examples/linkaudio/AudioPlatform_Asio.hpp
new file mode 100644
--- /dev/null
+++ b/link/examples/linkaudio/AudioPlatform_Asio.hpp
@@ -0,0 +1,103 @@
+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.
+ *
+ *  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 2 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 <http://www.gnu.org/licenses/>.
+ *
+ *  If you would like to incorporate Link into a proprietary software application,
+ *  please contact <link-devs@ableton.com>.
+ */
+
+#pragma once
+
+#include "AudioEngine.hpp"
+
+#include <ableton/Link.hpp>
+#include <ableton/link/HostTimeFilter.hpp>
+
+#include "asiosys.h" // Should be included before asio.h
+
+#include "asio.h"
+#include "asiodrivers.h"
+
+// External functions in the ASIO SDK which aren't declared in the SDK headers
+extern AsioDrivers* asioDrivers;
+bool loadAsioDriver(char* name);
+
+namespace ableton
+{
+namespace linkaudio
+{
+
+#ifndef LINK_ASIO_DRIVER_NAME
+#define LINK_ASIO_DRIVER_NAME "ASIO4ALL v2"
+#endif
+#ifndef LINK_ASIO_INPUT_CHANNELS
+#define LINK_ASIO_INPUT_CHANNELS 0
+#endif
+#ifndef LINK_ASIO_OUTPUT_CHANNELS
+#define LINK_ASIO_OUTPUT_CHANNELS 2
+#endif
+
+struct DriverInfo
+{
+  ASIODriverInfo driverInfo;
+  long inputChannels;
+  long outputChannels;
+  long preferredSize;
+  ASIOSampleRate sampleRate;
+  bool outputReady;
+  long numBuffers;
+  ASIOBufferInfo bufferInfos[LINK_ASIO_INPUT_CHANNELS + LINK_ASIO_OUTPUT_CHANNELS];
+  ASIOChannelInfo channelInfos[LINK_ASIO_INPUT_CHANNELS + LINK_ASIO_OUTPUT_CHANNELS];
+};
+
+// Helper functions
+
+// Convenience function to print out an ASIO error code along with the function called
+void fatalError(const ASIOError result, const std::string& function);
+double asioSamplesToDouble(const ASIOSamples& samples);
+
+ASIOTime* bufferSwitchTimeInfo(ASIOTime* timeInfo, long index, ASIOBool);
+void bufferSwitch(long index, ASIOBool processNow);
+
+class AudioPlatform
+{
+public:
+  AudioPlatform(Link& link);
+  ~AudioPlatform();
+
+  void audioCallback(ASIOTime* timeInfo, long index);
+
+  AudioEngine mEngine;
+
+  // Unfortunately, the ASIO SDK does not allow passing void* user data to callback
+  // functions, so we need to keep a singleton instance of the audio engine
+  static AudioPlatform* singleton();
+  static void setSingleton(AudioPlatform* platform);
+
+private:
+  void createAsioBuffers();
+  void initializeDriverInfo();
+  void initialize();
+  void start();
+  void stop();
+
+  DriverInfo mDriverInfo;
+  ASIOCallbacks mAsioCallbacks;
+  link::HostTimeFilter<platforms::windows::Clock> mHostTimeFilter;
+
+  static AudioPlatform* _singleton;
+};
+
+} // namespace linkaudio
+} // namespace ableton
diff --git a/link/examples/linkaudio/AudioPlatform_CoreAudio.hpp b/link/examples/linkaudio/AudioPlatform_CoreAudio.hpp
new file mode 100644
--- /dev/null
+++ b/link/examples/linkaudio/AudioPlatform_CoreAudio.hpp
@@ -0,0 +1,54 @@
+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.
+ *
+ *  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 2 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 <http://www.gnu.org/licenses/>.
+ *
+ *  If you would like to incorporate Link into a proprietary software application,
+ *  please contact <link-devs@ableton.com>.
+ */
+
+#pragma once
+
+#include "AudioEngine.hpp"
+#include <AudioToolbox/AudioToolbox.h>
+
+namespace ableton
+{
+namespace linkaudio
+{
+
+class AudioPlatform
+{
+public:
+  AudioPlatform(Link& link);
+  ~AudioPlatform();
+  AudioEngine mEngine;
+
+private:
+  static OSStatus audioCallback(void* inRefCon,
+    AudioUnitRenderActionFlags*,
+    const AudioTimeStamp* inTimeStamp,
+    UInt32,
+    UInt32 inNumberFrames,
+    AudioBufferList* ioData);
+
+  void initialize();
+  void uninitialize();
+  void start();
+  void stop();
+
+  AudioUnit mIoUnit;
+};
+
+} // namespace linkaudio
+} // namespace ableton
diff --git a/link/examples/linkaudio/AudioPlatform_Dummy.hpp b/link/examples/linkaudio/AudioPlatform_Dummy.hpp
new file mode 100644
--- /dev/null
+++ b/link/examples/linkaudio/AudioPlatform_Dummy.hpp
@@ -0,0 +1,112 @@
+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.
+ *
+ *  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 2 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 <http://www.gnu.org/licenses/>.
+ *
+ *  If you would like to incorporate Link into a proprietary software application,
+ *  please contact <link-devs@ableton.com>.
+ */
+
+#pragma once
+
+#include <ableton/Link.hpp>
+
+namespace ableton
+{
+namespace linkaudio
+{
+
+class AudioPlatform
+{
+  class AudioEngine
+  {
+  public:
+    AudioEngine(Link& link)
+      : mLink(link)
+      , mQuantum(4.)
+    {
+    }
+
+    void startPlaying()
+    {
+      auto sessionState = mLink.captureAppSessionState();
+      sessionState.setIsPlayingAndRequestBeatAtTime(true, now(), 0., mQuantum);
+      mLink.commitAppSessionState(sessionState);
+    }
+
+    void stopPlaying()
+    {
+      auto sessionState = mLink.captureAppSessionState();
+      sessionState.setIsPlaying(false, now());
+      mLink.commitAppSessionState(sessionState);
+    }
+
+    bool isPlaying() const
+    {
+      return mLink.captureAppSessionState().isPlaying();
+    }
+
+    double beatTime() const
+    {
+      auto sessionState = mLink.captureAppSessionState();
+      return sessionState.beatAtTime(now(), mQuantum);
+    }
+
+    void setTempo(double tempo)
+    {
+      auto sessionState = mLink.captureAppSessionState();
+      sessionState.setTempo(tempo, now());
+      mLink.commitAppSessionState(sessionState);
+    }
+
+    double quantum() const
+    {
+      return mQuantum;
+    }
+
+    void setQuantum(double quantum)
+    {
+      mQuantum = quantum;
+    }
+
+    bool isStartStopSyncEnabled() const
+    {
+      return mLink.isStartStopSyncEnabled();
+    }
+
+    void setStartStopSyncEnabled(bool enabled)
+    {
+      mLink.enableStartStopSync(enabled);
+    }
+
+  private:
+    std::chrono::microseconds now() const
+    {
+      return mLink.clock().micros();
+    }
+
+    Link& mLink;
+    double mQuantum;
+  };
+
+public:
+  AudioPlatform(Link& link)
+    : mEngine(link)
+  {
+  }
+
+  AudioEngine mEngine;
+};
+
+} // namespace linkaudio
+} // namespace ableton
diff --git a/link/examples/linkaudio/AudioPlatform_Jack.hpp b/link/examples/linkaudio/AudioPlatform_Jack.hpp
new file mode 100644
--- /dev/null
+++ b/link/examples/linkaudio/AudioPlatform_Jack.hpp
@@ -0,0 +1,58 @@
+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.
+ *
+ *  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 2 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 <http://www.gnu.org/licenses/>.
+ *
+ *  If you would like to incorporate Link into a proprietary software application,
+ *  please contact <link-devs@ableton.com>.
+ */
+
+#pragma once
+
+#include "AudioEngine.hpp"
+#include <ableton/link/HostTimeFilter.hpp>
+#include <ableton/platforms/Config.hpp>
+#include <jack/jack.h>
+
+namespace ableton
+{
+namespace linkaudio
+{
+
+class AudioPlatform
+{
+public:
+  AudioPlatform(Link& link);
+  ~AudioPlatform();
+
+  AudioEngine mEngine;
+
+private:
+  static int audioCallback(jack_nframes_t nframes, void* pvUserData);
+  int audioCallback(jack_nframes_t nframes);
+  static void latencyCallback(jack_latency_callback_mode_t mode, void* pvUserData);
+  void updateLatency();
+
+  void initialize();
+  void uninitialize();
+  void start();
+  void stop();
+
+  link::HostTimeFilter<link::platform::Clock> mHostTimeFilter;
+  double mSampleTime;
+  jack_client_t* mpJackClient;
+  jack_port_t** mpJackPorts;
+};
+
+} // namespace linkaudio
+} // namespace ableton
diff --git a/link/examples/linkaudio/AudioPlatform_Portaudio.hpp b/link/examples/linkaudio/AudioPlatform_Portaudio.hpp
new file mode 100644
--- /dev/null
+++ b/link/examples/linkaudio/AudioPlatform_Portaudio.hpp
@@ -0,0 +1,59 @@
+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.
+ *
+ *  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 2 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 <http://www.gnu.org/licenses/>.
+ *
+ *  If you would like to incorporate Link into a proprietary software application,
+ *  please contact <link-devs@ableton.com>.
+ */
+
+#pragma once
+
+#include "AudioEngine.hpp"
+#include <ableton/link/HostTimeFilter.hpp>
+#include <ableton/platforms/Config.hpp>
+#include <portaudio.h>
+
+namespace ableton
+{
+namespace linkaudio
+{
+
+class AudioPlatform
+{
+public:
+  AudioPlatform(Link& link);
+  ~AudioPlatform();
+
+  AudioEngine mEngine;
+
+private:
+  static int audioCallback(const void* inputBuffer,
+    void* outputBuffer,
+    unsigned long inNumFrames,
+    const PaStreamCallbackTimeInfo* timeInfo,
+    PaStreamCallbackFlags statusFlags,
+    void* userData);
+
+  void initialize();
+  void uninitialize();
+  void start();
+  void stop();
+
+  link::HostTimeFilter<link::platform::Clock> mHostTimeFilter;
+  double mSampleTime;
+  PaStream* pStream;
+};
+
+} // namespace linkaudio
+} // namespace ableton
diff --git a/link/examples/linkaudio/AudioPlatform_Wasapi.hpp b/link/examples/linkaudio/AudioPlatform_Wasapi.hpp
new file mode 100644
--- /dev/null
+++ b/link/examples/linkaudio/AudioPlatform_Wasapi.hpp
@@ -0,0 +1,72 @@
+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.
+ *
+ *  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 2 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 <http://www.gnu.org/licenses/>.
+ *
+ *  If you would like to incorporate Link into a proprietary software application,
+ *  please contact <link-devs@ableton.com>.
+ */
+
+#pragma once
+
+#include "AudioEngine.hpp"
+#include <Audioclient.h>
+#include <Mmdeviceapi.h>
+#include <ableton/link/HostTimeFilter.hpp>
+#include <atomic>
+
+// WARNING: This file provides an audio driver for Windows using WASAPI. This driver is
+// considered experimental and has problems with low-latency playback. Please consider
+// using the ASIO driver instead.
+
+namespace ableton
+{
+namespace linkaudio
+{
+
+// Convenience function to look up the human-readable WinAPI error code, print it out,
+// and then terminate the application.
+void fatalError(HRESULT result, LPCTSTR context);
+
+DWORD renderAudioRunloop(LPVOID);
+
+class AudioPlatform
+{
+public:
+  AudioPlatform(Link& link);
+  ~AudioPlatform();
+
+  DWORD audioRunloop();
+
+  AudioEngine mEngine;
+
+private:
+  UINT32 bufferSize();
+
+  void initialize();
+  void start();
+
+  link::HostTimeFilter<platforms::windows::Clock> mHostTimeFilter;
+  double mSampleTime;
+
+  IMMDevice* mDevice;
+  IAudioClient* mAudioClient;
+  IAudioRenderClient* mRenderClient;
+  WAVEFORMATEX* mStreamFormat;
+  HANDLE mEventHandle;
+  HANDLE mAudioThreadHandle;
+  std::atomic<bool> mIsRunning;
+};
+
+} // namespace linkaudio
+} // namespace ableton
diff --git a/link/extensions/abl_link/include/abl_link.h b/link/extensions/abl_link/include/abl_link.h
new file mode 100644
--- /dev/null
+++ b/link/extensions/abl_link/include/abl_link.h
@@ -0,0 +1,352 @@
+/* Copyright 2021, Ableton AG, Berlin. All rights reserved.
+ *
+ *  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 2 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 <http://www.gnu.org/licenses/>.
+ *
+ *  If you would like to incorporate Link into a proprietary software application,
+ *  please contact <link-devs@ableton.com>.
+ */
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif // __cplusplus
+
+  /*!
+   *  @discussion Each abl_link instance has its own session state which
+   *  represents a beat timeline and a transport start/stop state. The
+   *  timeline starts running from beat 0 at the initial tempo when
+   *  constructed. The timeline always advances at a speed defined by
+   *  its current tempo, even if transport is stopped. Synchronizing to the
+   *  transport start/stop state of Link is optional for every peer.
+   *  The transport start/stop state is only shared with other peers when
+   *  start/stop synchronization is enabled.
+   *
+   *  An abl_link instance is initially disabled after construction, which
+   *  means that it will not communicate on the network. Once enabled,
+   *  an abl_link instance initiates network communication in an effort to
+   *  discover other peers. When peers are discovered, they immediately
+   *  become part of a shared Link session.
+   *
+   *  Each function documents its thread-safety and
+   *  realtime-safety properties. When a function is marked thread-safe,
+   *  it means it is safe to call from multiple threads
+   *  concurrently. When a function is marked realtime-safe, it means that
+   *  it does not block and is appropriate for use in the thread that
+   *  performs audio IO.
+   *
+   *  One session state capture/commit function pair for use
+   *  in the audio thread and one for all other application contexts is provided.
+   *  In general, modifying the session state should be done in the audio
+   *  thread for the most accurate timing results. The ability to modify
+   *  the session state from application threads should only be used in
+   *  cases where an application's audio thread is not actively running
+   *  or if it doesn't generate audio at all. Modifying the Link session
+   *  state from both the audio thread and an application thread
+   *  concurrently is not advised and will potentially lead to unexpected
+   *  behavior.
+   */
+
+  /*! @brief The representation of an abl_link instance*/
+  typedef struct abl_link
+  {
+    void *impl;
+  } abl_link;
+
+  /*! @brief Construct a new abl_link instance with an initial tempo.
+   *  Thread-safe: yes
+   *  Realtime-safe: no
+   */
+  abl_link abl_link_create(double bpm);
+
+  /*! @brief Delete an abl_link instance.
+   *  Thread-safe: yes
+   *  Realtime-safe: no
+   */
+  void abl_link_destroy(abl_link link);
+
+  /*! @brief Is Link currently enabled?
+   *  Thread-safe: yes
+   *  Realtime-safe: yes
+   */
+  bool abl_link_is_enabled(abl_link link);
+
+  /*! @brief Enable/disable Link.
+   *  Thread-safe: yes
+   *  Realtime-safe: no
+   */
+  void abl_link_enable(abl_link link, bool enable);
+
+  /*! @brief: Is start/stop synchronization enabled?
+   *  Thread-safe: yes
+   *  Realtime-safe: no
+   */
+  bool abl_link_is_start_stop_sync_enabled(abl_link link);
+
+  /*! @brief: Enable start/stop synchronization.
+   *  Thread-safe: yes
+   *  Realtime-safe: no
+   */
+  void abl_link_enable_start_stop_sync(abl_link link, bool enabled);
+
+  /*! @brief How many peers are currently connected in a Link session?
+   *  Thread-safe: yes
+   *  Realtime-safe: yes
+   */
+  uint64_t abl_link_num_peers(abl_link link);
+
+  /*! @brief Register a callback to be notified when the number of
+   *  peers in the Link session changes.
+   *  Thread-safe: yes
+   *  Realtime-safe: no
+   *
+   *  @discussion The callback is invoked on a Link-managed thread.
+   */
+  typedef void (*abl_link_num_peers_callback)(uint64_t num_peers, void *context);
+  void abl_link_set_num_peers_callback(
+    abl_link link, abl_link_num_peers_callback callback, void *context);
+
+  /*! @brief Register a callback to be notified when the session
+   *  tempo changes.
+   *  Thread-safe: yes
+   *  Realtime-safe: no
+   *
+   *  @discussion The callback is invoked on a Link-managed thread.
+   */
+  typedef void (*abl_link_tempo_callback)(double tempo, void *context);
+  void abl_link_set_tempo_callback(
+    abl_link link, abl_link_tempo_callback callback, void *context);
+
+  /*! brief: Register a callback to be notified when the state of
+   *  start/stop isPlaying changes.
+   *  Thread-safe: yes
+   *  Realtime-safe: no
+   *
+   *  @discussion The callback is invoked on a Link-managed thread.
+   */
+  typedef void (*abl_link_start_stop_callback)(bool is_playing, void *context);
+  void abl_link_set_start_stop_callback(
+    abl_link link, abl_link_start_stop_callback callback, void *context);
+
+  /*! brief: Get the current link clock time in microseconds.
+   *  Thread-safe: yes
+   *  Realtime-safe: yes
+   */
+  int64_t abl_link_clock_micros(abl_link link);
+
+  /*! @brief The representation of the current local state of a client in a Link Session
+   *
+   *  @discussion A session state represents a timeline and the start/stop
+   *  state. The timeline is a representation of a mapping between time and
+   *  beats for varying quanta. The start/stop state represents the user
+   *  intention to start or stop transport at a specific time. Start stop
+   *  synchronization is an optional feature that allows to share the user
+   *  request to start or stop transport between a subgroup of peers in a
+   *  Link session. When observing a change of start/stop state, audio
+   *  playback of a peer should be started or stopped the same way it would
+   *  have happened if the user had requested that change at the according
+   *  time locally. The start/stop state can only be changed by the user.
+   *  This means that the current local start/stop state persists when
+   *  joining or leaving a Link session. After joining a Link session
+   *  start/stop change requests will be communicated to all connected peers.
+   */
+  typedef struct abl_link_session_state
+  {
+    void *impl;
+  } abl_link_session_state;
+
+  /*! @brief Create a new session_state instance.
+   *  Thread-safe: yes
+   *  Realtime-safe: no
+   *
+   *  @discussion The session_state is to be used with the abl_link_capture... and
+   *  abl_link_commit... functions to capture snapshots of the current link state and pass
+   *  changes to the link session.
+   */
+  abl_link_session_state abl_link_create_session_state(void);
+
+  /*! @brief Delete a session_state instance.
+   *  Thread-safe: yes
+   *  Realtime-safe: no
+   */
+  void abl_link_destroy_session_state(abl_link_session_state abl_link_session_state);
+
+  /*! @brief Capture the current Link Session State from the audio thread.
+   *  Thread-safe: no
+   *  Realtime-safe: yes
+   *
+   *  @discussion This function should ONLY be called in the audio thread and must not be
+   *  accessed from any other threads. After capturing the session_state holds a snapshot
+   *  of the current Link Session State, so it should be used in a local scope. The
+   *  session_state should not be created on the audio thread.
+   */
+  void abl_link_capture_audio_session_state(
+    abl_link link, abl_link_session_state session_state);
+
+  /*! @brief Commit the given Session State to the Link session from the
+   *  audio thread.
+   *  Thread-safe: no
+   *  Realtime-safe: yes
+   *
+   *  @discussion This function should ONLY be called in the audio thread. The given
+   *  session_state will replace the current Link state. Modifications will be
+   *  communicated to other peers in the session.
+   */
+  void abl_link_commit_audio_session_state(
+    abl_link link, abl_link_session_state session_state);
+
+  /*! @brief Capture the current Link Session State from an application thread.
+   *  Thread-safe: no
+   *  Realtime-safe: yes
+   *
+   *  @discussion Provides a mechanism for capturing the Link Session State from an
+   *  application thread (other than the audio thread). After capturing the session_state
+   *  contains a snapshot of the current Link state, so it should be used in a local
+   *  scope.
+   */
+  void abl_link_capture_app_session_state(
+    abl_link link, abl_link_session_state session_state);
+
+  /*! @brief Commit the given Session State to the Link session from an
+   *  application thread.
+   *  Thread-safe: yes
+   *  Realtime-safe: no
+   *
+   *  @discussion The given session_state will replace the current Link Session State.
+   *  Modifications of the Session State will be communicated to other peers in the
+   *  session.
+   */
+  void abl_link_commit_app_session_state(
+    abl_link link, abl_link_session_state session_state);
+
+  /*! @brief: The tempo of the timeline, in Beats Per Minute.
+   *
+   *  @discussion This is a stable value that is appropriate for display to the user. Beat
+   *  time progress will not necessarily match this tempo exactly because of clock drift
+   *  compensation.
+   */
+  double abl_link_tempo(abl_link_session_state session_state);
+
+  /*! @brief: Set the timeline tempo to the given bpm value, taking effect at the given
+   *  time.
+   */
+  void abl_link_set_tempo(
+    abl_link_session_state session_state, double bpm, int64_t at_time);
+
+  /*! @brief: Get the beat value corresponding to the given time for the given quantum.
+   *
+   *  @discussion: The magnitude of the resulting beat value is unique to this Link
+   *  client, but its phase with respect to the provided quantum is shared among all
+   *  session peers. For non-negative beat values, the following property holds:
+   *  fmod(beatAtTime(t, q), q) == phaseAtTime(t, q)
+   */
+  double abl_link_beat_at_time(
+    abl_link_session_state session_state, int64_t time, double quantum);
+
+  /*! @brief: Get the session phase at the given time for the given quantum.
+   *
+   *  @discussion: The result is in the interval [0, quantum). The result is equivalent to
+   *  fmod(beatAtTime(t, q), q) for non-negative beat values. This function is convenient
+   *  if the client application is only interested in the phase and not the beat
+   *  magnitude. Also, unlike fmod, it handles negative beat values correctly.
+   */
+  double abl_link_phase_at_time(
+    abl_link_session_state session_state, int64_t time, double quantum);
+
+  /*! @brief: Get the time at which the given beat occurs for the given quantum.
+   *
+   *  @discussion: The inverse of beatAtTime, assuming a constant tempo.
+   *  beatAtTime(timeAtBeat(b, q), q) === b.
+   */
+  int64_t abl_link_time_at_beat(
+    abl_link_session_state session_state, double beat, double quantum);
+
+  /*! @brief: Attempt to map the given beat to the given time in the context of the given
+   * quantum.
+   *
+   *  @discussion: This function behaves differently depending on the state of the
+   *  session. If no other peers are connected, then this abl_link instance is in a
+   *  session by itself and is free to re-map the beat/time relationship whenever it
+   *  pleases. In this case, beatAtTime(time, quantum) == beat after this funtion has been
+   *  called.
+   *
+   *  If there are other peers in the session, this abl_link instance should not abruptly
+   *  re-map the beat/time relationship in the session because that would lead to beat
+   *  discontinuities among the other peers. In this case, the given beat will be mapped
+   *  to the next time value greater than the given time with the same phase as the given
+   *  beat.
+   *
+   *  This function is specifically designed to enable the concept of "quantized launch"
+   *  in client applications. If there are no other peers in the session, then an event
+   *  (such as starting transport) happens immediately when it is requested. If there are
+   *  other peers, however, we wait until the next time at which the session phase matches
+   *  the phase of the event, thereby executing the event in-phase with the other peers in
+   *  the session. The client application only needs to invoke this function to achieve
+   *  this behavior and should not need to explicitly check the number of peers.
+   */
+  void abl_link_request_beat_at_time(
+    abl_link_session_state session_state, double beat, int64_t time, double quantum);
+
+  /*! @brief: Rudely re-map the beat/time relationship for all peers in a session.
+   *
+   *  @discussion: DANGER: This function should only be needed in certain special
+   *  circumstances. Most applications should not use it. It is very similar to
+   *  requestBeatAtTime except that it does not fall back to the quantizing behavior when
+   *  it is in a session with other peers. Calling this function will unconditionally map
+   *  the given beat to the given time and broadcast the result to the session. This is
+   *  very anti-social behavior and should be avoided.
+   *
+   *  One of the few legitimate uses of this function is to synchronize a Link session
+   *  with an external clock source. By periodically forcing the beat/time mapping
+   *  according to an external clock source, a peer can effectively bridge that clock into
+   *  a Link session. Much care must be taken at the application layer when implementing
+   *  such a feature so that users do not accidentally disrupt Link sessions that they may
+   *  join.
+   */
+  void abl_link_force_beat_at_time(
+    abl_link_session_state session_state, double beat, uint64_t time, double quantum);
+
+  /*! @brief: Set if transport should be playing or stopped, taking effect at the given
+   *  time.
+   */
+  void abl_link_set_is_playing(
+    abl_link_session_state session_state, bool is_playing, uint64_t time);
+
+  /*! @brief: Is transport playing? */
+  bool abl_link_is_playing(abl_link_session_state session_state);
+
+  /*! @brief: Get the time at which a transport start/stop occurs */
+  uint64_t abl_link_time_for_is_playing(abl_link_session_state session_state);
+
+  /*! @brief: Convenience function to attempt to map the given beat to the time
+   *  when transport is starting to play in context of the given quantum.
+   *  This function evaluates to a no-op if abl_link_is_playing equals false.
+   */
+  void abl_link_request_beat_at_start_playing_time(
+    abl_link_session_state session_state, double beat, double quantum);
+
+  /*! @brief: Convenience function to start or stop transport at a given time and attempt
+   *  to map the given beat to this time in context of the given quantum. */
+  void abl_link_set_is_playing_and_request_beat_at_time(
+    abl_link_session_state session_state,
+    bool is_playing,
+    uint64_t time,
+    double beat,
+    double quantum);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif // __cplusplus
diff --git a/link/extensions/abl_link/src/abl_link.cpp b/link/extensions/abl_link/src/abl_link.cpp
new file mode 100644
--- /dev/null
+++ b/link/extensions/abl_link/src/abl_link.cpp
@@ -0,0 +1,214 @@
+/* Copyright 2021, Ableton AG, Berlin. All rights reserved.
+ *
+ *  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 2 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 <http://www.gnu.org/licenses/>.
+ *
+ *  If you would like to incorporate Link into a proprietary software application,
+ *  please contact <link-devs@ableton.com>.
+ */
+
+#include <abl_link.h>
+#include <ableton/Link.hpp>
+
+extern "C"
+{
+  abl_link abl_link_create(double bpm)
+  {
+    return abl_link{reinterpret_cast<void *>(new ableton::Link(bpm))};
+  }
+
+  void abl_link_destroy(abl_link link)
+  {
+    delete reinterpret_cast<ableton::Link *>(link.impl);
+  }
+
+  bool abl_link_is_enabled(abl_link link)
+  {
+    return reinterpret_cast<ableton::Link *>(link.impl)->isEnabled();
+  }
+
+  void abl_link_enable(abl_link link, bool enabled)
+  {
+    reinterpret_cast<ableton::Link *>(link.impl)->enable(enabled);
+  }
+
+  bool abl_link_is_start_stop_sync_enabled(abl_link link)
+  {
+    return reinterpret_cast<ableton::Link *>(link.impl)->isStartStopSyncEnabled();
+  }
+
+  void abl_link_enable_start_stop_sync(abl_link link, bool enabled)
+  {
+    reinterpret_cast<ableton::Link *>(link.impl)->enableStartStopSync(enabled);
+  }
+
+  uint64_t abl_link_num_peers(abl_link link)
+  {
+    return reinterpret_cast<ableton::Link *>(link.impl)->numPeers();
+  }
+
+  void abl_link_set_num_peers_callback(
+    abl_link link, abl_link_num_peers_callback callback, void *context)
+  {
+    reinterpret_cast<ableton::Link *>(link.impl)->setNumPeersCallback(
+      [callback, context](
+        std::size_t numPeers) { (*callback)(static_cast<uint64_t>(numPeers), context); });
+  }
+
+  void abl_link_set_tempo_callback(
+    abl_link link, abl_link_tempo_callback callback, void *context)
+  {
+    reinterpret_cast<ableton::Link *>(link.impl)->setTempoCallback(
+      [callback, context](double tempo) { (*callback)(tempo, context); });
+  }
+
+  void abl_link_set_start_stop_callback(
+    abl_link link, abl_link_start_stop_callback callback, void *context)
+  {
+    reinterpret_cast<ableton::Link *>(link.impl)->setStartStopCallback(
+      [callback, context](bool isPlaying) { (*callback)(isPlaying, context); });
+  }
+
+  int64_t abl_link_clock_micros(abl_link link)
+  {
+    return reinterpret_cast<ableton::Link *>(link.impl)->clock().micros().count();
+  }
+
+  abl_link_session_state abl_link_create_session_state(void)
+  {
+    return abl_link_session_state{reinterpret_cast<void *>(
+      new ableton::Link::SessionState{ableton::link::ApiState{}, {}})};
+  }
+
+  void abl_link_destroy_session_state(abl_link_session_state session_state)
+  {
+    delete reinterpret_cast<ableton::Link::SessionState *>(session_state.impl);
+  }
+
+  void abl_link_capture_app_session_state(
+    abl_link link, abl_link_session_state session_state)
+  {
+    *reinterpret_cast<ableton::Link::SessionState *>(session_state.impl) =
+      reinterpret_cast<ableton::Link *>(link.impl)->captureAppSessionState();
+  }
+
+  void abl_link_commit_app_session_state(
+    abl_link link, abl_link_session_state session_state)
+  {
+    reinterpret_cast<ableton::Link *>(link.impl)->commitAppSessionState(
+      *reinterpret_cast<ableton::Link::SessionState *>(session_state.impl));
+  }
+
+  void abl_link_capture_audio_session_state(
+    abl_link link, abl_link_session_state session_state)
+  {
+    *reinterpret_cast<ableton::Link::SessionState *>(session_state.impl) =
+      reinterpret_cast<ableton::Link *>(link.impl)->captureAudioSessionState();
+  }
+
+  void abl_link_commit_audio_session_state(
+    abl_link link, abl_link_session_state session_state)
+  {
+    reinterpret_cast<ableton::Link *>(link.impl)->commitAudioSessionState(
+      *reinterpret_cast<ableton::Link::SessionState *>(session_state.impl));
+  }
+
+  double abl_link_tempo(abl_link_session_state session_state)
+  {
+    return reinterpret_cast<ableton::Link::SessionState *>(session_state.impl)->tempo();
+  }
+
+  void abl_link_set_tempo(
+    abl_link_session_state session_state, double bpm, int64_t at_time)
+  {
+    reinterpret_cast<ableton::Link::SessionState *>(session_state.impl)
+      ->setTempo(bpm, std::chrono::microseconds{at_time});
+  }
+
+  double abl_link_beat_at_time(
+    abl_link_session_state session_state, int64_t time, double quantum)
+  {
+    auto micros = std::chrono::microseconds{time};
+    return reinterpret_cast<ableton::Link::SessionState *>(session_state.impl)
+      ->beatAtTime(micros, quantum);
+  }
+
+  double abl_link_phase_at_time(
+    abl_link_session_state session_state, int64_t time, double quantum)
+  {
+    return reinterpret_cast<ableton::Link::SessionState *>(session_state.impl)
+      ->phaseAtTime(std::chrono::microseconds{time}, quantum);
+  }
+
+  int64_t abl_link_time_at_beat(
+    abl_link_session_state session_state, double beat, double quantum)
+  {
+    return reinterpret_cast<ableton::Link::SessionState *>(session_state.impl)
+      ->timeAtBeat(beat, quantum)
+      .count();
+  }
+
+  void abl_link_request_beat_at_time(
+    abl_link_session_state session_state, double beat, int64_t time, double quantum)
+  {
+    reinterpret_cast<ableton::Link::SessionState *>(session_state.impl)
+      ->requestBeatAtTime(beat, std::chrono::microseconds{time}, quantum);
+  }
+
+  void abl_link_force_beat_at_time(
+    abl_link_session_state session_state, double beat, uint64_t time, double quantum)
+  {
+    reinterpret_cast<ableton::Link::SessionState *>(session_state.impl)
+      ->forceBeatAtTime(beat, std::chrono::microseconds{time}, quantum);
+  }
+
+  void abl_link_set_is_playing(
+    abl_link_session_state session_state, bool is_playing, uint64_t time)
+  {
+    reinterpret_cast<ableton::Link::SessionState *>(session_state.impl)
+      ->setIsPlaying(is_playing, std::chrono::microseconds(time));
+  }
+
+  bool abl_link_is_playing(abl_link_session_state session_state)
+  {
+    return reinterpret_cast<ableton::Link::SessionState *>(session_state.impl)
+      ->isPlaying();
+  }
+
+  uint64_t abl_link_time_for_is_playing(abl_link_session_state session_state)
+  {
+    return static_cast<uint64_t>(
+      reinterpret_cast<ableton::Link::SessionState *>(session_state.impl)
+        ->timeForIsPlaying()
+        .count());
+  }
+
+  void abl_link_request_beat_at_start_playing_time(
+    abl_link_session_state session_state, double beat, double quantum)
+  {
+    reinterpret_cast<ableton::Link::SessionState *>(session_state.impl)
+      ->requestBeatAtStartPlayingTime(beat, quantum);
+  }
+
+  void abl_link_set_is_playing_and_request_beat_at_time(
+    abl_link_session_state session_state,
+    bool is_playing,
+    uint64_t time,
+    double beat,
+    double quantum)
+  {
+    reinterpret_cast<ableton::Link::SessionState *>(session_state.impl)
+      ->setIsPlayingAndRequestBeatAtTime(
+        is_playing, std::chrono::microseconds{time}, beat, quantum);
+  }
+}
diff --git a/link/include/ableton/Link.hpp b/link/include/ableton/Link.hpp
new file mode 100644
--- /dev/null
+++ b/link/include/ableton/Link.hpp
@@ -0,0 +1,403 @@
+/*! @file Link.hpp
+ *  @copyright 2016, Ableton AG, Berlin. All rights reserved.
+ *  @brief Library for cross-device shared tempo and quantized beat grid
+ *
+ *  @license:
+ *  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 2 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 <http://www.gnu.org/licenses/>.
+ *
+ *  If you would like to incorporate Link into a proprietary software application,
+ *  please contact <link-devs@ableton.com>.
+ */
+
+#pragma once
+
+#include <ableton/platforms/Config.hpp>
+#include <chrono>
+#include <mutex>
+
+namespace ableton
+{
+
+/*! @class Link and BasicLink
+ *  @brief Classes representing a participant in a Link session.
+ *  The BasicLink type allows to customize the clock. The Link type
+ *  uses the recommended platform-dependent representation of the
+ *  system clock as defined in platforms/Config.hpp.
+ *  It's preferred to use Link instead of BasicLink.
+ *
+ *  @discussion Each Link instance has its own session state which
+ *  represents a beat timeline and a transport start/stop state. The
+ *  timeline starts running from beat 0 at the initial tempo when
+ *  constructed. The timeline always advances at a speed defined by
+ *  its current tempo, even if transport is stopped. Synchronizing to the
+ *  transport start/stop state of Link is optional for every peer.
+ *  The transport start/stop state is only shared with other peers when
+ *  start/stop synchronization is enabled.
+ *
+ *  A Link instance is initially disabled after construction, which
+ *  means that it will not communicate on the network. Once enabled,
+ *  a Link instance initiates network communication in an effort to
+ *  discover other peers. When peers are discovered, they immediately
+ *  become part of a shared Link session.
+ *
+ *  Each method of the Link type documents its thread-safety and
+ *  realtime-safety properties. When a method is marked thread-safe,
+ *  it means it is safe to call from multiple threads
+ *  concurrently. When a method is marked realtime-safe, it means that
+ *  it does not block and is appropriate for use in the thread that
+ *  performs audio IO.
+ *
+ *  Link provides one session state capture/commit method pair for use
+ *  in the audio thread and one for all other application contexts. In
+ *  general, modifying the session state should be done in the audio
+ *  thread for the most accurate timing results. The ability to modify
+ *  the session state from application threads should only be used in
+ *  cases where an application's audio thread is not actively running
+ *  or if it doesn't generate audio at all. Modifying the Link session
+ *  state from both the audio thread and an application thread
+ *  concurrently is not advised and will potentially lead to unexpected
+ *  behavior.
+ *
+ *  Only use the BasicLink class if the default platform clock does not
+ *  fulfill other requirements of the client application. Please note this
+ *  will require providing a custom Clock implementation. See the clock()
+ *  documentation for details.
+ */
+template <typename Clock>
+class BasicLink
+{
+public:
+  class SessionState;
+
+  /*! @brief Construct with an initial tempo. */
+  BasicLink(double bpm);
+
+  /*! @brief Link instances cannot be copied or moved */
+  BasicLink(const BasicLink<Clock>&) = delete;
+  BasicLink& operator=(const BasicLink<Clock>&) = delete;
+  BasicLink(BasicLink<Clock>&&) = delete;
+  BasicLink& operator=(BasicLink<Clock>&&) = delete;
+
+  /*! @brief Is Link currently enabled?
+   *  Thread-safe: yes
+   *  Realtime-safe: yes
+   */
+  bool isEnabled() const;
+
+  /*! @brief Enable/disable Link.
+   *  Thread-safe: yes
+   *  Realtime-safe: no
+   */
+  void enable(bool bEnable);
+
+  /*! @brief: Is start/stop synchronization enabled?
+   *  Thread-safe: yes
+   *  Realtime-safe: no
+   */
+  bool isStartStopSyncEnabled() const;
+
+  /*! @brief: Enable start/stop synchronization.
+   *  Thread-safe: yes
+   *  Realtime-safe: no
+   */
+  void enableStartStopSync(bool bEnable);
+
+  /*! @brief How many peers are currently connected in a Link session?
+   *  Thread-safe: yes
+   *  Realtime-safe: yes
+   */
+  std::size_t numPeers() const;
+
+  /*! @brief Register a callback to be notified when the number of
+   *  peers in the Link session changes.
+   *  Thread-safe: yes
+   *  Realtime-safe: no
+   *
+   *  @discussion The callback is invoked on a Link-managed thread.
+   *
+   *  @param callback The callback signature is:
+   *  void (std::size_t numPeers)
+   */
+  template <typename Callback>
+  void setNumPeersCallback(Callback callback);
+
+  /*! @brief Register a callback to be notified when the session
+   *  tempo changes.
+   *  Thread-safe: yes
+   *  Realtime-safe: no
+   *
+   *  @discussion The callback is invoked on a Link-managed thread.
+   *
+   *  @param callback The callback signature is: void (double bpm)
+   */
+  template <typename Callback>
+  void setTempoCallback(Callback callback);
+
+  /*! brief: Register a callback to be notified when the state of
+   *  start/stop isPlaying changes.
+   *  Thread-safe: yes
+   *  Realtime-safe: no
+   *
+   *  @discussion The callback is invoked on a Link-managed thread.
+   *
+   *  @param callback The callback signature is:
+   *  void (bool isPlaying)
+   */
+  template <typename Callback>
+  void setStartStopCallback(Callback callback);
+
+  /*! @brief The clock used by Link.
+   *  Thread-safe: yes
+   *  Realtime-safe: yes
+   *
+   *  @discussion The Clock type is a platform-dependent representation
+   *  of the system clock. It exposes a micros() method, which is a
+   *  normalized representation of the current system time in
+   *  std::chrono::microseconds.
+   */
+  Clock clock() const;
+
+  /*! @brief Capture the current Link Session State from the audio thread.
+   *  Thread-safe: no
+   *  Realtime-safe: yes
+   *
+   *  @discussion This method should ONLY be called in the audio thread
+   *  and must not be accessed from any other threads. The returned
+   *  object stores a snapshot of the current Link Session State, so it
+   *  should be captured and used in a local scope. Storing the
+   *  Session State for later use in a different context is not advised
+   *  because it will provide an outdated view.
+   */
+  SessionState captureAudioSessionState() const;
+
+  /*! @brief Commit the given Session State to the Link session from the
+   *  audio thread.
+   *  Thread-safe: no
+   *  Realtime-safe: yes
+   *
+   *  @discussion This method should ONLY be called in the audio
+   *  thread. The given Session State will replace the current Link
+   *  state. Modifications will be communicated to other peers in the
+   *  session.
+   */
+  void commitAudioSessionState(SessionState state);
+
+  /*! @brief Capture the current Link Session State from an application
+   *  thread.
+   *  Thread-safe: yes
+   *  Realtime-safe: no
+   *
+   *  @discussion Provides a mechanism for capturing the Link Session
+   *  State from an application thread (other than the audio thread).
+   *  The returned Session State stores a snapshot of the current Link
+   *  state, so it should be captured and used in a local scope.
+   *  Storing the it for later use in a different context is not
+   *  advised because it will provide an outdated view.
+   */
+  SessionState captureAppSessionState() const;
+
+  /*! @brief Commit the given Session State to the Link session from an
+   *  application thread.
+   *  Thread-safe: yes
+   *  Realtime-safe: no
+   *
+   *  @discussion The given Session State will replace the current Link
+   *  Session State. Modifications of the Session State will be
+   *  communicated to other peers in the session.
+   */
+  void commitAppSessionState(SessionState state);
+
+  /*! @class SessionState
+   *  @brief Representation of a timeline and the start/stop state
+   *
+   *  @discussion A SessionState object is intended for use in a local scope within
+   *  a single thread - none of its methods are thread-safe. All of its methods are
+   *  non-blocking, so it is safe to use from a realtime thread.
+   *  It provides functions to observe and manipulate the timeline and start/stop
+   *  state.
+   *
+   *  The timeline is a representation of a mapping between time and beats for varying
+   *  quanta.
+   *  The start/stop state represents the user intention to start or stop transport at
+   *  a specific time. Start stop synchronization is an optional feature that allows to
+   *  share the user request to start or stop transport between a subgroup of peers in
+   *  a Link session. When observing a change of start/stop state, audio playback of a
+   *  peer should be started or stopped the same way it would have happened if the user
+   *  had requested that change at the according time locally. The start/stop state can
+   *  only be changed by the user. This means that the current local start/stop state
+   *  persists when joining or leaving a Link session. After joining a Link session
+   *  start/stop change requests will be communicated to all connected peers.
+   */
+  class SessionState
+  {
+  public:
+    SessionState(const link::ApiState state, const bool bRespectQuantum);
+
+    /*! @brief: The tempo of the timeline, in Beats Per Minute.
+     *
+     *  @discussion This is a stable value that is appropriate for display
+     *  to the user. Beat time progress will not necessarily match this tempo
+     *  exactly because of clock drift compensation.
+     */
+    double tempo() const;
+
+    /*! @brief: Set the timeline tempo to the given bpm value, taking
+     *  effect at the given time.
+     */
+    void setTempo(double bpm, std::chrono::microseconds atTime);
+
+    /*! @brief: Get the beat value corresponding to the given time
+     *  for the given quantum.
+     *
+     *  @discussion: The magnitude of the resulting beat value is
+     *  unique to this Link instance, but its phase with respect to
+     *  the provided quantum is shared among all session
+     *  peers. For non-negative beat values, the following
+     *  property holds: fmod(beatAtTime(t, q), q) == phaseAtTime(t, q)
+     */
+    double beatAtTime(std::chrono::microseconds time, double quantum) const;
+
+    /*! @brief: Get the session phase at the given time for the given
+     *  quantum.
+     *
+     *  @discussion: The result is in the interval [0, quantum). The
+     *  result is equivalent to fmod(beatAtTime(t, q), q) for
+     *  non-negative beat values. This method is convenient if the
+     *  client is only interested in the phase and not the beat
+     *  magnitude. Also, unlike fmod, it handles negative beat values
+     *  correctly.
+     */
+    double phaseAtTime(std::chrono::microseconds time, double quantum) const;
+
+    /*! @brief: Get the time at which the given beat occurs for the
+     *  given quantum.
+     *
+     *  @discussion: The inverse of beatAtTime, assuming a constant
+     *  tempo. beatAtTime(timeAtBeat(b, q), q) === b.
+     */
+    std::chrono::microseconds timeAtBeat(double beat, double quantum) const;
+
+    /*! @brief: Attempt to map the given beat to the given time in the
+     *  context of the given quantum.
+     *
+     *  @discussion: This method behaves differently depending on the
+     *  state of the session. If no other peers are connected,
+     *  then this instance is in a session by itself and is free to
+     *  re-map the beat/time relationship whenever it pleases. In this
+     *  case, beatAtTime(time, quantum) == beat after this method has
+     *  been called.
+     *
+     *  If there are other peers in the session, this instance
+     *  should not abruptly re-map the beat/time relationship in the
+     *  session because that would lead to beat discontinuities among
+     *  the other peers. In this case, the given beat will be mapped
+     *  to the next time value greater than the given time with the
+     *  same phase as the given beat.
+     *
+     *  This method is specifically designed to enable the concept of
+     *  "quantized launch" in client applications. If there are no other
+     *  peers in the session, then an event (such as starting
+     *  transport) happens immediately when it is requested. If there
+     *  are other peers, however, we wait until the next time at which
+     *  the session phase matches the phase of the event, thereby
+     *  executing the event in-phase with the other peers in the
+     *  session. The client only needs to invoke this method to
+     *  achieve this behavior and should not need to explicitly check
+     *  the number of peers.
+     */
+    void requestBeatAtTime(double beat, std::chrono::microseconds time, double quantum);
+
+    /*! @brief: Rudely re-map the beat/time relationship for all peers
+     *  in a session.
+     *
+     *  @discussion: DANGER: This method should only be needed in
+     *  certain special circumstances. Most applications should not
+     *  use it. It is very similar to requestBeatAtTime except that it
+     *  does not fall back to the quantizing behavior when it is in a
+     *  session with other peers. Calling this method will
+     *  unconditionally map the given beat to the given time and
+     *  broadcast the result to the session. This is very anti-social
+     *  behavior and should be avoided.
+     *
+     *  One of the few legitimate uses of this method is to
+     *  synchronize a Link session with an external clock source. By
+     *  periodically forcing the beat/time mapping according to an
+     *  external clock source, a peer can effectively bridge that
+     *  clock into a Link session. Much care must be taken at the
+     *  application layer when implementing such a feature so that
+     *  users do not accidentally disrupt Link sessions that they may
+     *  join.
+     */
+    void forceBeatAtTime(double beat, std::chrono::microseconds time, double quantum);
+
+    /*! @brief: Set if transport should be playing or stopped, taking effect
+     *  at the given time.
+     */
+    void setIsPlaying(bool isPlaying, std::chrono::microseconds time);
+
+    /*! @brief: Is transport playing? */
+    bool isPlaying() const;
+
+    /*! @brief: Get the time at which a transport start/stop occurs */
+    std::chrono::microseconds timeForIsPlaying() const;
+
+    /*! @brief: Convenience function to attempt to map the given beat to the time
+     *  when transport is starting to play in context of the given quantum.
+     *  This function evaluates to a no-op if isPlaying() equals false.
+     */
+    void requestBeatAtStartPlayingTime(double beat, double quantum);
+
+    /*! @brief: Convenience function to start or stop transport at a given time and
+     *  attempt to map the given beat to this time in context of the given quantum.
+     */
+    void setIsPlayingAndRequestBeatAtTime(
+      bool isPlaying, std::chrono::microseconds time, double beat, double quantum);
+
+  private:
+    friend BasicLink<Clock>;
+    link::ApiState mOriginalState;
+    link::ApiState mState;
+    bool mbRespectQuantum;
+  };
+
+private:
+  using Controller = ableton::link::Controller<link::PeerCountCallback,
+    link::TempoCallback,
+    link::StartStopStateCallback,
+    Clock,
+    link::platform::Random,
+    link::platform::IoContext>;
+
+  std::mutex mCallbackMutex;
+  link::PeerCountCallback mPeerCountCallback = [](std::size_t) {};
+  link::TempoCallback mTempoCallback = [](link::Tempo) {};
+  link::StartStopStateCallback mStartStopCallback = [](bool) {};
+  Clock mClock;
+  Controller mController;
+};
+
+class Link : public BasicLink<link::platform::Clock>
+{
+public:
+  using Clock = link::platform::Clock;
+
+  Link(double bpm)
+    : BasicLink(bpm)
+  {
+  }
+};
+
+} // namespace ableton
+
+#include <ableton/Link.ipp>
diff --git a/link/include/ableton/Link.ipp b/link/include/ableton/Link.ipp
new file mode 100644
--- /dev/null
+++ b/link/include/ableton/Link.ipp
@@ -0,0 +1,280 @@
+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.
+ *
+ *  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 2 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 <http://www.gnu.org/licenses/>.
+ *
+ *  If you would like to incorporate Link into a proprietary software application,
+ *  please contact <link-devs@ableton.com>.
+ */
+
+#pragma once
+
+#include <ableton/link/Phase.hpp>
+
+namespace ableton
+{
+namespace detail
+{
+
+template <typename Clock>
+inline typename BasicLink<Clock>::SessionState toSessionState(
+  const link::ClientState& state, const bool isConnected)
+{
+  return {{state.timeline, {state.startStopState.isPlaying, state.startStopState.time}},
+    isConnected};
+}
+
+inline link::IncomingClientState toIncomingClientState(const link::ApiState& state,
+  const link::ApiState& originalState,
+  const std::chrono::microseconds timestamp)
+{
+  const auto timeline = originalState.timeline != state.timeline
+                          ? link::OptionalTimeline{state.timeline}
+                          : link::OptionalTimeline{};
+  const auto startStopState =
+    originalState.startStopState != state.startStopState
+      ? link::OptionalClientStartStopState{{state.startStopState.isPlaying,
+          state.startStopState.time, timestamp}}
+      : link::OptionalClientStartStopState{};
+  return {timeline, startStopState, timestamp};
+}
+
+} // namespace detail
+
+template <typename Clock>
+inline BasicLink<Clock>::BasicLink(const double bpm)
+  : mController(link::Tempo(bpm),
+      [this](const std::size_t peers) {
+        std::lock_guard<std::mutex> lock(mCallbackMutex);
+        mPeerCountCallback(peers);
+      },
+      [this](const link::Tempo tempo) {
+        std::lock_guard<std::mutex> lock(mCallbackMutex);
+        mTempoCallback(tempo);
+      },
+      [this](const bool isPlaying) {
+        std::lock_guard<std::mutex> lock(mCallbackMutex);
+        mStartStopCallback(isPlaying);
+      },
+      mClock)
+{
+}
+
+template <typename Clock>
+inline bool BasicLink<Clock>::isEnabled() const
+{
+  return mController.isEnabled();
+}
+
+template <typename Clock>
+inline void BasicLink<Clock>::enable(const bool bEnable)
+{
+  mController.enable(bEnable);
+}
+
+template <typename Clock>
+inline bool BasicLink<Clock>::isStartStopSyncEnabled() const
+{
+  return mController.isStartStopSyncEnabled();
+}
+
+template <typename Clock>
+inline void BasicLink<Clock>::enableStartStopSync(bool bEnable)
+{
+  mController.enableStartStopSync(bEnable);
+}
+
+template <typename Clock>
+inline std::size_t BasicLink<Clock>::numPeers() const
+{
+  return mController.numPeers();
+}
+
+template <typename Clock>
+template <typename Callback>
+void BasicLink<Clock>::setNumPeersCallback(Callback callback)
+{
+  std::lock_guard<std::mutex> lock(mCallbackMutex);
+  mPeerCountCallback = [callback](const std::size_t numPeers) { callback(numPeers); };
+}
+
+template <typename Clock>
+template <typename Callback>
+void BasicLink<Clock>::setTempoCallback(Callback callback)
+{
+  std::lock_guard<std::mutex> lock(mCallbackMutex);
+  mTempoCallback = [callback](const link::Tempo tempo) { callback(tempo.bpm()); };
+}
+
+template <typename Clock>
+template <typename Callback>
+void BasicLink<Clock>::setStartStopCallback(Callback callback)
+{
+  std::lock_guard<std::mutex> lock(mCallbackMutex);
+  mStartStopCallback = callback;
+}
+
+template <typename Clock>
+inline Clock BasicLink<Clock>::clock() const
+{
+  return mClock;
+}
+
+template <typename Clock>
+inline typename BasicLink<Clock>::SessionState BasicLink<
+  Clock>::captureAudioSessionState() const
+{
+  return detail::toSessionState<Clock>(mController.clientStateRtSafe(), numPeers() > 0);
+}
+
+template <typename Clock>
+inline void BasicLink<Clock>::commitAudioSessionState(
+  const typename BasicLink<Clock>::SessionState state)
+{
+  mController.setClientStateRtSafe(
+    detail::toIncomingClientState(state.mState, state.mOriginalState, mClock.micros()));
+}
+
+template <typename Clock>
+inline typename BasicLink<Clock>::SessionState BasicLink<Clock>::captureAppSessionState()
+  const
+{
+  return detail::toSessionState<Clock>(mController.clientState(), numPeers() > 0);
+}
+
+template <typename Clock>
+inline void BasicLink<Clock>::commitAppSessionState(
+  const typename BasicLink<Clock>::SessionState state)
+{
+  mController.setClientState(
+    detail::toIncomingClientState(state.mState, state.mOriginalState, mClock.micros()));
+}
+
+// Link::SessionState
+
+template <typename Clock>
+inline BasicLink<Clock>::SessionState::SessionState(
+  const link::ApiState state, const bool bRespectQuantum)
+  : mOriginalState(state)
+  , mState(state)
+  , mbRespectQuantum(bRespectQuantum)
+{
+}
+
+template <typename Clock>
+inline double BasicLink<Clock>::SessionState::tempo() const
+{
+  return mState.timeline.tempo.bpm();
+}
+
+template <typename Clock>
+inline void BasicLink<Clock>::SessionState::setTempo(
+  const double bpm, const std::chrono::microseconds atTime)
+{
+  const auto desiredTl = link::clampTempo(
+    link::Timeline{link::Tempo(bpm), mState.timeline.toBeats(atTime), atTime});
+  mState.timeline.tempo = desiredTl.tempo;
+  mState.timeline.timeOrigin = desiredTl.fromBeats(mState.timeline.beatOrigin);
+}
+
+template <typename Clock>
+inline double BasicLink<Clock>::SessionState::beatAtTime(
+  const std::chrono::microseconds time, const double quantum) const
+{
+  return link::toPhaseEncodedBeats(mState.timeline, time, link::Beats{quantum})
+    .floating();
+}
+
+template <typename Clock>
+inline double BasicLink<Clock>::SessionState::phaseAtTime(
+  const std::chrono::microseconds time, const double quantum) const
+{
+  return link::phase(link::Beats{beatAtTime(time, quantum)}, link::Beats{quantum})
+    .floating();
+}
+
+template <typename Clock>
+inline std::chrono::microseconds BasicLink<Clock>::SessionState::timeAtBeat(
+  const double beat, const double quantum) const
+{
+  return link::fromPhaseEncodedBeats(
+    mState.timeline, link::Beats{beat}, link::Beats{quantum});
+}
+
+template <typename Clock>
+inline void BasicLink<Clock>::SessionState::requestBeatAtTime(
+  const double beat, std::chrono::microseconds time, const double quantum)
+{
+  if (mbRespectQuantum)
+  {
+    time = timeAtBeat(link::nextPhaseMatch(link::Beats{beatAtTime(time, quantum)},
+                        link::Beats{beat}, link::Beats{quantum})
+                        .floating(),
+      quantum);
+  }
+  forceBeatAtTime(beat, time, quantum);
+}
+
+template <typename Clock>
+inline void BasicLink<Clock>::SessionState::forceBeatAtTime(
+  const double beat, const std::chrono::microseconds time, const double quantum)
+{
+  // There are two components to the beat adjustment: a phase shift
+  // and a beat magnitude adjustment.
+  const auto curBeatAtTime = link::Beats{beatAtTime(time, quantum)};
+  const auto closestInPhase =
+    link::closestPhaseMatch(curBeatAtTime, link::Beats{beat}, link::Beats{quantum});
+  mState.timeline = shiftClientTimeline(mState.timeline, closestInPhase - curBeatAtTime);
+  // Now adjust the magnitude
+  mState.timeline.beatOrigin =
+    mState.timeline.beatOrigin + (link::Beats{beat} - closestInPhase);
+}
+
+template <typename Clock>
+inline void BasicLink<Clock>::SessionState::setIsPlaying(
+  const bool isPlaying, const std::chrono::microseconds time)
+{
+  mState.startStopState = {isPlaying, time};
+}
+
+template <typename Clock>
+inline bool BasicLink<Clock>::SessionState::isPlaying() const
+{
+  return mState.startStopState.isPlaying;
+}
+
+template <typename Clock>
+inline std::chrono::microseconds BasicLink<Clock>::SessionState::timeForIsPlaying() const
+{
+  return mState.startStopState.time;
+}
+
+template <typename Clock>
+inline void BasicLink<Clock>::SessionState::requestBeatAtStartPlayingTime(
+  const double beat, const double quantum)
+{
+  if (isPlaying())
+  {
+    requestBeatAtTime(beat, mState.startStopState.time, quantum);
+  }
+}
+
+template <typename Clock>
+inline void BasicLink<Clock>::SessionState::setIsPlayingAndRequestBeatAtTime(
+  bool isPlaying, std::chrono::microseconds time, double beat, double quantum)
+{
+  mState.startStopState = {isPlaying, time};
+  requestBeatAtStartPlayingTime(beat, quantum);
+}
+
+} // namespace ableton
diff --git a/link/include/ableton/discovery/InterfaceScanner.hpp b/link/include/ableton/discovery/InterfaceScanner.hpp
new file mode 100644
--- /dev/null
+++ b/link/include/ableton/discovery/InterfaceScanner.hpp
@@ -0,0 +1,102 @@
+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.
+ *
+ *  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 2 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 <http://www.gnu.org/licenses/>.
+ *
+ *  If you would like to incorporate Link into a proprietary software application,
+ *  please contact <link-devs@ableton.com>.
+ */
+
+#pragma once
+
+#include <ableton/platforms/asio/AsioWrapper.hpp>
+#include <ableton/util/Injected.hpp>
+#include <chrono>
+#include <vector>
+
+namespace ableton
+{
+namespace discovery
+{
+
+// Callback takes a range of asio::ip:address which is
+// guaranteed to be sorted and unique
+template <typename Callback, typename IoContext>
+class InterfaceScanner
+{
+public:
+  using Timer = typename util::Injected<IoContext>::type::Timer;
+
+  InterfaceScanner(const std::chrono::seconds period,
+    util::Injected<Callback> callback,
+    util::Injected<IoContext> io)
+    : mPeriod(period)
+    , mCallback(std::move(callback))
+    , mIo(std::move(io))
+    , mTimer(mIo->makeTimer())
+  {
+  }
+
+  void enable(const bool bEnable)
+  {
+    if (bEnable)
+    {
+      scan();
+    }
+    else
+    {
+      mTimer.cancel();
+    }
+  }
+
+  void scan()
+  {
+    using namespace std;
+    debug(mIo->log()) << "Scanning network interfaces";
+    // Rescan the hardware for available network interface addresses
+    vector<asio::ip::address> addrs = mIo->scanNetworkInterfaces();
+    // Sort and unique them to guarantee consistent comparison
+    sort(begin(addrs), end(addrs));
+    addrs.erase(unique(begin(addrs), end(addrs)), end(addrs));
+    // Pass them to the callback
+    (*mCallback)(std::move(addrs));
+    // setup the next scanning
+    mTimer.expires_from_now(mPeriod);
+    using ErrorCode = typename Timer::ErrorCode;
+    mTimer.async_wait([this](const ErrorCode e) {
+      if (!e)
+      {
+        scan();
+      }
+    });
+  }
+
+private:
+  const std::chrono::seconds mPeriod;
+  util::Injected<Callback> mCallback;
+  util::Injected<IoContext> mIo;
+  Timer mTimer;
+};
+
+// Factory function
+template <typename Callback, typename IoContext>
+InterfaceScanner<Callback, IoContext> makeInterfaceScanner(
+  const std::chrono::seconds period,
+  util::Injected<Callback> callback,
+  util::Injected<IoContext> io)
+{
+  return {period, std::move(callback), std::move(io)};
+}
+
+} // namespace discovery
+} // namespace ableton
diff --git a/link/include/ableton/discovery/IpV4Interface.hpp b/link/include/ableton/discovery/IpV4Interface.hpp
new file mode 100644
--- /dev/null
+++ b/link/include/ableton/discovery/IpV4Interface.hpp
@@ -0,0 +1,123 @@
+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.
+ *
+ *  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 2 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 <http://www.gnu.org/licenses/>.
+ *
+ *  If you would like to incorporate Link into a proprietary software application,
+ *  please contact <link-devs@ableton.com>.
+ */
+
+#pragma once
+
+#include <ableton/platforms/asio/AsioWrapper.hpp>
+#include <ableton/util/Injected.hpp>
+
+namespace ableton
+{
+namespace discovery
+{
+
+inline asio::ip::udp::endpoint multicastEndpoint()
+{
+  return {asio::ip::address_v4::from_string("224.76.78.75"), 20808};
+}
+
+// Type tags for dispatching between unicast and multicast packets
+struct MulticastTag
+{
+};
+struct UnicastTag
+{
+};
+
+template <typename IoContext, std::size_t MaxPacketSize>
+class IpV4Interface
+{
+public:
+  using Socket = typename util::Injected<IoContext>::type::template Socket<MaxPacketSize>;
+
+  IpV4Interface(util::Injected<IoContext> io, const asio::ip::address_v4& addr)
+    : mIo(std::move(io))
+    , mMulticastReceiveSocket(mIo->template openMulticastSocket<MaxPacketSize>(addr))
+    , mSendSocket(mIo->template openUnicastSocket<MaxPacketSize>(addr))
+  {
+  }
+
+  IpV4Interface(const IpV4Interface&) = delete;
+  IpV4Interface& operator=(const IpV4Interface&) = delete;
+
+  IpV4Interface(IpV4Interface&& rhs)
+    : mIo(std::move(rhs.mIo))
+    , mMulticastReceiveSocket(std::move(rhs.mMulticastReceiveSocket))
+    , mSendSocket(std::move(rhs.mSendSocket))
+  {
+  }
+
+
+  std::size_t send(
+    const uint8_t* const pData, const size_t numBytes, const asio::ip::udp::endpoint& to)
+  {
+    return mSendSocket.send(pData, numBytes, to);
+  }
+
+  template <typename Handler>
+  void receive(Handler handler, UnicastTag)
+  {
+    mSendSocket.receive(SocketReceiver<UnicastTag, Handler>{std::move(handler)});
+  }
+
+  template <typename Handler>
+  void receive(Handler handler, MulticastTag)
+  {
+    mMulticastReceiveSocket.receive(
+      SocketReceiver<MulticastTag, Handler>(std::move(handler)));
+  }
+
+  asio::ip::udp::endpoint endpoint() const
+  {
+    return mSendSocket.endpoint();
+  }
+
+private:
+  template <typename Tag, typename Handler>
+  struct SocketReceiver
+  {
+    SocketReceiver(Handler handler)
+      : mHandler(std::move(handler))
+    {
+    }
+
+    template <typename It>
+    void operator()(
+      const asio::ip::udp::endpoint& from, const It messageBegin, const It messageEnd)
+    {
+      mHandler(Tag{}, from, messageBegin, messageEnd);
+    }
+
+    Handler mHandler;
+  };
+
+  util::Injected<IoContext> mIo;
+  Socket mMulticastReceiveSocket;
+  Socket mSendSocket;
+};
+
+template <std::size_t MaxPacketSize, typename IoContext>
+IpV4Interface<IoContext, MaxPacketSize> makeIpV4Interface(
+  util::Injected<IoContext> io, const asio::ip::address_v4& addr)
+{
+  return {std::move(io), addr};
+}
+
+} // namespace discovery
+} // namespace ableton
diff --git a/link/include/ableton/discovery/MessageTypes.hpp b/link/include/ableton/discovery/MessageTypes.hpp
new file mode 100644
--- /dev/null
+++ b/link/include/ableton/discovery/MessageTypes.hpp
@@ -0,0 +1,50 @@
+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.
+ *
+ *  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 2 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 <http://www.gnu.org/licenses/>.
+ *
+ *  If you would like to incorporate Link into a proprietary software application,
+ *  please contact <link-devs@ableton.com>.
+ */
+
+#pragma once
+
+namespace ableton
+{
+namespace discovery
+{
+
+// Message types used in the Ableton service discovery protocol. There
+// are two logical messages: a state dump and a bye bye.
+//
+// A state dump provides all relevant information about the peer's
+// current state as well as a Time To Live (TTL) value that indicates
+// how many seconds this state should be considered valid.
+//
+// The bye bye indicates that the sender is leaving the session.
+
+template <typename NodeState>
+struct PeerState
+{
+  NodeState peerState;
+  int ttl;
+};
+
+template <typename NodeId>
+struct ByeBye
+{
+  NodeId peerId;
+};
+
+} // namespace discovery
+} // namespace ableton
diff --git a/link/include/ableton/discovery/NetworkByteStreamSerializable.hpp b/link/include/ableton/discovery/NetworkByteStreamSerializable.hpp
new file mode 100644
--- /dev/null
+++ b/link/include/ableton/discovery/NetworkByteStreamSerializable.hpp
@@ -0,0 +1,462 @@
+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.
+ *
+ *  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 2 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 <http://www.gnu.org/licenses/>.
+ *
+ *  If you would like to incorporate Link into a proprietary software application,
+ *  please contact <link-devs@ableton.com>.
+ */
+
+#pragma once
+
+#include <ableton/platforms/asio/AsioWrapper.hpp>
+#if defined(LINK_PLATFORM_MACOSX)
+#include <ableton/platforms/darwin/Darwin.hpp>
+#elif defined(LINK_PLATFORM_LINUX)
+#include <ableton/platforms/linux/Linux.hpp>
+#elif defined(LINK_PLATFORM_WINDOWS)
+#include <ableton/platforms/windows/Windows.hpp>
+#elif defined(ESP_PLATFORM)
+#include <ableton/platforms/esp32/Esp32.hpp>
+#endif
+
+#include <chrono>
+#include <cstdint>
+#include <type_traits>
+#include <utility>
+#include <vector>
+
+#if defined(LINK_PLATFORM_WINDOWS)
+#include <WS2tcpip.h>
+#include <WinSock2.h>
+#include <Windows.h>
+#endif
+
+namespace ableton
+{
+namespace discovery
+{
+
+// Concept: NetworkByteStreamSerializable
+//
+// A type that can be encoded to a stream of bytes and decoded from a
+// stream of bytes in network byte order. The following type is for
+// documentation purposes only.
+
+struct NetworkByteStreamSerializable
+{
+  friend std::uint32_t sizeInByteStream(const NetworkByteStreamSerializable&);
+
+  // The byte stream pointed to by 'out' must have sufficient space to
+  // hold this object, as defined by sizeInByteStream.
+  template <typename It>
+  friend It toNetworkByteStream(const NetworkByteStreamSerializable&, It out);
+};
+
+// Deserialization aspect of the concept. Outside of the demonstration
+// type above because clients must specify the type
+// explicitly. Default implementation just defers to a class static
+// method on T. For types that can't provide such a method, specialize
+// this template.
+template <typename T>
+struct Deserialize
+{
+  // Throws std::runtime_exception if parsing the type from the given
+  // byte range fails. Returns a pair of the correctly parsed value
+  // and an iterator to the next byte to parse.
+  template <typename It>
+  static std::pair<T, It> fromNetworkByteStream(It begin, It end)
+  {
+    return T::fromNetworkByteStream(std::move(begin), std::move(end));
+  }
+};
+
+
+// Default size implementation. Works for primitive types.
+
+template <typename T,
+  typename std::enable_if<std::is_fundamental<T>::value>::type* = nullptr>
+std::uint32_t sizeInByteStream(T)
+{
+  return sizeof(T);
+}
+
+namespace detail
+{
+
+// utilities for implementing concept for primitive types
+
+template <typename T, typename It>
+It copyToByteStream(T t, It out)
+{
+  using namespace std;
+  return copy_n(
+    reinterpret_cast<typename iterator_traits<It>::pointer>(&t), sizeof(t), out);
+}
+
+template <typename T, typename It>
+std::pair<T, It> copyFromByteStream(It begin, const It end)
+{
+  using namespace std;
+  using ItDiff = typename iterator_traits<It>::difference_type;
+
+  if (distance(begin, end) < static_cast<ItDiff>(sizeof(T)))
+  {
+    throw range_error("Parsing type from byte stream failed");
+  }
+  else
+  {
+    T t;
+    const auto n = sizeof(t);
+    copy_n(begin, n, reinterpret_cast<uint8_t*>(&t));
+    return make_pair(t, begin + n);
+  }
+}
+
+} // namespace detail
+
+
+// Model the concept for unsigned integral types
+
+// uint8_t
+template <typename It>
+It toNetworkByteStream(const uint8_t byte, It out)
+{
+  return detail::copyToByteStream(byte, std::move(out));
+}
+
+template <>
+struct Deserialize<uint8_t>
+{
+  template <typename It>
+  static std::pair<uint8_t, It> fromNetworkByteStream(It begin, It end)
+  {
+    return detail::copyFromByteStream<uint8_t>(std::move(begin), std::move(end));
+  }
+};
+
+// uint16_t
+template <typename It>
+It toNetworkByteStream(uint16_t s, It out)
+{
+  return detail::copyToByteStream(htons(s), std::move(out));
+}
+
+template <>
+struct Deserialize<uint16_t>
+{
+  template <typename It>
+  static std::pair<uint16_t, It> fromNetworkByteStream(It begin, It end)
+  {
+    auto result = detail::copyFromByteStream<uint16_t>(std::move(begin), std::move(end));
+    result.first = ntohs(result.first);
+    return result;
+  }
+};
+
+// uint32_t
+template <typename It>
+It toNetworkByteStream(uint32_t l, It out)
+{
+  return detail::copyToByteStream(htonl(l), std::move(out));
+}
+
+template <>
+struct Deserialize<uint32_t>
+{
+  template <typename It>
+  static std::pair<uint32_t, It> fromNetworkByteStream(It begin, It end)
+  {
+    auto result = detail::copyFromByteStream<uint32_t>(std::move(begin), std::move(end));
+    result.first = ntohl(result.first);
+    return result;
+  }
+};
+
+// int32_t in terms of uint32_t
+template <typename It>
+It toNetworkByteStream(int32_t l, It out)
+{
+  return toNetworkByteStream(reinterpret_cast<const uint32_t&>(l), std::move(out));
+}
+
+template <>
+struct Deserialize<int32_t>
+{
+  template <typename It>
+  static std::pair<int32_t, It> fromNetworkByteStream(It begin, It end)
+  {
+    auto result =
+      Deserialize<uint32_t>::fromNetworkByteStream(std::move(begin), std::move(end));
+    return std::make_pair(reinterpret_cast<const int32_t&>(result.first), result.second);
+  }
+};
+
+// uint64_t
+template <typename It>
+It toNetworkByteStream(uint64_t ll, It out)
+{
+  return detail::copyToByteStream(htonll(ll), std::move(out));
+}
+
+template <>
+struct Deserialize<uint64_t>
+{
+  template <typename It>
+  static std::pair<uint64_t, It> fromNetworkByteStream(It begin, It end)
+  {
+    auto result = detail::copyFromByteStream<uint64_t>(std::move(begin), std::move(end));
+    result.first = ntohll(result.first);
+    return result;
+  }
+};
+
+// int64_t in terms of uint64_t
+template <typename It>
+It toNetworkByteStream(int64_t ll, It out)
+{
+  return toNetworkByteStream(reinterpret_cast<const uint64_t&>(ll), std::move(out));
+}
+
+template <>
+struct Deserialize<int64_t>
+{
+  template <typename It>
+  static std::pair<int64_t, It> fromNetworkByteStream(It begin, It end)
+  {
+    auto result =
+      Deserialize<uint64_t>::fromNetworkByteStream(std::move(begin), std::move(end));
+    return std::make_pair(reinterpret_cast<const int64_t&>(result.first), result.second);
+  }
+};
+
+// bool
+inline std::uint32_t sizeInByteStream(bool)
+{
+  return sizeof(uint8_t);
+}
+
+template <typename It>
+It toNetworkByteStream(bool bl, It out)
+{
+  return toNetworkByteStream(static_cast<uint8_t>(bl), std::move(out));
+}
+
+template <>
+struct Deserialize<bool>
+{
+  template <typename It>
+  static std::pair<bool, It> fromNetworkByteStream(It begin, It end)
+  {
+    auto result =
+      Deserialize<uint8_t>::fromNetworkByteStream(std::move(begin), std::move(end));
+    return std::make_pair(result.first != 0, result.second);
+  }
+};
+
+// std::chrono::microseconds
+inline std::uint32_t sizeInByteStream(const std::chrono::microseconds micros)
+{
+  return sizeInByteStream(micros.count());
+}
+
+template <typename It>
+It toNetworkByteStream(const std::chrono::microseconds micros, It out)
+{
+  static_assert(sizeof(int64_t) == sizeof(std::chrono::microseconds::rep),
+    "The size of microseconds::rep must matche the size of int64_t.");
+  return toNetworkByteStream(static_cast<int64_t>(micros.count()), std::move(out));
+}
+
+template <>
+struct Deserialize<std::chrono::microseconds>
+{
+  template <typename It>
+  static std::pair<std::chrono::microseconds, It> fromNetworkByteStream(It begin, It end)
+  {
+    using namespace std;
+    auto result =
+      Deserialize<int64_t>::fromNetworkByteStream(std::move(begin), std::move(end));
+    return make_pair(chrono::microseconds{result.first}, result.second);
+  }
+};
+
+namespace detail
+{
+
+// Generic serialize/deserialize utilities for containers
+
+template <typename Container>
+std::uint32_t containerSizeInByteStream(const Container& container)
+{
+  std::uint32_t totalSize = 0;
+  for (const auto& val : container)
+  {
+    totalSize += sizeInByteStream(val);
+  }
+  return totalSize;
+}
+
+template <typename Container, typename It>
+It containerToNetworkByteStream(const Container& container, It out)
+{
+  for (const auto& val : container)
+  {
+    out = toNetworkByteStream(val, out);
+  }
+  return out;
+}
+
+template <typename T, typename BytesIt, typename InsertIt>
+BytesIt deserializeContainer(BytesIt bytesBegin,
+  const BytesIt bytesEnd,
+  InsertIt contBegin,
+  const std::uint32_t maxElements)
+{
+  using namespace std;
+  std::uint32_t numElements = 0;
+  while (bytesBegin < bytesEnd && numElements < maxElements)
+  {
+    T newVal;
+    tie(newVal, bytesBegin) = Deserialize<T>::fromNetworkByteStream(bytesBegin, bytesEnd);
+    *contBegin++ = newVal;
+    ++numElements;
+  }
+  return bytesBegin;
+}
+
+} // namespace detail
+
+// Need specific overloads for each container type, but use above
+// utilities for common implementation
+
+// array
+template <typename T, std::size_t Size>
+std::uint32_t sizeInByteStream(const std::array<T, Size>& arr)
+{
+  return detail::containerSizeInByteStream(arr);
+}
+
+template <typename T, std::size_t Size, typename It>
+It toNetworkByteStream(const std::array<T, Size>& arr, It out)
+{
+  return detail::containerToNetworkByteStream(arr, std::move(out));
+}
+
+template <typename T, std::size_t Size>
+struct Deserialize<std::array<T, Size>>
+{
+  template <typename It>
+  static std::pair<std::array<T, Size>, It> fromNetworkByteStream(It begin, It end)
+  {
+    using namespace std;
+    array<T, Size> result{};
+    auto resultIt = detail::deserializeContainer<T>(
+      std::move(begin), std::move(end), std::move(result.begin()), Size);
+    return make_pair(std::move(result), std::move(resultIt));
+  }
+};
+
+// vector
+template <typename T, typename Alloc>
+std::uint32_t sizeInByteStream(const std::vector<T, Alloc>& vec)
+{
+  return sizeof(uint32_t) + detail::containerSizeInByteStream(vec);
+}
+
+template <typename T, typename Alloc, typename It>
+It toNetworkByteStream(const std::vector<T, Alloc>& vec, It out)
+{
+  out = toNetworkByteStream(static_cast<uint32_t>(vec.size()), out);
+  return detail::containerToNetworkByteStream(vec, std::move(out));
+}
+
+template <typename T, typename Alloc>
+struct Deserialize<std::vector<T, Alloc>>
+{
+  template <typename It>
+  static std::pair<std::vector<T, Alloc>, It> fromNetworkByteStream(
+    It bytesBegin, It bytesEnd)
+  {
+    using namespace std;
+    auto result_size =
+      Deserialize<uint32_t>::fromNetworkByteStream(std::move(bytesBegin), bytesEnd);
+    vector<T, Alloc> result;
+    auto resultIt = detail::deserializeContainer<T>(std::move(result_size.second),
+      std::move(bytesEnd), back_inserter(result), result_size.first);
+    return make_pair(std::move(result), std::move(resultIt));
+  }
+};
+
+// 2-tuple
+template <typename X, typename Y>
+std::uint32_t sizeInByteStream(const std::tuple<X, Y>& tup)
+{
+  return sizeInByteStream(std::get<0>(tup)) + sizeInByteStream(std::get<1>(tup));
+}
+
+template <typename X, typename Y, typename It>
+It toNetworkByteStream(const std::tuple<X, Y>& tup, It out)
+{
+  return toNetworkByteStream(
+    std::get<1>(tup), toNetworkByteStream(std::get<0>(tup), std::move(out)));
+}
+
+template <typename X, typename Y>
+struct Deserialize<std::tuple<X, Y>>
+{
+  template <typename It>
+  static std::pair<std::tuple<X, Y>, It> fromNetworkByteStream(It begin, It end)
+  {
+    using namespace std;
+    auto xres = Deserialize<X>::fromNetworkByteStream(begin, end);
+    auto yres = Deserialize<Y>::fromNetworkByteStream(xres.second, end);
+    return make_pair(
+      make_tuple(std::move(xres.first), std::move(yres.first)), std::move(yres.second));
+  }
+};
+
+// 3-tuple
+template <typename X, typename Y, typename Z>
+std::uint32_t sizeInByteStream(const std::tuple<X, Y, Z>& tup)
+{
+  return sizeInByteStream(std::get<0>(tup)) + sizeInByteStream(std::get<1>(tup))
+         + sizeInByteStream(std::get<2>(tup));
+}
+
+template <typename X, typename Y, typename Z, typename It>
+It toNetworkByteStream(const std::tuple<X, Y, Z>& tup, It out)
+{
+  return toNetworkByteStream(
+    std::get<2>(tup), toNetworkByteStream(std::get<1>(tup),
+                        toNetworkByteStream(std::get<0>(tup), std::move(out))));
+}
+
+template <typename X, typename Y, typename Z>
+struct Deserialize<std::tuple<X, Y, Z>>
+{
+  template <typename It>
+  static std::pair<std::tuple<X, Y, Z>, It> fromNetworkByteStream(It begin, It end)
+  {
+    using namespace std;
+    auto xres = Deserialize<X>::fromNetworkByteStream(begin, end);
+    auto yres = Deserialize<Y>::fromNetworkByteStream(xres.second, end);
+    auto zres = Deserialize<Z>::fromNetworkByteStream(yres.second, end);
+    return make_pair(
+      make_tuple(std::move(xres.first), std::move(yres.first), std::move(zres.first)),
+      std::move(zres.second));
+  }
+};
+
+} // namespace discovery
+} // namespace ableton
diff --git a/link/include/ableton/discovery/Payload.hpp b/link/include/ableton/discovery/Payload.hpp
new file mode 100644
--- /dev/null
+++ b/link/include/ableton/discovery/Payload.hpp
@@ -0,0 +1,296 @@
+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.
+ *
+ *  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 2 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 <http://www.gnu.org/licenses/>.
+ *
+ *  If you would like to incorporate Link into a proprietary software application,
+ *  please contact <link-devs@ableton.com>.
+ */
+
+#pragma once
+
+#include <ableton/discovery/NetworkByteStreamSerializable.hpp>
+#include <functional>
+#include <sstream>
+#include <unordered_map>
+
+namespace ableton
+{
+namespace discovery
+{
+
+struct PayloadEntryHeader
+{
+  using Key = std::uint32_t;
+  using Size = std::uint32_t;
+
+  Key key;
+  Size size;
+
+  friend Size sizeInByteStream(const PayloadEntryHeader& header)
+  {
+    return sizeInByteStream(header.key) + sizeInByteStream(header.size);
+  }
+
+  template <typename It>
+  friend It toNetworkByteStream(const PayloadEntryHeader& header, It out)
+  {
+    return toNetworkByteStream(
+      header.size, toNetworkByteStream(header.key, std::move(out)));
+  }
+
+  template <typename It>
+  static std::pair<PayloadEntryHeader, It> fromNetworkByteStream(It begin, const It end)
+  {
+    using namespace std;
+    Key key;
+    Size size;
+    tie(key, begin) = Deserialize<Key>::fromNetworkByteStream(begin, end);
+    tie(size, begin) = Deserialize<Size>::fromNetworkByteStream(begin, end);
+    return make_pair(
+      PayloadEntryHeader{std::move(key), std::move(size)}, std::move(begin));
+  }
+};
+
+template <typename EntryType>
+struct PayloadEntry
+{
+  PayloadEntry(EntryType entryVal)
+    : value(std::move(entryVal))
+  {
+    header = {EntryType::key, sizeInByteStream(value)};
+  }
+
+  PayloadEntryHeader header;
+  EntryType value;
+
+  friend std::uint32_t sizeInByteStream(const PayloadEntry& entry)
+  {
+    return sizeInByteStream(entry.header) + sizeInByteStream(entry.value);
+  }
+
+  template <typename It>
+  friend It toNetworkByteStream(const PayloadEntry& entry, It out)
+  {
+    return toNetworkByteStream(
+      entry.value, toNetworkByteStream(entry.header, std::move(out)));
+  }
+};
+
+namespace detail
+{
+
+template <typename It>
+using HandlerMap =
+  std::unordered_map<typename PayloadEntryHeader::Key, std::function<void(It, It)>>;
+
+// Given an index of handlers and a byte range, parse the bytes as a
+// sequence of payload entries and invoke the appropriate handler for
+// each entry type. Entries that are encountered that do not have a
+// corresponding handler in the map are ignored. Throws
+// std::runtime_error if parsing fails for any entry. Note that if an
+// exception is thrown, some of the handlers may have already been called.
+template <typename It>
+void parseByteStream(HandlerMap<It>& map, It bsBegin, const It bsEnd)
+{
+  using namespace std;
+
+  while (bsBegin < bsEnd)
+  {
+    // Try to parse an entry header at this location in the byte stream
+    PayloadEntryHeader header;
+    It valueBegin;
+    tie(header, valueBegin) =
+      Deserialize<PayloadEntryHeader>::fromNetworkByteStream(bsBegin, bsEnd);
+
+    // Ensure that the reported size of the entry does not exceed the
+    // length of the byte stream
+    It valueEnd = valueBegin + header.size;
+    if (bsEnd < valueEnd)
+    {
+      throw range_error("Payload with incorrect size.");
+    }
+
+    // The next entry will start at the end of this one
+    bsBegin = valueEnd;
+
+    // Use the appropriate handler for this entry, if available
+    auto handlerIt = map.find(header.key);
+    if (handlerIt != end(map))
+    {
+      handlerIt->second(std::move(valueBegin), std::move(valueEnd));
+    }
+  }
+}
+
+} // namespace detail
+
+
+// Payload encoding
+template <typename... Entries>
+struct Payload;
+
+template <typename First, typename Rest>
+struct Payload<First, Rest>
+{
+  Payload(First first, Rest rest)
+    : mFirst(std::move(first))
+    , mRest(std::move(rest))
+  {
+  }
+
+  Payload(PayloadEntry<First> first, Rest rest)
+    : mFirst(std::move(first))
+    , mRest(std::move(rest))
+  {
+  }
+
+  template <typename RhsFirst, typename RhsRest>
+  using PayloadSum =
+    Payload<First, typename Rest::template PayloadSum<RhsFirst, RhsRest>>;
+
+  // Concatenate payloads together into a single payload
+  template <typename RhsFirst, typename RhsRest>
+  friend PayloadSum<RhsFirst, RhsRest> operator+(
+    Payload lhs, Payload<RhsFirst, RhsRest> rhs)
+  {
+    return {std::move(lhs.mFirst), std::move(lhs.mRest) + std::move(rhs)};
+  }
+
+  friend std::size_t sizeInByteStream(const Payload& payload)
+  {
+    return sizeInByteStream(payload.mFirst) + sizeInByteStream(payload.mRest);
+  }
+
+  template <typename It>
+  friend It toNetworkByteStream(const Payload& payload, It streamIt)
+  {
+    return toNetworkByteStream(
+      payload.mRest, toNetworkByteStream(payload.mFirst, std::move(streamIt)));
+  }
+
+  PayloadEntry<First> mFirst;
+  Rest mRest;
+};
+
+template <>
+struct Payload<>
+{
+  template <typename RhsFirst, typename RhsRest>
+  using PayloadSum = Payload<RhsFirst, RhsRest>;
+
+  template <typename RhsFirst, typename RhsRest>
+  friend PayloadSum<RhsFirst, RhsRest> operator+(Payload, Payload<RhsFirst, RhsRest> rhs)
+  {
+    return rhs;
+  }
+
+  friend std::size_t sizeInByteStream(const Payload&)
+  {
+    return 0;
+  }
+
+  template <typename It>
+  friend It toNetworkByteStream(const Payload&, It streamIt)
+  {
+    return streamIt;
+  }
+};
+
+template <typename... Entries>
+struct PayloadBuilder;
+
+// Payload factory function
+template <typename... Entries>
+auto makePayload(Entries... entries)
+  -> decltype(PayloadBuilder<Entries...>{}(std::move(entries)...))
+{
+  return PayloadBuilder<Entries...>{}(std::move(entries)...);
+}
+
+template <typename First, typename... Rest>
+struct PayloadBuilder<First, Rest...>
+{
+  auto operator()(First first, Rest... rest)
+    -> Payload<First, decltype(makePayload(std::move(rest)...))>
+  {
+    return {std::move(first), makePayload(std::move(rest)...)};
+  }
+};
+
+template <>
+struct PayloadBuilder<>
+{
+  Payload<> operator()()
+  {
+    return {};
+  }
+};
+
+// Parse payloads to values
+template <typename... Entries>
+struct ParsePayload;
+
+template <typename First, typename... Rest>
+struct ParsePayload<First, Rest...>
+{
+  template <typename It, typename... Handlers>
+  static void parse(It begin, It end, Handlers... handlers)
+  {
+    detail::HandlerMap<It> map;
+    collectHandlers(map, std::move(handlers)...);
+    detail::parseByteStream(map, std::move(begin), std::move(end));
+  }
+
+  template <typename It, typename FirstHandler, typename... RestHandlers>
+  static void collectHandlers(
+    detail::HandlerMap<It>& map, FirstHandler handler, RestHandlers... rest)
+  {
+    using namespace std;
+    map[First::key] = [handler](const It begin, const It end) {
+      const auto res = First::fromNetworkByteStream(begin, end);
+      if (res.second != end)
+      {
+        std::ostringstream stringStream;
+        stringStream << "Parsing payload entry " << First::key
+                     << " did not consume the expected number of bytes. "
+                     << " Expected: " << distance(begin, end)
+                     << ", Actual: " << distance(begin, res.second);
+        throw range_error(stringStream.str());
+      }
+      handler(res.first);
+    };
+
+    ParsePayload<Rest...>::collectHandlers(map, std::move(rest)...);
+  }
+};
+
+template <>
+struct ParsePayload<>
+{
+  template <typename It>
+  static void collectHandlers(detail::HandlerMap<It>&)
+  {
+  }
+};
+
+template <typename... Entries, typename It, typename... Handlers>
+void parsePayload(It begin, It end, Handlers... handlers)
+{
+  using namespace std;
+  ParsePayload<Entries...>::parse(
+    std::move(begin), std::move(end), std::move(handlers)...);
+}
+
+} // namespace discovery
+} // namespace ableton
diff --git a/link/include/ableton/discovery/PeerGateway.hpp b/link/include/ableton/discovery/PeerGateway.hpp
new file mode 100644
--- /dev/null
+++ b/link/include/ableton/discovery/PeerGateway.hpp
@@ -0,0 +1,251 @@
+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.
+ *
+ *  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 2 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 <http://www.gnu.org/licenses/>.
+ *
+ *  If you would like to incorporate Link into a proprietary software application,
+ *  please contact <link-devs@ableton.com>.
+ */
+
+#pragma once
+
+#include <ableton/discovery/UdpMessenger.hpp>
+#include <ableton/discovery/v1/Messages.hpp>
+#include <ableton/util/SafeAsyncHandler.hpp>
+#include <memory>
+
+namespace ableton
+{
+namespace discovery
+{
+
+template <typename Messenger, typename PeerObserver, typename IoContext>
+class PeerGateway
+{
+public:
+  // The peer types are defined by the observer but must match with those
+  // used by the Messenger
+  using ObserverT = typename util::Injected<PeerObserver>::type;
+  using NodeState = typename ObserverT::GatewayObserverNodeState;
+  using NodeId = typename ObserverT::GatewayObserverNodeId;
+  using Timer = typename util::Injected<IoContext>::type::Timer;
+  using TimerError = typename Timer::ErrorCode;
+
+  PeerGateway(util::Injected<Messenger> messenger,
+    util::Injected<PeerObserver> observer,
+    util::Injected<IoContext> io)
+    : mpImpl(new Impl(std::move(messenger), std::move(observer), std::move(io)))
+  {
+    mpImpl->listen();
+  }
+
+  PeerGateway(const PeerGateway&) = delete;
+  PeerGateway& operator=(const PeerGateway&) = delete;
+
+  PeerGateway(PeerGateway&& rhs)
+    : mpImpl(std::move(rhs.mpImpl))
+  {
+  }
+
+  void updateState(NodeState state)
+  {
+    mpImpl->updateState(std::move(state));
+  }
+
+private:
+  using PeerTimeout = std::pair<std::chrono::system_clock::time_point, NodeId>;
+  using PeerTimeouts = std::vector<PeerTimeout>;
+
+  struct Impl : std::enable_shared_from_this<Impl>
+  {
+    Impl(util::Injected<Messenger> messenger,
+      util::Injected<PeerObserver> observer,
+      util::Injected<IoContext> io)
+      : mMessenger(std::move(messenger))
+      , mObserver(std::move(observer))
+      , mIo(std::move(io))
+      , mPruneTimer(mIo->makeTimer())
+    {
+    }
+
+    void updateState(NodeState state)
+    {
+      mMessenger->updateState(std::move(state));
+      try
+      {
+        mMessenger->broadcastState();
+      }
+      catch (const std::runtime_error& err)
+      {
+        info(mIo->log()) << "State broadcast failed on gateway: " << err.what();
+      }
+    }
+
+    void listen()
+    {
+      mMessenger->receive(util::makeAsyncSafe(this->shared_from_this()));
+    }
+
+    // Operators for handling incoming messages
+    void operator()(const PeerState<NodeState>& msg)
+    {
+      onPeerState(msg.peerState, msg.ttl);
+      listen();
+    }
+
+    void operator()(const ByeBye<NodeId>& msg)
+    {
+      onByeBye(msg.peerId);
+      listen();
+    }
+
+    void onPeerState(const NodeState& nodeState, const int ttl)
+    {
+      using namespace std;
+      const auto peerId = nodeState.ident();
+      const auto existing = findPeer(peerId);
+      if (existing != end(mPeerTimeouts))
+      {
+        // If the peer is already present in our timeout list, remove it
+        // as it will be re-inserted below.
+        mPeerTimeouts.erase(existing);
+      }
+
+      auto newTo = make_pair(mPruneTimer.now() + std::chrono::seconds(ttl), peerId);
+      mPeerTimeouts.insert(
+        upper_bound(begin(mPeerTimeouts), end(mPeerTimeouts), newTo, TimeoutCompare{}),
+        std::move(newTo));
+
+      sawPeer(*mObserver, nodeState);
+      scheduleNextPruning();
+    }
+
+    void onByeBye(const NodeId& peerId)
+    {
+      const auto it = findPeer(peerId);
+      if (it != mPeerTimeouts.end())
+      {
+        peerLeft(*mObserver, it->second);
+        mPeerTimeouts.erase(it);
+      }
+    }
+
+    void pruneExpiredPeers()
+    {
+      using namespace std;
+
+      const auto test = make_pair(mPruneTimer.now(), NodeId{});
+      debug(mIo->log()) << "pruning peers @ " << test.first.time_since_epoch().count();
+
+      const auto endExpired =
+        lower_bound(begin(mPeerTimeouts), end(mPeerTimeouts), test, TimeoutCompare{});
+
+      for_each(begin(mPeerTimeouts), endExpired, [this](const PeerTimeout& pto) {
+        info(mIo->log()) << "pruning peer " << pto.second;
+        peerTimedOut(*mObserver, pto.second);
+      });
+      mPeerTimeouts.erase(begin(mPeerTimeouts), endExpired);
+      scheduleNextPruning();
+    }
+
+    void scheduleNextPruning()
+    {
+      // Find the next peer to expire and set the timer based on it
+      if (!mPeerTimeouts.empty())
+      {
+        // Add a second of padding to the timer to avoid over-eager timeouts
+        const auto t = mPeerTimeouts.front().first + std::chrono::seconds(1);
+
+        debug(mIo->log()) << "scheduling next pruning for "
+                          << t.time_since_epoch().count() << " because of peer "
+                          << mPeerTimeouts.front().second;
+
+        mPruneTimer.expires_at(t);
+        mPruneTimer.async_wait([this](const TimerError e) {
+          if (!e)
+          {
+            pruneExpiredPeers();
+          }
+        });
+      }
+    }
+
+    struct TimeoutCompare
+    {
+      bool operator()(const PeerTimeout& lhs, const PeerTimeout& rhs) const
+      {
+        return lhs.first < rhs.first;
+      }
+    };
+
+    typename PeerTimeouts::iterator findPeer(const NodeId& peerId)
+    {
+      return std::find_if(begin(mPeerTimeouts), end(mPeerTimeouts),
+        [&peerId](const PeerTimeout& pto) { return pto.second == peerId; });
+    }
+
+    util::Injected<Messenger> mMessenger;
+    util::Injected<PeerObserver> mObserver;
+    util::Injected<IoContext> mIo;
+    Timer mPruneTimer;
+    PeerTimeouts mPeerTimeouts; // Invariant: sorted by time_point
+  };
+
+  std::shared_ptr<Impl> mpImpl;
+};
+
+template <typename Messenger, typename PeerObserver, typename IoContext>
+PeerGateway<Messenger, PeerObserver, IoContext> makePeerGateway(
+  util::Injected<Messenger> messenger,
+  util::Injected<PeerObserver> observer,
+  util::Injected<IoContext> io)
+{
+  return {std::move(messenger), std::move(observer), std::move(io)};
+}
+
+// IpV4 gateway types
+template <typename StateQuery, typename IoContext>
+using IpV4Messenger = UdpMessenger<
+  IpV4Interface<typename util::Injected<IoContext>::type&, v1::kMaxMessageSize>,
+  StateQuery,
+  IoContext>;
+
+template <typename PeerObserver, typename StateQuery, typename IoContext>
+using IpV4Gateway =
+  PeerGateway<IpV4Messenger<StateQuery, typename util::Injected<IoContext>::type&>,
+    PeerObserver,
+    IoContext>;
+
+// Factory function to bind a PeerGateway to an IpV4Interface with the given address.
+template <typename PeerObserver, typename NodeState, typename IoContext>
+IpV4Gateway<PeerObserver, NodeState, IoContext> makeIpV4Gateway(
+  util::Injected<IoContext> io,
+  const asio::ip::address_v4& addr,
+  util::Injected<PeerObserver> observer,
+  NodeState state)
+{
+  using namespace std;
+  using namespace util;
+
+  const uint8_t ttl = 5;
+  const uint8_t ttlRatio = 20;
+
+  auto iface = makeIpV4Interface<v1::kMaxMessageSize>(injectRef(*io), addr);
+
+  auto messenger = makeUdpMessenger(
+    injectVal(std::move(iface)), std::move(state), injectRef(*io), ttl, ttlRatio);
+  return {injectVal(std::move(messenger)), std::move(observer), std::move(io)};
+}
+
+} // namespace discovery
+} // namespace ableton
diff --git a/link/include/ableton/discovery/PeerGateways.hpp b/link/include/ableton/discovery/PeerGateways.hpp
new file mode 100644
--- /dev/null
+++ b/link/include/ableton/discovery/PeerGateways.hpp
@@ -0,0 +1,182 @@
+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.
+ *
+ *  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 2 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 <http://www.gnu.org/licenses/>.
+ *
+ *  If you would like to incorporate Link into a proprietary software application,
+ *  please contact <link-devs@ableton.com>.
+ */
+
+#pragma once
+
+#include <ableton/discovery/InterfaceScanner.hpp>
+#include <ableton/platforms/asio/AsioWrapper.hpp>
+#include <map>
+
+namespace ableton
+{
+namespace discovery
+{
+
+// GatewayFactory must have an operator()(NodeState, IoRef, asio::ip::address)
+// that constructs a new PeerGateway on a given interface address.
+template <typename NodeState, typename GatewayFactory, typename IoContext>
+class PeerGateways
+{
+public:
+  using IoType = typename util::Injected<IoContext>::type;
+  using Gateway = typename std::result_of<GatewayFactory(
+    NodeState, util::Injected<IoType&>, asio::ip::address)>::type;
+  using GatewayMap = std::map<asio::ip::address, Gateway>;
+
+  PeerGateways(const std::chrono::seconds rescanPeriod,
+    NodeState state,
+    GatewayFactory factory,
+    util::Injected<IoContext> io)
+    : mIo(std::move(io))
+  {
+    mpScannerCallback =
+      std::make_shared<Callback>(std::move(state), std::move(factory), *mIo);
+    mpScanner = std::make_shared<Scanner>(
+      rescanPeriod, util::injectShared(mpScannerCallback), util::injectRef(*mIo));
+  }
+
+  ~PeerGateways()
+  {
+    mpScanner.reset();
+    mpScannerCallback.reset();
+  }
+
+  PeerGateways(const PeerGateways&) = delete;
+  PeerGateways& operator=(const PeerGateways&) = delete;
+
+  PeerGateways(PeerGateways&&) = delete;
+  PeerGateways& operator=(PeerGateways&&) = delete;
+
+  void enable(const bool bEnable)
+  {
+    mpScannerCallback->mGateways.clear();
+    mpScanner->enable(bEnable);
+  }
+
+  template <typename Handler>
+  void withGateways(Handler handler)
+  {
+    handler(mpScannerCallback->mGateways.begin(), mpScannerCallback->mGateways.end());
+  }
+
+  void updateNodeState(const NodeState& state)
+  {
+    mpScannerCallback->mState = state;
+    for (const auto& entry : mpScannerCallback->mGateways)
+    {
+      entry.second->updateNodeState(state);
+    }
+  }
+
+  // If a gateway has become non-responsive or is throwing exceptions,
+  // this method can be invoked to either fix it or discard it.
+  void repairGateway(const asio::ip::address& gatewayAddr)
+  {
+    if (mpScannerCallback->mGateways.erase(gatewayAddr))
+    {
+      // If we erased a gateway, rescan again immediately so that
+      // we will re-initialize it if it's still present
+      mpScanner->scan();
+    }
+  }
+
+private:
+  struct Callback
+  {
+    Callback(NodeState state, GatewayFactory factory, IoType& io)
+      : mState(std::move(state))
+      , mFactory(std::move(factory))
+      , mIo(io)
+    {
+    }
+
+    template <typename AddrRange>
+    void operator()(const AddrRange& range)
+    {
+      using namespace std;
+      // Get the set of current addresses.
+      vector<asio::ip::address> curAddrs;
+      curAddrs.reserve(mGateways.size());
+      transform(std::begin(mGateways), std::end(mGateways), back_inserter(curAddrs),
+        [](const typename GatewayMap::value_type& vt) { return vt.first; });
+
+      // Now use set_difference to determine the set of addresses that
+      // are new and the set of cur addresses that are no longer there
+      vector<asio::ip::address> newAddrs;
+      set_difference(std::begin(range), std::end(range), std::begin(curAddrs),
+        std::end(curAddrs), back_inserter(newAddrs));
+
+      vector<asio::ip::address> staleAddrs;
+      set_difference(std::begin(curAddrs), std::end(curAddrs), std::begin(range),
+        std::end(range), back_inserter(staleAddrs));
+
+      // Remove the stale addresses
+      for (const auto& addr : staleAddrs)
+      {
+        mGateways.erase(addr);
+      }
+
+      // Add the new addresses
+      for (const auto& addr : newAddrs)
+      {
+        try
+        {
+          // Only handle v4 for now
+          if (addr.is_v4())
+          {
+            info(mIo.log()) << "initializing peer gateway on interface " << addr;
+            mGateways.emplace(addr, mFactory(mState, util::injectRef(mIo), addr.to_v4()));
+          }
+        }
+        catch (const runtime_error& e)
+        {
+          warning(mIo.log()) << "failed to init gateway on interface " << addr
+                             << " reason: " << e.what();
+        }
+      }
+    }
+
+    NodeState mState;
+    GatewayFactory mFactory;
+    IoType& mIo;
+    GatewayMap mGateways;
+  };
+
+  using Scanner = InterfaceScanner<std::shared_ptr<Callback>, IoType&>;
+  std::shared_ptr<Callback> mpScannerCallback;
+  std::shared_ptr<Scanner> mpScanner;
+  util::Injected<IoContext> mIo;
+};
+
+// Factory function
+template <typename NodeState, typename GatewayFactory, typename IoContext>
+std::unique_ptr<PeerGateways<NodeState, GatewayFactory, IoContext>> makePeerGateways(
+  const std::chrono::seconds rescanPeriod,
+  NodeState state,
+  GatewayFactory factory,
+  util::Injected<IoContext> io)
+{
+  using namespace std;
+  using Gateways = PeerGateways<NodeState, GatewayFactory, IoContext>;
+  return unique_ptr<Gateways>{
+    new Gateways{rescanPeriod, std::move(state), std::move(factory), std::move(io)}};
+}
+
+} // namespace discovery
+} // namespace ableton
diff --git a/link/include/ableton/discovery/Service.hpp b/link/include/ableton/discovery/Service.hpp
new file mode 100644
--- /dev/null
+++ b/link/include/ableton/discovery/Service.hpp
@@ -0,0 +1,72 @@
+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.
+ *
+ *  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 2 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 <http://www.gnu.org/licenses/>.
+ *
+ *  If you would like to incorporate Link into a proprietary software application,
+ *  please contact <link-devs@ableton.com>.
+ */
+
+#pragma once
+
+#include <ableton/discovery/PeerGateways.hpp>
+
+namespace ableton
+{
+namespace discovery
+{
+
+template <typename NodeState, typename GatewayFactory, typename IoContext>
+class Service
+{
+public:
+  using ServicePeerGateways = PeerGateways<NodeState, GatewayFactory, IoContext>;
+
+  Service(NodeState state, GatewayFactory factory, util::Injected<IoContext> io)
+    : mGateways(
+        std::chrono::seconds(5), std::move(state), std::move(factory), std::move(io))
+  {
+  }
+
+  void enable(const bool bEnable)
+  {
+    mGateways.enable(bEnable);
+  }
+
+  // Asynchronously operate on the current set of peer gateways. The
+  // handler will be invoked in the service's io context.
+  template <typename Handler>
+  void withGateways(Handler handler)
+  {
+    mGateways.withGateways(std::move(handler));
+  }
+
+  void updateNodeState(const NodeState& state)
+  {
+    mGateways.updateNodeState(state);
+  }
+
+  // Repair the gateway with the given address if possible. Its
+  // sockets may have been closed, for example, and the gateway needs
+  // to be regenerated.
+  void repairGateway(const asio::ip::address& gatewayAddr)
+  {
+    mGateways.repairGateway(gatewayAddr);
+  }
+
+private:
+  ServicePeerGateways mGateways;
+};
+
+} // namespace discovery
+} // namespace ableton
diff --git a/link/include/ableton/discovery/UdpMessenger.hpp b/link/include/ableton/discovery/UdpMessenger.hpp
new file mode 100644
--- /dev/null
+++ b/link/include/ableton/discovery/UdpMessenger.hpp
@@ -0,0 +1,330 @@
+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.
+ *
+ *  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 2 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 <http://www.gnu.org/licenses/>.
+ *
+ *  If you would like to incorporate Link into a proprietary software application,
+ *  please contact <link-devs@ableton.com>.
+ */
+
+#pragma once
+
+#include <ableton/discovery/IpV4Interface.hpp>
+#include <ableton/discovery/MessageTypes.hpp>
+#include <ableton/discovery/v1/Messages.hpp>
+#include <ableton/platforms/asio/AsioWrapper.hpp>
+#include <ableton/util/Injected.hpp>
+#include <ableton/util/SafeAsyncHandler.hpp>
+#include <algorithm>
+#include <memory>
+
+namespace ableton
+{
+namespace discovery
+{
+
+// An exception thrown when sending a udp message fails. Stores the
+// interface through which the sending failed.
+struct UdpSendException : std::runtime_error
+{
+  UdpSendException(const std::runtime_error& e, asio::ip::address ifAddr)
+    : std::runtime_error(e.what())
+    , interfaceAddr(std::move(ifAddr))
+  {
+  }
+
+  asio::ip::address interfaceAddr;
+};
+
+// Throws UdpSendException
+template <typename Interface, typename NodeId, typename Payload>
+void sendUdpMessage(Interface& iface,
+  NodeId from,
+  const uint8_t ttl,
+  const v1::MessageType messageType,
+  const Payload& payload,
+  const asio::ip::udp::endpoint& to)
+{
+  using namespace std;
+  v1::MessageBuffer buffer;
+  const auto messageBegin = begin(buffer);
+  const auto messageEnd =
+    v1::detail::encodeMessage(std::move(from), ttl, messageType, payload, messageBegin);
+  const auto numBytes = static_cast<size_t>(distance(messageBegin, messageEnd));
+  try
+  {
+    iface.send(buffer.data(), numBytes, to);
+  }
+  catch (const std::runtime_error& err)
+  {
+    throw UdpSendException{err, iface.endpoint().address()};
+  }
+}
+
+// UdpMessenger uses a "shared_ptr pImpl" pattern to make it movable
+// and to support safe async handler callbacks when receiving messages
+// on the given interface.
+template <typename Interface, typename NodeStateT, typename IoContext>
+class UdpMessenger
+{
+public:
+  using NodeState = NodeStateT;
+  using NodeId = typename NodeState::IdType;
+  using Timer = typename util::Injected<IoContext>::type::Timer;
+  using TimerError = typename Timer::ErrorCode;
+  using TimePoint = typename Timer::TimePoint;
+
+  UdpMessenger(util::Injected<Interface> iface,
+    NodeState state,
+    util::Injected<IoContext> io,
+    const uint8_t ttl,
+    const uint8_t ttlRatio)
+    : mpImpl(std::make_shared<Impl>(
+        std::move(iface), std::move(state), std::move(io), ttl, ttlRatio))
+  {
+    // We need to always listen for incoming traffic in order to
+    // respond to peer state broadcasts
+    mpImpl->listen(MulticastTag{});
+    mpImpl->listen(UnicastTag{});
+    mpImpl->broadcastState();
+  }
+
+  UdpMessenger(const UdpMessenger&) = delete;
+  UdpMessenger& operator=(const UdpMessenger&) = delete;
+
+  UdpMessenger(UdpMessenger&& rhs)
+    : mpImpl(std::move(rhs.mpImpl))
+  {
+  }
+
+  ~UdpMessenger()
+  {
+    if (mpImpl != nullptr)
+    {
+      try
+      {
+        mpImpl->sendByeBye();
+      }
+      catch (const UdpSendException& err)
+      {
+        debug(mpImpl->mIo->log()) << "Failed to send bye bye message: " << err.what();
+      }
+    }
+  }
+
+  void updateState(NodeState state)
+  {
+    mpImpl->updateState(std::move(state));
+  }
+
+  // Broadcast the current state of the system to all peers. May throw
+  // std::runtime_error if assembling a broadcast message fails or if
+  // there is an error at the transport layer. Throws on failure.
+  void broadcastState()
+  {
+    mpImpl->broadcastState();
+  }
+
+  // Asynchronous receive function for incoming messages from peers. Will
+  // return immediately and the handler will be invoked when a message
+  // is received. Handler must have operator() overloads for PeerState and
+  // ByeBye messages.
+  template <typename Handler>
+  void receive(Handler handler)
+  {
+    mpImpl->setReceiveHandler(std::move(handler));
+  }
+
+private:
+  struct Impl : std::enable_shared_from_this<Impl>
+  {
+    Impl(util::Injected<Interface> iface,
+      NodeState state,
+      util::Injected<IoContext> io,
+      const uint8_t ttl,
+      const uint8_t ttlRatio)
+      : mIo(std::move(io))
+      , mInterface(std::move(iface))
+      , mState(std::move(state))
+      , mTimer(mIo->makeTimer())
+      , mLastBroadcastTime{}
+      , mTtl(ttl)
+      , mTtlRatio(ttlRatio)
+      , mPeerStateHandler([](PeerState<NodeState>) {})
+      , mByeByeHandler([](ByeBye<NodeId>) {})
+    {
+    }
+
+    template <typename Handler>
+    void setReceiveHandler(Handler handler)
+    {
+      mPeerStateHandler = [handler](
+                            PeerState<NodeState> state) { handler(std::move(state)); };
+
+      mByeByeHandler = [handler](ByeBye<NodeId> byeBye) { handler(std::move(byeBye)); };
+    }
+
+    void sendByeBye()
+    {
+      sendUdpMessage(
+        *mInterface, mState.ident(), 0, v1::kByeBye, makePayload(), multicastEndpoint());
+    }
+
+    void updateState(NodeState state)
+    {
+      mState = std::move(state);
+    }
+
+    void broadcastState()
+    {
+      using namespace std::chrono;
+
+      const auto minBroadcastPeriod = milliseconds{50};
+      const auto nominalBroadcastPeriod = milliseconds(mTtl * 1000 / mTtlRatio);
+      const auto timeSinceLastBroadcast =
+        duration_cast<milliseconds>(mTimer.now() - mLastBroadcastTime);
+
+      // The rate is limited to maxBroadcastRate to prevent flooding the network.
+      const auto delay = minBroadcastPeriod - timeSinceLastBroadcast;
+
+      // Schedule the next broadcast before we actually send the
+      // message so that if sending throws an exception we are still
+      // scheduled to try again. We want to keep trying at our
+      // interval as long as this instance is alive.
+      mTimer.expires_from_now(delay > milliseconds{0} ? delay : nominalBroadcastPeriod);
+      mTimer.async_wait([this](const TimerError e) {
+        if (!e)
+        {
+          broadcastState();
+        }
+      });
+
+      // If we're not delaying, broadcast now
+      if (delay < milliseconds{1})
+      {
+        debug(mIo->log()) << "Broadcasting state";
+        sendPeerState(v1::kAlive, multicastEndpoint());
+      }
+    }
+
+    void sendPeerState(
+      const v1::MessageType messageType, const asio::ip::udp::endpoint& to)
+    {
+      sendUdpMessage(
+        *mInterface, mState.ident(), mTtl, messageType, toPayload(mState), to);
+      mLastBroadcastTime = mTimer.now();
+    }
+
+    void sendResponse(const asio::ip::udp::endpoint& to)
+    {
+      sendPeerState(v1::kResponse, to);
+    }
+
+    template <typename Tag>
+    void listen(Tag tag)
+    {
+      mInterface->receive(util::makeAsyncSafe(this->shared_from_this()), tag);
+    }
+
+    template <typename Tag, typename It>
+    void operator()(Tag tag,
+      const asio::ip::udp::endpoint& from,
+      const It messageBegin,
+      const It messageEnd)
+    {
+      auto result = v1::parseMessageHeader<NodeId>(messageBegin, messageEnd);
+
+      const auto& header = result.first;
+      // Ignore messages from self and other groups
+      if (header.ident != mState.ident() && header.groupId == 0)
+      {
+        debug(mIo->log()) << "Received message type "
+                          << static_cast<int>(header.messageType) << " from peer "
+                          << header.ident;
+
+        switch (header.messageType)
+        {
+        case v1::kAlive:
+          sendResponse(from);
+          receivePeerState(std::move(result.first), result.second, messageEnd);
+          break;
+        case v1::kResponse:
+          receivePeerState(std::move(result.first), result.second, messageEnd);
+          break;
+        case v1::kByeBye:
+          receiveByeBye(std::move(result.first.ident));
+          break;
+        default:
+          info(mIo->log()) << "Unknown message received of type: " << header.messageType;
+        }
+      }
+      listen(tag);
+    }
+
+    template <typename It>
+    void receivePeerState(
+      v1::MessageHeader<NodeId> header, It payloadBegin, It payloadEnd)
+    {
+      try
+      {
+        auto state = NodeState::fromPayload(
+          std::move(header.ident), std::move(payloadBegin), std::move(payloadEnd));
+
+        // Handlers must only be called once
+        auto handler = std::move(mPeerStateHandler);
+        mPeerStateHandler = [](PeerState<NodeState>) {};
+        handler(PeerState<NodeState>{std::move(state), header.ttl});
+      }
+      catch (const std::runtime_error& err)
+      {
+        info(mIo->log()) << "Ignoring peer state message: " << err.what();
+      }
+    }
+
+    void receiveByeBye(NodeId nodeId)
+    {
+      // Handlers must only be called once
+      auto byeByeHandler = std::move(mByeByeHandler);
+      mByeByeHandler = [](ByeBye<NodeId>) {};
+      byeByeHandler(ByeBye<NodeId>{std::move(nodeId)});
+    }
+
+    util::Injected<IoContext> mIo;
+    util::Injected<Interface> mInterface;
+    NodeState mState;
+    Timer mTimer;
+    TimePoint mLastBroadcastTime;
+    uint8_t mTtl;
+    uint8_t mTtlRatio;
+    std::function<void(PeerState<NodeState>)> mPeerStateHandler;
+    std::function<void(ByeBye<NodeId>)> mByeByeHandler;
+  };
+
+  std::shared_ptr<Impl> mpImpl;
+};
+
+// Factory function
+template <typename Interface, typename NodeState, typename IoContext>
+UdpMessenger<Interface, NodeState, IoContext> makeUdpMessenger(
+  util::Injected<Interface> iface,
+  NodeState state,
+  util::Injected<IoContext> io,
+  const uint8_t ttl,
+  const uint8_t ttlRatio)
+{
+  return UdpMessenger<Interface, NodeState, IoContext>{
+    std::move(iface), std::move(state), std::move(io), ttl, ttlRatio};
+}
+
+} // namespace discovery
+} // namespace ableton
diff --git a/link/include/ableton/discovery/test/Interface.hpp b/link/include/ableton/discovery/test/Interface.hpp
new file mode 100644
--- /dev/null
+++ b/link/include/ableton/discovery/test/Interface.hpp
@@ -0,0 +1,75 @@
+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.
+ *
+ *  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 2 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 <http://www.gnu.org/licenses/>.
+ *
+ *  If you would like to incorporate Link into a proprietary software application,
+ *  please contact <link-devs@ableton.com>.
+ */
+
+#pragma once
+
+#include <ableton/util/Log.hpp>
+
+namespace ableton
+{
+namespace discovery
+{
+namespace test
+{
+
+class Interface
+{
+public:
+  void send(const uint8_t* const bytes,
+    const size_t numBytes,
+    const asio::ip::udp::endpoint& endpoint)
+  {
+    sentMessages.push_back(
+      std::make_pair(std::vector<uint8_t>{bytes, bytes + numBytes}, endpoint));
+  }
+
+  template <typename Callback, typename Tag>
+  void receive(Callback callback, Tag tag)
+  {
+    mCallback = [callback, tag](const asio::ip::udp::endpoint& from,
+                  const std::vector<uint8_t>& buffer) {
+      callback(tag, from, begin(buffer), end(buffer));
+    };
+  }
+
+  template <typename It>
+  void incomingMessage(
+    const asio::ip::udp::endpoint& from, It messageBegin, It messageEnd)
+  {
+    std::vector<uint8_t> buffer{messageBegin, messageEnd};
+    mCallback(from, buffer);
+  }
+
+  asio::ip::udp::endpoint endpoint() const
+  {
+    return asio::ip::udp::endpoint({}, 0);
+  }
+
+  using SentMessage = std::pair<std::vector<uint8_t>, asio::ip::udp::endpoint>;
+  std::vector<SentMessage> sentMessages;
+
+private:
+  using ReceiveCallback =
+    std::function<void(const asio::ip::udp::endpoint&, const std::vector<uint8_t>&)>;
+  ReceiveCallback mCallback;
+};
+
+} // namespace test
+} // namespace discovery
+} // namespace ableton
diff --git a/link/include/ableton/discovery/test/PayloadEntries.hpp b/link/include/ableton/discovery/test/PayloadEntries.hpp
new file mode 100644
--- /dev/null
+++ b/link/include/ableton/discovery/test/PayloadEntries.hpp
@@ -0,0 +1,133 @@
+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.
+ *
+ *  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 2 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 <http://www.gnu.org/licenses/>.
+ *
+ *  If you would like to incorporate Link into a proprietary software application,
+ *  please contact <link-devs@ableton.com>.
+ */
+
+#pragma once
+
+#include <ableton/discovery/NetworkByteStreamSerializable.hpp>
+#include <cstdint>
+#include <tuple>
+#include <utility>
+
+namespace ableton
+{
+namespace discovery
+{
+namespace test
+{
+
+// Test payload entries
+
+// A fixed-size entry type
+struct Foo
+{
+  static const std::int32_t key = '_foo';
+  static_assert(key == 0x5f666f6f, "Unexpected byte order");
+
+  std::int32_t fooVal;
+
+  friend std::uint32_t sizeInByteStream(const Foo& foo)
+  {
+    // Namespace qualification is needed to avoid ambiguous function definitions
+    return discovery::sizeInByteStream(foo.fooVal);
+  }
+
+  template <typename It>
+  friend It toNetworkByteStream(const Foo& foo, It out)
+  {
+    return discovery::toNetworkByteStream(foo.fooVal, std::move(out));
+  }
+
+  template <typename It>
+  static std::pair<Foo, It> fromNetworkByteStream(It begin, It end)
+  {
+    auto result = Deserialize<decltype(fooVal)>::fromNetworkByteStream(
+      std::move(begin), std::move(end));
+    return std::make_pair(Foo{std::move(result.first)}, std::move(result.second));
+  }
+};
+
+// A variable-size entry type
+struct Bar
+{
+  static const std::int32_t key = '_bar';
+  static_assert(key == 0x5f626172, "Unexpected byte order");
+
+  std::vector<std::uint64_t> barVals;
+
+  friend std::uint32_t sizeInByteStream(const Bar& bar)
+  {
+    return discovery::sizeInByteStream(bar.barVals);
+  }
+
+  template <typename It>
+  friend It toNetworkByteStream(const Bar& bar, It out)
+  {
+    return discovery::toNetworkByteStream(bar.barVals, out);
+  }
+
+  template <typename It>
+  static std::pair<Bar, It> fromNetworkByteStream(It begin, It end)
+  {
+    auto result = Deserialize<decltype(barVals)>::fromNetworkByteStream(
+      std::move(begin), std::move(end));
+    return std::make_pair(Bar{std::move(result.first)}, std::move(result.second));
+  }
+};
+
+// An entry type with two vectors
+struct Foobar
+{
+  static const std::int32_t key = 'fbar';
+  static_assert(key == 0x66626172, "Unexpected byte order");
+
+  using FoobarVector = std::vector<std::uint64_t>;
+  using FoobarTuple = std::tuple<FoobarVector, FoobarVector>;
+
+  FoobarVector fooVals;
+  FoobarVector barVals;
+
+  friend std::uint32_t sizeInByteStream(const Foobar& foobar)
+  {
+    return discovery::sizeInByteStream(foobar.asTuple());
+  }
+
+  template <typename It>
+  friend It toNetworkByteStream(const Foobar& foobar, It out)
+  {
+    return discovery::toNetworkByteStream(foobar.asTuple(), out);
+  }
+
+  template <typename It>
+  static std::pair<Foobar, It> fromNetworkByteStream(It begin, It end)
+  {
+    const auto result =
+      Deserialize<FoobarTuple>::fromNetworkByteStream(std::move(begin), std::move(end));
+    const auto foobar = Foobar{std::get<0>(result.first), std::get<1>(result.first)};
+    return std::make_pair(std::move(foobar), std::move(result.second));
+  }
+
+  FoobarTuple asTuple() const
+  {
+    return std::make_tuple(fooVals, barVals);
+  }
+};
+
+} // namespace test
+} // namespace discovery
+} // namespace ableton
diff --git a/link/include/ableton/discovery/test/Socket.hpp b/link/include/ableton/discovery/test/Socket.hpp
new file mode 100644
--- /dev/null
+++ b/link/include/ableton/discovery/test/Socket.hpp
@@ -0,0 +1,85 @@
+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.
+ *
+ *  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 2 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 <http://www.gnu.org/licenses/>.
+ *
+ *  If you would like to incorporate Link into a proprietary software application,
+ *  please contact <link-devs@ableton.com>.
+ */
+
+#pragma once
+
+#include <ableton/platforms/asio/AsioWrapper.hpp>
+#include <ableton/util/Log.hpp>
+#include <ableton/util/test/IoService.hpp>
+
+namespace ableton
+{
+namespace discovery
+{
+namespace test
+{
+
+class Socket
+{
+public:
+  Socket(util::test::IoService&)
+  {
+  }
+
+  friend void configureUnicastSocket(Socket&, const asio::ip::address_v4&)
+  {
+  }
+
+  std::size_t send(
+    const uint8_t* const pData, const size_t numBytes, const asio::ip::udp::endpoint& to)
+  {
+    sentMessages.push_back(
+      std::make_pair(std::vector<uint8_t>{pData, pData + numBytes}, to));
+    return numBytes;
+  }
+
+  template <typename Handler>
+  void receive(Handler handler)
+  {
+    mCallback = [handler](const asio::ip::udp::endpoint& from,
+                  const std::vector<uint8_t>& buffer) {
+      handler(from, begin(buffer), end(buffer));
+    };
+  }
+
+  template <typename It>
+  void incomingMessage(
+    const asio::ip::udp::endpoint& from, It messageBegin, It messageEnd)
+  {
+    std::vector<uint8_t> buffer{messageBegin, messageEnd};
+    mCallback(from, buffer);
+  }
+
+  asio::ip::udp::endpoint endpoint() const
+  {
+    return asio::ip::udp::endpoint({}, 0);
+  }
+
+  using SentMessage = std::pair<std::vector<uint8_t>, asio::ip::udp::endpoint>;
+  std::vector<SentMessage> sentMessages;
+
+private:
+  using ReceiveCallback =
+    std::function<void(const asio::ip::udp::endpoint&, const std::vector<uint8_t>&)>;
+  ReceiveCallback mCallback;
+};
+
+} // namespace test
+} // namespace discovery
+} // namespace ableton
diff --git a/link/include/ableton/discovery/v1/Messages.hpp b/link/include/ableton/discovery/v1/Messages.hpp
new file mode 100644
--- /dev/null
+++ b/link/include/ableton/discovery/v1/Messages.hpp
@@ -0,0 +1,168 @@
+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.
+ *
+ *  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 2 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 <http://www.gnu.org/licenses/>.
+ *
+ *  If you would like to incorporate Link into a proprietary software application,
+ *  please contact <link-devs@ableton.com>.
+ */
+
+#pragma once
+
+#include <ableton/discovery/Payload.hpp>
+#include <array>
+
+namespace ableton
+{
+namespace discovery
+{
+namespace v1
+{
+
+// The maximum size of a message, in bytes
+const std::size_t kMaxMessageSize = 512;
+// Utility typedef for an array of bytes of maximum message size
+using MessageBuffer = std::array<uint8_t, v1::kMaxMessageSize>;
+
+using MessageType = uint8_t;
+using SessionGroupId = uint16_t;
+
+const MessageType kInvalid = 0;
+const MessageType kAlive = 1;
+const MessageType kResponse = 2;
+const MessageType kByeBye = 3;
+
+template <typename NodeId>
+struct MessageHeader
+{
+  MessageType messageType;
+  uint8_t ttl;
+  SessionGroupId groupId;
+  NodeId ident;
+
+  friend std::uint32_t sizeInByteStream(const MessageHeader& header)
+  {
+    return discovery::sizeInByteStream(header.messageType)
+           + discovery::sizeInByteStream(header.ttl)
+           + discovery::sizeInByteStream(header.groupId)
+           + discovery::sizeInByteStream(header.ident);
+  }
+
+  template <typename It>
+  friend It toNetworkByteStream(const MessageHeader& header, It out)
+  {
+    return discovery::toNetworkByteStream(header.ident,
+      discovery::toNetworkByteStream(header.groupId,
+        discovery::toNetworkByteStream(header.ttl,
+          discovery::toNetworkByteStream(header.messageType, std::move(out)))));
+  }
+
+  template <typename It>
+  static std::pair<MessageHeader, It> fromNetworkByteStream(It begin, const It end)
+  {
+    using namespace std;
+
+    MessageHeader header;
+    tie(header.messageType, begin) =
+      Deserialize<decltype(header.messageType)>::fromNetworkByteStream(begin, end);
+    tie(header.ttl, begin) =
+      Deserialize<decltype(header.ttl)>::fromNetworkByteStream(begin, end);
+    tie(header.groupId, begin) =
+      Deserialize<decltype(header.groupId)>::fromNetworkByteStream(begin, end);
+    tie(header.ident, begin) =
+      Deserialize<decltype(header.ident)>::fromNetworkByteStream(begin, end);
+
+    return make_pair(std::move(header), std::move(begin));
+  }
+};
+
+namespace detail
+{
+
+// Types that are only used in the sending/parsing of messages, not
+// publicly exposed.
+using ProtocolHeader = std::array<char, 8>;
+const ProtocolHeader kProtocolHeader = {{'_', 'a', 's', 'd', 'p', '_', 'v', 1}};
+
+// Must have at least kMaxMessageSize bytes available in the output stream
+template <typename NodeId, typename Payload, typename It>
+It encodeMessage(NodeId from,
+  const uint8_t ttl,
+  const MessageType messageType,
+  const Payload& payload,
+  It out)
+{
+  using namespace std;
+  const MessageHeader<NodeId> header = {messageType, ttl, 0, std::move(from)};
+  const auto messageSize =
+    kProtocolHeader.size() + sizeInByteStream(header) + sizeInByteStream(payload);
+
+  if (messageSize < kMaxMessageSize)
+  {
+    return toNetworkByteStream(
+      payload, toNetworkByteStream(header,
+                 copy(begin(kProtocolHeader), end(kProtocolHeader), std::move(out))));
+  }
+  else
+  {
+    throw range_error("Exceeded maximum message size");
+  }
+}
+
+} // namespace detail
+
+template <typename NodeId, typename Payload, typename It>
+It aliveMessage(NodeId from, const uint8_t ttl, const Payload& payload, It out)
+{
+  return detail::encodeMessage(std::move(from), ttl, kAlive, payload, std::move(out));
+}
+
+template <typename NodeId, typename Payload, typename It>
+It responseMessage(NodeId from, const uint8_t ttl, const Payload& payload, It out)
+{
+  return detail::encodeMessage(std::move(from), ttl, kResponse, payload, std::move(out));
+}
+
+template <typename NodeId, typename It>
+It byeByeMessage(NodeId from, It out)
+{
+  return detail::encodeMessage(
+    std::move(from), 0, kByeBye, makePayload(), std::move(out));
+}
+
+template <typename NodeId, typename It>
+std::pair<MessageHeader<NodeId>, It> parseMessageHeader(It bytesBegin, const It bytesEnd)
+{
+  using namespace std;
+  using ItDiff = typename iterator_traits<It>::difference_type;
+
+  MessageHeader<NodeId> header = {};
+  const auto protocolHeaderSize = discovery::sizeInByteStream(detail::kProtocolHeader);
+  const auto minMessageSize =
+    static_cast<ItDiff>(protocolHeaderSize + sizeInByteStream(header));
+
+  // If there are enough bytes in the stream to make a header and if
+  // the first bytes in the stream are the protocol header, then
+  // proceed to parse the stream.
+  if (distance(bytesBegin, bytesEnd) >= minMessageSize
+      && equal(begin(detail::kProtocolHeader), end(detail::kProtocolHeader), bytesBegin))
+  {
+    tie(header, bytesBegin) = MessageHeader<NodeId>::fromNetworkByteStream(
+      bytesBegin + protocolHeaderSize, bytesEnd);
+  }
+  return make_pair(std::move(header), std::move(bytesBegin));
+}
+
+} // namespace v1
+} // namespace discovery
+} // namespace ableton
diff --git a/link/include/ableton/link/Beats.hpp b/link/include/ableton/link/Beats.hpp
new file mode 100644
--- /dev/null
+++ b/link/include/ableton/link/Beats.hpp
@@ -0,0 +1,125 @@
+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.
+ *
+ *  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 2 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 <http://www.gnu.org/licenses/>.
+ *
+ *  If you would like to incorporate Link into a proprietary software application,
+ *  please contact <link-devs@ableton.com>.
+ */
+
+#pragma once
+
+#include <ableton/discovery/NetworkByteStreamSerializable.hpp>
+#include <cmath>
+#include <cstdint>
+
+namespace ableton
+{
+namespace link
+{
+
+struct Beats
+{
+  Beats() = default;
+
+  explicit Beats(const double beats)
+    : mValue(std::llround(beats * 1e6))
+  {
+  }
+
+  explicit Beats(const std::int64_t microBeats)
+    : mValue(microBeats)
+  {
+  }
+
+  double floating() const
+  {
+    return static_cast<double>(mValue) / 1e6;
+  }
+
+  std::int64_t microBeats() const
+  {
+    return mValue;
+  }
+
+  Beats operator-() const
+  {
+    return Beats{-mValue};
+  }
+
+  friend Beats abs(const Beats b)
+  {
+    return Beats{std::abs(b.mValue)};
+  }
+
+  friend Beats operator+(const Beats lhs, const Beats rhs)
+  {
+    return Beats{lhs.mValue + rhs.mValue};
+  }
+
+  friend Beats operator-(const Beats lhs, const Beats rhs)
+  {
+    return Beats{lhs.mValue - rhs.mValue};
+  }
+
+  friend Beats operator%(const Beats lhs, const Beats rhs)
+  {
+    return Beats{rhs.mValue == 0 ? 0 : (lhs.mValue % rhs.mValue)};
+  }
+
+  friend bool operator<(const Beats lhs, const Beats rhs)
+  {
+    return lhs.mValue < rhs.mValue;
+  }
+
+  friend bool operator>(const Beats lhs, const Beats rhs)
+  {
+    return lhs.mValue > rhs.mValue;
+  }
+
+  friend bool operator==(const Beats lhs, const Beats rhs)
+  {
+    return lhs.mValue == rhs.mValue;
+  }
+
+  friend bool operator!=(const Beats lhs, const Beats rhs)
+  {
+    return lhs.mValue != rhs.mValue;
+  }
+
+  // Model the NetworkByteStreamSerializable concept
+  friend std::uint32_t sizeInByteStream(const Beats beats)
+  {
+    return discovery::sizeInByteStream(beats.microBeats());
+  }
+
+  template <typename It>
+  friend It toNetworkByteStream(const Beats beats, It out)
+  {
+    return discovery::toNetworkByteStream(beats.microBeats(), std::move(out));
+  }
+
+  template <typename It>
+  static std::pair<Beats, It> fromNetworkByteStream(It begin, It end)
+  {
+    auto result = discovery::Deserialize<std::int64_t>::fromNetworkByteStream(
+      std::move(begin), std::move(end));
+    return std::make_pair(Beats{result.first}, std::move(result.second));
+  }
+
+private:
+  std::int64_t mValue = 0;
+};
+
+} // namespace link
+} // namespace ableton
diff --git a/link/include/ableton/link/ClientSessionTimelines.hpp b/link/include/ableton/link/ClientSessionTimelines.hpp
new file mode 100644
--- /dev/null
+++ b/link/include/ableton/link/ClientSessionTimelines.hpp
@@ -0,0 +1,115 @@
+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.
+ *
+ *  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 2 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 <http://www.gnu.org/licenses/>.
+ *
+ *  If you would like to incorporate Link into a proprietary software application,
+ *  please contact <link-devs@ableton.com>.
+ */
+
+#pragma once
+
+#include <ableton/link/GhostXForm.hpp>
+#include <ableton/link/Timeline.hpp>
+
+namespace ableton
+{
+namespace link
+{
+
+// Clamp the tempo of the given timeline to the valid Link range
+inline Timeline clampTempo(const Timeline timeline)
+{
+  const double kMinBpm = 20.0;
+  const double kMaxBpm = 999.0;
+  return {Tempo{(std::min)((std::max)(timeline.tempo.bpm(), kMinBpm), kMaxBpm)},
+    timeline.beatOrigin, timeline.timeOrigin};
+}
+
+// Given an existing client timeline, a session timeline, and the
+// global host transform of the session, return a new version of the client
+// timeline. The resulting new client timeline is continuous with the
+// previous timeline so that curClient.toBeats(atTime) ==
+// result.toBeats(atTime).
+inline Timeline updateClientTimelineFromSession(const Timeline curClient,
+  const Timeline session,
+  const std::chrono::microseconds atTime,
+  const GhostXForm xform)
+{
+  // An intermediate timeline representing the continuation of the
+  // existing client timeline with the tempo from the session timeline.
+  const auto tempTl = Timeline{session.tempo, curClient.toBeats(atTime), atTime};
+  // The host time corresponding to beat 0 on the session
+  // timeline. Beat 0 on the session timeline is important because it
+  // serves as the origin of the quantization grid for all participants.
+  const auto hostBeatZero = xform.ghostToHost(session.fromBeats(Beats{INT64_C(0)}));
+  // The new client timeline becomes the result of sliding the
+  // intermediate timeline back so that it's anchor corresponds to
+  // beat zero on the session timeline. The result preserves the
+  // magnitude of beats on the client timeline while encoding the
+  // quantization reference point in the time and beatOrigins.
+  return {tempTl.tempo, tempTl.toBeats(hostBeatZero), hostBeatZero};
+}
+
+
+inline Timeline updateSessionTimelineFromClient(const Timeline curSession,
+  const Timeline client,
+  const std::chrono::microseconds atTime,
+  const GhostXForm xform)
+{
+  // The client timeline was constructed so that it's timeOrigin
+  // corresponds to beat 0 on the session timeline.
+  const auto ghostBeat0 = xform.hostToGhost(client.timeOrigin);
+
+  const auto zero = Beats{INT64_C(0)};
+  // If beat 0 was not shifted and there is not a new tempo, an update
+  // of the session timeline is not required. Don't create an
+  // equivalent timeline with different anchor points if not needed as
+  // this will trigger other unnecessary changes.
+  if (curSession.toBeats(ghostBeat0) == zero && client.tempo == curSession.tempo)
+  {
+    return curSession;
+  }
+  else
+  {
+    // An intermediate timeline representing the new tempo, the
+    // effective time, and a possibly adjusted origin.
+    const auto tempTl = Timeline{client.tempo, zero, ghostBeat0};
+    // The final session timeline must have the beat corresponding to
+    // atTime on the old session timeline as its beatOrigin because this is
+    // used for prioritization of timelines among peers - we can't let a
+    // modification applied by the client artificially increase or
+    // reduce the timeline's priority in the session. The new beat
+    // origin should be as close as possible to lining up with atTime,
+    // but we must also make sure that it's > curSession.beatOrigin
+    // because otherwise it will get ignored.
+    const auto newBeatOrigin = (std::max)(curSession.toBeats(xform.hostToGhost(atTime)),
+      curSession.beatOrigin + Beats{INT64_C(1)});
+    return {client.tempo, newBeatOrigin, tempTl.fromBeats(newBeatOrigin)};
+  }
+}
+
+// Shift timeline so result.toBeats(t) == client.toBeats(t) +
+// shift. This takes into account the fact that the timeOrigin
+// corresponds to beat 0 on the session timeline. Using this function
+// and then setting the session timeline with the result will change
+// the phase of the session by the given shift amount.
+inline Timeline shiftClientTimeline(Timeline client, const Beats shift)
+{
+  const auto timeDelta = client.fromBeats(shift) - client.fromBeats(Beats{INT64_C(0)});
+  client.timeOrigin = client.timeOrigin - timeDelta;
+  return client;
+}
+
+} // namespace link
+} // namespace ableton
diff --git a/link/include/ableton/link/Controller.hpp b/link/include/ableton/link/Controller.hpp
new file mode 100644
--- /dev/null
+++ b/link/include/ableton/link/Controller.hpp
@@ -0,0 +1,792 @@
+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.
+ *
+ *  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 2 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 <http://www.gnu.org/licenses/>.
+ *
+ *  If you would like to incorporate Link into a proprietary software application,
+ *  please contact <link-devs@ableton.com>.
+ */
+
+#pragma once
+
+#include <ableton/discovery/Service.hpp>
+#include <ableton/link/ClientSessionTimelines.hpp>
+#include <ableton/link/Gateway.hpp>
+#include <ableton/link/GhostXForm.hpp>
+#include <ableton/link/NodeState.hpp>
+#include <ableton/link/Peers.hpp>
+#include <ableton/link/SessionState.hpp>
+#include <ableton/link/Sessions.hpp>
+#include <ableton/link/StartStopState.hpp>
+#include <ableton/link/TripleBuffer.hpp>
+#include <condition_variable>
+#include <mutex>
+
+namespace ableton
+{
+namespace link
+{
+namespace detail
+{
+
+template <typename Clock>
+GhostXForm initXForm(const Clock& clock)
+{
+  // Make the current time map to a ghost time of 0 with ghost time
+  // increasing at the same rate as clock time
+  return {1.0, -clock.micros()};
+}
+
+template <typename Clock>
+inline SessionState initSessionState(const Tempo tempo, const Clock& clock)
+{
+  using namespace std::chrono;
+  return {clampTempo(Timeline{tempo, Beats{0.}, microseconds{0}}),
+    StartStopState{false, Beats{0.}, microseconds{0}}, initXForm(clock)};
+}
+
+inline ClientState initClientState(const SessionState& sessionState)
+{
+  const auto hostTime = sessionState.ghostXForm.ghostToHost(std::chrono::microseconds{0});
+  return {
+    Timeline{sessionState.timeline.tempo, sessionState.timeline.beatOrigin, hostTime},
+    ClientStartStopState{sessionState.startStopState.isPlaying, hostTime, hostTime}};
+}
+
+inline RtClientState initRtClientState(const ClientState& clientState)
+{
+  using namespace std::chrono;
+  return {
+    clientState.timeline, clientState.startStopState, microseconds{0}, microseconds{0}};
+}
+
+// The timespan in which local modifications to the timeline will be
+// preferred over any modifications coming from the network.
+const auto kLocalModGracePeriod = std::chrono::milliseconds(1000);
+const auto kRtHandlerFallbackPeriod = kLocalModGracePeriod / 2;
+
+inline ClientStartStopState selectPreferredStartStopState(
+  const ClientStartStopState currentStartStopState,
+  const ClientStartStopState startStopState)
+{
+  return startStopState.timestamp > currentStartStopState.timestamp
+           ? startStopState
+           : currentStartStopState;
+}
+
+inline ClientStartStopState mapStartStopStateFromSessionToClient(
+  const StartStopState& sessionStartStopState,
+  const Timeline& sessionTimeline,
+  const GhostXForm& xForm)
+{
+  const auto time =
+    xForm.ghostToHost(sessionTimeline.fromBeats(sessionStartStopState.beats));
+  const auto timestamp = xForm.ghostToHost(sessionStartStopState.timestamp);
+  return ClientStartStopState{sessionStartStopState.isPlaying, time, timestamp};
+}
+
+inline StartStopState mapStartStopStateFromClientToSession(
+  const ClientStartStopState& clientStartStopState,
+  const Timeline& sessionTimeline,
+  const GhostXForm& xForm)
+{
+  const auto sessionBeats =
+    sessionTimeline.toBeats(xForm.hostToGhost(clientStartStopState.time));
+  const auto timestamp = xForm.hostToGhost(clientStartStopState.timestamp);
+  return StartStopState{clientStartStopState.isPlaying, sessionBeats, timestamp};
+}
+
+} // namespace detail
+
+// function types corresponding to the Controller callback type params
+using PeerCountCallback = std::function<void(std::size_t)>;
+using TempoCallback = std::function<void(ableton::link::Tempo)>;
+using StartStopStateCallback = std::function<void(bool)>;
+
+
+// The main Link controller
+template <typename PeerCountCallback,
+  typename TempoCallback,
+  typename StartStopStateCallback,
+  typename Clock,
+  typename Random,
+  typename IoContext>
+class Controller
+{
+public:
+  Controller(Tempo tempo,
+    PeerCountCallback peerCallback,
+    TempoCallback tempoCallback,
+    StartStopStateCallback startStopStateCallback,
+    Clock clock)
+    : mTempoCallback(std::move(tempoCallback))
+    , mStartStopStateCallback(std::move(startStopStateCallback))
+    , mClock(std::move(clock))
+    , mNodeId(NodeId::random<Random>())
+    , mSessionId(mNodeId)
+    , mSessionState(detail::initSessionState(tempo, mClock))
+    , mClientState(detail::initClientState(mSessionState))
+    , mLastIsPlayingForStartStopStateCallback(false)
+    , mRtClientState(detail::initRtClientState(mClientState.get()))
+    , mHasPendingRtClientStates(false)
+    , mSessionPeerCounter(*this, std::move(peerCallback))
+    , mEnabled(false)
+    , mStartStopSyncEnabled(false)
+    , mIo(IoContext{UdpSendExceptionHandler{this}})
+    , mRtClientStateSetter(*this)
+    , mPeers(util::injectRef(*mIo),
+        std::ref(mSessionPeerCounter),
+        SessionTimelineCallback{*this},
+        SessionStartStopStateCallback{*this})
+    , mSessions(
+        {mSessionId, mSessionState.timeline, {mSessionState.ghostXForm, mClock.micros()}},
+        util::injectRef(mPeers),
+        MeasurePeer{*this},
+        JoinSessionCallback{*this},
+        util::injectRef(*mIo),
+        mClock)
+    , mDiscovery(std::make_pair(NodeState{mNodeId, mSessionId, mSessionState.timeline,
+                                  mSessionState.startStopState},
+                   mSessionState.ghostXForm),
+        GatewayFactory{*this},
+        util::injectRef(*mIo))
+  {
+  }
+
+  Controller(const Controller&) = delete;
+  Controller(Controller&&) = delete;
+
+  Controller& operator=(const Controller&) = delete;
+  Controller& operator=(Controller&&) = delete;
+
+  ~Controller()
+  {
+    std::mutex mutex;
+    std::condition_variable condition;
+    auto stopped = false;
+
+    mIo->async([this, &mutex, &condition, &stopped]() {
+      enable(false);
+      std::unique_lock<std::mutex> lock(mutex);
+      stopped = true;
+      condition.notify_one();
+    });
+
+    std::unique_lock<std::mutex> lock(mutex);
+    condition.wait(lock, [&stopped] { return stopped; });
+
+    mIo->stop();
+  }
+
+  void enable(const bool bEnable)
+  {
+    const bool bWasEnabled = mEnabled.exchange(bEnable);
+    if (bWasEnabled != bEnable)
+    {
+      mIo->async([this, bEnable] {
+        if (bEnable)
+        {
+          // Process the pending client states to make sure we don't push one after we
+          // have joined a running session
+          mRtClientStateSetter.processPendingClientStates();
+          // Always reset when first enabling to avoid hijacking
+          // tempo in existing sessions
+          resetState();
+        }
+        mDiscovery.enable(bEnable);
+      });
+    }
+  }
+
+  bool isEnabled() const
+  {
+    return mEnabled;
+  }
+
+  void enableStartStopSync(const bool bEnable)
+  {
+    mStartStopSyncEnabled = bEnable;
+  }
+
+  bool isStartStopSyncEnabled() const
+  {
+    return mStartStopSyncEnabled;
+  }
+
+  std::size_t numPeers() const
+  {
+    return mSessionPeerCounter.mSessionPeerCount;
+  }
+
+  // Get the current Link client state. Thread-safe but may block, so
+  // it cannot be used from audio thread.
+  ClientState clientState() const
+  {
+    return mClientState.get();
+  }
+
+  // Set the client state to be used, starting at the given time.
+  // Thread-safe but may block, so it cannot be used from audio thread.
+  void setClientState(IncomingClientState newClientState)
+  {
+    mClientState.update([&](ClientState& clientState) {
+      if (newClientState.timeline)
+      {
+        *newClientState.timeline = clampTempo(*newClientState.timeline);
+        clientState.timeline = *newClientState.timeline;
+      }
+      if (newClientState.startStopState)
+      {
+        // Prevent updating client start stop state with an outdated start stop state
+        *newClientState.startStopState = detail::selectPreferredStartStopState(
+          clientState.startStopState, *newClientState.startStopState);
+        clientState.startStopState = *newClientState.startStopState;
+      }
+    });
+    mIo->async([this, newClientState] { handleClientState(newClientState); });
+  }
+
+  // Non-blocking client state access for a realtime context. NOT
+  // thread-safe. Must not be called from multiple threads
+  // concurrently and must not be called concurrently with setClientStateRtSafe.
+  ClientState clientStateRtSafe() const
+  {
+    // Respect the session state guard and the client state guard but don't
+    // block on them. If we can't access one or both because of concurrent modification
+    // we fall back to our cached version of the timeline and/or start stop state.
+
+    if (!mHasPendingRtClientStates)
+    {
+      const auto now = mClock.micros();
+      const auto timelineGracePeriodOver =
+        now - mRtClientState.timelineTimestamp > detail::kLocalModGracePeriod;
+      const auto startStopStateGracePeriodOver =
+        now - mRtClientState.startStopStateTimestamp > detail::kLocalModGracePeriod;
+
+      if (timelineGracePeriodOver || startStopStateGracePeriodOver)
+      {
+        const auto clientState = mClientState.getRt();
+
+        if (timelineGracePeriodOver && clientState.timeline != mRtClientState.timeline)
+        {
+          mRtClientState.timeline = clientState.timeline;
+        }
+
+        if (startStopStateGracePeriodOver
+            && clientState.startStopState != mRtClientState.startStopState)
+        {
+          mRtClientState.startStopState = clientState.startStopState;
+        }
+      }
+    }
+
+    return {mRtClientState.timeline, mRtClientState.startStopState};
+  }
+
+  // should only be called from the audio thread
+  void setClientStateRtSafe(IncomingClientState newClientState)
+  {
+    if (!newClientState.timeline && !newClientState.startStopState)
+    {
+      return;
+    }
+
+    if (newClientState.timeline)
+    {
+      *newClientState.timeline = clampTempo(*newClientState.timeline);
+    }
+
+    if (newClientState.startStopState)
+    {
+      // Prevent updating client start stop state with an outdated start stop state
+      *newClientState.startStopState = detail::selectPreferredStartStopState(
+        mRtClientState.startStopState, *newClientState.startStopState);
+    }
+
+    // This flag ensures that mRtClientState is only updated after all incoming
+    // client states were processed
+    mHasPendingRtClientStates = true;
+    mRtClientStateSetter.push(newClientState);
+    const auto now = mClock.micros();
+    // Cache the new timeline and StartStopState for serving back to the client
+    if (newClientState.timeline)
+    {
+      // Cache the new timeline and StartStopState for serving back to the client
+      mRtClientState.timeline = *newClientState.timeline;
+      mRtClientState.timelineTimestamp = makeRtTimestamp(now);
+    }
+    if (newClientState.startStopState)
+    {
+      mRtClientState.startStopState = *newClientState.startStopState;
+      mRtClientState.startStopStateTimestamp = makeRtTimestamp(now);
+    }
+  }
+
+private:
+  std::chrono::microseconds makeRtTimestamp(const std::chrono::microseconds now) const
+  {
+    return isEnabled() ? now : std::chrono::microseconds(0);
+  }
+
+  void invokeStartStopStateCallbackIfChanged()
+  {
+    bool shouldInvokeCallback = false;
+
+    mClientState.update([&](ClientState& clientState) {
+      shouldInvokeCallback =
+        mLastIsPlayingForStartStopStateCallback != clientState.startStopState.isPlaying;
+      mLastIsPlayingForStartStopStateCallback = clientState.startStopState.isPlaying;
+    });
+
+    if (shouldInvokeCallback)
+    {
+      mStartStopStateCallback(mLastIsPlayingForStartStopStateCallback);
+    }
+  }
+
+  void updateDiscovery()
+  {
+    // Push the change to the discovery service
+    mDiscovery.updateNodeState(
+      std::make_pair(NodeState{mNodeId, mSessionId, mSessionState.timeline,
+                       mSessionState.startStopState},
+        mSessionState.ghostXForm));
+  }
+
+  void updateSessionTiming(Timeline newTimeline, const GhostXForm newXForm)
+  {
+    // Clamp the session tempo because it may slightly overshoot (999 bpm is
+    // transferred as 60606 us/beat and received as 999.000999... bpm).
+    newTimeline = clampTempo(newTimeline);
+    const auto oldTimeline = mSessionState.timeline;
+    const auto oldXForm = mSessionState.ghostXForm;
+
+    if (oldTimeline != newTimeline || oldXForm != newXForm)
+    {
+      {
+        std::lock_guard<std::mutex> lock(mSessionStateGuard);
+        mSessionState.timeline = newTimeline;
+        mSessionState.ghostXForm = newXForm;
+      }
+
+      // Update the client timeline and start stop state based on the new session timing
+      mClientState.update([&](ClientState& clientState) {
+        clientState.timeline = updateClientTimelineFromSession(clientState.timeline,
+          mSessionState.timeline, mClock.micros(), mSessionState.ghostXForm);
+        // Don't pass the start stop state to the client when start stop sync is disabled
+        // or when we have a default constructed start stop state
+        if (mStartStopSyncEnabled && mSessionState.startStopState != StartStopState{})
+        {
+          std::lock_guard<std::mutex> startStopStateLock(mSessionStateGuard);
+          clientState.startStopState =
+            detail::mapStartStopStateFromSessionToClient(mSessionState.startStopState,
+              mSessionState.timeline, mSessionState.ghostXForm);
+        }
+      });
+
+      if (oldTimeline.tempo != newTimeline.tempo)
+      {
+        mTempoCallback(newTimeline.tempo);
+      }
+    }
+  }
+
+  void handleTimelineFromSession(SessionId id, Timeline timeline)
+  {
+    debug(mIo->log()) << "Received timeline with tempo: " << timeline.tempo.bpm()
+                      << " for session: " << id;
+    updateSessionTiming(mSessions.sawSessionTimeline(std::move(id), std::move(timeline)),
+      mSessionState.ghostXForm);
+    updateDiscovery();
+  }
+
+  void resetSessionStartStopState()
+  {
+    mSessionState.startStopState = StartStopState{};
+  }
+
+  void handleStartStopStateFromSession(SessionId sessionId, StartStopState startStopState)
+  {
+    debug(mIo->log()) << "Received start stop state. isPlaying: "
+                      << startStopState.isPlaying
+                      << ", beats: " << startStopState.beats.floating()
+                      << ", time: " << startStopState.timestamp.count()
+                      << " for session: " << sessionId;
+    if (sessionId == mSessionId
+        && startStopState.timestamp > mSessionState.startStopState.timestamp)
+    {
+      mSessionState.startStopState = startStopState;
+
+      // Always propagate the session start stop state so even a client that doesn't have
+      // the feature enabled can function as a relay.
+      updateDiscovery();
+
+      if (mStartStopSyncEnabled)
+      {
+        mClientState.update([&](ClientState& clientState) {
+          clientState.startStopState = detail::mapStartStopStateFromSessionToClient(
+            startStopState, mSessionState.timeline, mSessionState.ghostXForm);
+        });
+        invokeStartStopStateCallbackIfChanged();
+      }
+    }
+  }
+
+  void handleClientState(const IncomingClientState clientState)
+  {
+    auto mustUpdateDiscovery = false;
+
+    if (clientState.timeline)
+    {
+      auto sessionTimeline = updateSessionTimelineFromClient(mSessionState.timeline,
+        *clientState.timeline, clientState.timelineTimestamp, mSessionState.ghostXForm);
+
+      mSessions.resetTimeline(sessionTimeline);
+      mPeers.setSessionTimeline(mSessionId, sessionTimeline);
+      updateSessionTiming(std::move(sessionTimeline), mSessionState.ghostXForm);
+
+      mustUpdateDiscovery = true;
+    }
+
+    if (mStartStopSyncEnabled && clientState.startStopState)
+    {
+      // Prevent updating with an outdated start stop state
+      const auto newGhostTime =
+        mSessionState.ghostXForm.hostToGhost(clientState.startStopState->timestamp);
+      if (newGhostTime > mSessionState.startStopState.timestamp)
+      {
+        mClientState.update([&](ClientState& currentClientState) {
+          mSessionState.startStopState =
+            detail::mapStartStopStateFromClientToSession(*clientState.startStopState,
+              mSessionState.timeline, mSessionState.ghostXForm);
+          currentClientState.startStopState = *clientState.startStopState;
+        });
+
+        mustUpdateDiscovery = true;
+      }
+    }
+
+    if (mustUpdateDiscovery)
+    {
+      updateDiscovery();
+    }
+
+    invokeStartStopStateCallbackIfChanged();
+  }
+
+  void handleRtClientState(IncomingClientState clientState)
+  {
+    mClientState.update([&](ClientState& currentClientState) {
+      if (clientState.timeline)
+      {
+        currentClientState.timeline = *clientState.timeline;
+      }
+      if (clientState.startStopState)
+      {
+        // Prevent updating client start stop state with an outdated start stop state
+        *clientState.startStopState = detail::selectPreferredStartStopState(
+          currentClientState.startStopState, *clientState.startStopState);
+        currentClientState.startStopState = *clientState.startStopState;
+      }
+    });
+
+    handleClientState(clientState);
+    mHasPendingRtClientStates = false;
+  }
+
+  void joinSession(const Session& session)
+  {
+    const bool sessionIdChanged = mSessionId != session.sessionId;
+    mSessionId = session.sessionId;
+
+    // Prevent passing the state of the previous session to the new one.
+    if (sessionIdChanged)
+    {
+      mRtClientStateSetter.processPendingClientStates();
+      resetSessionStartStopState();
+    }
+
+    updateSessionTiming(session.timeline, session.measurement.xform);
+    updateDiscovery();
+
+    if (sessionIdChanged)
+    {
+      debug(mIo->log()) << "Joining session " << session.sessionId << " with tempo "
+                        << session.timeline.tempo.bpm();
+      mSessionPeerCounter();
+    }
+  }
+
+  void resetState()
+  {
+    mNodeId = NodeId::random<Random>();
+    mSessionId = mNodeId;
+
+    const auto xform = detail::initXForm(mClock);
+    const auto hostTime = -xform.intercept;
+    // When creating the new timeline, make it continuous by finding
+    // the beat on the old session timeline corresponding to the
+    // current host time and mapping it to the new ghost time
+    // representation of the current host time.
+    const auto newTl = Timeline{mSessionState.timeline.tempo,
+      mSessionState.timeline.toBeats(mSessionState.ghostXForm.hostToGhost(hostTime)),
+      xform.hostToGhost(hostTime)};
+
+    resetSessionStartStopState();
+
+    updateSessionTiming(newTl, xform);
+    updateDiscovery();
+
+    mSessions.resetSession({mNodeId, newTl, {xform, hostTime}});
+    mPeers.resetPeers();
+  }
+
+  struct SessionTimelineCallback
+  {
+    void operator()(SessionId id, Timeline timeline)
+    {
+      mController.handleTimelineFromSession(std::move(id), std::move(timeline));
+    }
+
+    Controller& mController;
+  };
+
+  struct RtClientStateSetter
+  {
+    using CallbackDispatcher =
+      typename IoContext::template LockFreeCallbackDispatcher<std::function<void()>,
+        std::chrono::milliseconds>;
+
+    RtClientStateSetter(Controller& controller)
+      : mController(controller)
+      , mCallbackDispatcher(
+          [this] { mController.mIo->async([this]() { processPendingClientStates(); }); },
+          detail::kRtHandlerFallbackPeriod)
+    {
+    }
+
+    void push(const IncomingClientState clientState)
+    {
+      if (clientState.timeline)
+      {
+        mTimelineBuffer.write(
+          std::make_pair(clientState.timelineTimestamp, *clientState.timeline));
+      }
+
+      if (clientState.startStopState)
+      {
+        mStartStopStateBuffer.write(*clientState.startStopState);
+      }
+
+      if (clientState.timeline || clientState.startStopState)
+      {
+        mCallbackDispatcher.invoke();
+      }
+    }
+
+    void processPendingClientStates()
+    {
+      const auto clientState = buildMergedPendingClientState();
+      mController.handleRtClientState(clientState);
+    }
+
+  private:
+    IncomingClientState buildMergedPendingClientState()
+    {
+      auto clientState = IncomingClientState{};
+      if (auto tl = mTimelineBuffer.readNew())
+      {
+        clientState.timelineTimestamp = (*tl).first;
+        clientState.timeline = OptionalTimeline{(*tl).second};
+      }
+      if (auto sss = mStartStopStateBuffer.readNew())
+      {
+        clientState.startStopState = sss;
+      }
+      return clientState;
+    }
+
+    Controller& mController;
+    // Use separate TripleBuffers for the Timeline and the StartStopState so we read the
+    // latest set value from either optional.
+    TripleBuffer<std::pair<std::chrono::microseconds, Timeline>> mTimelineBuffer;
+    TripleBuffer<ClientStartStopState> mStartStopStateBuffer;
+    CallbackDispatcher mCallbackDispatcher;
+  };
+
+  struct SessionStartStopStateCallback
+  {
+    void operator()(SessionId sessionId, StartStopState startStopState)
+    {
+      mController.handleStartStopStateFromSession(sessionId, startStopState);
+    }
+
+    Controller& mController;
+  };
+
+  struct SessionPeerCounter
+  {
+    SessionPeerCounter(Controller& controller, PeerCountCallback callback)
+      : mController(controller)
+      , mCallback(std::move(callback))
+      , mSessionPeerCount(0)
+    {
+    }
+
+    void operator()()
+    {
+      const auto count =
+        mController.mPeers.uniqueSessionPeerCount(mController.mSessionId);
+      const auto oldCount = mSessionPeerCount.exchange(count);
+      if (oldCount != count)
+      {
+        if (count == 0)
+        {
+          // When the count goes down to zero, completely reset the
+          // state, effectively founding a new session
+          mController.mIo->async([this] { mController.resetState(); });
+        }
+        mCallback(count);
+      }
+    }
+
+    Controller& mController;
+    PeerCountCallback mCallback;
+    std::atomic<std::size_t> mSessionPeerCount;
+  };
+
+  struct MeasurePeer
+  {
+    template <typename Peer, typename Handler>
+    void operator()(Peer peer, Handler handler)
+    {
+      using It = typename Discovery::ServicePeerGateways::GatewayMap::iterator;
+      using ValueType = typename Discovery::ServicePeerGateways::GatewayMap::value_type;
+      mController.mDiscovery.withGateways([peer, handler](It begin, const It end) {
+        const auto addr = peer.second;
+        const auto it = std::find_if(
+          begin, end, [&addr](const ValueType& vt) { return vt.first == addr; });
+        if (it != end)
+        {
+          it->second->measurePeer(std::move(peer.first), std::move(handler));
+        }
+        else
+        {
+          // invoke the handler with an empty result if we couldn't
+          // find the peer's gateway
+          handler(GhostXForm{});
+        }
+      });
+    }
+
+    Controller& mController;
+  };
+
+  struct JoinSessionCallback
+  {
+    void operator()(Session session)
+    {
+      mController.joinSession(std::move(session));
+    }
+
+    Controller& mController;
+  };
+
+  using IoType = typename util::Injected<IoContext>::type;
+
+  using ControllerPeers = Peers<IoType&,
+    std::reference_wrapper<SessionPeerCounter>,
+    SessionTimelineCallback,
+    SessionStartStopStateCallback>;
+
+  using ControllerGateway =
+    Gateway<typename ControllerPeers::GatewayObserver, Clock, IoType&>;
+  using GatewayPtr = std::shared_ptr<ControllerGateway>;
+
+  struct GatewayFactory
+  {
+    GatewayPtr operator()(std::pair<NodeState, GhostXForm> state,
+      util::Injected<IoType&> io,
+      const asio::ip::address& addr)
+    {
+      if (addr.is_v4())
+      {
+        return GatewayPtr{new ControllerGateway{std::move(io), addr.to_v4(),
+          util::injectVal(makeGatewayObserver(mController.mPeers, addr)),
+          std::move(state.first), std::move(state.second), mController.mClock}};
+      }
+      else
+      {
+        throw std::runtime_error("Could not create peer gateway on non-ipV4 address");
+      }
+    }
+
+    Controller& mController;
+  };
+
+  struct UdpSendExceptionHandler
+  {
+    using Exception = discovery::UdpSendException;
+
+    void operator()(const Exception exception)
+    {
+      mpController->mIo->async([this, exception] {
+        mpController->mDiscovery.repairGateway(exception.interfaceAddr);
+      });
+    }
+
+    Controller* mpController;
+  };
+
+  TempoCallback mTempoCallback;
+  StartStopStateCallback mStartStopStateCallback;
+  Clock mClock;
+  NodeId mNodeId;
+  SessionId mSessionId;
+
+  mutable std::mutex mSessionStateGuard;
+  SessionState mSessionState;
+
+  ControllerClientState mClientState;
+  bool mLastIsPlayingForStartStopStateCallback;
+
+  mutable RtClientState mRtClientState;
+  std::atomic<bool> mHasPendingRtClientStates;
+
+  SessionPeerCounter mSessionPeerCounter;
+
+  std::atomic<bool> mEnabled;
+
+  std::atomic<bool> mStartStopSyncEnabled;
+
+  util::Injected<IoContext> mIo;
+
+  RtClientStateSetter mRtClientStateSetter;
+
+  ControllerPeers mPeers;
+
+  using ControllerSessions = Sessions<ControllerPeers&,
+    MeasurePeer,
+    JoinSessionCallback,
+    typename util::Injected<IoContext>::type&,
+    Clock>;
+  ControllerSessions mSessions;
+
+  using Discovery = discovery::Service<std::pair<NodeState, GhostXForm>,
+    GatewayFactory,
+    typename util::Injected<IoContext>::type&>;
+  Discovery mDiscovery;
+};
+
+} // namespace link
+} // namespace ableton
diff --git a/link/include/ableton/link/Gateway.hpp b/link/include/ableton/link/Gateway.hpp
new file mode 100644
--- /dev/null
+++ b/link/include/ableton/link/Gateway.hpp
@@ -0,0 +1,93 @@
+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.
+ *
+ *  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 2 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 <http://www.gnu.org/licenses/>.
+ *
+ *  If you would like to incorporate Link into a proprietary software application,
+ *  please contact <link-devs@ableton.com>.
+ */
+
+#pragma once
+
+#include <ableton/discovery/PeerGateway.hpp>
+#include <ableton/link/MeasurementService.hpp>
+#include <ableton/link/PeerState.hpp>
+
+namespace ableton
+{
+namespace link
+{
+
+template <typename PeerObserver, typename Clock, typename IoContext>
+class Gateway
+{
+public:
+  Gateway(util::Injected<IoContext> io,
+    asio::ip::address_v4 addr,
+    util::Injected<PeerObserver> observer,
+    NodeState nodeState,
+    GhostXForm ghostXForm,
+    Clock clock)
+    : mIo(std::move(io))
+    , mMeasurement(addr,
+        nodeState.sessionId,
+        std::move(ghostXForm),
+        std::move(clock),
+        util::injectRef(*mIo))
+    , mPeerGateway(discovery::makeIpV4Gateway(util::injectRef(*mIo),
+        std::move(addr),
+        std::move(observer),
+        PeerState{std::move(nodeState), mMeasurement.endpoint()}))
+  {
+  }
+
+  Gateway(const Gateway& rhs) = delete;
+  Gateway& operator=(const Gateway& rhs) = delete;
+
+  Gateway(Gateway&& rhs)
+    : mIo(std::move(rhs.mIo))
+    , mMeasurement(std::move(rhs.mMeasurement))
+    , mPeerGateway(std::move(rhs.mPeerGateway))
+  {
+  }
+
+  Gateway& operator=(Gateway&& rhs)
+  {
+    mIo = std::move(rhs.mIo);
+    mMeasurement = std::move(rhs.mMeasurement);
+    mPeerGateway = std::move(rhs.mPeerGateway);
+    return *this;
+  }
+
+  void updateNodeState(std::pair<NodeState, GhostXForm> state)
+  {
+    mMeasurement.updateNodeState(state.first.sessionId, state.second);
+    mPeerGateway.updateState(PeerState{std::move(state.first), mMeasurement.endpoint()});
+  }
+
+  template <typename Handler>
+  void measurePeer(const PeerState& peer, Handler handler)
+  {
+    mMeasurement.measurePeer(peer, std::move(handler));
+  }
+
+private:
+  util::Injected<IoContext> mIo;
+  MeasurementService<Clock, typename util::Injected<IoContext>::type&> mMeasurement;
+  discovery::
+    IpV4Gateway<PeerObserver, PeerState, typename util::Injected<IoContext>::type&>
+      mPeerGateway;
+};
+
+} // namespace link
+} // namespace ableton
diff --git a/link/include/ableton/link/GhostXForm.hpp b/link/include/ableton/link/GhostXForm.hpp
new file mode 100644
--- /dev/null
+++ b/link/include/ableton/link/GhostXForm.hpp
@@ -0,0 +1,61 @@
+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.
+ *
+ *  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 2 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 <http://www.gnu.org/licenses/>.
+ *
+ *  If you would like to incorporate Link into a proprietary software application,
+ *  please contact <link-devs@ableton.com>.
+ */
+
+#pragma once
+
+#include <chrono>
+#include <cmath>
+
+namespace ableton
+{
+namespace link
+{
+
+using std::chrono::microseconds;
+
+struct GhostXForm
+{
+  microseconds hostToGhost(const microseconds hostTime) const
+  {
+    return microseconds{llround(slope * static_cast<double>(hostTime.count()))}
+           + intercept;
+  }
+
+  microseconds ghostToHost(const microseconds ghostTime) const
+  {
+    return microseconds{
+      llround(static_cast<double>((ghostTime - intercept).count()) / slope)};
+  }
+
+  friend bool operator==(const GhostXForm lhs, const GhostXForm rhs)
+  {
+    return lhs.slope == rhs.slope && lhs.intercept == rhs.intercept;
+  }
+
+  friend bool operator!=(const GhostXForm lhs, const GhostXForm rhs)
+  {
+    return !(lhs == rhs);
+  }
+
+  double slope;
+  microseconds intercept;
+};
+
+} // namespace link
+} // namespace ableton
diff --git a/link/include/ableton/link/HostTimeFilter.hpp b/link/include/ableton/link/HostTimeFilter.hpp
new file mode 100644
--- /dev/null
+++ b/link/include/ableton/link/HostTimeFilter.hpp
@@ -0,0 +1,86 @@
+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.
+ *
+ *  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 2 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 <http://www.gnu.org/licenses/>.
+ *
+ *  If you would like to incorporate Link into a proprietary software application,
+ *  please contact <link-devs@ableton.com>.
+ */
+
+#pragma once
+
+#include <ableton/link/LinearRegression.hpp>
+#include <chrono>
+#include <cmath>
+#include <utility>
+#include <vector>
+
+namespace ableton
+{
+namespace link
+{
+
+template <typename Clock, typename NumberType, std::size_t kNumPoints = 512>
+class BasicHostTimeFilter
+{
+  using Points = std::vector<std::pair<NumberType, NumberType>>;
+  using PointIt = typename Points::iterator;
+
+public:
+  BasicHostTimeFilter()
+    : mIndex(0)
+  {
+    mPoints.reserve(kNumPoints);
+  }
+
+  ~BasicHostTimeFilter() = default;
+
+  void reset()
+  {
+    mIndex = 0;
+    mPoints.clear();
+  }
+
+  std::chrono::microseconds sampleTimeToHostTime(const NumberType sampleTime)
+  {
+    const auto micros = static_cast<NumberType>(mHostTimeSampler.micros().count());
+    const auto point = std::make_pair(sampleTime, micros);
+
+    if (mPoints.size() < kNumPoints)
+    {
+      mPoints.push_back(point);
+    }
+    else
+    {
+      mPoints[mIndex] = point;
+    }
+    mIndex = (mIndex + 1) % kNumPoints;
+
+    const auto result = linearRegression(mPoints.begin(), mPoints.end());
+
+    const auto hostTime = (result.first * sampleTime) + result.second;
+
+    return std::chrono::microseconds(llround(hostTime));
+  }
+
+private:
+  std::size_t mIndex;
+  Points mPoints;
+  Clock mHostTimeSampler;
+};
+
+template <typename Clock>
+using HostTimeFilter = BasicHostTimeFilter<Clock, double, 512>;
+
+} // namespace link
+} // namespace ableton
diff --git a/link/include/ableton/link/LinearRegression.hpp b/link/include/ableton/link/LinearRegression.hpp
new file mode 100644
--- /dev/null
+++ b/link/include/ableton/link/LinearRegression.hpp
@@ -0,0 +1,61 @@
+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.
+ *
+ *  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 2 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 <http://www.gnu.org/licenses/>.
+ *
+ *  If you would like to incorporate Link into a proprietary software application,
+ *  please contact <link-devs@ableton.com>.
+ */
+
+#pragma once
+
+#include <cassert>
+#include <iterator>
+#include <utility>
+
+namespace ableton
+{
+namespace link
+{
+
+template <typename It>
+typename std::iterator_traits<It>::value_type linearRegression(It begin, It end)
+{
+  using NumberType =
+    typename std::tuple_element<0, typename std::iterator_traits<It>::value_type>::type;
+
+  NumberType sumX = 0.0;
+  NumberType sumXX = 0.0;
+  NumberType sumXY = 0.0;
+  NumberType sumY = 0.0;
+  for (auto i = begin; i != end; ++i)
+  {
+    sumX += i->first;
+    sumXX += i->first * i->first;
+    sumXY += i->first * i->second;
+    sumY += i->second;
+  }
+
+  const NumberType numPoints = static_cast<NumberType>(distance(begin, end));
+  assert(numPoints > 0);
+  const NumberType denominator = numPoints * sumXX - sumX * sumX;
+  const NumberType slope = denominator == NumberType{0}
+                             ? NumberType{0}
+                             : (numPoints * sumXY - sumX * sumY) / denominator;
+  const NumberType intercept = (sumY - slope * sumX) / numPoints;
+
+  return std::make_pair(slope, intercept);
+}
+
+} // namespace link
+} // namespace ableton
diff --git a/link/include/ableton/link/Measurement.hpp b/link/include/ableton/link/Measurement.hpp
new file mode 100644
--- /dev/null
+++ b/link/include/ableton/link/Measurement.hpp
@@ -0,0 +1,250 @@
+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.
+ *
+ *  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 2 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 <http://www.gnu.org/licenses/>.
+ *
+ *  If you would like to incorporate Link into a proprietary software application,
+ *  please contact <link-devs@ableton.com>.
+ */
+
+#pragma once
+
+#include <ableton/discovery/Payload.hpp>
+#include <ableton/link/PayloadEntries.hpp>
+#include <ableton/link/PeerState.hpp>
+#include <ableton/link/SessionId.hpp>
+#include <ableton/link/v1/Messages.hpp>
+#include <ableton/util/Injected.hpp>
+#include <ableton/util/SafeAsyncHandler.hpp>
+#include <chrono>
+#include <memory>
+
+namespace ableton
+{
+namespace link
+{
+
+template <typename Clock, typename IoContext>
+struct Measurement
+{
+  using Callback = std::function<void(std::vector<double>&)>;
+  using Micros = std::chrono::microseconds;
+
+  static const std::size_t kNumberDataPoints = 100;
+  static const std::size_t kNumberMeasurements = 5;
+
+  Measurement(const PeerState& state,
+    Callback callback,
+    asio::ip::address_v4 address,
+    Clock clock,
+    util::Injected<IoContext> io)
+    : mIo(std::move(io))
+    , mpImpl(std::make_shared<Impl>(
+        std::move(state), std::move(callback), std::move(address), std::move(clock), mIo))
+  {
+    mpImpl->listen();
+  }
+
+  Measurement(const Measurement&) = delete;
+  Measurement& operator=(Measurement&) = delete;
+  Measurement(const Measurement&&) = delete;
+  Measurement& operator=(Measurement&&) = delete;
+
+  struct Impl : std::enable_shared_from_this<Impl>
+  {
+    using Socket =
+      typename util::Injected<IoContext>::type::template Socket<v1::kMaxMessageSize>;
+    using Timer = typename util::Injected<IoContext>::type::Timer;
+    using Log = typename util::Injected<IoContext>::type::Log;
+
+    Impl(const PeerState& state,
+      Callback callback,
+      asio::ip::address_v4 address,
+      Clock clock,
+      util::Injected<IoContext> io)
+      : mSocket(io->template openUnicastSocket<v1::kMaxMessageSize>(address))
+      , mSessionId(state.nodeState.sessionId)
+      , mEndpoint(state.endpoint)
+      , mCallback(std::move(callback))
+      , mClock(std::move(clock))
+      , mTimer(io->makeTimer())
+      , mMeasurementsStarted(0)
+      , mLog(channel(io->log(), "Measurement on gateway@" + address.to_string()))
+      , mSuccess(false)
+    {
+      const auto ht = HostTime{mClock.micros()};
+      sendPing(mEndpoint, discovery::makePayload(ht));
+      resetTimer();
+    }
+
+    void resetTimer()
+    {
+      mTimer.cancel();
+      mTimer.expires_from_now(std::chrono::milliseconds(50));
+      mTimer.async_wait([this](const typename Timer::ErrorCode e) {
+        if (!e)
+        {
+          if (mMeasurementsStarted < kNumberMeasurements)
+          {
+            const auto ht = HostTime{mClock.micros()};
+            sendPing(mEndpoint, discovery::makePayload(ht));
+            ++mMeasurementsStarted;
+            resetTimer();
+          }
+          else
+          {
+            fail();
+          }
+        }
+      });
+    }
+
+    void listen()
+    {
+      mSocket.receive(util::makeAsyncSafe(this->shared_from_this()));
+    }
+
+    // Operator to handle incoming messages on the interface
+    template <typename It>
+    void operator()(
+      const asio::ip::udp::endpoint& from, const It messageBegin, const It messageEnd)
+    {
+      using namespace std;
+      const auto result = v1::parseMessageHeader(messageBegin, messageEnd);
+      const auto& header = result.first;
+      const auto payloadBegin = result.second;
+
+      if (header.messageType == v1::kPong)
+      {
+        debug(mLog) << "Received Pong message from " << from;
+
+        // parse for all entries
+        SessionId sessionId{};
+        std::chrono::microseconds ghostTime{0};
+        std::chrono::microseconds prevGHostTime{0};
+        std::chrono::microseconds prevHostTime{0};
+
+        try
+        {
+          discovery::parsePayload<SessionMembership, GHostTime, PrevGHostTime, HostTime>(
+            payloadBegin, messageEnd,
+            [&sessionId](const SessionMembership& sms) { sessionId = sms.sessionId; },
+            [&ghostTime](GHostTime gt) { ghostTime = std::move(gt.time); },
+            [&prevGHostTime](PrevGHostTime gt) { prevGHostTime = std::move(gt.time); },
+            [&prevHostTime](HostTime ht) { prevHostTime = std::move(ht.time); });
+        }
+        catch (const std::runtime_error& err)
+        {
+          warning(mLog) << "Failed parsing payload, caught exception: " << err.what();
+          listen();
+          return;
+        }
+
+        if (mSessionId == sessionId)
+        {
+          const auto hostTime = mClock.micros();
+
+          const auto payload =
+            discovery::makePayload(HostTime{hostTime}, PrevGHostTime{ghostTime});
+
+          sendPing(from, payload);
+          listen();
+
+
+          if (ghostTime != Micros{0} && prevHostTime != Micros{0})
+          {
+            mData.push_back(
+              static_cast<double>(ghostTime.count())
+              - (static_cast<double>((hostTime + prevHostTime).count()) * 0.5));
+
+            if (prevGHostTime != Micros{0})
+            {
+              mData.push_back(
+                (static_cast<double>((ghostTime + prevGHostTime).count()) * 0.5)
+                - static_cast<double>(prevHostTime.count()));
+            }
+          }
+
+          if (mData.size() > kNumberDataPoints)
+          {
+            finish();
+          }
+          else
+          {
+            resetTimer();
+          }
+        }
+        else
+        {
+          fail();
+        }
+      }
+      else
+      {
+        debug(mLog) << "Received invalid message from " << from;
+        listen();
+      }
+    }
+
+    template <typename Payload>
+    void sendPing(asio::ip::udp::endpoint to, const Payload& payload)
+    {
+      v1::MessageBuffer buffer;
+      const auto msgBegin = std::begin(buffer);
+      const auto msgEnd = v1::pingMessage(payload, msgBegin);
+      const auto numBytes = static_cast<size_t>(std::distance(msgBegin, msgEnd));
+
+      try
+      {
+        mSocket.send(buffer.data(), numBytes, to);
+      }
+      catch (const std::runtime_error& err)
+      {
+        info(mLog) << "Failed to send Ping to " << to.address().to_string() << ": "
+                   << err.what();
+      }
+    }
+
+    void finish()
+    {
+      mTimer.cancel();
+      mSuccess = true;
+      debug(mLog) << "Measuring " << mEndpoint << " done.";
+      mCallback(mData);
+    }
+
+    void fail()
+    {
+      mData.clear();
+      debug(mLog) << "Measuring " << mEndpoint << " failed.";
+      mCallback(mData);
+    }
+
+    Socket mSocket;
+    SessionId mSessionId;
+    asio::ip::udp::endpoint mEndpoint;
+    std::vector<double> mData;
+    Callback mCallback;
+    Clock mClock;
+    Timer mTimer;
+    std::size_t mMeasurementsStarted;
+    Log mLog;
+    bool mSuccess;
+  };
+
+  util::Injected<IoContext> mIo;
+  std::shared_ptr<Impl> mpImpl;
+};
+
+} // namespace link
+} // namespace ableton
diff --git a/link/include/ableton/link/MeasurementEndpointV4.hpp b/link/include/ableton/link/MeasurementEndpointV4.hpp
new file mode 100644
--- /dev/null
+++ b/link/include/ableton/link/MeasurementEndpointV4.hpp
@@ -0,0 +1,69 @@
+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.
+ *
+ *  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 2 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 <http://www.gnu.org/licenses/>.
+ *
+ *  If you would like to incorporate Link into a proprietary software application,
+ *  please contact <link-devs@ableton.com>.
+ */
+
+#pragma once
+
+#include <ableton/discovery/NetworkByteStreamSerializable.hpp>
+#include <ableton/platforms/asio/AsioWrapper.hpp>
+
+namespace ableton
+{
+namespace link
+{
+
+struct MeasurementEndpointV4
+{
+  static const std::int32_t key = 'mep4';
+  static_assert(key == 0x6d657034, "Unexpected byte order");
+
+  // Model the NetworkByteStreamSerializable concept
+  friend std::uint32_t sizeInByteStream(const MeasurementEndpointV4 mep)
+  {
+    return discovery::sizeInByteStream(
+             static_cast<std::uint32_t>(mep.ep.address().to_v4().to_ulong()))
+           + discovery::sizeInByteStream(mep.ep.port());
+  }
+
+  template <typename It>
+  friend It toNetworkByteStream(const MeasurementEndpointV4 mep, It out)
+  {
+    return discovery::toNetworkByteStream(mep.ep.port(),
+      discovery::toNetworkByteStream(
+        static_cast<std::uint32_t>(mep.ep.address().to_v4().to_ulong()), std::move(out)));
+  }
+
+  template <typename It>
+  static std::pair<MeasurementEndpointV4, It> fromNetworkByteStream(It begin, It end)
+  {
+    using namespace std;
+    auto addrRes =
+      discovery::Deserialize<std::uint32_t>::fromNetworkByteStream(std::move(begin), end);
+    auto portRes = discovery::Deserialize<std::uint16_t>::fromNetworkByteStream(
+      std::move(addrRes.second), end);
+    return make_pair(
+      MeasurementEndpointV4{
+        {asio::ip::address_v4{std::move(addrRes.first)}, std::move(portRes.first)}},
+      std::move(portRes.second));
+  }
+
+  asio::ip::udp::endpoint ep;
+};
+
+} // namespace link
+} // namespace ableton
diff --git a/link/include/ableton/link/MeasurementService.hpp b/link/include/ableton/link/MeasurementService.hpp
new file mode 100644
--- /dev/null
+++ b/link/include/ableton/link/MeasurementService.hpp
@@ -0,0 +1,144 @@
+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.
+ *
+ *  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 2 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 <http://www.gnu.org/licenses/>.
+ *
+ *  If you would like to incorporate Link into a proprietary software application,
+ *  please contact <link-devs@ableton.com>.
+ */
+
+#pragma once
+
+#include <ableton/link/GhostXForm.hpp>
+#include <ableton/link/LinearRegression.hpp>
+#include <ableton/link/Measurement.hpp>
+#include <ableton/link/Median.hpp>
+#include <ableton/link/PeerState.hpp>
+#include <ableton/link/PingResponder.hpp>
+#include <ableton/link/SessionId.hpp>
+#include <ableton/link/v1/Messages.hpp>
+#include <map>
+#include <memory>
+
+namespace ableton
+{
+namespace link
+{
+
+template <typename Clock, typename IoContext>
+class MeasurementService
+{
+public:
+  using IoType = util::Injected<IoContext>;
+  using MeasurementInstance = Measurement<Clock, IoContext>;
+
+  MeasurementService(asio::ip::address_v4 address,
+    SessionId sessionId,
+    GhostXForm ghostXForm,
+    Clock clock,
+    IoType io)
+    : mClock(std::move(clock))
+    , mIo(std::move(io))
+    , mPingResponder(std::move(address),
+        std::move(sessionId),
+        std::move(ghostXForm),
+        mClock,
+        util::injectRef(*mIo))
+  {
+  }
+
+  MeasurementService(const MeasurementService&) = delete;
+  MeasurementService(MeasurementService&&) = delete;
+
+  void updateNodeState(const SessionId& sessionId, const GhostXForm& xform)
+  {
+    mPingResponder.updateNodeState(sessionId, xform);
+  }
+
+  asio::ip::udp::endpoint endpoint() const
+  {
+    return mPingResponder.endpoint();
+  }
+
+  // Measure the peer and invoke the handler with a GhostXForm
+  template <typename Handler>
+  void measurePeer(const PeerState& state, const Handler handler)
+  {
+    using namespace std;
+
+    const auto nodeId = state.nodeState.nodeId;
+    auto addr = mPingResponder.endpoint().address().to_v4();
+    auto callback = CompletionCallback<Handler>{*this, nodeId, handler};
+
+    try
+    {
+      mMeasurementMap[nodeId] =
+        std::unique_ptr<MeasurementInstance>(new MeasurementInstance{
+          state, std::move(callback), std::move(addr), mClock, mIo});
+    }
+    catch (const runtime_error& err)
+    {
+      info(mIo->log()) << "gateway@" + addr.to_string()
+                       << " Failed to measure. Reason: " << err.what();
+      handler(GhostXForm{});
+    }
+  }
+
+private:
+  template <typename Handler>
+  struct CompletionCallback
+  {
+    void operator()(std::vector<double>& data)
+    {
+      using namespace std;
+      using std::chrono::microseconds;
+
+      // Post this to the measurement service's IoContext so that we
+      // don't delete the measurement object in its stack. Capture all
+      // needed data separately from this, since this object may be
+      // gone by the time the block gets executed.
+      auto nodeId = mNodeId;
+      auto handler = mHandler;
+      auto& measurementMap = mMeasurementService.mMeasurementMap;
+      const auto it = measurementMap.find(nodeId);
+      if (it != measurementMap.end())
+      {
+        if (data.empty())
+        {
+          handler(GhostXForm{});
+        }
+        else
+        {
+          handler(GhostXForm{1, microseconds(llround(median(data.begin(), data.end())))});
+        }
+        measurementMap.erase(it);
+      }
+    }
+
+    MeasurementService& mMeasurementService;
+    NodeId mNodeId;
+    Handler mHandler;
+  };
+
+  // Make sure the measurement map outlives the IoContext so that the rest of
+  // the members are guaranteed to be valid when any final handlers
+  // are begin run.
+  using MeasurementMap = std::map<NodeId, std::unique_ptr<MeasurementInstance>>;
+  MeasurementMap mMeasurementMap;
+  Clock mClock;
+  IoType mIo;
+  PingResponder<Clock, IoContext> mPingResponder;
+};
+
+} // namespace link
+} // namespace ableton
diff --git a/link/include/ableton/link/Median.hpp b/link/include/ableton/link/Median.hpp
new file mode 100644
--- /dev/null
+++ b/link/include/ableton/link/Median.hpp
@@ -0,0 +1,50 @@
+/* Copyright 2021, Ableton AG, Berlin. All rights reserved.
+ *
+ *  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 2 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 <http://www.gnu.org/licenses/>.
+ *
+ *  If you would like to incorporate Link into a proprietary software application,
+ *  please contact <link-devs@ableton.com>.
+ */
+
+#pragma once
+
+#include <algorithm>
+#include <cassert>
+#include <vector>
+
+namespace ableton
+{
+namespace link
+{
+
+template <typename It>
+double median(It begin, It end)
+{
+  const auto n = std::distance(begin, end);
+  assert(n > 2);
+  if (n % 2 == 0)
+  {
+    std::nth_element(begin, begin + n / 2, end);
+    std::nth_element(begin, begin + (n - 1) / 2, end);
+    return (*(begin + (n / 2)) + *(begin + (n - 1) / 2)) / 2.0;
+  }
+  else
+  {
+    std::nth_element(begin, begin + n / 2, end);
+    return *(begin + (n / 2));
+  }
+};
+
+} // namespace link
+} // namespace ableton
diff --git a/link/include/ableton/link/NodeId.hpp b/link/include/ableton/link/NodeId.hpp
new file mode 100644
--- /dev/null
+++ b/link/include/ableton/link/NodeId.hpp
@@ -0,0 +1,78 @@
+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.
+ *
+ *  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 2 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 <http://www.gnu.org/licenses/>.
+ *
+ *  If you would like to incorporate Link into a proprietary software application,
+ *  please contact <link-devs@ableton.com>.
+ */
+
+#pragma once
+
+#include <ableton/discovery/NetworkByteStreamSerializable.hpp>
+#include <algorithm>
+#include <array>
+#include <cstdint>
+#include <string>
+
+namespace ableton
+{
+namespace link
+{
+
+using NodeIdArray = std::array<std::uint8_t, 8>;
+
+struct NodeId : NodeIdArray
+{
+  NodeId() = default;
+
+  NodeId(NodeIdArray rhs)
+    : NodeIdArray(std::move(rhs))
+  {
+  }
+
+  template <typename Random>
+  static NodeId random()
+  {
+    using namespace std;
+    NodeId nodeId;
+
+    Random random;
+    generate(nodeId.begin(), nodeId.end(), [&] { return random(); });
+
+    return nodeId;
+  }
+
+  friend std::ostream& operator<<(std::ostream& stream, const NodeId& id)
+  {
+    return stream << std::string{id.cbegin(), id.cend()};
+  }
+
+  template <typename It>
+  friend It toNetworkByteStream(const NodeId& nodeId, It out)
+  {
+    return discovery::toNetworkByteStream(nodeId, std::move(out));
+  }
+
+  template <typename It>
+  static std::pair<NodeId, It> fromNetworkByteStream(It begin, It end)
+  {
+    using namespace std;
+    auto result = discovery::Deserialize<NodeIdArray>::fromNetworkByteStream(
+      std::move(begin), std::move(end));
+    return make_pair(NodeId(std::move(result.first)), std::move(result.second));
+  }
+};
+
+} // namespace link
+} // namespace ableton
diff --git a/link/include/ableton/link/NodeState.hpp b/link/include/ableton/link/NodeState.hpp
new file mode 100644
--- /dev/null
+++ b/link/include/ableton/link/NodeState.hpp
@@ -0,0 +1,77 @@
+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.
+ *
+ *  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 2 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 <http://www.gnu.org/licenses/>.
+ *
+ *  If you would like to incorporate Link into a proprietary software application,
+ *  please contact <link-devs@ableton.com>.
+ */
+
+#pragma once
+
+#include <ableton/discovery/Payload.hpp>
+#include <ableton/link/NodeId.hpp>
+#include <ableton/link/SessionId.hpp>
+#include <ableton/link/StartStopState.hpp>
+#include <ableton/link/Timeline.hpp>
+
+namespace ableton
+{
+namespace link
+{
+
+struct NodeState
+{
+  using Payload =
+    decltype(discovery::makePayload(Timeline{}, SessionMembership{}, StartStopState{}));
+
+  NodeId ident() const
+  {
+    return nodeId;
+  }
+
+  friend bool operator==(const NodeState& lhs, const NodeState& rhs)
+  {
+    return std::tie(lhs.nodeId, lhs.sessionId, lhs.timeline, lhs.startStopState)
+           == std::tie(rhs.nodeId, rhs.sessionId, rhs.timeline, rhs.startStopState);
+  }
+
+  friend Payload toPayload(const NodeState& state)
+  {
+    return discovery::makePayload(
+      state.timeline, SessionMembership{state.sessionId}, state.startStopState);
+  }
+
+  template <typename It>
+  static NodeState fromPayload(NodeId nodeId, It begin, It end)
+  {
+    using namespace std;
+    auto nodeState = NodeState{std::move(nodeId), {}, {}, {}};
+    discovery::parsePayload<Timeline, SessionMembership, StartStopState>(std::move(begin),
+      std::move(end), [&nodeState](Timeline tl) { nodeState.timeline = std::move(tl); },
+      [&nodeState](SessionMembership membership) {
+        nodeState.sessionId = std::move(membership.sessionId);
+      },
+      [&nodeState](
+        StartStopState ststst) { nodeState.startStopState = std::move(ststst); });
+    return nodeState;
+  }
+
+  NodeId nodeId;
+  SessionId sessionId;
+  Timeline timeline;
+  StartStopState startStopState;
+};
+
+} // namespace link
+} // namespace ableton
diff --git a/link/include/ableton/link/Optional.hpp b/link/include/ableton/link/Optional.hpp
new file mode 100644
--- /dev/null
+++ b/link/include/ableton/link/Optional.hpp
@@ -0,0 +1,97 @@
+/* Copyright 2017, Ableton AG, Berlin. All rights reserved.
+ *
+ *  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 2 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 <http://www.gnu.org/licenses/>.
+ *
+ *  If you would like to incorporate Link into a proprietary software application,
+ *  please contact <link-devs@ableton.com>.
+ */
+
+#pragma once
+
+#include <cassert>
+#include <utility>
+
+namespace ableton
+{
+namespace link
+{
+
+// Subset of the C++ 17 std::optional API. T has to be default constructible.
+template <typename T>
+struct Optional
+{
+  Optional()
+    : mHasValue(false)
+  {
+  }
+
+  explicit Optional(T value)
+    : mValue(std::move(value))
+    , mHasValue(true)
+  {
+  }
+
+  Optional(const Optional&) = default;
+
+  Optional(Optional&& other)
+    : mValue(std::move(other.mValue))
+    , mHasValue(other.mHasValue)
+  {
+  }
+
+  Optional& operator=(const Optional&) = default;
+
+  Optional& operator=(Optional&& other)
+  {
+    mValue = std::move(other.mValue);
+    mHasValue = other.mHasValue;
+    return *this;
+  }
+
+  explicit operator bool() const
+  {
+    return mHasValue;
+  }
+
+  const T& operator*() const
+  {
+    assert(mHasValue);
+    return mValue;
+  }
+
+  T& operator*()
+  {
+    assert(mHasValue);
+    return mValue;
+  }
+
+  const T* operator->() const
+  {
+    assert(mHasValue);
+    return &mValue;
+  }
+
+  T* operator->()
+  {
+    assert(mHasValue);
+    return &mValue;
+  }
+
+private:
+  T mValue;
+  bool mHasValue;
+};
+
+} // namespace link
+} // namespace ableton
diff --git a/link/include/ableton/link/PayloadEntries.hpp b/link/include/ableton/link/PayloadEntries.hpp
new file mode 100644
--- /dev/null
+++ b/link/include/ableton/link/PayloadEntries.hpp
@@ -0,0 +1,140 @@
+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.
+ *
+ *  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 2 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 <http://www.gnu.org/licenses/>.
+ *
+ *  If you would like to incorporate Link into a proprietary software application,
+ *  please contact <link-devs@ableton.com>.
+ */
+
+#pragma once
+
+#include <ableton/discovery/NetworkByteStreamSerializable.hpp>
+#include <cmath>
+#include <cstdint>
+
+namespace ableton
+{
+namespace link
+{
+
+struct HostTime
+{
+  static const std::int32_t key = '__ht';
+  static_assert(key == 0x5f5f6874, "Unexpected byte order");
+
+  HostTime() = default;
+
+  HostTime(const std::chrono::microseconds tm)
+    : time(tm)
+  {
+  }
+
+  // Model the NetworkByteStreamSerializable concept
+  friend std::uint32_t sizeInByteStream(const HostTime& sht)
+  {
+    return discovery::sizeInByteStream(std::move(sht.time));
+  }
+
+  template <typename It>
+  friend It toNetworkByteStream(const HostTime& sht, It out)
+  {
+    return discovery::toNetworkByteStream(std::move(sht.time), std::move(out));
+  }
+
+  template <typename It>
+  static std::pair<HostTime, It> fromNetworkByteStream(It begin, It end)
+  {
+    using namespace std;
+    auto result = discovery::Deserialize<chrono::microseconds>::fromNetworkByteStream(
+      std::move(begin), std::move(end));
+    return make_pair(HostTime{std::move(result.first)}, std::move(result.second));
+  }
+
+  std::chrono::microseconds time;
+};
+
+struct GHostTime
+{
+  static const std::int32_t key = '__gt';
+  static_assert(key == 0x5f5f6774, "Unexpected byte order");
+
+  GHostTime() = default;
+
+  GHostTime(const std::chrono::microseconds tm)
+    : time(tm)
+  {
+  }
+
+  // Model the NetworkByteStreamSerializable concept
+  friend std::uint32_t sizeInByteStream(const GHostTime& dgt)
+  {
+    return discovery::sizeInByteStream(std::move(dgt.time));
+  }
+
+  template <typename It>
+  friend It toNetworkByteStream(const GHostTime& dgt, It out)
+  {
+    return discovery::toNetworkByteStream(std::move(dgt.time), std::move(out));
+  }
+
+  template <typename It>
+  static std::pair<GHostTime, It> fromNetworkByteStream(It begin, It end)
+  {
+    using namespace std;
+    auto result = discovery::Deserialize<chrono::microseconds>::fromNetworkByteStream(
+      std::move(begin), std::move(end));
+    return make_pair(GHostTime{std::move(result.first)}, std::move(result.second));
+  }
+
+  std::chrono::microseconds time;
+};
+
+struct PrevGHostTime
+{
+  static const std::int32_t key = '_pgt';
+  static_assert(key == 0x5f706774, "Unexpected byte order");
+
+  PrevGHostTime() = default;
+
+  PrevGHostTime(const std::chrono::microseconds tm)
+    : time(tm)
+  {
+  }
+
+  // Model the NetworkByteStreamSerializable concept
+  friend std::uint32_t sizeInByteStream(const PrevGHostTime& dgt)
+  {
+    return discovery::sizeInByteStream(std::move(dgt.time));
+  }
+
+  template <typename It>
+  friend It toNetworkByteStream(const PrevGHostTime& pdgt, It out)
+  {
+    return discovery::toNetworkByteStream(std::move(pdgt.time), std::move(out));
+  }
+
+  template <typename It>
+  static std::pair<PrevGHostTime, It> fromNetworkByteStream(It begin, It end)
+  {
+    using namespace std;
+    auto result = discovery::Deserialize<chrono::microseconds>::fromNetworkByteStream(
+      std::move(begin), std::move(end));
+    return make_pair(PrevGHostTime{std::move(result.first)}, std::move(result.second));
+  }
+
+  std::chrono::microseconds time;
+};
+
+} // namespace link
+} // namespace ableton
diff --git a/link/include/ableton/link/PeerState.hpp b/link/include/ableton/link/PeerState.hpp
new file mode 100644
--- /dev/null
+++ b/link/include/ableton/link/PeerState.hpp
@@ -0,0 +1,90 @@
+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.
+ *
+ *  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 2 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 <http://www.gnu.org/licenses/>.
+ *
+ *  If you would like to incorporate Link into a proprietary software application,
+ *  please contact <link-devs@ableton.com>.
+ */
+
+#pragma once
+
+#include <ableton/discovery/Payload.hpp>
+#include <ableton/link/MeasurementEndpointV4.hpp>
+#include <ableton/link/NodeState.hpp>
+
+namespace ableton
+{
+namespace link
+{
+
+// A state type for peers. PeerState stores the normal NodeState plus
+// additional information (the remote endpoint at which to find its
+// ping/pong measurement server).
+
+struct PeerState
+{
+  using IdType = NodeId;
+
+  IdType ident() const
+  {
+    return nodeState.ident();
+  }
+
+  SessionId sessionId() const
+  {
+    return nodeState.sessionId;
+  }
+
+  Timeline timeline() const
+  {
+    return nodeState.timeline;
+  }
+
+  StartStopState startStopState() const
+  {
+    return nodeState.startStopState;
+  }
+
+  friend bool operator==(const PeerState& lhs, const PeerState& rhs)
+  {
+    return lhs.nodeState == rhs.nodeState && lhs.endpoint == rhs.endpoint;
+  }
+
+  friend auto toPayload(const PeerState& state)
+    -> decltype(std::declval<NodeState::Payload>()
+                + discovery::makePayload(MeasurementEndpointV4{{}}))
+  {
+    return toPayload(state.nodeState)
+           + discovery::makePayload(MeasurementEndpointV4{state.endpoint});
+  }
+
+  template <typename It>
+  static PeerState fromPayload(NodeId id, It begin, It end)
+  {
+    using namespace std;
+    auto peerState = PeerState{NodeState::fromPayload(std::move(id), begin, end), {}};
+
+    discovery::parsePayload<MeasurementEndpointV4>(
+      std::move(begin), std::move(end), [&peerState](MeasurementEndpointV4 me4) {
+        peerState.endpoint = std::move(me4.ep);
+      });
+    return peerState;
+  }
+
+  NodeState nodeState;
+  asio::ip::udp::endpoint endpoint;
+};
+
+} // namespace link
+} // namespace ableton
diff --git a/link/include/ableton/link/Peers.hpp b/link/include/ableton/link/Peers.hpp
new file mode 100644
--- /dev/null
+++ b/link/include/ableton/link/Peers.hpp
@@ -0,0 +1,368 @@
+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.
+ *
+ *  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 2 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 <http://www.gnu.org/licenses/>.
+ *
+ *  If you would like to incorporate Link into a proprietary software application,
+ *  please contact <link-devs@ableton.com>.
+ */
+
+#pragma once
+
+#include <ableton/link/PeerState.hpp>
+#include <ableton/util/Injected.hpp>
+#include <cassert>
+
+namespace ableton
+{
+namespace link
+{
+
+// SessionMembershipCallback is invoked when any change to session
+// membership occurs (when any peer joins or leaves a session)
+//
+// SessionTimelineCallback is invoked with a session id and a timeline
+// whenever a new combination of these values is seen
+//
+// SessionStartStopStateCallback is invoked with a session id and a startStopState
+// whenever a new combination of these values is seen
+
+template <typename IoContext,
+  typename SessionMembershipCallback,
+  typename SessionTimelineCallback,
+  typename SessionStartStopStateCallback>
+class Peers
+{
+  // non-movable private implementation type
+  struct Impl;
+
+public:
+  using Peer = std::pair<PeerState, asio::ip::address>;
+
+  Peers(util::Injected<IoContext> io,
+    SessionMembershipCallback membership,
+    SessionTimelineCallback timeline,
+    SessionStartStopStateCallback startStop)
+    : mpImpl(std::make_shared<Impl>(
+        std::move(io), std::move(membership), std::move(timeline), std::move(startStop)))
+  {
+  }
+
+  // The set of peers for a given session, ordered by (peerId, addr).
+  // The result will possibly contain multiple entries for the same
+  // peer if it is visible through multiple gateways.
+  std::vector<Peer> sessionPeers(const SessionId& sid) const
+  {
+    using namespace std;
+    vector<Peer> result;
+    auto& peerVec = mpImpl->mPeers;
+    copy_if(begin(peerVec), end(peerVec), back_inserter(result), SessionMemberPred{sid});
+    return result;
+  }
+
+  // Number of individual for a given session.
+  std::size_t uniqueSessionPeerCount(const SessionId& sid) const
+  {
+    using namespace std;
+    auto peerVec = sessionPeers(sid);
+    auto last = unique(begin(peerVec), end(peerVec),
+      [](const Peer& a, const Peer& b) { return a.first.ident() == b.first.ident(); });
+    return static_cast<size_t>(distance(begin(peerVec), last));
+  }
+
+  void setSessionTimeline(const SessionId& sid, const Timeline& tl)
+  {
+    // Set the cached timeline for all peers to a new client-specified
+    // timeline. When we make a timeline change, we do so
+    // optimistically and clients assume that all peers in a session
+    // have adopted the newly specified timeline. We must represent
+    // this in our cache or else we risk failing to notify about a
+    // higher-priority peer timeline that was already seen.
+    for (auto& peer : mpImpl->mPeers)
+    {
+      if (peer.first.sessionId() == sid)
+      {
+        peer.first.nodeState.timeline = tl;
+      }
+    }
+  }
+
+  // Purge all cached peers that are members of the given session
+  void forgetSession(const SessionId& sid)
+  {
+    using namespace std;
+    auto& peerVec = mpImpl->mPeers;
+    peerVec.erase(
+      remove_if(begin(peerVec), end(peerVec), SessionMemberPred{sid}), end(peerVec));
+  }
+
+  void resetPeers()
+  {
+    mpImpl->mPeers.clear();
+  }
+
+  // Observer type that monitors peer discovery on a particular
+  // gateway and relays the information to a Peers instance.
+  // Models the PeerObserver concept from the discovery module.
+  struct GatewayObserver
+  {
+    using GatewayObserverNodeState = PeerState;
+    using GatewayObserverNodeId = NodeId;
+
+    GatewayObserver(std::shared_ptr<Impl> pImpl, asio::ip::address addr)
+      : mpImpl(std::move(pImpl))
+      , mAddr(std::move(addr))
+    {
+    }
+    GatewayObserver(const GatewayObserver&) = delete;
+
+    GatewayObserver(GatewayObserver&& rhs)
+      : mpImpl(std::move(rhs.mpImpl))
+      , mAddr(std::move(rhs.mAddr))
+    {
+    }
+
+    ~GatewayObserver()
+    {
+      // Check to handle the moved from case
+      if (mpImpl)
+      {
+        mpImpl->gatewayClosed(mAddr);
+      }
+    }
+
+    // model the PeerObserver concept from discovery
+    friend void sawPeer(GatewayObserver& observer, const PeerState& state)
+    {
+      auto pImpl = observer.mpImpl;
+      auto addr = observer.mAddr;
+      assert(pImpl);
+      pImpl->sawPeerOnGateway(std::move(state), std::move(addr));
+    }
+
+    friend void peerLeft(GatewayObserver& observer, const NodeId& id)
+    {
+      auto pImpl = observer.mpImpl;
+      auto addr = observer.mAddr;
+      pImpl->peerLeftGateway(std::move(id), std::move(addr));
+    }
+
+    friend void peerTimedOut(GatewayObserver& observer, const NodeId& id)
+    {
+      auto pImpl = observer.mpImpl;
+      auto addr = observer.mAddr;
+      pImpl->peerLeftGateway(std::move(id), std::move(addr));
+    }
+
+    std::shared_ptr<Impl> mpImpl;
+    asio::ip::address mAddr;
+  };
+
+  // Factory function for the gateway observer
+  friend GatewayObserver makeGatewayObserver(Peers& peers, asio::ip::address addr)
+  {
+    return GatewayObserver{peers.mpImpl, std::move(addr)};
+  }
+
+private:
+  struct Impl
+  {
+    Impl(util::Injected<IoContext> io,
+      SessionMembershipCallback membership,
+      SessionTimelineCallback timeline,
+      SessionStartStopStateCallback startStop)
+      : mIo(std::move(io))
+      , mSessionMembershipCallback(std::move(membership))
+      , mSessionTimelineCallback(std::move(timeline))
+      , mSessionStartStopStateCallback(std::move(startStop))
+    {
+    }
+
+    void sawPeerOnGateway(PeerState peerState, asio::ip::address gatewayAddr)
+    {
+      using namespace std;
+
+      const auto peerSession = peerState.sessionId();
+      const auto peerTimeline = peerState.timeline();
+      const auto peerStartStopState = peerState.startStopState();
+
+      bool isNewSessionTimeline = !sessionTimelineExists(peerSession, peerTimeline);
+      bool isNewSessionStartStopState =
+        !sessionStartStopStateExists(peerSession, peerStartStopState);
+
+      auto peer = make_pair(std::move(peerState), std::move(gatewayAddr));
+      const auto idRange = equal_range(begin(mPeers), end(mPeers), peer, PeerIdComp{});
+
+      bool didSessionMembershipChange = false;
+      if (idRange.first == idRange.second)
+      {
+        // This peer is not currently known on any gateway
+        didSessionMembershipChange = true;
+        mPeers.insert(std::move(idRange.first), std::move(peer));
+      }
+      else
+      {
+        // We've seen this peer before... does it have a new session?
+        didSessionMembershipChange =
+          all_of(idRange.first, idRange.second, [&peerSession](const Peer& test) {
+            return test.first.sessionId() != peerSession;
+          });
+
+        // was it on this gateway?
+        const auto addrRange =
+          equal_range(idRange.first, idRange.second, peer, AddrComp{});
+
+        if (addrRange.first == addrRange.second)
+        {
+          // First time on this gateway, add it
+          mPeers.insert(std::move(addrRange.first), std::move(peer));
+        }
+        else
+        {
+          // We have an entry for this peer on this gateway, update it
+          *addrRange.first = std::move(peer);
+        }
+      }
+
+      // Invoke callbacks outside the critical section
+      if (isNewSessionTimeline)
+      {
+        mSessionTimelineCallback(peerSession, peerTimeline);
+      }
+
+      // Pass the start stop state to the Controller after it processed the timeline.
+      // A new timeline can cause a session Id change which will prevent processing the
+      // new start stop state. By handling the start stop state after the timeline we
+      // assure that the start stop state is processed with the correct session Id.
+      if (isNewSessionStartStopState)
+      {
+        mSessionStartStopStateCallback(peerSession, peerStartStopState);
+      }
+
+      if (didSessionMembershipChange)
+      {
+        mSessionMembershipCallback();
+      }
+    }
+
+    void peerLeftGateway(const NodeId& nodeId, const asio::ip::address& gatewayAddr)
+    {
+      using namespace std;
+
+      auto it = find_if(begin(mPeers), end(mPeers), [&](const Peer& peer) {
+        return peer.first.ident() == nodeId && peer.second == gatewayAddr;
+      });
+
+      bool didSessionMembershipChange = false;
+      if (it != end(mPeers))
+      {
+        mPeers.erase(std::move(it));
+        didSessionMembershipChange = true;
+      }
+
+      if (didSessionMembershipChange)
+      {
+        mSessionMembershipCallback();
+      }
+    }
+
+    void gatewayClosed(const asio::ip::address& gatewayAddr)
+    {
+      using namespace std;
+
+      mPeers.erase(
+        remove_if(begin(mPeers), end(mPeers),
+          [&gatewayAddr](const Peer& peer) { return peer.second == gatewayAddr; }),
+        end(mPeers));
+
+      mSessionMembershipCallback();
+    }
+
+    template <typename Predicate>
+    bool hasPeerWith(const SessionId& sessionId, Predicate predicate)
+    {
+      using namespace std;
+      return find_if(begin(mPeers), end(mPeers), [&](const Peer& peer) {
+        return peer.first.sessionId() == sessionId && predicate(peer.first);
+      }) != end(mPeers);
+    }
+
+    bool sessionTimelineExists(const SessionId& session, const Timeline& timeline)
+    {
+      return hasPeerWith(session,
+        [&](const PeerState& peerState) { return peerState.timeline() == timeline; });
+    }
+
+    bool sessionStartStopStateExists(
+      const SessionId& sessionId, const StartStopState& startStopState)
+    {
+      return hasPeerWith(sessionId, [&](const PeerState& peerState) {
+        return peerState.startStopState() == startStopState;
+      });
+    }
+
+    struct PeerIdComp
+    {
+      bool operator()(const Peer& lhs, const Peer& rhs) const
+      {
+        return lhs.first.ident() < rhs.first.ident();
+      }
+    };
+
+    struct AddrComp
+    {
+      bool operator()(const Peer& lhs, const Peer& rhs) const
+      {
+        return lhs.second < rhs.second;
+      }
+    };
+
+    util::Injected<IoContext> mIo;
+    SessionMembershipCallback mSessionMembershipCallback;
+    SessionTimelineCallback mSessionTimelineCallback;
+    SessionStartStopStateCallback mSessionStartStopStateCallback;
+    std::vector<Peer> mPeers; // sorted by peerId, unique by (peerId, addr)
+  };
+
+  struct SessionMemberPred
+  {
+    bool operator()(const Peer& peer) const
+    {
+      return peer.first.sessionId() == sid;
+    }
+
+    const SessionId& sid;
+  };
+
+  std::shared_ptr<Impl> mpImpl;
+};
+
+template <typename Io,
+  typename SessionMembershipCallback,
+  typename SessionTimelineCallback,
+  typename SessionStartStopStateCallback>
+Peers<Io,
+  SessionMembershipCallback,
+  SessionTimelineCallback,
+  SessionStartStopStateCallback>
+makePeers(util::Injected<Io> io,
+  SessionMembershipCallback membershipCallback,
+  SessionTimelineCallback timelineCallback,
+  SessionStartStopStateCallback startStopStateCallback)
+{
+  return {std::move(io), std::move(membershipCallback), std::move(timelineCallback),
+    std::move(startStopStateCallback)};
+}
+
+} // namespace link
+} // namespace ableton
diff --git a/link/include/ableton/link/Phase.hpp b/link/include/ableton/link/Phase.hpp
new file mode 100644
--- /dev/null
+++ b/link/include/ableton/link/Phase.hpp
@@ -0,0 +1,100 @@
+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.
+ *
+ *  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 2 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 <http://www.gnu.org/licenses/>.
+ *
+ *  If you would like to incorporate Link into a proprietary software application,
+ *  please contact <link-devs@ableton.com>.
+ */
+
+#pragma once
+
+#include <ableton/link/Beats.hpp>
+#include <ableton/link/Timeline.hpp>
+#include <chrono>
+
+namespace ableton
+{
+namespace link
+{
+
+// Returns a value in the range [0,quantum) corresponding to beats %
+// quantum except that negative beat values are handled correctly.
+// If the given quantum is zero, returns zero.
+inline Beats phase(const Beats beats, const Beats quantum)
+{
+  if (quantum == Beats{INT64_C(0)})
+  {
+    return Beats{INT64_C(0)};
+  }
+  else
+  {
+    // Handle negative beat values by doing the computation relative to an
+    // origin that is on the nearest quantum boundary less than -(abs(x))
+    const auto quantumMicros = quantum.microBeats();
+    const auto quantumBins = (llabs(beats.microBeats()) + quantumMicros) / quantumMicros;
+    const std::int64_t quantumBeats{quantumBins * quantumMicros};
+    return (beats + Beats{quantumBeats}) % quantum;
+  }
+}
+
+// Return the least value greater than x that matches the phase of
+// target with respect to the given quantum. If the given quantum
+// quantum is 0, x is returned.
+inline Beats nextPhaseMatch(const Beats x, const Beats target, const Beats quantum)
+{
+  const auto desiredPhase = phase(target, quantum);
+  const auto xPhase = phase(x, quantum);
+  const auto phaseDiff = (desiredPhase - xPhase + quantum) % quantum;
+  return x + phaseDiff;
+}
+
+// Return the closest value to x that matches the phase of the target
+// with respect to the given quantum. The result deviates from x by at
+// most quantum/2, but may be less than x.
+inline Beats closestPhaseMatch(const Beats x, const Beats target, const Beats quantum)
+{
+  return nextPhaseMatch(x - Beats{0.5 * quantum.floating()}, target, quantum);
+}
+
+// Interprets the given timeline as encoding a quantum boundary at its
+// origin. Given such a timeline, returns a phase-encoded beat value
+// relative to the given quantum that corresponds to the given
+// time. The phase of the resulting beat value can be calculated with
+// phase(beats, quantum). The result will deviate by up to +-
+// (quantum/2) beats compared to the result of tl.toBeats(time).
+inline Beats toPhaseEncodedBeats(
+  const Timeline& tl, const std::chrono::microseconds time, const Beats quantum)
+{
+  const auto beat = tl.toBeats(time);
+  return closestPhaseMatch(beat, beat - tl.beatOrigin, quantum);
+}
+
+// The inverse of toPhaseEncodedBeats. Given a phase encoded beat
+// value from the given timeline and quantum, find the time value that
+// it maps to.
+inline std::chrono::microseconds fromPhaseEncodedBeats(
+  const Timeline& tl, const Beats beat, const Beats quantum)
+{
+  const auto fromOrigin = beat - tl.beatOrigin;
+  const auto originOffset = fromOrigin - phase(fromOrigin, quantum);
+  // invert the phase calculation so that it always rounds up in the
+  // middle instead of down like closestPhaseMatch. Otherwise we'll
+  // end up rounding down twice when a value is at phase quantum/2.
+  const auto inversePhaseOffset = closestPhaseMatch(
+    quantum - phase(fromOrigin, quantum), quantum - phase(beat, quantum), quantum);
+  return tl.fromBeats(tl.beatOrigin + originOffset + quantum - inversePhaseOffset);
+}
+
+} // namespace link
+} // namespace ableton
diff --git a/link/include/ableton/link/PingResponder.hpp b/link/include/ableton/link/PingResponder.hpp
new file mode 100644
--- /dev/null
+++ b/link/include/ableton/link/PingResponder.hpp
@@ -0,0 +1,171 @@
+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.
+ *
+ *  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 2 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 <http://www.gnu.org/licenses/>.
+ *
+ *  If you would like to incorporate Link into a proprietary software application,
+ *  please contact <link-devs@ableton.com>.
+ */
+
+#pragma once
+
+#include <ableton/link/GhostXForm.hpp>
+#include <ableton/link/PayloadEntries.hpp>
+#include <ableton/link/SessionId.hpp>
+#include <ableton/link/v1/Messages.hpp>
+#include <ableton/util/Injected.hpp>
+#include <ableton/util/SafeAsyncHandler.hpp>
+#include <chrono>
+#include <memory>
+
+namespace ableton
+{
+namespace link
+{
+
+template <typename Clock, typename IoContext>
+class PingResponder
+{
+  using IoType = util::Injected<IoContext&>;
+  using Socket = typename IoType::type::template Socket<v1::kMaxMessageSize>;
+
+public:
+  PingResponder(asio::ip::address_v4 address,
+    SessionId sessionId,
+    GhostXForm ghostXForm,
+    Clock clock,
+    IoType io)
+    : mIo(io)
+    , mpImpl(std::make_shared<Impl>(std::move(address),
+        std::move(sessionId),
+        std::move(ghostXForm),
+        std::move(clock),
+        std::move(io)))
+  {
+    mpImpl->listen();
+  }
+
+  PingResponder(const PingResponder&) = delete;
+  PingResponder(PingResponder&&) = delete;
+
+  void updateNodeState(const SessionId& sessionId, const GhostXForm& xform)
+  {
+    mpImpl->mSessionId = std::move(sessionId);
+    mpImpl->mGhostXForm = std::move(xform);
+  }
+
+  asio::ip::udp::endpoint endpoint() const
+  {
+    return mpImpl->mSocket.endpoint();
+  }
+
+  asio::ip::address address() const
+  {
+    return endpoint().address();
+  }
+
+  Socket socket() const
+  {
+    return mpImpl->mSocket;
+  }
+
+private:
+  struct Impl : std::enable_shared_from_this<Impl>
+  {
+    Impl(asio::ip::address_v4 address,
+      SessionId sessionId,
+      GhostXForm ghostXForm,
+      Clock clock,
+      IoType io)
+      : mSessionId(std::move(sessionId))
+      , mGhostXForm(std::move(ghostXForm))
+      , mClock(std::move(clock))
+      , mLog(channel(io->log(), "gateway@" + address.to_string()))
+      , mSocket(io->template openUnicastSocket<v1::kMaxMessageSize>(address))
+    {
+    }
+
+    void listen()
+    {
+      mSocket.receive(util::makeAsyncSafe(this->shared_from_this()));
+    }
+
+    // Operator to handle incoming messages on the interface
+    template <typename It>
+    void operator()(const asio::ip::udp::endpoint& from, const It begin, const It end)
+    {
+      using namespace discovery;
+
+      // Decode Ping Message
+      const auto result = link::v1::parseMessageHeader(begin, end);
+      const auto& header = result.first;
+      const auto payloadBegin = result.second;
+
+      // Check Payload size
+      const auto payloadSize = static_cast<std::size_t>(std::distance(payloadBegin, end));
+      const auto maxPayloadSize =
+        sizeInByteStream(makePayload(HostTime{}, PrevGHostTime{}));
+      if (header.messageType == v1::kPing && payloadSize <= maxPayloadSize)
+      {
+        debug(mLog) << " Received ping message from " << from;
+
+        try
+        {
+          reply(std::move(payloadBegin), std::move(end), from);
+        }
+        catch (const std::runtime_error& err)
+        {
+          info(mLog) << " Failed to send pong to " << from << ". Reason: " << err.what();
+        }
+      }
+      else
+      {
+        info(mLog) << " Received invalid Message from " << from << ".";
+      }
+      listen();
+    }
+
+    template <typename It>
+    void reply(It begin, It end, const asio::ip::udp::endpoint& to)
+    {
+      using namespace discovery;
+
+      // Encode Pong Message
+      const auto id = SessionMembership{mSessionId};
+      const auto currentGt = GHostTime{mGhostXForm.hostToGhost(mClock.micros())};
+      const auto pongPayload = makePayload(id, currentGt);
+
+      v1::MessageBuffer pongBuffer;
+      const auto pongMsgBegin = std::begin(pongBuffer);
+      auto pongMsgEnd = v1::pongMessage(pongPayload, pongMsgBegin);
+      // Append ping payload to pong message.
+      pongMsgEnd = std::copy(begin, end, pongMsgEnd);
+
+      const auto numBytes =
+        static_cast<std::size_t>(std::distance(pongMsgBegin, pongMsgEnd));
+      mSocket.send(pongBuffer.data(), numBytes, to);
+    }
+
+    SessionId mSessionId;
+    GhostXForm mGhostXForm;
+    Clock mClock;
+    typename IoType::type::Log mLog;
+    Socket mSocket;
+  };
+
+  IoType mIo;
+  std::shared_ptr<Impl> mpImpl;
+};
+
+} // namespace link
+} // namespace ableton
diff --git a/link/include/ableton/link/SessionId.hpp b/link/include/ableton/link/SessionId.hpp
new file mode 100644
--- /dev/null
+++ b/link/include/ableton/link/SessionId.hpp
@@ -0,0 +1,63 @@
+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.
+ *
+ *  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 2 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 <http://www.gnu.org/licenses/>.
+ *
+ *  If you would like to incorporate Link into a proprietary software application,
+ *  please contact <link-devs@ableton.com>.
+ */
+
+#pragma once
+
+#include <ableton/link/NodeId.hpp>
+
+namespace ableton
+{
+namespace link
+{
+
+// SessionIds occupy the same value space as NodeIds and are
+// identified by their founding node.
+using SessionId = NodeId;
+
+// A payload entry indicating membership in a particular session
+struct SessionMembership
+{
+  static const std::int32_t key = 'sess';
+  static_assert(key == 0x73657373, "Unexpected byte order");
+
+  // Model the NetworkByteStreamSerializable concept
+  friend std::uint32_t sizeInByteStream(const SessionMembership& sm)
+  {
+    return discovery::sizeInByteStream(sm.sessionId);
+  }
+
+  template <typename It>
+  friend It toNetworkByteStream(const SessionMembership& sm, It out)
+  {
+    return discovery::toNetworkByteStream(sm.sessionId, std::move(out));
+  }
+
+  template <typename It>
+  static std::pair<SessionMembership, It> fromNetworkByteStream(It begin, It end)
+  {
+    using namespace std;
+    auto idRes = SessionId::fromNetworkByteStream(std::move(begin), std::move(end));
+    return make_pair(SessionMembership{std::move(idRes.first)}, std::move(idRes.second));
+  }
+
+  SessionId sessionId;
+};
+
+} // namespace link
+} // namespace ableton
diff --git a/link/include/ableton/link/SessionState.hpp b/link/include/ableton/link/SessionState.hpp
new file mode 100644
--- /dev/null
+++ b/link/include/ableton/link/SessionState.hpp
@@ -0,0 +1,115 @@
+/* Copyright 2017, Ableton AG, Berlin. All rights reserved.
+ *
+ *  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 2 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 <http://www.gnu.org/licenses/>.
+ *
+ *  If you would like to incorporate Link into a proprietary software application,
+ *  please contact <link-devs@ableton.com>.
+ */
+
+#pragma once
+
+#include <ableton/link/Optional.hpp>
+#include <ableton/link/StartStopState.hpp>
+#include <ableton/link/Timeline.hpp>
+#include <ableton/link/TripleBuffer.hpp>
+
+namespace ableton
+{
+namespace link
+{
+
+using OptionalTimeline = Optional<Timeline>;
+using OptionalStartStopState = Optional<StartStopState>;
+using OptionalClientStartStopState = Optional<ClientStartStopState>;
+
+struct SessionState
+{
+  Timeline timeline;
+  StartStopState startStopState;
+  GhostXForm ghostXForm;
+};
+
+struct ClientState
+{
+  friend bool operator==(const ClientState& lhs, const ClientState& rhs)
+  {
+    return std::tie(lhs.timeline, lhs.startStopState)
+           == std::tie(rhs.timeline, rhs.startStopState);
+  }
+
+  friend bool operator!=(const ClientState& lhs, const ClientState& rhs)
+  {
+    return !(lhs == rhs);
+  }
+
+  Timeline timeline;
+  ClientStartStopState startStopState;
+};
+
+struct ControllerClientState
+{
+  ControllerClientState(ClientState state)
+    : mState(state)
+    , mRtState(state)
+  {
+  }
+
+  template <typename Fn>
+  void update(Fn fn)
+  {
+    std::unique_lock<std::mutex> lock(mMutex);
+    fn(mState);
+    mRtState.write(mState);
+  }
+
+  ClientState get() const
+  {
+    std::unique_lock<std::mutex> lock(mMutex);
+    return mState;
+  }
+
+  ClientState getRt() const
+  {
+    return mRtState.read();
+  }
+
+private:
+  mutable std::mutex mMutex;
+  ClientState mState;
+  mutable TripleBuffer<ClientState> mRtState;
+};
+
+struct RtClientState
+{
+  Timeline timeline;
+  ClientStartStopState startStopState;
+  std::chrono::microseconds timelineTimestamp;
+  std::chrono::microseconds startStopStateTimestamp;
+};
+
+struct IncomingClientState
+{
+  OptionalTimeline timeline;
+  OptionalClientStartStopState startStopState;
+  std::chrono::microseconds timelineTimestamp;
+};
+
+struct ApiState
+{
+  Timeline timeline;
+  ApiStartStopState startStopState;
+};
+
+} // namespace link
+} // namespace ableton
diff --git a/link/include/ableton/link/Sessions.hpp b/link/include/ableton/link/Sessions.hpp
new file mode 100644
--- /dev/null
+++ b/link/include/ableton/link/Sessions.hpp
@@ -0,0 +1,301 @@
+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.
+ *
+ *  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 2 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 <http://www.gnu.org/licenses/>.
+ *
+ *  If you would like to incorporate Link into a proprietary software application,
+ *  please contact <link-devs@ableton.com>.
+ */
+
+#pragma once
+
+#include <ableton/link/GhostXForm.hpp>
+#include <ableton/link/SessionId.hpp>
+#include <ableton/link/Timeline.hpp>
+
+namespace ableton
+{
+namespace link
+{
+
+struct SessionMeasurement
+{
+  GhostXForm xform;
+  std::chrono::microseconds timestamp;
+};
+
+struct Session
+{
+  SessionId sessionId;
+  Timeline timeline;
+  SessionMeasurement measurement;
+};
+
+template <typename Peers,
+  typename MeasurePeer,
+  typename JoinSessionCallback,
+  typename IoContext,
+  typename Clock>
+class Sessions
+{
+public:
+  using Timer = typename util::Injected<IoContext>::type::Timer;
+
+  Sessions(Session init,
+    util::Injected<Peers> peers,
+    MeasurePeer measure,
+    JoinSessionCallback join,
+    util::Injected<IoContext> io,
+    Clock clock)
+    : mPeers(std::move(peers))
+    , mMeasure(std::move(measure))
+    , mCallback(std::move(join))
+    , mCurrent(std::move(init))
+    , mIo(std::move(io))
+    , mTimer(mIo->makeTimer())
+    , mClock(std::move(clock))
+  {
+  }
+
+  void resetSession(Session session)
+  {
+    mCurrent = std::move(session);
+    mOtherSessions.clear();
+  }
+
+  void resetTimeline(Timeline timeline)
+  {
+    mCurrent.timeline = std::move(timeline);
+  }
+
+  // Consider the observed session/timeline pair and return a possibly
+  // new timeline that should be used going forward.
+  Timeline sawSessionTimeline(SessionId sid, Timeline timeline)
+  {
+    using namespace std;
+    if (sid == mCurrent.sessionId)
+    {
+      // matches our current session, update the timeline if necessary
+      updateTimeline(mCurrent, std::move(timeline));
+    }
+    else
+    {
+      auto session = Session{std::move(sid), std::move(timeline), {}};
+      const auto range =
+        equal_range(begin(mOtherSessions), end(mOtherSessions), session, SessionIdComp{});
+      if (range.first == range.second)
+      {
+        // brand new session, insert it into our list of known
+        // sessions and launch a measurement
+        launchSessionMeasurement(session);
+        mOtherSessions.insert(range.first, std::move(session));
+      }
+      else
+      {
+        // we've seen this session before, update its timeline if necessary
+        updateTimeline(*range.first, std::move(timeline));
+      }
+    }
+    return mCurrent.timeline;
+  }
+
+private:
+  void launchSessionMeasurement(Session& session)
+  {
+    using namespace std;
+    auto peers = mPeers->sessionPeers(session.sessionId);
+    if (!peers.empty())
+    {
+      // first criteria: always prefer the founding peer
+      const auto it = find_if(begin(peers), end(peers),
+        [&session](const Peer& peer) { return session.sessionId == peer.first.ident(); });
+      // TODO: second criteria should be degree. We don't have that
+      // represented yet so just use the first peer for now
+      auto peer = it == end(peers) ? peers.front() : *it;
+      // mark that a session is in progress by clearing out the
+      // session's timestamp
+      session.measurement.timestamp = {};
+      mMeasure(std::move(peer), MeasurementResultsHandler{*this, session.sessionId});
+    }
+  }
+
+  void handleSuccessfulMeasurement(const SessionId& id, GhostXForm xform)
+  {
+    using namespace std;
+
+    debug(mIo->log()) << "Session " << id << " measurement completed with result "
+                      << "(" << xform.slope << ", " << xform.intercept.count() << ")";
+
+    auto measurement = SessionMeasurement{std::move(xform), mClock.micros()};
+
+    if (mCurrent.sessionId == id)
+    {
+      mCurrent.measurement = std::move(measurement);
+      mCallback(mCurrent);
+    }
+    else
+    {
+      const auto range = equal_range(
+        begin(mOtherSessions), end(mOtherSessions), Session{id, {}, {}}, SessionIdComp{});
+
+      if (range.first != range.second)
+      {
+        const auto SESSION_EPS = chrono::microseconds{500000};
+        // should we join this session?
+        const auto hostTime = mClock.micros();
+        const auto curGhost = mCurrent.measurement.xform.hostToGhost(hostTime);
+        const auto newGhost = measurement.xform.hostToGhost(hostTime);
+        // update the measurement for the session entry
+        range.first->measurement = std::move(measurement);
+        // If session times too close - fall back to session id order
+        const auto ghostDiff = newGhost - curGhost;
+        if (ghostDiff > SESSION_EPS
+            || (std::abs(ghostDiff.count()) < SESSION_EPS.count()
+                 && id < mCurrent.sessionId))
+        {
+          // The new session wins, switch over to it
+          auto current = mCurrent;
+          mCurrent = std::move(*range.first);
+          mOtherSessions.erase(range.first);
+          // Put the old current session back into our list of known
+          // sessions so that we won't re-measure it
+          const auto it = upper_bound(
+            begin(mOtherSessions), end(mOtherSessions), current, SessionIdComp{});
+          mOtherSessions.insert(it, std::move(current));
+          // And notify that we have a new session and make sure that
+          // we remeasure it periodically.
+          mCallback(mCurrent);
+          scheduleRemeasurement();
+        }
+      }
+    }
+  }
+
+  void scheduleRemeasurement()
+  {
+    // set a timer to re-measure the active session after a period
+    mTimer.expires_from_now(std::chrono::microseconds{30000000});
+    mTimer.async_wait([this](const typename Timer::ErrorCode e) {
+      if (!e)
+      {
+        launchSessionMeasurement(mCurrent);
+        scheduleRemeasurement();
+      }
+    });
+  }
+
+  void handleFailedMeasurement(const SessionId& id)
+  {
+    using namespace std;
+
+    debug(mIo->log()) << "Session " << id << " measurement failed.";
+
+    // if we failed to measure for our current session, schedule a
+    // retry in the future. Otherwise, remove the session from our set
+    // of known sessions (if it is seen again it will be measured as
+    // if new).
+    if (mCurrent.sessionId == id)
+    {
+      scheduleRemeasurement();
+    }
+    else
+    {
+      const auto range = equal_range(
+        begin(mOtherSessions), end(mOtherSessions), Session{id, {}, {}}, SessionIdComp{});
+      if (range.first != range.second)
+      {
+        mOtherSessions.erase(range.first);
+        mPeers->forgetSession(id);
+      }
+    }
+  }
+
+  void updateTimeline(Session& session, Timeline timeline)
+  {
+    // We use beat origin magnitude to prioritize sessions.
+    if (timeline.beatOrigin > session.timeline.beatOrigin)
+    {
+      debug(mIo->log()) << "Adopting peer timeline (" << timeline.tempo.bpm() << ", "
+                        << timeline.beatOrigin.floating() << ", "
+                        << timeline.timeOrigin.count() << ")";
+
+      session.timeline = std::move(timeline);
+    }
+    else
+    {
+      debug(mIo->log()) << "Rejecting peer timeline with beat origin: "
+                        << timeline.beatOrigin.floating()
+                        << ". Current timeline beat origin: "
+                        << session.timeline.beatOrigin.floating();
+    }
+  }
+
+  struct MeasurementResultsHandler
+  {
+    void operator()(GhostXForm xform) const
+    {
+      Sessions& sessions = mSessions;
+      const SessionId& sessionId = mSessionId;
+      if (xform == GhostXForm{})
+      {
+        sessions.handleFailedMeasurement(std::move(sessionId));
+      }
+      else
+      {
+        sessions.handleSuccessfulMeasurement(std::move(sessionId), std::move(xform));
+      }
+    }
+
+    Sessions& mSessions;
+    SessionId mSessionId;
+  };
+
+  struct SessionIdComp
+  {
+    bool operator()(const Session& lhs, const Session& rhs) const
+    {
+      return lhs.sessionId < rhs.sessionId;
+    }
+  };
+
+  using Peer = typename util::Injected<Peers>::type::Peer;
+  util::Injected<Peers> mPeers;
+  MeasurePeer mMeasure;
+  JoinSessionCallback mCallback;
+  Session mCurrent;
+  util::Injected<IoContext> mIo;
+  Timer mTimer;
+  Clock mClock;
+  std::vector<Session> mOtherSessions; // sorted/unique by session id
+};
+
+template <typename Peers,
+  typename MeasurePeer,
+  typename JoinSessionCallback,
+  typename IoContext,
+  typename Clock>
+Sessions<Peers, MeasurePeer, JoinSessionCallback, IoContext, Clock> makeSessions(
+  Session init,
+  util::Injected<Peers> peers,
+  MeasurePeer measure,
+  JoinSessionCallback join,
+  util::Injected<IoContext> io,
+  Clock clock)
+{
+  using namespace std;
+  return {std::move(init), std::move(peers), std::move(measure), std::move(join),
+    std::move(io), std::move(clock)};
+}
+
+} // namespace link
+} // namespace ableton
diff --git a/link/include/ableton/link/StartStopState.hpp b/link/include/ableton/link/StartStopState.hpp
new file mode 100644
--- /dev/null
+++ b/link/include/ableton/link/StartStopState.hpp
@@ -0,0 +1,152 @@
+/* Copyright 2017, Ableton AG, Berlin. All rights reserved.
+ *
+ *  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 2 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 <http://www.gnu.org/licenses/>.
+ *
+ *  If you would like to incorporate Link into a proprietary software application,
+ *  please contact <link-devs@ableton.com>.
+ */
+
+#pragma once
+
+#include <ableton/discovery/NetworkByteStreamSerializable.hpp>
+#include <ableton/link/Beats.hpp>
+#include <chrono>
+#include <tuple>
+
+namespace ableton
+{
+namespace link
+{
+
+// A tuple of (isPlaying, time) that represents the playing state
+// with an according timestamp in microseconds. It also serves as a
+// payload entry.
+
+struct StartStopState
+{
+  static const std::int32_t key = 'stst';
+  static_assert(key == 0x73747374, "Unexpected byte order");
+
+  using StartStopStateTuple = std::tuple<bool, Beats, std::chrono::microseconds>;
+
+  StartStopState() = default;
+
+  StartStopState(
+    const bool aIsPlaying, const Beats aBeats, const std::chrono::microseconds aTimestamp)
+    : isPlaying(aIsPlaying)
+    , beats(aBeats)
+    , timestamp(aTimestamp)
+  {
+  }
+
+  friend bool operator==(const StartStopState& lhs, const StartStopState& rhs)
+  {
+    return std::tie(lhs.isPlaying, lhs.beats, lhs.timestamp)
+           == std::tie(rhs.isPlaying, rhs.beats, rhs.timestamp);
+  }
+
+  friend bool operator!=(const StartStopState& lhs, const StartStopState& rhs)
+  {
+    return !(lhs == rhs);
+  }
+
+  // Model the NetworkByteStreamSerializable concept
+  friend std::uint32_t sizeInByteStream(const StartStopState& state)
+  {
+    return discovery::sizeInByteStream(state.asTuple());
+  }
+
+  template <typename It>
+  friend It toNetworkByteStream(const StartStopState& state, It out)
+  {
+    return discovery::toNetworkByteStream(state.asTuple(), std::move(out));
+  }
+
+  template <typename It>
+  static std::pair<StartStopState, It> fromNetworkByteStream(It begin, It end)
+  {
+    using namespace std;
+    using namespace discovery;
+    auto result = Deserialize<StartStopStateTuple>::fromNetworkByteStream(
+      std::move(begin), std::move(end));
+    auto state =
+      StartStopState{get<0>(result.first), get<1>(result.first), get<2>(result.first)};
+    return make_pair(std::move(state), std::move(result.second));
+  }
+
+  bool isPlaying{false};
+  Beats beats{0.};
+  std::chrono::microseconds timestamp{0};
+
+private:
+  StartStopStateTuple asTuple() const
+  {
+    return std::make_tuple(isPlaying, beats, timestamp);
+  }
+};
+
+struct ClientStartStopState
+{
+  ClientStartStopState() = default;
+
+  ClientStartStopState(const bool aIsPlaying,
+    const std::chrono::microseconds aTime,
+    const std::chrono::microseconds aTimestamp)
+    : isPlaying(aIsPlaying)
+    , time(aTime)
+    , timestamp(aTimestamp)
+  {
+  }
+
+  friend bool operator==(const ClientStartStopState& lhs, const ClientStartStopState& rhs)
+  {
+    return std::tie(lhs.isPlaying, lhs.time, lhs.timestamp)
+           == std::tie(rhs.isPlaying, rhs.time, rhs.timestamp);
+  }
+
+  friend bool operator!=(const ClientStartStopState& lhs, const ClientStartStopState& rhs)
+  {
+    return !(lhs == rhs);
+  }
+
+  bool isPlaying{false};
+  std::chrono::microseconds time{0};
+  std::chrono::microseconds timestamp{0};
+};
+
+struct ApiStartStopState
+{
+  ApiStartStopState() = default;
+
+  ApiStartStopState(const bool aIsPlaying, const std::chrono::microseconds aTime)
+    : isPlaying(aIsPlaying)
+    , time(aTime)
+  {
+  }
+
+  friend bool operator==(const ApiStartStopState& lhs, const ApiStartStopState& rhs)
+  {
+    return std::tie(lhs.isPlaying, lhs.time) == std::tie(rhs.isPlaying, rhs.time);
+  }
+
+  friend bool operator!=(const ApiStartStopState& lhs, const ApiStartStopState& rhs)
+  {
+    return !(lhs == rhs);
+  }
+
+  bool isPlaying{false};
+  std::chrono::microseconds time{0};
+};
+} // namespace link
+} // namespace ableton
diff --git a/link/include/ableton/link/Tempo.hpp b/link/include/ableton/link/Tempo.hpp
new file mode 100644
--- /dev/null
+++ b/link/include/ableton/link/Tempo.hpp
@@ -0,0 +1,125 @@
+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.
+ *
+ *  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 2 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 <http://www.gnu.org/licenses/>.
+ *
+ *  If you would like to incorporate Link into a proprietary software application,
+ *  please contact <link-devs@ableton.com>.
+ */
+
+#pragma once
+
+#include <ableton/link/Beats.hpp>
+#include <chrono>
+
+namespace ableton
+{
+namespace link
+{
+
+struct Tempo
+{
+  Tempo() = default;
+
+  // Beats per minute
+  explicit Tempo(const double bpm)
+    : mValue(bpm)
+  {
+  }
+
+  Tempo(const std::chrono::microseconds microsPerBeat)
+    : mValue(60. * 1e6 / static_cast<double>(microsPerBeat.count()))
+  {
+  }
+
+  double bpm() const
+  {
+    return mValue;
+  }
+
+  std::chrono::microseconds microsPerBeat() const
+  {
+    return std::chrono::microseconds{std::llround(60. * 1e6 / bpm())};
+  }
+
+  // Given the tempo, convert a time to a beat value
+  Beats microsToBeats(const std::chrono::microseconds micros) const
+  {
+    return Beats{
+      static_cast<double>(micros.count()) / static_cast<double>(microsPerBeat().count())};
+  }
+
+  // Given the tempo, convert a beat to a time value
+  std::chrono::microseconds beatsToMicros(const Beats beats) const
+  {
+    return std::chrono::microseconds{
+      std::llround(beats.floating() * static_cast<double>(microsPerBeat().count()))};
+  }
+
+  // Model the NetworkByteStreamSerializable concept
+  friend std::uint32_t sizeInByteStream(const Tempo tempo)
+  {
+    return discovery::sizeInByteStream(tempo.microsPerBeat());
+  }
+
+  template <typename It>
+  friend It toNetworkByteStream(const Tempo tempo, It out)
+  {
+    return discovery::toNetworkByteStream(tempo.microsPerBeat(), std::move(out));
+  }
+
+  template <typename It>
+  static std::pair<Tempo, It> fromNetworkByteStream(It begin, It end)
+  {
+    auto result =
+      discovery::Deserialize<std::chrono::microseconds>::fromNetworkByteStream(
+        std::move(begin), std::move(end));
+    return std::make_pair(Tempo{std::move(result.first)}, std::move(result.second));
+  }
+
+  friend bool operator==(const Tempo lhs, const Tempo rhs)
+  {
+    return lhs.mValue == rhs.mValue;
+  }
+
+  friend bool operator!=(const Tempo lhs, const Tempo rhs)
+  {
+    return lhs.mValue != rhs.mValue;
+  }
+
+  friend bool operator<(const Tempo lhs, const Tempo rhs)
+  {
+    return lhs.mValue < rhs.mValue;
+  }
+
+  friend bool operator>(const Tempo lhs, const Tempo rhs)
+  {
+    return lhs.mValue > rhs.mValue;
+  }
+
+  friend bool operator<=(const Tempo lhs, const Tempo rhs)
+  {
+    return lhs.mValue <= rhs.mValue;
+  }
+
+  friend bool operator>=(const Tempo lhs, const Tempo rhs)
+  {
+    return lhs.mValue >= rhs.mValue;
+  }
+
+private:
+  double mValue = 0;
+};
+
+} // namespace link
+} // namespace ableton
diff --git a/link/include/ableton/link/Timeline.hpp b/link/include/ableton/link/Timeline.hpp
new file mode 100644
--- /dev/null
+++ b/link/include/ableton/link/Timeline.hpp
@@ -0,0 +1,98 @@
+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.
+ *
+ *  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 2 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 <http://www.gnu.org/licenses/>.
+ *
+ *  If you would like to incorporate Link into a proprietary software application,
+ *  please contact <link-devs@ableton.com>.
+ */
+
+#pragma once
+
+#include <ableton/discovery/NetworkByteStreamSerializable.hpp>
+#include <ableton/link/Beats.hpp>
+#include <ableton/link/Tempo.hpp>
+#include <cmath>
+#include <cstdint>
+#include <tuple>
+
+namespace ableton
+{
+namespace link
+{
+
+// A tuple of (tempo, beats, time), with integral units
+// based on microseconds. This type establishes a bijection between
+// beats and wall time, given a valid tempo. It also serves as a
+// payload entry.
+
+struct Timeline
+{
+  static const std::int32_t key = 'tmln';
+  static_assert(key == 0x746d6c6e, "Unexpected byte order");
+
+  Beats toBeats(const std::chrono::microseconds time) const
+  {
+    return beatOrigin + tempo.microsToBeats(time - timeOrigin);
+  }
+
+  std::chrono::microseconds fromBeats(const Beats beats) const
+  {
+    return timeOrigin + tempo.beatsToMicros(beats - beatOrigin);
+  }
+
+  friend bool operator==(const Timeline& lhs, const Timeline& rhs)
+  {
+    return std::tie(lhs.tempo, lhs.beatOrigin, lhs.timeOrigin)
+           == std::tie(rhs.tempo, rhs.beatOrigin, rhs.timeOrigin);
+  }
+
+  friend bool operator!=(const Timeline& lhs, const Timeline& rhs)
+  {
+    return !(lhs == rhs);
+  }
+
+  // Model the NetworkByteStreamSerializable concept
+  friend std::uint32_t sizeInByteStream(const Timeline& tl)
+  {
+    return discovery::sizeInByteStream(std::tie(tl.tempo, tl.beatOrigin, tl.timeOrigin));
+  }
+
+  template <typename It>
+  friend It toNetworkByteStream(const Timeline& tl, It out)
+  {
+    return discovery::toNetworkByteStream(
+      std::tie(tl.tempo, tl.beatOrigin, tl.timeOrigin), std::move(out));
+  }
+
+  template <typename It>
+  static std::pair<Timeline, It> fromNetworkByteStream(It begin, It end)
+  {
+    using namespace std;
+    using namespace discovery;
+    Timeline timeline;
+    auto result =
+      Deserialize<tuple<Tempo, Beats, chrono::microseconds>>::fromNetworkByteStream(
+        std::move(begin), std::move(end));
+    tie(timeline.tempo, timeline.beatOrigin, timeline.timeOrigin) =
+      std::move(result.first);
+    return make_pair(std::move(timeline), std::move(result.second));
+  }
+
+  Tempo tempo;
+  Beats beatOrigin;
+  std::chrono::microseconds timeOrigin;
+};
+
+} // namespace link
+} // namespace ableton
diff --git a/link/include/ableton/link/TripleBuffer.hpp b/link/include/ableton/link/TripleBuffer.hpp
new file mode 100644
--- /dev/null
+++ b/link/include/ableton/link/TripleBuffer.hpp
@@ -0,0 +1,121 @@
+/* Copyright 2022, Ableton AG, Berlin. All rights reserved.
+ *
+ *  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 2 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 <http://www.gnu.org/licenses/>.
+ *
+ *  If you would like to incorporate Link into a proprietary software application,
+ *  please contact <link-devs@ableton.com>.
+ */
+
+
+#pragma once
+
+#include <ableton/link/Optional.hpp>
+
+#include <array>
+#include <atomic>
+#include <cassert>
+#include <cstdint>
+
+namespace ableton
+{
+namespace link
+{
+
+template <typename T>
+struct TripleBuffer
+{
+public:
+  TripleBuffer()
+    : mBuffers{{{}, {}, {}}}
+  {
+    assert(mState.is_lock_free());
+  }
+
+  explicit TripleBuffer(const T& initial)
+    : mBuffers{{initial, initial, initial}}
+  {
+    assert(mState.is_lock_free());
+  }
+
+  TripleBuffer(const TripleBuffer&) = delete;
+  TripleBuffer& operator=(const TripleBuffer&) = delete;
+
+  T read() noexcept
+  {
+    loadReadBuffer();
+    return mBuffers[mReadIndex];
+  }
+
+  Optional<T> readNew()
+  {
+    if (loadReadBuffer())
+    {
+      return Optional<T>(mBuffers[mReadIndex]);
+    }
+    return {};
+  }
+
+  template <typename U>
+  void write(U&& value)
+  {
+    mBuffers[mWriteIndex] = std::forward<U>(value);
+
+    const auto prevState =
+      mState.exchange(makeState(mWriteIndex, true), std::memory_order_acq_rel);
+
+    mWriteIndex = backIndex(prevState);
+  }
+
+private:
+  bool loadReadBuffer()
+  {
+    auto state = mState.load(std::memory_order_acquire);
+    auto isNew = isNewWrite(state);
+    if (isNew)
+    {
+      const auto prevState =
+        mState.exchange(makeState(mReadIndex, false), std::memory_order_acq_rel);
+
+      mReadIndex = backIndex(prevState);
+    }
+    return isNew;
+  }
+
+  using BackingState = uint32_t;
+
+  static constexpr bool isNewWrite(const BackingState state)
+  {
+    return (state & 0x0000FFFFu) != 0;
+  }
+
+  static constexpr uint32_t backIndex(const BackingState state)
+  {
+    return state >> 16;
+  }
+
+  static constexpr BackingState makeState(
+    const uint32_t backBufferIndex, const bool isWrite)
+  {
+    return (backBufferIndex << 16) | uint32_t(isWrite);
+  }
+
+  std::atomic<BackingState> mState{makeState(1u, false)}; // Reader and writer
+  uint32_t mReadIndex = 0u;                               // Reader only
+  uint32_t mWriteIndex = 2u;                              // Writer only
+
+  std::array<T, 3> mBuffers{};
+};
+
+} // namespace link
+} // namespace ableton
diff --git a/link/include/ableton/link/v1/Messages.hpp b/link/include/ableton/link/v1/Messages.hpp
new file mode 100644
--- /dev/null
+++ b/link/include/ableton/link/v1/Messages.hpp
@@ -0,0 +1,138 @@
+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.
+ *
+ *  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 2 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 <http://www.gnu.org/licenses/>.
+ *
+ *  If you would like to incorporate Link into a proprietary software application,
+ *  please contact <link-devs@ableton.com>.
+ */
+
+#pragma once
+
+#include <ableton/discovery/Payload.hpp>
+#include <array>
+
+namespace ableton
+{
+namespace link
+{
+namespace v1
+{
+
+// The maximum size of a message, in bytes
+const std::size_t kMaxMessageSize = 512;
+// Utility typedef for an array of bytes of maximum message size
+using MessageBuffer = std::array<uint8_t, v1::kMaxMessageSize>;
+
+using MessageType = uint8_t;
+
+const MessageType kPing = 1;
+const MessageType kPong = 2;
+
+struct MessageHeader
+{
+  MessageType messageType;
+
+  friend std::uint32_t sizeInByteStream(const MessageHeader& header)
+  {
+    return discovery::sizeInByteStream(header.messageType);
+  }
+
+  template <typename It>
+  friend It toNetworkByteStream(const MessageHeader& header, It out)
+  {
+    return discovery::toNetworkByteStream(header.messageType, std::move(out));
+  }
+
+  template <typename It>
+  static std::pair<MessageHeader, It> fromNetworkByteStream(It begin, const It end)
+  {
+    using namespace discovery;
+
+    MessageHeader header;
+    std::tie(header.messageType, begin) =
+      Deserialize<decltype(header.messageType)>::fromNetworkByteStream(begin, end);
+
+    return std::make_pair(std::move(header), std::move(begin));
+  }
+};
+
+namespace detail
+{
+
+// Types that are only used in the sending/parsing of messages, not
+// publicly exposed.
+using ProtocolHeader = std::array<char, 8>;
+const ProtocolHeader kProtocolHeader = {{'_', 'l', 'i', 'n', 'k', '_', 'v', 1}};
+
+// Must have at least kMaxMessageSize bytes available in the output stream
+template <typename Payload, typename It>
+It encodeMessage(const MessageType messageType, const Payload& payload, It out)
+{
+  using namespace std;
+  const MessageHeader header = {messageType};
+  const auto messageSize =
+    kProtocolHeader.size() + sizeInByteStream(header) + sizeInByteStream(payload);
+
+  if (messageSize < kMaxMessageSize)
+  {
+    return toNetworkByteStream(
+      payload, toNetworkByteStream(header,
+                 copy(begin(kProtocolHeader), end(kProtocolHeader), std::move(out))));
+  }
+  else
+  {
+    throw range_error("Exceeded maximum message size");
+  }
+}
+
+} // namespace detail
+
+template <typename Payload, typename It>
+It pingMessage(const Payload& payload, It out)
+{
+  return detail::encodeMessage(kPing, payload, std::move(out));
+}
+
+template <typename Payload, typename It>
+It pongMessage(const Payload& payload, It out)
+{
+  return detail::encodeMessage(kPong, payload, std::move(out));
+}
+
+template <typename It>
+std::pair<MessageHeader, It> parseMessageHeader(It bytesBegin, const It bytesEnd)
+{
+  using ItDiff = typename std::iterator_traits<It>::difference_type;
+
+  MessageHeader header = {};
+  const auto protocolHeaderSize = discovery::sizeInByteStream(detail::kProtocolHeader);
+  const auto minMessageSize =
+    static_cast<ItDiff>(protocolHeaderSize + sizeInByteStream(header));
+
+  // If there are enough bytes in the stream to make a header and if
+  // the first bytes in the stream are the protocol header, then
+  // proceed to parse the stream.
+  if (std::distance(bytesBegin, bytesEnd) >= minMessageSize
+      && std::equal(
+           begin(detail::kProtocolHeader), end(detail::kProtocolHeader), bytesBegin))
+  {
+    std::tie(header, bytesBegin) =
+      MessageHeader::fromNetworkByteStream(bytesBegin + protocolHeaderSize, bytesEnd);
+  }
+  return std::make_pair(std::move(header), std::move(bytesBegin));
+}
+
+} // namespace v1
+} // namespace link
+} // namespace ableton
diff --git a/link/include/ableton/platforms/Config.hpp b/link/include/ableton/platforms/Config.hpp
new file mode 100644
--- /dev/null
+++ b/link/include/ableton/platforms/Config.hpp
@@ -0,0 +1,101 @@
+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.
+ *
+ *  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 2 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 <http://www.gnu.org/licenses/>.
+ *
+ *  If you would like to incorporate Link into a proprietary software application,
+ *  please contact <link-devs@ableton.com>.
+ */
+
+#pragma once
+
+#include <ableton/link/Controller.hpp>
+#include <ableton/util/Log.hpp>
+
+#if defined(LINK_PLATFORM_WINDOWS)
+#include <ableton/platforms/asio/Context.hpp>
+#include <ableton/platforms/stl/Random.hpp>
+#include <ableton/platforms/windows/Clock.hpp>
+#include <ableton/platforms/windows/ScanIpIfAddrs.hpp>
+#if defined(LINK_WINDOWS_SETTHREADDESCRIPTION)
+#include <ableton/platforms/windows/ThreadFactory.hpp>
+#endif
+#elif defined(LINK_PLATFORM_MACOSX)
+#include <ableton/platforms/asio/Context.hpp>
+#include <ableton/platforms/darwin/Clock.hpp>
+#include <ableton/platforms/darwin/ThreadFactory.hpp>
+#include <ableton/platforms/posix/ScanIpIfAddrs.hpp>
+#include <ableton/platforms/stl/Random.hpp>
+#elif defined(LINK_PLATFORM_LINUX)
+#include <ableton/platforms/asio/Context.hpp>
+#include <ableton/platforms/linux/Clock.hpp>
+#include <ableton/platforms/posix/ScanIpIfAddrs.hpp>
+#include <ableton/platforms/stl/Random.hpp>
+#ifdef __linux__
+#include <ableton/platforms/linux/ThreadFactory.hpp>
+#endif
+#elif defined(ESP_PLATFORM)
+#include <ableton/platforms/esp32/Clock.hpp>
+#include <ableton/platforms/esp32/Context.hpp>
+#include <ableton/platforms/esp32/Random.hpp>
+#include <ableton/platforms/esp32/ScanIpIfAddrs.hpp>
+#endif
+
+namespace ableton
+{
+namespace link
+{
+namespace platform
+{
+
+#if defined(LINK_PLATFORM_WINDOWS)
+using Clock = platforms::windows::Clock;
+using Random = platforms::stl::Random;
+#if defined(LINK_WINDOWS_SETTHREADDESCRIPTION)
+using IoContext = platforms::asio::Context<platforms::windows::ScanIpIfAddrs,
+  util::NullLog,
+  platforms::windows::ThreadFactory>;
+#else
+using IoContext =
+  platforms::asio::Context<platforms::windows::ScanIpIfAddrs, util::NullLog>;
+#endif
+
+#elif defined(LINK_PLATFORM_MACOSX)
+using Clock = platforms::darwin::Clock;
+using IoContext = platforms::asio::Context<platforms::posix::ScanIpIfAddrs,
+  util::NullLog,
+  platforms::darwin::ThreadFactory>;
+using Random = platforms::stl::Random;
+
+#elif defined(LINK_PLATFORM_LINUX)
+using Clock = platforms::linux::ClockMonotonicRaw;
+using Random = platforms::stl::Random;
+#ifdef __linux__
+using IoContext = platforms::asio::Context<platforms::posix::ScanIpIfAddrs,
+  util::NullLog,
+  platforms::linux::ThreadFactory>;
+#else
+using IoContext =
+  platforms::asio::Context<platforms::posix::ScanIpIfAddrs, util::NullLog>;
+#endif
+
+#elif defined(ESP_PLATFORM)
+using Clock = platforms::esp32::Clock;
+using IoContext =
+  platforms::esp32::Context<platforms::esp32::ScanIpIfAddrs, util::NullLog>;
+using Random = platforms::esp32::Random;
+#endif
+
+} // namespace platform
+} // namespace link
+} // namespace ableton
diff --git a/link/include/ableton/platforms/asio/AsioTimer.hpp b/link/include/ableton/platforms/asio/AsioTimer.hpp
new file mode 100644
--- /dev/null
+++ b/link/include/ableton/platforms/asio/AsioTimer.hpp
@@ -0,0 +1,132 @@
+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.
+ *
+ *  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 2 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 <http://www.gnu.org/licenses/>.
+ *
+ *  If you would like to incorporate Link into a proprietary software application,
+ *  please contact <link-devs@ableton.com>.
+ */
+
+#pragma once
+
+#include <ableton/platforms/asio/AsioWrapper.hpp>
+#include <ableton/util/SafeAsyncHandler.hpp>
+#include <functional>
+
+namespace ableton
+{
+namespace platforms
+{
+namespace asio
+{
+
+// This implementation is based on the boost::asio::system_timer concept.
+// Since boost::system_timer doesn't support move semantics, we create a wrapper
+// with a unique_ptr to get a movable type. It also handles an inconvenient
+// aspect of asio timers, which is that you must explicitly guard against the
+// handler firing after cancellation. We handle this by use of the SafeAsyncHandler
+// utility. AsioTimer therefore guarantees that a handler will not be called after
+// the destruction of the timer, or after the timer has been canceled.
+
+class AsioTimer
+{
+public:
+  using ErrorCode = ::asio::error_code;
+  using TimePoint = std::chrono::system_clock::time_point;
+
+  AsioTimer(::asio::io_service& io)
+    : mpTimer(new ::asio::system_timer(io))
+    , mpAsyncHandler(std::make_shared<AsyncHandler>())
+  {
+  }
+
+  ~AsioTimer()
+  {
+    // The timer may not be valid anymore if this instance was moved from
+    if (mpTimer != nullptr)
+    {
+      // Ignore errors during cancellation
+      cancel();
+    }
+  }
+
+  AsioTimer(const AsioTimer&) = delete;
+  AsioTimer& operator=(const AsioTimer&) = delete;
+
+  // Enable move construction but not move assignment. Move assignment
+  // would get weird - would have to handle outstanding handlers
+  AsioTimer(AsioTimer&& rhs)
+    : mpTimer(std::move(rhs.mpTimer))
+    , mpAsyncHandler(std::move(rhs.mpAsyncHandler))
+  {
+  }
+
+  void expires_at(std::chrono::system_clock::time_point tp)
+  {
+    mpTimer->expires_at(std::move(tp));
+  }
+
+  template <typename T>
+  void expires_from_now(T duration)
+  {
+    mpTimer->expires_from_now(std::move(duration));
+  }
+
+  ErrorCode cancel()
+  {
+    ErrorCode ec;
+    mpTimer->cancel(ec);
+    mpAsyncHandler->mpHandler = nullptr;
+    return ec;
+  }
+
+  template <typename Handler>
+  void async_wait(Handler handler)
+  {
+    *mpAsyncHandler = std::move(handler);
+    mpTimer->async_wait(util::makeAsyncSafe(mpAsyncHandler));
+  }
+
+  TimePoint now() const
+  {
+    return std::chrono::system_clock::now();
+  }
+
+private:
+  struct AsyncHandler
+  {
+    template <typename Handler>
+    AsyncHandler& operator=(Handler handler)
+    {
+      mpHandler = [handler](ErrorCode ec) { handler(std::move(ec)); };
+      return *this;
+    }
+
+    void operator()(ErrorCode ec)
+    {
+      if (mpHandler)
+      {
+        mpHandler(std::move(ec));
+      }
+    }
+
+    std::function<void(const ErrorCode)> mpHandler;
+  };
+
+  std::unique_ptr<::asio::system_timer> mpTimer;
+  std::shared_ptr<AsyncHandler> mpAsyncHandler;
+};
+
+} // namespace asio
+} // namespace platforms
+} // namespace ableton
diff --git a/link/include/ableton/platforms/asio/AsioWrapper.hpp b/link/include/ableton/platforms/asio/AsioWrapper.hpp
new file mode 100644
--- /dev/null
+++ b/link/include/ableton/platforms/asio/AsioWrapper.hpp
@@ -0,0 +1,90 @@
+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.
+ *
+ *  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 2 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 <http://www.gnu.org/licenses/>.
+ *
+ *  If you would like to incorporate Link into a proprietary software application,
+ *  please contact <link-devs@ableton.com>.
+ */
+
+#pragma once
+
+/*!
+ * \brief Wrapper file for AsioStandalone library
+ *
+ * This file includes all necessary headers from the AsioStandalone library which are used
+ * by Link.
+ */
+
+#if !defined(ESP_PLATFORM)
+#pragma push_macro("ASIO_STANDALONE")
+#define ASIO_STANDALONE 1
+
+#pragma push_macro("ASIO_NO_TYPEID")
+#define ASIO_NO_TYPEID 1
+#endif
+
+#if defined(LINK_PLATFORM_WINDOWS)
+#pragma push_macro("INCL_EXTRA_HTON_FUNCTIONS")
+#define INCL_EXTRA_HTON_FUNCTIONS 1
+#endif
+
+#if defined(WIN32) || defined(_WIN32)
+#if !defined(_WIN32_WINNT)
+#define _WIN32_WINNT 0x0501
+#endif
+#endif
+
+#if defined(__clang__)
+#pragma clang diagnostic push
+#if __has_warning("-Wcomma")
+#pragma clang diagnostic ignored "-Wcomma"
+#endif
+#if __has_warning("-Wshorten-64-to-32")
+#pragma clang diagnostic ignored "-Wshorten-64-to-32"
+#endif
+#if __has_warning("-Wunused-local-typedef")
+#pragma clang diagnostic ignored "-Wunused-local-typedef"
+#endif
+#endif
+
+#if defined(_MSC_VER)
+#define _SCL_SECURE_NO_WARNINGS 1
+#pragma warning(push, 0)
+#pragma warning(disable : 4242)
+#pragma warning(disable : 4668)
+#pragma warning(disable : 4702)
+#pragma warning(disable : 5204)
+#pragma warning(disable : 5220)
+#endif
+
+#include <asio.hpp>
+#include <asio/system_timer.hpp>
+
+#if defined(LINK_PLATFORM_WINDOWS)
+#pragma pop_macro("INCL_EXTRA_HTON_FUNCTIONS")
+#endif
+
+#if !defined(ESP_PLATFORM)
+#pragma pop_macro("ASIO_STANDALONE")
+#pragma pop_macro("ASIO_NO_TYPEID")
+#endif
+
+#if defined(_MSC_VER)
+#pragma warning(pop)
+#undef _SCL_SECURE_NO_WARNINGS
+#endif
+
+#if defined(__clang__)
+#pragma clang diagnostic pop
+#endif
diff --git a/link/include/ableton/platforms/asio/Context.hpp b/link/include/ableton/platforms/asio/Context.hpp
new file mode 100644
--- /dev/null
+++ b/link/include/ableton/platforms/asio/Context.hpp
@@ -0,0 +1,196 @@
+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.
+ *
+ *  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 2 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 <http://www.gnu.org/licenses/>.
+ *
+ *  If you would like to incorporate Link into a proprietary software application,
+ *  please contact <link-devs@ableton.com>.
+ */
+
+#pragma once
+
+#include <ableton/discovery/IpV4Interface.hpp>
+#include <ableton/platforms/asio/AsioTimer.hpp>
+#include <ableton/platforms/asio/AsioWrapper.hpp>
+#include <ableton/platforms/asio/LockFreeCallbackDispatcher.hpp>
+#include <ableton/platforms/asio/Socket.hpp>
+#include <thread>
+#include <utility>
+
+namespace ableton
+{
+namespace platforms
+{
+namespace asio
+{
+namespace
+{
+
+struct ThreadFactory
+{
+  template <typename Callable, typename... Args>
+  static std::thread makeThread(std::string, Callable&& f, Args&&... args)
+  {
+    return std::thread(std::forward<Callable>(f), std::forward<Args>(args)...);
+  }
+};
+
+} // namespace
+
+template <typename ScanIpIfAddrs, typename LogT, typename ThreadFactoryT = ThreadFactory>
+class Context
+{
+public:
+  using Timer = AsioTimer;
+  using Log = LogT;
+
+  template <typename Handler, typename Duration>
+  using LockFreeCallbackDispatcher =
+    LockFreeCallbackDispatcher<Handler, Duration, ThreadFactoryT>;
+
+  template <std::size_t BufferSize>
+  using Socket = asio::Socket<BufferSize>;
+
+  Context()
+    : Context(DefaultHandler{})
+  {
+  }
+
+  template <typename ExceptionHandler>
+  explicit Context(ExceptionHandler exceptHandler)
+    : mpService(new ::asio::io_service())
+    , mpWork(new ::asio::io_service::work(*mpService))
+  {
+    mThread = ThreadFactoryT::makeThread("Link Main",
+      [](::asio::io_service& service, ExceptionHandler handler) {
+        for (;;)
+        {
+          try
+          {
+            service.run();
+            break;
+          }
+          catch (const typename ExceptionHandler::Exception& exception)
+          {
+            handler(exception);
+          }
+        }
+      },
+      std::ref(*mpService), std::move(exceptHandler));
+  }
+
+  Context(const Context&) = delete;
+
+  Context(Context&& rhs)
+    : mpService(std::move(rhs.mpService))
+    , mpWork(std::move(rhs.mpWork))
+    , mThread(std::move(rhs.mThread))
+    , mLog(std::move(rhs.mLog))
+    , mScanIpIfAddrs(std::move(rhs.mScanIpIfAddrs))
+  {
+  }
+
+  ~Context()
+  {
+    if (mpService && mpWork)
+    {
+      mpWork.reset();
+      mThread.join();
+    }
+  }
+
+  void stop()
+  {
+    if (mpService && mpWork)
+    {
+      mpWork.reset();
+      mpService->stop();
+      mThread.join();
+    }
+  }
+
+
+  template <std::size_t BufferSize>
+  Socket<BufferSize> openUnicastSocket(const ::asio::ip::address_v4& addr)
+  {
+    auto socket = Socket<BufferSize>{*mpService};
+    socket.mpImpl->mSocket.set_option(
+      ::asio::ip::multicast::enable_loopback(addr.is_loopback()));
+    socket.mpImpl->mSocket.set_option(::asio::ip::multicast::outbound_interface(addr));
+    socket.mpImpl->mSocket.bind(::asio::ip::udp::endpoint{addr, 0});
+    return socket;
+  }
+
+  template <std::size_t BufferSize>
+  Socket<BufferSize> openMulticastSocket(const ::asio::ip::address_v4& addr)
+  {
+    auto socket = Socket<BufferSize>{*mpService};
+    socket.mpImpl->mSocket.set_option(::asio::ip::udp::socket::reuse_address(true));
+    socket.mpImpl->mSocket.set_option(
+      ::asio::socket_base::broadcast(!addr.is_loopback()));
+    socket.mpImpl->mSocket.set_option(
+      ::asio::ip::multicast::enable_loopback(addr.is_loopback()));
+    socket.mpImpl->mSocket.set_option(::asio::ip::multicast::outbound_interface(addr));
+    socket.mpImpl->mSocket.bind({::asio::ip::address::from_string("0.0.0.0"),
+      discovery::multicastEndpoint().port()});
+    socket.mpImpl->mSocket.set_option(::asio::ip::multicast::join_group(
+      discovery::multicastEndpoint().address().to_v4(), addr));
+    return socket;
+  }
+
+  std::vector<::asio::ip::address> scanNetworkInterfaces()
+  {
+    return mScanIpIfAddrs();
+  }
+
+  Timer makeTimer() const
+  {
+    return {*mpService};
+  }
+
+  Log& log()
+  {
+    return mLog;
+  }
+
+  template <typename Handler>
+  void async(Handler handler)
+  {
+    mpService->post(std::move(handler));
+  }
+
+private:
+  // Default handler is hidden and defines a hidden exception type
+  // that will never be thrown by other code, so it effectively does
+  // not catch.
+  struct DefaultHandler
+  {
+    struct Exception
+    {
+    };
+
+    void operator()(const Exception&)
+    {
+    }
+  };
+
+  std::unique_ptr<::asio::io_service> mpService;
+  std::unique_ptr<::asio::io_service::work> mpWork;
+  std::thread mThread;
+  Log mLog;
+  ScanIpIfAddrs mScanIpIfAddrs;
+};
+
+} // namespace asio
+} // namespace platforms
+} // namespace ableton
diff --git a/link/include/ableton/platforms/asio/LockFreeCallbackDispatcher.hpp b/link/include/ableton/platforms/asio/LockFreeCallbackDispatcher.hpp
new file mode 100644
--- /dev/null
+++ b/link/include/ableton/platforms/asio/LockFreeCallbackDispatcher.hpp
@@ -0,0 +1,88 @@
+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.
+ *
+ *  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 2 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 <http://www.gnu.org/licenses/>.
+ *
+ *  If you would like to incorporate Link into a proprietary software application,
+ *  please contact <link-devs@ableton.com>.
+ */
+
+#pragma once
+
+#include <atomic>
+#include <condition_variable>
+#include <thread>
+
+namespace ableton
+{
+namespace platforms
+{
+namespace asio
+{
+
+// Utility to signal invocation of a callback on another thread in a lock free manner.
+// The callback is evoked on a thread owned by the instance of this class.
+//
+// A condition variable is used to notify a waiting thread, but only if the required
+// lock can be acquired immediately. If that fails, we fall back on signaling
+// after a timeout. This gives us a guaranteed minimum signaling rate which is defined
+// by the fallbackPeriod parameter.
+
+template <typename Callback, typename Duration, typename ThreadFactory>
+class LockFreeCallbackDispatcher
+{
+public:
+  LockFreeCallbackDispatcher(Callback callback, Duration fallbackPeriod)
+    : mCallback(std::move(callback))
+    , mFallbackPeriod(std::move(fallbackPeriod))
+    , mRunning(true)
+    , mThread(ThreadFactory::makeThread("Link Dispatcher", [this] { run(); }))
+  {
+  }
+
+  ~LockFreeCallbackDispatcher()
+  {
+    mRunning = false;
+    mCondition.notify_one();
+    mThread.join();
+  }
+
+  void invoke()
+  {
+    mCondition.notify_one();
+  }
+
+private:
+  void run()
+  {
+    while (mRunning.load())
+    {
+      {
+        std::unique_lock<std::mutex> lock(mMutex);
+        mCondition.wait_for(lock, mFallbackPeriod);
+      }
+      mCallback();
+    }
+  }
+
+  Callback mCallback;
+  Duration mFallbackPeriod;
+  std::atomic<bool> mRunning;
+  std::mutex mMutex;
+  std::condition_variable mCondition;
+  std::thread mThread;
+};
+
+} // namespace asio
+} // namespace platforms
+} // namespace ableton
diff --git a/link/include/ableton/platforms/asio/Socket.hpp b/link/include/ableton/platforms/asio/Socket.hpp
new file mode 100644
--- /dev/null
+++ b/link/include/ableton/platforms/asio/Socket.hpp
@@ -0,0 +1,110 @@
+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.
+ *
+ *  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 2 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 <http://www.gnu.org/licenses/>.
+ *
+ *  If you would like to incorporate Link into a proprietary software application,
+ *  please contact <link-devs@ableton.com>.
+ */
+
+#pragma once
+
+#include <ableton/platforms/asio/AsioWrapper.hpp>
+#include <ableton/util/SafeAsyncHandler.hpp>
+#include <array>
+#include <cassert>
+
+namespace ableton
+{
+namespace platforms
+{
+namespace asio
+{
+
+template <std::size_t MaxPacketSize>
+struct Socket
+{
+  Socket(::asio::io_service& io)
+    : mpImpl(std::make_shared<Impl>(io))
+  {
+  }
+
+  Socket(const Socket&) = delete;
+  Socket& operator=(const Socket&) = delete;
+
+  Socket(Socket&& rhs)
+    : mpImpl(std::move(rhs.mpImpl))
+  {
+  }
+
+  std::size_t send(const uint8_t* const pData,
+    const size_t numBytes,
+    const ::asio::ip::udp::endpoint& to)
+  {
+    assert(numBytes < MaxPacketSize);
+    return mpImpl->mSocket.send_to(::asio::buffer(pData, numBytes), to);
+  }
+
+  template <typename Handler>
+  void receive(Handler handler)
+  {
+    mpImpl->mHandler = std::move(handler);
+    mpImpl->mSocket.async_receive_from(
+      ::asio::buffer(mpImpl->mReceiveBuffer, MaxPacketSize), mpImpl->mSenderEndpoint,
+      util::makeAsyncSafe(mpImpl));
+  }
+
+  ::asio::ip::udp::endpoint endpoint() const
+  {
+    return mpImpl->mSocket.local_endpoint();
+  }
+
+  struct Impl
+  {
+    Impl(::asio::io_service& io)
+      : mSocket(io, ::asio::ip::udp::v4())
+    {
+    }
+
+    ~Impl()
+    {
+      // Ignore error codes in shutdown and close as the socket may
+      // have already been forcibly closed
+      ::asio::error_code ec;
+      mSocket.shutdown(::asio::ip::udp::socket::shutdown_both, ec);
+      mSocket.close(ec);
+    }
+
+    void operator()(const ::asio::error_code& error, const std::size_t numBytes)
+    {
+      if (!error && numBytes > 0 && numBytes <= MaxPacketSize)
+      {
+        const auto bufBegin = begin(mReceiveBuffer);
+        mHandler(mSenderEndpoint, bufBegin, bufBegin + static_cast<ptrdiff_t>(numBytes));
+      }
+    }
+
+    ::asio::ip::udp::socket mSocket;
+    ::asio::ip::udp::endpoint mSenderEndpoint;
+    using Buffer = std::array<uint8_t, MaxPacketSize>;
+    Buffer mReceiveBuffer;
+    using ByteIt = typename Buffer::const_iterator;
+    std::function<void(const ::asio::ip::udp::endpoint&, ByteIt, ByteIt)> mHandler;
+  };
+
+  std::shared_ptr<Impl> mpImpl;
+};
+
+} // namespace asio
+} // namespace platforms
+} // namespace ableton
diff --git a/link/include/ableton/platforms/asio/Util.hpp b/link/include/ableton/platforms/asio/Util.hpp
new file mode 100644
--- /dev/null
+++ b/link/include/ableton/platforms/asio/Util.hpp
@@ -0,0 +1,43 @@
+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.
+ *
+ *  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 2 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 <http://www.gnu.org/licenses/>.
+ *
+ *  If you would like to incorporate Link into a proprietary software application,
+ *  please contact <link-devs@ableton.com>.
+ */
+
+#pragma once
+
+#include <algorithm>
+
+namespace ableton
+{
+namespace platforms
+{
+namespace asio
+{
+
+// Utility for making v4 or v6 ip addresses from raw bytes in network byte-order
+template <typename AsioAddrType>
+AsioAddrType makeAddress(const char* pAddr)
+{
+  using namespace std;
+  typename AsioAddrType::bytes_type bytes;
+  copy(pAddr, pAddr + bytes.size(), begin(bytes));
+  return AsioAddrType{bytes};
+}
+
+} // namespace asio
+} // namespace platforms
+} // namespace ableton
diff --git a/link/include/ableton/platforms/darwin/Clock.hpp b/link/include/ableton/platforms/darwin/Clock.hpp
new file mode 100644
--- /dev/null
+++ b/link/include/ableton/platforms/darwin/Clock.hpp
@@ -0,0 +1,70 @@
+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.
+ *
+ *  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 2 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 <http://www.gnu.org/licenses/>.
+ *
+ *  If you would like to incorporate Link into a proprietary software application,
+ *  please contact <link-devs@ableton.com>.
+ */
+
+#pragma once
+
+#include <chrono>
+#include <mach/mach_time.h>
+
+namespace ableton
+{
+namespace platforms
+{
+namespace darwin
+{
+
+struct Clock
+{
+  using Ticks = std::uint64_t;
+  using Micros = std::chrono::microseconds;
+
+  Clock()
+  {
+    mach_timebase_info_data_t timeInfo;
+    mach_timebase_info(&timeInfo);
+    // numer / denom gives nanoseconds, we want microseconds
+    mTicksToMicros = timeInfo.numer / (timeInfo.denom * 1000.);
+  }
+
+  Micros ticksToMicros(const Ticks ticks) const
+  {
+    return Micros{llround(mTicksToMicros * ticks)};
+  }
+
+  Ticks microsToTicks(const Micros micros) const
+  {
+    return static_cast<Ticks>(micros.count() / mTicksToMicros);
+  }
+
+  Ticks ticks() const
+  {
+    return mach_absolute_time();
+  }
+
+  std::chrono::microseconds micros() const
+  {
+    return ticksToMicros(ticks());
+  }
+
+  double mTicksToMicros;
+};
+
+} // namespace darwin
+} // namespace platforms
+} // namespace ableton
diff --git a/link/include/ableton/platforms/darwin/Darwin.hpp b/link/include/ableton/platforms/darwin/Darwin.hpp
new file mode 100644
--- /dev/null
+++ b/link/include/ableton/platforms/darwin/Darwin.hpp
@@ -0,0 +1,30 @@
+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.
+ *
+ *  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 2 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 <http://www.gnu.org/licenses/>.
+ *
+ *  If you would like to incorporate Link into a proprietary software application,
+ *  please contact <link-devs@ableton.com>.
+ */
+
+#pragma once
+
+// ntohll and htonll are not defined in 10.7 SDK, so we provide a compatibility macro here
+
+#ifndef ntohll
+#define ntohll(x) __DARWIN_OSSwapInt64(x)
+#endif
+
+#ifndef htonll
+#define htonll(x) __DARWIN_OSSwapInt64(x)
+#endif
diff --git a/link/include/ableton/platforms/darwin/ThreadFactory.hpp b/link/include/ableton/platforms/darwin/ThreadFactory.hpp
new file mode 100644
--- /dev/null
+++ b/link/include/ableton/platforms/darwin/ThreadFactory.hpp
@@ -0,0 +1,48 @@
+/* Copyright 2021, Ableton AG, Berlin. All rights reserved.
+ *
+ *  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 2 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 <http://www.gnu.org/licenses/>.
+ *
+ *  If you would like to incorporate Link into a proprietary software application,
+ *  please contact <link-devs@ableton.com>.
+ */
+
+#pragma once
+
+#include <pthread.h>
+#include <thread>
+#include <utility>
+
+namespace ableton
+{
+namespace platforms
+{
+namespace darwin
+{
+
+struct ThreadFactory
+{
+  template <typename Callable, typename... Args>
+  static std::thread makeThread(std::string name, Callable&& f, Args&&... args)
+  {
+    return std::thread{[](std::string name, Callable&& f, Args&&... args) {
+                         pthread_setname_np(name.c_str());
+                         f(args...);
+                       },
+      std::move(name), std::forward<Callable>(f), std::forward<Args>(args)...};
+  }
+};
+
+} // namespace darwin
+} // namespace platforms
+} // namespace ableton
diff --git a/link/include/ableton/platforms/esp32/Clock.hpp b/link/include/ableton/platforms/esp32/Clock.hpp
new file mode 100644
--- /dev/null
+++ b/link/include/ableton/platforms/esp32/Clock.hpp
@@ -0,0 +1,36 @@
+/* Copyright 2019, Mathias Bredholt, Torso Electronics, Copenhagen. All rights reserved.
+ *
+ *  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 2 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 <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include "esp_timer.h"
+
+namespace ableton
+{
+namespace platforms
+{
+namespace esp32
+{
+struct Clock
+{
+  std::chrono::microseconds micros() const
+  {
+    return static_cast<std::chrono::microseconds>(esp_timer_get_time());
+  }
+};
+} // namespace esp32
+} // namespace platforms
+} // namespace ableton
diff --git a/link/include/ableton/platforms/esp32/Context.hpp b/link/include/ableton/platforms/esp32/Context.hpp
new file mode 100644
--- /dev/null
+++ b/link/include/ableton/platforms/esp32/Context.hpp
@@ -0,0 +1,228 @@
+/* Copyright 2020, Ableton AG, Berlin. All rights reserved.
+ *
+ *  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 2 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 <http://www.gnu.org/licenses/>.
+ *
+ *  If you would like to incorporate Link into a proprietary software application,
+ *  please contact <link-devs@ableton.com>.
+ */
+
+#pragma once
+
+#include <ableton/discovery/IpV4Interface.hpp>
+#include <ableton/platforms/asio/AsioTimer.hpp>
+#include <ableton/platforms/asio/AsioWrapper.hpp>
+#include <ableton/platforms/asio/Socket.hpp>
+#include <ableton/platforms/esp32/LockFreeCallbackDispatcher.hpp>
+#include <driver/timer.h>
+#include <freertos/FreeRTOS.h>
+#include <freertos/task.h>
+
+namespace ableton
+{
+namespace platforms
+{
+namespace esp32
+{
+
+template <typename ScanIpIfAddrs, typename LogT>
+class Context
+{
+  class ServiceRunner
+  {
+
+    static void run(void* userParams)
+    {
+      auto runner = static_cast<ServiceRunner*>(userParams);
+      for (;;)
+      {
+        try
+        {
+          ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
+          runner->mpService->poll_one();
+        }
+        catch (...)
+        {
+        }
+      }
+    }
+
+    static void IRAM_ATTR timerIsr(void* userParam)
+    {
+      static BaseType_t xHigherPriorityTaskWoken = pdFALSE;
+
+      timer_group_clr_intr_status_in_isr(TIMER_GROUP_0, TIMER_1);
+      timer_group_enable_alarm_in_isr(TIMER_GROUP_0, TIMER_1);
+
+      vTaskNotifyGiveFromISR(userParam, &xHigherPriorityTaskWoken);
+      if (xHigherPriorityTaskWoken)
+      {
+        portYIELD_FROM_ISR();
+      }
+    }
+
+  public:
+    ServiceRunner()
+      : mpService(new ::asio::io_service())
+      , mpWork(new ::asio::io_service::work(*mpService))
+    {
+      xTaskCreatePinnedToCore(run, "link", 8192, this, 2 | portPRIVILEGE_BIT,
+        &mTaskHandle, LINK_ESP_TASK_CORE_ID);
+
+      timer_config_t config = {.alarm_en = TIMER_ALARM_EN,
+        .counter_en = TIMER_PAUSE,
+        .intr_type = TIMER_INTR_LEVEL,
+        .counter_dir = TIMER_COUNT_UP,
+        .auto_reload = TIMER_AUTORELOAD_EN,
+        .divider = 80};
+
+      timer_init(TIMER_GROUP_0, TIMER_1, &config);
+      timer_set_counter_value(TIMER_GROUP_0, TIMER_1, 0);
+      timer_set_alarm_value(TIMER_GROUP_0, TIMER_1, 100);
+      timer_enable_intr(TIMER_GROUP_0, TIMER_1);
+      timer_isr_register(TIMER_GROUP_0, TIMER_1, &timerIsr, mTaskHandle, 0, nullptr);
+
+      timer_start(TIMER_GROUP_0, TIMER_1);
+    }
+
+    ~ServiceRunner()
+    {
+      vTaskDelete(mTaskHandle);
+    }
+
+    template <typename Handler>
+    void async(Handler handler)
+    {
+      mpService->post(std::move(handler));
+    }
+
+    ::asio::io_service& service() const
+    {
+      return *mpService;
+    }
+
+  private:
+    TaskHandle_t mTaskHandle;
+    std::unique_ptr<::asio::io_service> mpService;
+    std::unique_ptr<::asio::io_service::work> mpWork;
+  };
+
+public:
+  using Timer = ::ableton::platforms::asio::AsioTimer;
+  using Log = LogT;
+
+  template <typename Handler, typename Duration>
+  using LockFreeCallbackDispatcher = LockFreeCallbackDispatcher<Handler, Duration>;
+
+  template <std::size_t BufferSize>
+  using Socket = asio::Socket<BufferSize>;
+
+  Context()
+    : Context(DefaultHandler{})
+  {
+  }
+
+  template <typename ExceptionHandler>
+  explicit Context(ExceptionHandler exceptHandler)
+  {
+  }
+
+  Context(const Context&) = delete;
+
+  Context(Context&& rhs)
+    : mLog(std::move(rhs.mLog))
+    , mScanIpIfAddrs(std::move(rhs.mScanIpIfAddrs))
+  {
+  }
+
+  void stop()
+  {
+  }
+
+  template <std::size_t BufferSize>
+  Socket<BufferSize> openUnicastSocket(const ::asio::ip::address_v4& addr)
+  {
+    auto socket = Socket<BufferSize>{serviceRunner().service()};
+    socket.mpImpl->mSocket.set_option(
+      ::asio::ip::multicast::enable_loopback(addr.is_loopback()));
+    socket.mpImpl->mSocket.set_option(::asio::ip::multicast::outbound_interface(addr));
+    socket.mpImpl->mSocket.bind(::asio::ip::udp::endpoint{addr, 0});
+    return socket;
+  }
+
+  template <std::size_t BufferSize>
+  Socket<BufferSize> openMulticastSocket(const ::asio::ip::address_v4& addr)
+  {
+    auto socket = Socket<BufferSize>{serviceRunner().service()};
+    socket.mpImpl->mSocket.set_option(::asio::ip::udp::socket::reuse_address(true));
+    socket.mpImpl->mSocket.set_option(
+      ::asio::socket_base::broadcast(!addr.is_loopback()));
+    socket.mpImpl->mSocket.set_option(
+      ::asio::ip::multicast::enable_loopback(addr.is_loopback()));
+    socket.mpImpl->mSocket.set_option(::asio::ip::multicast::outbound_interface(addr));
+    socket.mpImpl->mSocket.bind({::asio::ip::address::from_string("0.0.0.0"),
+      discovery::multicastEndpoint().port()});
+    socket.mpImpl->mSocket.set_option(::asio::ip::multicast::join_group(
+      discovery::multicastEndpoint().address().to_v4(), addr));
+    return socket;
+  }
+
+  std::vector<::asio::ip::address> scanNetworkInterfaces()
+  {
+    return mScanIpIfAddrs();
+  }
+
+  Timer makeTimer() const
+  {
+    return {serviceRunner().service()};
+  }
+
+  Log& log()
+  {
+    return mLog;
+  }
+
+  template <typename Handler>
+  void async(Handler handler)
+  {
+    serviceRunner().service().post(std::move(handler));
+  }
+
+private:
+  // Default handler is hidden and defines a hidden exception type
+  // that will never be thrown by other code, so it effectively does
+  // not catch.
+  struct DefaultHandler
+  {
+    struct Exception
+    {
+    };
+
+    void operator()(const Exception&)
+    {
+    }
+  };
+
+  static ServiceRunner& serviceRunner()
+  {
+    static ServiceRunner runner;
+    return runner;
+  }
+
+  Log mLog;
+  ScanIpIfAddrs mScanIpIfAddrs;
+};
+
+} // namespace esp32
+} // namespace platforms
+} // namespace ableton
diff --git a/link/include/ableton/platforms/esp32/Esp32.hpp b/link/include/ableton/platforms/esp32/Esp32.hpp
new file mode 100644
--- /dev/null
+++ b/link/include/ableton/platforms/esp32/Esp32.hpp
@@ -0,0 +1,27 @@
+/* Copyright 2019, Mathias Bredholt, Torso Electronics, Copenhagen. All rights reserved.
+ *
+ *  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 2 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 <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include <endian.h>
+
+#ifndef ntohll
+#define ntohll(x) bswap64(x)
+#endif
+
+#ifndef htonll
+#define htonll(x) bswap64(x)
+#endif
diff --git a/link/include/ableton/platforms/esp32/LockFreeCallbackDispatcher.hpp b/link/include/ableton/platforms/esp32/LockFreeCallbackDispatcher.hpp
new file mode 100644
--- /dev/null
+++ b/link/include/ableton/platforms/esp32/LockFreeCallbackDispatcher.hpp
@@ -0,0 +1,94 @@
+/* Copyright 2020, Ableton AG, Berlin. All rights reserved.
+ *
+ *  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 2 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 <http://www.gnu.org/licenses/>.
+ *
+ *  If you would like to incorporate Link into a proprietary software application,
+ *  please contact <link-devs@ableton.com>.
+ */
+
+#pragma once
+
+#include <atomic>
+#include <condition_variable>
+#include <freertos/task.h>
+
+namespace ableton
+{
+namespace platforms
+{
+namespace esp32
+{
+
+// Utility to signal invocation of a callback on another thread in a lock free manner.
+// The callback is evoked on a thread owned by the instance of this class.
+//
+// A condition variable is used to notify a waiting thread, but only if the required
+// lock can be acquired immediately. If that fails, we fall back on signaling
+// after a timeout. This gives us a guaranteed minimum signaling rate which is defined
+// by the fallbackPeriod parameter.
+
+template <typename Callback, typename Duration>
+class LockFreeCallbackDispatcher
+{
+public:
+  LockFreeCallbackDispatcher(Callback callback, Duration fallbackPeriod)
+    : mCallback(std::move(callback))
+    , mFallbackPeriod(std::move(fallbackPeriod))
+    , mRunning(true)
+  {
+    xTaskCreate(run, "link", 4096, this, tskIDLE_PRIORITY, &mTaskHandle);
+  }
+
+  ~LockFreeCallbackDispatcher()
+  {
+    mRunning = false;
+    mCondition.notify_one();
+    vTaskDelete(mTaskHandle);
+  }
+
+  void invoke()
+  {
+    if (mMutex.try_lock())
+    {
+      mCondition.notify_one();
+      mMutex.unlock();
+    }
+  }
+
+private:
+  static void run(void* userData)
+  {
+    auto dispatcher = static_cast<LockFreeCallbackDispatcher*>(userData);
+    while (dispatcher->mRunning.load())
+    {
+      {
+        std::unique_lock<std::mutex> lock(dispatcher->mMutex);
+        dispatcher->mCondition.wait_for(lock, dispatcher->mFallbackPeriod);
+      }
+      dispatcher->mCallback();
+      vTaskDelay(1);
+    }
+  }
+
+  Callback mCallback;
+  Duration mFallbackPeriod;
+  std::atomic<bool> mRunning;
+  std::mutex mMutex;
+  std::condition_variable mCondition;
+  TaskHandle_t mTaskHandle;
+};
+
+} // namespace esp32
+} // namespace platforms
+} // namespace ableton
diff --git a/link/include/ableton/platforms/esp32/Random.hpp b/link/include/ableton/platforms/esp32/Random.hpp
new file mode 100644
--- /dev/null
+++ b/link/include/ableton/platforms/esp32/Random.hpp
@@ -0,0 +1,36 @@
+/* Copyright 2019, Ableton AG, Berlin. All rights reserved.
+ *
+ *  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 2 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 <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+namespace ableton
+{
+namespace platforms
+{
+namespace esp32
+{
+
+struct Random
+{
+  uint8_t operator()()
+  {
+    return static_cast<uint8_t>((esp_random() % 93) + 33); // printable ascii chars
+  }
+};
+
+} // namespace esp32
+} // namespace platforms
+} // namespace ableton
diff --git a/link/include/ableton/platforms/esp32/ScanIpIfAddrs.hpp b/link/include/ableton/platforms/esp32/ScanIpIfAddrs.hpp
new file mode 100644
--- /dev/null
+++ b/link/include/ableton/platforms/esp32/ScanIpIfAddrs.hpp
@@ -0,0 +1,59 @@
+/* Copyright 2020, Ableton AG, Berlin and 2019, Mathias Bredholt, Torso Electronics,
+ * Copenhagen. All rights reserved.
+ *
+ *  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 2 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 <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include <ableton/platforms/asio/AsioWrapper.hpp>
+#include <arpa/inet.h>
+#include <esp_netif.h>
+#include <net/if.h>
+#include <vector>
+
+namespace ableton
+{
+namespace platforms
+{
+namespace esp32
+{
+
+// ESP32 implementation of ip interface address scanner
+struct ScanIpIfAddrs
+{
+  std::vector<::asio::ip::address> operator()()
+  {
+    std::vector<::asio::ip::address> addrs;
+    // Get first network interface
+    esp_netif_t* esp_netif = esp_netif_next(NULL);
+    while (esp_netif)
+    {
+      // Check if interface is active
+      if (esp_netif_is_netif_up(esp_netif))
+      {
+        esp_netif_ip_info_t ip_info;
+        esp_netif_get_ip_info(esp_netif, &ip_info);
+        addrs.emplace_back(::asio::ip::address_v4(ntohl(ip_info.ip.addr)));
+      }
+      // Get next network interface
+      esp_netif = esp_netif_next(esp_netif);
+    }
+    return addrs;
+  }
+};
+
+} // namespace esp32
+} // namespace platforms
+} // namespace ableton
diff --git a/link/include/ableton/platforms/linux/Clock.hpp b/link/include/ableton/platforms/linux/Clock.hpp
new file mode 100644
--- /dev/null
+++ b/link/include/ableton/platforms/linux/Clock.hpp
@@ -0,0 +1,60 @@
+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.
+ *
+ *  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 2 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 <http://www.gnu.org/licenses/>.
+ *
+ *  If you would like to incorporate Link into a proprietary software application,
+ *  please contact <link-devs@ableton.com>.
+ */
+
+#pragma once
+
+#include <chrono>
+#include <cmath>
+#include <ctime>
+
+namespace ableton
+{
+namespace platforms
+{
+
+#ifdef linux
+#undef linux
+#endif
+
+#if defined(__FreeBSD_kernel__)
+#define CLOCK_MONOTONIC_RAW CLOCK_MONOTONIC
+#endif
+
+namespace linux
+{
+
+template <clockid_t CLOCK>
+class Clock
+{
+public:
+  std::chrono::microseconds micros() const
+  {
+    ::timespec ts;
+    ::clock_gettime(CLOCK, &ts);
+    std::uint64_t ns = ts.tv_sec * 1000000000ULL + ts.tv_nsec;
+    return std::chrono::microseconds(ns / 1000ULL);
+  }
+};
+
+using ClockMonotonic = Clock<CLOCK_MONOTONIC>;
+using ClockMonotonicRaw = Clock<CLOCK_MONOTONIC_RAW>;
+
+} // namespace linux
+} // namespace platforms
+} // namespace ableton
diff --git a/link/include/ableton/platforms/linux/Linux.hpp b/link/include/ableton/platforms/linux/Linux.hpp
new file mode 100644
--- /dev/null
+++ b/link/include/ableton/platforms/linux/Linux.hpp
@@ -0,0 +1,30 @@
+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.
+ *
+ *  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 2 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 <http://www.gnu.org/licenses/>.
+ *
+ *  If you would like to incorporate Link into a proprietary software application,
+ *  please contact <link-devs@ableton.com>.
+ */
+
+#pragma once
+
+#include <byteswap.h>
+
+#ifndef ntohll
+#define ntohll(x) bswap_64(x)
+#endif
+
+#ifndef htonll
+#define htonll(x) bswap_64(x)
+#endif
diff --git a/link/include/ableton/platforms/linux/ThreadFactory.hpp b/link/include/ableton/platforms/linux/ThreadFactory.hpp
new file mode 100644
--- /dev/null
+++ b/link/include/ableton/platforms/linux/ThreadFactory.hpp
@@ -0,0 +1,45 @@
+/* Copyright 2021, Ableton AG, Berlin. All rights reserved.
+ *
+ *  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 2 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 <http://www.gnu.org/licenses/>.
+ *
+ *  If you would like to incorporate Link into a proprietary software application,
+ *  please contact <link-devs@ableton.com>.
+ */
+
+#pragma once
+
+#include <pthread.h>
+#include <thread>
+
+namespace ableton
+{
+namespace platforms
+{
+namespace linux
+{
+
+struct ThreadFactory
+{
+  template <typename Callable, typename... Args>
+  static std::thread makeThread(std::string name, Callable&& f, Args&&... args)
+  {
+    auto thread = std::thread(std::forward<Callable>(f), std::forward<Args>(args)...);
+    pthread_setname_np(thread.native_handle(), name.c_str());
+    return thread;
+  }
+};
+
+} // namespace linux
+} // namespace platforms
+} // namespace ableton
diff --git a/link/include/ableton/platforms/posix/ScanIpIfAddrs.hpp b/link/include/ableton/platforms/posix/ScanIpIfAddrs.hpp
new file mode 100644
--- /dev/null
+++ b/link/include/ableton/platforms/posix/ScanIpIfAddrs.hpp
@@ -0,0 +1,110 @@
+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.
+ *
+ *  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 2 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 <http://www.gnu.org/licenses/>.
+ *
+ *  If you would like to incorporate Link into a proprietary software application,
+ *  please contact <link-devs@ableton.com>.
+ */
+
+#pragma once
+
+#include <ableton/platforms/asio/AsioWrapper.hpp>
+#include <ableton/platforms/asio/Util.hpp>
+#include <arpa/inet.h>
+#include <ifaddrs.h>
+#include <net/if.h>
+#include <vector>
+
+namespace ableton
+{
+namespace platforms
+{
+namespace posix
+{
+namespace detail
+{
+
+// RAII type to make [get,free]ifaddrs function pairs exception safe
+class GetIfAddrs
+{
+public:
+  GetIfAddrs()
+  {
+    if (getifaddrs(&interfaces)) // returns 0 on success
+    {
+      interfaces = NULL;
+    }
+  }
+  ~GetIfAddrs()
+  {
+    if (interfaces)
+      freeifaddrs(interfaces);
+  }
+
+  // RAII must not copy
+  GetIfAddrs(GetIfAddrs&) = delete;
+  GetIfAddrs& operator=(GetIfAddrs&) = delete;
+
+  template <typename Function>
+  void withIfAddrs(Function f)
+  {
+    if (interfaces)
+      f(*interfaces);
+  }
+
+private:
+  struct ifaddrs* interfaces = NULL;
+};
+
+} // namespace detail
+
+
+// Posix implementation of ip interface address scanner
+struct ScanIpIfAddrs
+{
+  // Scan active network interfaces and return corresponding addresses
+  // for all ip-based interfaces.
+  std::vector<::asio::ip::address> operator()()
+  {
+    std::vector<::asio::ip::address> addrs;
+
+    detail::GetIfAddrs getIfAddrs;
+    getIfAddrs.withIfAddrs([&addrs](const struct ifaddrs& interfaces) {
+      const struct ifaddrs* interface;
+      for (interface = &interfaces; interface; interface = interface->ifa_next)
+      {
+        auto addr = reinterpret_cast<const struct sockaddr_in*>(interface->ifa_addr);
+        if (addr && interface->ifa_flags & IFF_UP)
+        {
+          if (addr->sin_family == AF_INET)
+          {
+            auto bytes = reinterpret_cast<const char*>(&addr->sin_addr);
+            addrs.emplace_back(asio::makeAddress<::asio::ip::address_v4>(bytes));
+          }
+          else if (addr->sin_family == AF_INET6)
+          {
+            auto addr6 = reinterpret_cast<const struct sockaddr_in6*>(addr);
+            auto bytes = reinterpret_cast<const char*>(&addr6->sin6_addr);
+            addrs.emplace_back(asio::makeAddress<::asio::ip::address_v6>(bytes));
+          }
+        }
+      }
+    });
+    return addrs;
+  }
+};
+
+} // namespace posix
+} // namespace platforms
+} // namespace ableton
diff --git a/link/include/ableton/platforms/stl/Clock.hpp b/link/include/ableton/platforms/stl/Clock.hpp
new file mode 100644
--- /dev/null
+++ b/link/include/ableton/platforms/stl/Clock.hpp
@@ -0,0 +1,43 @@
+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.
+ *
+ *  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 2 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 <http://www.gnu.org/licenses/>.
+ *
+ *  If you would like to incorporate Link into a proprietary software application,
+ *  please contact <link-devs@ableton.com>.
+ */
+
+#pragma once
+
+#include <chrono>
+
+namespace ableton
+{
+namespace platforms
+{
+namespace stl
+{
+
+struct Clock
+{
+  std::chrono::microseconds micros() const
+  {
+    using namespace std::chrono;
+    auto nowInMicros = time_point_cast<microseconds>(steady_clock::now());
+    return nowInMicros.time_since_epoch();
+  }
+};
+
+} // namespace stl
+} // namespace platforms
+} // namespace ableton
diff --git a/link/include/ableton/platforms/stl/Random.hpp b/link/include/ableton/platforms/stl/Random.hpp
new file mode 100644
--- /dev/null
+++ b/link/include/ableton/platforms/stl/Random.hpp
@@ -0,0 +1,51 @@
+/* Copyright 2019, Ableton AG, Berlin. All rights reserved.
+ *
+ *  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 2 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 <http://www.gnu.org/licenses/>.
+ *
+ *  If you would like to incorporate Link into a proprietary software application,
+ *  please contact <link-devs@ableton.com>.
+ */
+
+#pragma once
+
+#include <random>
+
+namespace ableton
+{
+namespace platforms
+{
+namespace stl
+{
+
+struct Random
+{
+  Random()
+    : gen(rd())
+    , dist(33, 126) // printable ascii chars
+  {
+  }
+
+  uint8_t operator()()
+  {
+    return static_cast<uint8_t>(dist(gen));
+  }
+
+  std::random_device rd;
+  std::mt19937 gen;
+  std::uniform_int_distribution<unsigned> dist;
+};
+
+} // namespace stl
+} // namespace platforms
+} // namespace ableton
diff --git a/link/include/ableton/platforms/windows/Clock.hpp b/link/include/ableton/platforms/windows/Clock.hpp
new file mode 100644
--- /dev/null
+++ b/link/include/ableton/platforms/windows/Clock.hpp
@@ -0,0 +1,71 @@
+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.
+ *
+ *  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 2 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 <http://www.gnu.org/licenses/>.
+ *
+ *  If you would like to incorporate Link into a proprietary software application,
+ *  please contact <link-devs@ableton.com>.
+ */
+
+#pragma once
+
+#include <chrono>
+#include <cstdint>
+
+namespace ableton
+{
+namespace platforms
+{
+namespace windows
+{
+
+struct Clock
+{
+  using Ticks = std::int64_t;
+  using Micros = std::chrono::microseconds;
+
+  Clock()
+  {
+    LARGE_INTEGER frequency;
+    QueryPerformanceFrequency(&frequency);
+    mTicksToMicros = 1.0e6 / static_cast<double>(frequency.QuadPart);
+  }
+
+  Micros ticksToMicros(const Ticks ticks) const
+  {
+    return Micros{llround(mTicksToMicros * static_cast<double>(ticks))};
+  }
+
+  Ticks microsToTicks(const Micros micros) const
+  {
+    return static_cast<Ticks>(static_cast<double>(micros.count()) / mTicksToMicros);
+  }
+
+  Ticks ticks() const
+  {
+    LARGE_INTEGER count;
+    QueryPerformanceCounter(&count);
+    return count.QuadPart;
+  }
+
+  std::chrono::microseconds micros() const
+  {
+    return ticksToMicros(ticks());
+  }
+
+  double mTicksToMicros;
+};
+
+} // namespace windows
+} // namespace platforms
+} // namespace ableton
diff --git a/link/include/ableton/platforms/windows/ScanIpIfAddrs.hpp b/link/include/ableton/platforms/windows/ScanIpIfAddrs.hpp
new file mode 100644
--- /dev/null
+++ b/link/include/ableton/platforms/windows/ScanIpIfAddrs.hpp
@@ -0,0 +1,140 @@
+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.
+ *
+ *  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 2 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 <http://www.gnu.org/licenses/>.
+ *
+ *  If you would like to incorporate Link into a proprietary software application,
+ *  please contact <link-devs@ableton.com>.
+ */
+
+#pragma once
+
+#include <ableton/platforms/asio/AsioWrapper.hpp>
+#include <ableton/platforms/asio/Util.hpp>
+#include <iphlpapi.h>
+#include <stdio.h>
+#include <vector>
+#include <winsock2.h>
+#include <ws2tcpip.h>
+
+#pragma comment(lib, "iphlpapi.lib")
+#pragma comment(lib, "ws2_32.lib")
+
+namespace ableton
+{
+namespace platforms
+{
+namespace windows
+{
+namespace detail
+{
+// RAII type to make [get,free]ifaddrs function pairs exception safe
+class GetIfAddrs
+{
+public:
+  GetIfAddrs()
+  {
+    const int MAX_TRIES = 3;               // MSFT recommendation
+    const int WORKING_BUFFER_SIZE = 15000; // MSFT recommendation
+
+    DWORD adapter_addrs_buffer_size = WORKING_BUFFER_SIZE;
+    for (int i = 0; i < MAX_TRIES; i++)
+    {
+      adapter_addrs = (IP_ADAPTER_ADDRESSES*)malloc(adapter_addrs_buffer_size);
+      assert(adapter_addrs);
+
+      DWORD error = ::GetAdaptersAddresses(AF_UNSPEC,
+        GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER
+          | GAA_FLAG_SKIP_FRIENDLY_NAME,
+        NULL, adapter_addrs, &adapter_addrs_buffer_size);
+
+      if (error == ERROR_SUCCESS)
+      {
+        break;
+      }
+      // if buffer too small, use new buffer size in next iteration
+      if (error == ERROR_BUFFER_OVERFLOW)
+      {
+        free(adapter_addrs);
+        adapter_addrs = NULL;
+        continue;
+      }
+    }
+  }
+  ~GetIfAddrs()
+  {
+    if (adapter_addrs)
+      free(adapter_addrs);
+  }
+
+  // RAII must not copy
+  GetIfAddrs(GetIfAddrs&) = delete;
+  GetIfAddrs& operator=(GetIfAddrs&) = delete;
+
+  template <typename Function>
+  void withIfAddrs(Function f)
+  {
+    if (adapter_addrs)
+      f(*adapter_addrs);
+  }
+
+private:
+  IP_ADAPTER_ADDRESSES* adapter_addrs;
+  IP_ADAPTER_ADDRESSES* adapter;
+};
+
+} // namespace detail
+
+struct ScanIpIfAddrs
+{
+  // Scan active network interfaces and return corresponding addresses
+  // for all ip-based interfaces.
+  std::vector<::asio::ip::address> operator()()
+  {
+    std::vector<::asio::ip::address> addrs;
+
+    detail::GetIfAddrs getIfAddrs;
+    getIfAddrs.withIfAddrs([&addrs](const IP_ADAPTER_ADDRESSES& interfaces) {
+      const IP_ADAPTER_ADDRESSES* networkInterface;
+      for (networkInterface = &interfaces; networkInterface;
+           networkInterface = networkInterface->Next)
+      {
+        for (IP_ADAPTER_UNICAST_ADDRESS* address = networkInterface->FirstUnicastAddress;
+             NULL != address; address = address->Next)
+        {
+          auto family = address->Address.lpSockaddr->sa_family;
+          if (AF_INET == family)
+          {
+            // IPv4
+            SOCKADDR_IN* addr4 =
+              reinterpret_cast<SOCKADDR_IN*>(address->Address.lpSockaddr);
+            auto bytes = reinterpret_cast<const char*>(&addr4->sin_addr);
+            addrs.emplace_back(asio::makeAddress<::asio::ip::address_v4>(bytes));
+          }
+          else if (AF_INET6 == family)
+          {
+            SOCKADDR_IN6* addr6 =
+              reinterpret_cast<SOCKADDR_IN6*>(address->Address.lpSockaddr);
+            auto bytes = reinterpret_cast<const char*>(&addr6->sin6_addr);
+            addrs.emplace_back(asio::makeAddress<::asio::ip::address_v6>(bytes));
+          }
+        }
+      }
+    });
+    return addrs;
+  }
+};
+
+} // namespace windows
+} // namespace platforms
+} // namespace ableton
diff --git a/link/include/ableton/platforms/windows/ThreadFactory.hpp b/link/include/ableton/platforms/windows/ThreadFactory.hpp
new file mode 100644
--- /dev/null
+++ b/link/include/ableton/platforms/windows/ThreadFactory.hpp
@@ -0,0 +1,52 @@
+/* Copyright 2021, Ableton AG, Berlin. All rights reserved.
+ *
+ *  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 2 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 <http://www.gnu.org/licenses/>.
+ *
+ *  If you would like to incorporate Link into a proprietary software application,
+ *  please contact <link-devs@ableton.com>.
+ */
+
+#pragma once
+
+#include <processthreadsapi.h>
+#include <thread>
+#include <utility>
+
+namespace ableton
+{
+namespace platforms
+{
+namespace windows
+{
+
+struct ThreadFactory
+{
+  template <typename Callable, typename... Args>
+  static std::thread makeThread(std::string name, Callable&& f, Args&&... args)
+  {
+    return std::thread(
+      [](std::string name, Callable&& f, Args&&... args) {
+        assert(name.length() < 20);
+        wchar_t nativeName[20];
+        mbstowcs(nativeName, name.c_str(), name.length() + 1);
+        SetThreadDescription(GetCurrentThread(), nativeName);
+        f(args...);
+      },
+      std::move(name), std::forward<Callable>(f), std::forward<Args>(args)...);
+  }
+};
+
+} // namespace windows
+} // namespace platforms
+} // namespace ableton
diff --git a/link/include/ableton/platforms/windows/Windows.hpp b/link/include/ableton/platforms/windows/Windows.hpp
new file mode 100644
--- /dev/null
+++ b/link/include/ableton/platforms/windows/Windows.hpp
@@ -0,0 +1,32 @@
+/* Copyright 2020, Ableton AG, Berlin. All rights reserved.
+ *
+ *  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 2 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 <http://www.gnu.org/licenses/>.
+ *
+ *  If you would like to incorporate Link into a proprietary software application,
+ *  please contact <link-devs@ableton.com>.
+ */
+
+#pragma once
+
+// ntohll and htonll are not defined for MinGW
+
+#ifdef __MINGW32__
+#if __BIG_ENDIAN__
+#define htonll(x) (x)
+#define ntohll(x) (x)
+#else
+#define htonll(x) (((uint64_t)htonl((x)&0xFFFFFFFF) << 32) | htonl((x) >> 32))
+#define ntohll(x) (((uint64_t)ntohl((x)&0xFFFFFFFF) << 32) | ntohl((x) >> 32))
+#endif
+#endif
diff --git a/link/include/ableton/test/CatchWrapper.hpp b/link/include/ableton/test/CatchWrapper.hpp
new file mode 100644
--- /dev/null
+++ b/link/include/ableton/test/CatchWrapper.hpp
@@ -0,0 +1,42 @@
+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.
+ *
+ *  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 2 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 <http://www.gnu.org/licenses/>.
+ *
+ *  If you would like to incorporate Link into a proprietary software application,
+ *  please contact <link-devs@ableton.com>.
+ */
+
+#pragma once
+
+/*!
+ * \brief Wrapper file for Catch library
+ *
+ * This file includes the Catch header for Link, and also disables some compiler warnings
+ * which are specific to that library.
+ */
+
+#if defined(_MSC_VER)
+#pragma warning(push, 0)
+#pragma warning(disable : 4242)
+#pragma warning(disable : 4244)
+#pragma warning(disable : 4668)
+#pragma warning(disable : 4702)
+#pragma warning(disable : 5220)
+#endif
+
+#include <catch.hpp>
+
+#if defined(_MSC_VER)
+#pragma warning(pop)
+#endif
diff --git a/link/include/ableton/test/serial_io/Context.hpp b/link/include/ableton/test/serial_io/Context.hpp
new file mode 100644
--- /dev/null
+++ b/link/include/ableton/test/serial_io/Context.hpp
@@ -0,0 +1,109 @@
+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.
+ *
+ *  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 2 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 <http://www.gnu.org/licenses/>.
+ *
+ *  If you would like to incorporate Link into a proprietary software application,
+ *  please contact <link-devs@ableton.com>.
+ */
+
+#pragma once
+
+#include <ableton/platforms/asio/AsioWrapper.hpp>
+#include <ableton/test/serial_io/SchedulerTree.hpp>
+#include <ableton/test/serial_io/Timer.hpp>
+#include <ableton/util/Log.hpp>
+#include <chrono>
+#include <memory>
+
+namespace ableton
+{
+namespace test
+{
+namespace serial_io
+{
+
+class Context
+{
+public:
+  Context(const SchedulerTree::TimePoint& now,
+    const std::vector<::asio::ip::address>& ifAddrs,
+    std::shared_ptr<SchedulerTree> pScheduler)
+    : mNow(now)
+    , mIfAddrs(ifAddrs)
+    , mpScheduler(std::move(pScheduler))
+    , mNextTimerId(0)
+  {
+  }
+
+  ~Context()
+  {
+    if (mpScheduler != nullptr)
+    {
+      // Finish any pending tasks before shutting down
+      mpScheduler->run();
+    }
+  }
+
+  Context(const Context&) = delete;
+  Context& operator=(const Context&) = delete;
+
+  Context(Context&& rhs)
+    : mNow(rhs.mNow)
+    , mIfAddrs(rhs.mIfAddrs)
+    , mpScheduler(std::move(rhs.mpScheduler))
+    , mLog(std::move(rhs.mLog))
+    , mNextTimerId(rhs.mNextTimerId)
+  {
+  }
+
+  void stop()
+  {
+  }
+
+  template <typename Handler>
+  void async(Handler handler)
+  {
+    mpScheduler->async(std::move(handler));
+  }
+
+  using Timer = serial_io::Timer;
+
+  Timer makeTimer()
+  {
+    return {mNextTimerId++, mNow, mpScheduler};
+  }
+
+  using Log = util::NullLog;
+
+  Log& log()
+  {
+    return mLog;
+  }
+
+  std::vector<::asio::ip::address> scanNetworkInterfaces()
+  {
+    return mIfAddrs;
+  }
+
+private:
+  const SchedulerTree::TimePoint& mNow;
+  const std::vector<::asio::ip::address>& mIfAddrs;
+  std::shared_ptr<SchedulerTree> mpScheduler;
+  Log mLog;
+  SchedulerTree::TimerId mNextTimerId;
+};
+
+} // namespace serial_io
+} // namespace test
+} // namespace ableton
diff --git a/link/include/ableton/test/serial_io/Fixture.hpp b/link/include/ableton/test/serial_io/Fixture.hpp
new file mode 100644
--- /dev/null
+++ b/link/include/ableton/test/serial_io/Fixture.hpp
@@ -0,0 +1,92 @@
+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.
+ *
+ *  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 2 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 <http://www.gnu.org/licenses/>.
+ *
+ *  If you would like to incorporate Link into a proprietary software application,
+ *  please contact <link-devs@ableton.com>.
+ */
+
+#pragma once
+
+#include <ableton/platforms/asio/AsioWrapper.hpp>
+#include <ableton/test/serial_io/Context.hpp>
+#include <chrono>
+#include <memory>
+
+namespace ableton
+{
+namespace test
+{
+namespace serial_io
+{
+
+class Fixture
+{
+public:
+  Fixture()
+    : mpScheduler(std::make_shared<SchedulerTree>())
+    , mNow(std::chrono::milliseconds{123456789})
+  {
+  }
+
+  ~Fixture()
+  {
+    flush();
+  }
+
+  Fixture(const Fixture&) = delete;
+  Fixture& operator=(const Fixture&) = delete;
+  Fixture(Fixture&&) = delete;
+  Fixture& operator=(Fixture&&) = delete;
+
+  void setNetworkInterfaces(std::vector<::asio::ip::address> ifAddrs)
+  {
+    mIfAddrs = std::move(ifAddrs);
+  }
+
+  Context makeIoContext()
+  {
+    return {mNow, mIfAddrs, mpScheduler};
+  }
+
+  void flush()
+  {
+    mpScheduler->run();
+  }
+
+  template <typename T, typename Rep>
+  void advanceTime(std::chrono::duration<T, Rep> duration)
+  {
+    const auto target = mNow + duration;
+    mpScheduler->run();
+    auto nextTimer = mpScheduler->nextTimerExpiration();
+    while (nextTimer <= target)
+    {
+      mNow = nextTimer;
+      mpScheduler->triggerTimersUntil(mNow);
+      mpScheduler->run();
+      nextTimer = mpScheduler->nextTimerExpiration();
+    }
+    mNow = target;
+  }
+
+private:
+  std::shared_ptr<SchedulerTree> mpScheduler;
+  SchedulerTree::TimePoint mNow;
+  std::vector<::asio::ip::address> mIfAddrs;
+};
+
+} // namespace serial_io
+} // namespace test
+} // namespace ableton
diff --git a/link/include/ableton/test/serial_io/SchedulerTree.hpp b/link/include/ableton/test/serial_io/SchedulerTree.hpp
new file mode 100644
--- /dev/null
+++ b/link/include/ableton/test/serial_io/SchedulerTree.hpp
@@ -0,0 +1,104 @@
+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.
+ *
+ *  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 2 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 <http://www.gnu.org/licenses/>.
+ *
+ *  If you would like to incorporate Link into a proprietary software application,
+ *  please contact <link-devs@ableton.com>.
+ */
+
+#pragma once
+
+#include <chrono>
+#include <functional>
+#include <list>
+#include <map>
+#include <memory>
+
+namespace ableton
+{
+namespace test
+{
+namespace serial_io
+{
+
+class SchedulerTree
+{
+public:
+  using TimePoint = std::chrono::system_clock::time_point;
+  using TimerId = std::size_t;
+  using TimerErrorCode = int;
+
+  void run();
+
+  std::shared_ptr<SchedulerTree> makeChild();
+
+  template <typename Handler>
+  void async(Handler handler)
+  {
+    mPendingHandlers.push_back(std::move(handler));
+  }
+
+  template <typename Handler>
+  void setTimer(const TimerId timerId, const TimePoint expiration, Handler handler)
+  {
+    using namespace std;
+    mTimers[make_pair(std::move(expiration), timerId)] = std::move(handler);
+  }
+
+  void cancelTimer(const TimerId timerId);
+
+  // returns the time that the next timer in the subtree expires
+  TimePoint nextTimerExpiration();
+
+  // triggers all timers in the subtree that expire at time t or before
+  void triggerTimersUntil(const TimePoint t);
+
+private:
+  // returns true if some work was done, false if there was none to do
+  bool handlePending();
+
+  // returns the time that the next timer from this node expires
+  TimePoint nextOwnTimerExpiration();
+
+  // Traversal function over children that cleans up children that
+  // have been destroyed.
+  template <typename Fn>
+  void withChildren(Fn fn)
+  {
+    auto it = begin(mChildren);
+    while (it != end(mChildren))
+    {
+      const auto childIt = it++;
+      auto pChild = childIt->lock();
+      if (pChild)
+      {
+        fn(*pChild);
+      }
+      else
+      {
+        mChildren.erase(childIt);
+      }
+    }
+  }
+
+  using TimerHandler = std::function<void(TimerErrorCode)>;
+  using TimerMap = std::map<std::pair<TimePoint, TimerId>, TimerHandler>;
+  TimerMap mTimers;
+  std::list<std::function<void()>> mPendingHandlers;
+  std::list<std::weak_ptr<SchedulerTree>> mChildren;
+};
+
+} // namespace serial_io
+} // namespace test
+} // namespace ableton
diff --git a/link/include/ableton/test/serial_io/Timer.hpp b/link/include/ableton/test/serial_io/Timer.hpp
new file mode 100644
--- /dev/null
+++ b/link/include/ableton/test/serial_io/Timer.hpp
@@ -0,0 +1,110 @@
+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.
+ *
+ *  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 2 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 <http://www.gnu.org/licenses/>.
+ *
+ *  If you would like to incorporate Link into a proprietary software application,
+ *  please contact <link-devs@ableton.com>.
+ */
+
+#pragma once
+
+#include <ableton/test/serial_io/SchedulerTree.hpp>
+
+namespace ableton
+{
+namespace test
+{
+namespace serial_io
+{
+
+struct Timer
+{
+  using ErrorCode = SchedulerTree::TimerErrorCode;
+  using TimePoint = SchedulerTree::TimePoint;
+
+  Timer(const SchedulerTree::TimerId timerId,
+    const TimePoint& now,
+    std::shared_ptr<SchedulerTree> pScheduler)
+    : mId(timerId)
+    , mNow(now)
+    , mpScheduler(std::move(pScheduler))
+  {
+  }
+
+  ~Timer()
+  {
+    if (!mbMovedFrom)
+    {
+      cancel();
+    }
+  }
+
+  Timer(const Timer&) = delete;
+
+  Timer(Timer&& rhs)
+    : mId(rhs.mId)
+    , mNow(rhs.mNow)
+    , mExpiration(std::move(rhs.mExpiration))
+    , mpScheduler(std::move(rhs.mpScheduler))
+  {
+    rhs.mbMovedFrom = true;
+  }
+
+  void expires_at(const TimePoint t)
+  {
+    if (t < mNow)
+    {
+      throw std::runtime_error("Setting timer in the past");
+    }
+    else
+    {
+      cancel();
+      mExpiration = t;
+    }
+  }
+
+  template <typename T, typename Rep>
+  void expires_from_now(std::chrono::duration<T, Rep> duration)
+  {
+    expires_at(mNow + duration);
+  }
+
+  void cancel()
+  {
+    auto pScheduler = mpScheduler.lock();
+    pScheduler->cancelTimer(mId);
+  }
+
+  template <typename Handler>
+  void async_wait(Handler handler)
+  {
+    auto pScheduler = mpScheduler.lock();
+    pScheduler->setTimer(mId, mExpiration, std::move(handler));
+  }
+
+  TimePoint now() const
+  {
+    return mNow;
+  }
+
+  const SchedulerTree::TimerId mId;
+  const TimePoint& mNow;
+  TimePoint mExpiration;
+  std::weak_ptr<SchedulerTree> mpScheduler;
+  bool mbMovedFrom = false;
+};
+
+} // namespace serial_io
+} // namespace test
+} // namespace ableton
diff --git a/link/include/ableton/util/Injected.hpp b/link/include/ableton/util/Injected.hpp
new file mode 100644
--- /dev/null
+++ b/link/include/ableton/util/Injected.hpp
@@ -0,0 +1,254 @@
+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.
+ *
+ *  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 2 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 <http://www.gnu.org/licenses/>.
+ *
+ *  If you would like to incorporate Link into a proprietary software application,
+ *  please contact <link-devs@ableton.com>.
+ */
+
+#pragma once
+
+#include <memory>
+
+namespace ableton
+{
+namespace util
+{
+
+// Utility type for aiding in dependency injection.
+
+// Base template and implementation for injected valued
+template <typename T>
+struct Injected
+{
+  using type = T;
+
+  Injected() = default;
+
+  explicit Injected(T t)
+    : val(std::move(t))
+  {
+  }
+
+  Injected(const Injected&) = default;
+  Injected& operator=(const Injected&) = default;
+
+  Injected(Injected&& rhs)
+    : val(std::move(rhs.val))
+  {
+  }
+
+  Injected& operator=(Injected&& rhs)
+  {
+    val = std::move(rhs.val);
+    return *this;
+  }
+
+  T* operator->()
+  {
+    return &val;
+  }
+
+  const T* operator->() const
+  {
+    return &val;
+  }
+
+  T& operator*()
+  {
+    return val;
+  }
+
+  const T& operator*() const
+  {
+    return val;
+  }
+
+  T val;
+};
+
+// Utility function for injecting values
+template <typename T>
+Injected<T> injectVal(T t)
+{
+  return Injected<T>(std::move(t));
+}
+
+// Specialization for injected references
+template <typename T>
+struct Injected<T&>
+{
+  using type = T;
+
+  explicit Injected(T& t)
+    : ref(std::ref(t))
+  {
+  }
+
+  Injected(const Injected&) = default;
+  Injected& operator=(const Injected&) = default;
+
+  Injected(Injected&& rhs)
+    : ref(std::move(rhs.ref))
+  {
+  }
+
+  Injected& operator=(Injected&& rhs)
+  {
+    ref = std::move(rhs.ref);
+    return *this;
+  }
+
+  T* operator->()
+  {
+    return &ref.get();
+  }
+
+  const T* operator->() const
+  {
+    return &ref.get();
+  }
+
+  T& operator*()
+  {
+    return ref;
+  }
+
+  const T& operator*() const
+  {
+    return ref;
+  }
+
+  std::reference_wrapper<T> ref;
+};
+
+// Utility function for injecting references
+template <typename T>
+Injected<T&> injectRef(T& t)
+{
+  return Injected<T&>(t);
+}
+
+// Specialization for injected shared_ptr
+template <typename T>
+struct Injected<std::shared_ptr<T>>
+{
+  using type = T;
+
+  explicit Injected(std::shared_ptr<T> pT)
+    : shared(std::move(pT))
+  {
+  }
+
+  Injected(const Injected&) = default;
+  Injected& operator=(const Injected&) = default;
+
+  Injected(Injected&& rhs)
+    : shared(std::move(rhs.shared))
+  {
+  }
+
+  Injected& operator=(Injected&& rhs)
+  {
+    shared = std::move(rhs.shared);
+    return *this;
+  }
+
+  T* operator->()
+  {
+    return shared.get();
+  }
+
+  const T* operator->() const
+  {
+    return shared.get();
+  }
+
+  T& operator*()
+  {
+    return *shared;
+  }
+
+  const T& operator*() const
+  {
+    return *shared;
+  }
+
+  std::shared_ptr<T> shared;
+};
+
+// Utility function for injected shared_ptr
+template <typename T>
+Injected<std::shared_ptr<T>> injectShared(std::shared_ptr<T> shared)
+{
+  return Injected<std::shared_ptr<T>>(std::move(shared));
+}
+
+// Specialization for injected unique_ptr
+template <typename T>
+struct Injected<std::unique_ptr<T>>
+{
+  using type = T;
+
+  explicit Injected(std::unique_ptr<T> pT)
+    : unique(std::move(pT))
+  {
+  }
+
+  Injected(const Injected&) = default;
+  Injected& operator=(const Injected&) = default;
+
+  Injected(Injected&& rhs)
+    : unique(std::move(rhs.unique))
+  {
+  }
+
+  Injected& operator=(Injected&& rhs)
+  {
+    unique = std::move(rhs.unique);
+    return *this;
+  }
+
+  T* operator->()
+  {
+    return unique.get();
+  }
+
+  const T* operator->() const
+  {
+    return unique.get();
+  }
+
+  T& operator*()
+  {
+    return *unique;
+  }
+
+  const T& operator*() const
+  {
+    return *unique;
+  }
+
+  std::unique_ptr<T> unique;
+};
+
+// Utility function for injected unique_ptr
+template <typename T>
+Injected<std::unique_ptr<T>> injectUnique(std::unique_ptr<T> unique)
+{
+  return Injected<std::unique_ptr<T>>(std::move(unique));
+}
+
+} // namespace util
+} // namespace ableton
diff --git a/link/include/ableton/util/Log.hpp b/link/include/ableton/util/Log.hpp
new file mode 100644
--- /dev/null
+++ b/link/include/ableton/util/Log.hpp
@@ -0,0 +1,176 @@
+// Copyright: 2014, Ableton AG, Berlin, all rights reserved
+
+#pragma once
+
+#include <ableton/util/Injected.hpp>
+#include <iostream>
+#include <string>
+
+namespace ableton
+{
+namespace util
+{
+
+// Null object for the Log concept
+struct NullLog
+{
+  template <typename T>
+  friend const NullLog& operator<<(const NullLog& log, const T&)
+  {
+    return log;
+  }
+
+  friend const NullLog& debug(const NullLog& log)
+  {
+    return log;
+  }
+
+  friend const NullLog& info(const NullLog& log)
+  {
+    return log;
+  }
+
+  friend const NullLog& warning(const NullLog& log)
+  {
+    return log;
+  }
+
+  friend const NullLog& error(const NullLog& log)
+  {
+    return log;
+  }
+
+  friend NullLog channel(const NullLog&, std::string)
+  {
+    return {};
+  }
+};
+
+// std streams-based log
+struct StdLog
+{
+  StdLog(std::string channelName = "")
+    : mChannelName(std::move(channelName))
+  {
+  }
+
+  // Stream type used by std log to prepend the channel name to log messages
+  struct StdLogStream
+  {
+    StdLogStream(std::ostream& ioStream, const std::string& channelName)
+      : mpIoStream(&ioStream)
+      , mChannelName(channelName)
+    {
+      ioStream << "[" << mChannelName << "] ";
+    }
+
+    StdLogStream(StdLogStream&& rhs)
+      : mpIoStream(rhs.mpIoStream)
+      , mChannelName(rhs.mChannelName)
+    {
+      rhs.mpIoStream = nullptr;
+    }
+
+    ~StdLogStream()
+    {
+      if (mpIoStream)
+      {
+        (*mpIoStream) << "\n";
+      }
+    }
+
+    template <typename T>
+    std::ostream& operator<<(const T& rhs)
+    {
+      (*mpIoStream) << rhs;
+      return *mpIoStream;
+    }
+
+    std::ostream* mpIoStream;
+    const std::string& mChannelName;
+  };
+
+  friend StdLogStream debug(const StdLog& log)
+  {
+    return {std::clog, log.mChannelName};
+  }
+
+  friend StdLogStream info(const StdLog& log)
+  {
+    return {std::clog, log.mChannelName};
+  }
+
+  friend StdLogStream warning(const StdLog& log)
+  {
+    return {std::clog, log.mChannelName};
+  }
+
+  friend StdLogStream error(const StdLog& log)
+  {
+    return {std::cerr, log.mChannelName};
+  }
+
+  friend StdLog channel(const StdLog& log, const std::string& channelName)
+  {
+    auto compositeName =
+      log.mChannelName.empty() ? channelName : log.mChannelName + "::" + channelName;
+    return {std::move(compositeName)};
+  }
+
+  std::string mChannelName;
+};
+
+// Log adapter that adds timestamps
+template <typename Log>
+struct Timestamped
+{
+  using InnerLog = typename util::Injected<Log>::type;
+
+  Timestamped() = default;
+
+  Timestamped(util::Injected<Log> log)
+    : mLog(std::move(log))
+  {
+  }
+
+  util::Injected<Log> mLog;
+
+  friend decltype(debug(std::declval<InnerLog>())) debug(const Timestamped& log)
+  {
+    return log.logTimestamp(debug(*log.mLog));
+  }
+
+  friend decltype(info(std::declval<InnerLog>())) info(const Timestamped& log)
+  {
+    return log.logTimestamp(info(*log.mLog));
+  }
+
+  friend decltype(warning(std::declval<InnerLog>())) warning(const Timestamped& log)
+  {
+    return log.logTimestamp(warning(*log.mLog));
+  }
+
+  friend decltype(error(std::declval<InnerLog>())) error(const Timestamped& log)
+  {
+    return log.logTimestamp(error(*log.mLog));
+  }
+
+  friend Timestamped channel(const Timestamped& log, const std::string& channelName)
+  {
+    return {channel(*log.mLog, channelName)};
+  }
+
+  template <typename Stream>
+  Stream logTimestamp(Stream&& streamRef) const
+  {
+    using namespace std::chrono;
+    Stream stream = std::forward<Stream>(streamRef);
+    stream << "|"
+           << duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count()
+           << "ms| ";
+    return stream;
+  }
+};
+
+} // namespace util
+} // namespace ableton
diff --git a/link/include/ableton/util/SafeAsyncHandler.hpp b/link/include/ableton/util/SafeAsyncHandler.hpp
new file mode 100644
--- /dev/null
+++ b/link/include/ableton/util/SafeAsyncHandler.hpp
@@ -0,0 +1,66 @@
+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.
+ *
+ *  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 2 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 <http://www.gnu.org/licenses/>.
+ *
+ *  If you would like to incorporate Link into a proprietary software application,
+ *  please contact <link-devs@ableton.com>.
+ */
+
+#pragma once
+
+#include <memory>
+
+namespace ableton
+{
+namespace util
+{
+
+// A utility handler for passing to async functions that may call the
+// handler past the lifetime of the wrapped delegate object.
+// The need for this is particularly driven by boost::asio timer
+// objects, which explicitly document that they may be called without
+// an error code after they have been cancelled. This has led to
+// several crashes. This handler wrapper implements a useful idiom for
+// avoiding this problem.
+
+template <typename Delegate>
+struct SafeAsyncHandler
+{
+  SafeAsyncHandler(const std::shared_ptr<Delegate>& pDelegate)
+    : mpDelegate(pDelegate)
+  {
+  }
+
+  template <typename... T>
+  void operator()(T&&... t) const
+  {
+    std::shared_ptr<Delegate> pDelegate = mpDelegate.lock();
+    if (pDelegate)
+    {
+      (*pDelegate)(std::forward<T>(t)...);
+    }
+  }
+
+  std::weak_ptr<Delegate> mpDelegate;
+};
+
+// Factory function for easily wrapping a shared_ptr to a handler
+template <typename Delegate>
+SafeAsyncHandler<Delegate> makeAsyncSafe(const std::shared_ptr<Delegate>& pDelegate)
+{
+  return {pDelegate};
+}
+
+} // namespace util
+} // namespace ableton
diff --git a/link/include/ableton/util/SampleTiming.hpp b/link/include/ableton/util/SampleTiming.hpp
new file mode 100644
--- /dev/null
+++ b/link/include/ableton/util/SampleTiming.hpp
@@ -0,0 +1,52 @@
+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.
+ *
+ *  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 2 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 <http://www.gnu.org/licenses/>.
+ *
+ *  If you would like to incorporate Link into a proprietary software application,
+ *  please contact <link-devs@ableton.com>.
+ */
+
+#pragma once
+
+#include <chrono>
+
+namespace ableton
+{
+namespace util
+{
+
+/*! Utility type to convert between time and sample index given the
+ *  time at the beginning of a buffer and the sample rate.
+ */
+struct SampleTiming
+{
+  double sampleAtTime(std::chrono::microseconds time) const
+  {
+    using namespace std::chrono;
+    return duration_cast<duration<double>>(time - mBufferBegin).count() * mSampleRate;
+  }
+
+  std::chrono::microseconds timeAtSample(const double sample) const
+  {
+    using namespace std::chrono;
+    return mBufferBegin
+           + duration_cast<microseconds>(duration<double>{sample / mSampleRate});
+  }
+
+  std::chrono::microseconds mBufferBegin;
+  double mSampleRate;
+};
+
+} // namespace util
+} // namespace ableton
diff --git a/link/include/ableton/util/test/IoService.hpp b/link/include/ableton/util/test/IoService.hpp
new file mode 100644
--- /dev/null
+++ b/link/include/ableton/util/test/IoService.hpp
@@ -0,0 +1,114 @@
+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.
+ *
+ *  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 2 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 <http://www.gnu.org/licenses/>.
+ *
+ *  If you would like to incorporate Link into a proprietary software application,
+ *  please contact <link-devs@ableton.com>.
+ */
+
+#pragma once
+
+#include <ableton/util/test/Timer.hpp>
+
+namespace ableton
+{
+namespace util
+{
+namespace test
+{
+
+struct IoService
+{
+  // Wrapper around the internal util::test::Timer in the list
+  struct Timer
+  {
+    using ErrorCode = test::Timer::ErrorCode;
+    using TimePoint = test::Timer::TimePoint;
+
+    Timer(util::test::Timer* pTimer)
+      : mpTimer(pTimer)
+    {
+    }
+
+    void expires_at(std::chrono::system_clock::time_point t)
+    {
+      mpTimer->expires_at(t);
+    }
+
+    template <typename T, typename Rep>
+    void expires_from_now(std::chrono::duration<T, Rep> duration)
+    {
+      mpTimer->expires_from_now(duration);
+    }
+
+    ErrorCode cancel()
+    {
+      return mpTimer->cancel();
+    }
+
+    template <typename Handler>
+    void async_wait(Handler handler)
+    {
+      mpTimer->async_wait(std::move(handler));
+    }
+
+    TimePoint now() const
+    {
+      return mpTimer->now();
+    }
+
+    util::test::Timer* mpTimer;
+  };
+
+  IoService() = default;
+
+  Timer makeTimer()
+  {
+    mTimers.emplace_back();
+    return Timer{&mTimers.back()};
+  }
+
+  template <typename Handler>
+  void post(Handler handler)
+  {
+    mHandlers.emplace_back(std::move(handler));
+  }
+
+  template <typename T, typename Rep>
+  void advance(std::chrono::duration<T, Rep> duration)
+  {
+    runHandlers();
+
+    for (auto& timer : mTimers)
+    {
+      timer.advance(duration);
+    }
+  }
+
+  void runHandlers()
+  {
+    for (auto& handler : mHandlers)
+    {
+      handler();
+    }
+    mHandlers.clear();
+  }
+
+  std::vector<std::function<void()>> mHandlers;
+  std::vector<util::test::Timer> mTimers;
+};
+
+} // namespace test
+} // namespace util
+} // namespace ableton
diff --git a/link/include/ableton/util/test/Timer.hpp b/link/include/ableton/util/test/Timer.hpp
new file mode 100644
--- /dev/null
+++ b/link/include/ableton/util/test/Timer.hpp
@@ -0,0 +1,96 @@
+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.
+ *
+ *  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 2 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 <http://www.gnu.org/licenses/>.
+ *
+ *  If you would like to incorporate Link into a proprietary software application,
+ *  please contact <link-devs@ableton.com>.
+ */
+
+#pragma once
+
+#include <chrono>
+#include <functional>
+
+namespace ableton
+{
+namespace util
+{
+namespace test
+{
+
+struct Timer
+{
+  using ErrorCode = int;
+  using TimePoint = std::chrono::system_clock::time_point;
+
+  // Initialize timer with an arbitrary large value to simulate the
+  // time_since_epoch of a real clock.
+  Timer()
+    : mNow{std::chrono::milliseconds{123456789}}
+  {
+  }
+
+  void expires_at(std::chrono::system_clock::time_point t)
+  {
+    cancel();
+    mFireAt = std::move(t);
+  }
+
+  template <typename T, typename Rep>
+  void expires_from_now(std::chrono::duration<T, Rep> duration)
+  {
+    cancel();
+    mFireAt = now() + duration;
+  }
+
+  ErrorCode cancel()
+  {
+    if (mHandler)
+    {
+      mHandler(1); // call existing handler with truthy error code
+    }
+    mHandler = nullptr;
+    return 0;
+  }
+
+  template <typename Handler>
+  void async_wait(Handler handler)
+  {
+    mHandler = [handler](ErrorCode ec) { handler(ec); };
+  }
+
+  std::chrono::system_clock::time_point now() const
+  {
+    return mNow;
+  }
+
+  template <typename T, typename Rep>
+  void advance(std::chrono::duration<T, Rep> duration)
+  {
+    mNow += duration;
+    if (mHandler && mFireAt < mNow)
+    {
+      mHandler(0);
+      mHandler = nullptr;
+    }
+  }
+
+  std::function<void(ErrorCode)> mHandler;
+  std::chrono::system_clock::time_point mFireAt;
+  std::chrono::system_clock::time_point mNow;
+};
+
+} // namespace test
+} // namespace util
+} // namespace ableton
diff --git a/link/modules/asio-standalone/asio/include/asio.hpp b/link/modules/asio-standalone/asio/include/asio.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio.hpp
@@ -0,0 +1,182 @@
+//
+// asio.hpp
+// ~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_HPP
+#define ASIO_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/associated_allocator.hpp"
+#include "asio/associated_executor.hpp"
+#include "asio/async_result.hpp"
+#include "asio/awaitable.hpp"
+#include "asio/basic_datagram_socket.hpp"
+#include "asio/basic_deadline_timer.hpp"
+#include "asio/basic_io_object.hpp"
+#include "asio/basic_raw_socket.hpp"
+#include "asio/basic_seq_packet_socket.hpp"
+#include "asio/basic_serial_port.hpp"
+#include "asio/basic_signal_set.hpp"
+#include "asio/basic_socket.hpp"
+#include "asio/basic_socket_acceptor.hpp"
+#include "asio/basic_socket_iostream.hpp"
+#include "asio/basic_socket_streambuf.hpp"
+#include "asio/basic_stream_socket.hpp"
+#include "asio/basic_streambuf.hpp"
+#include "asio/basic_waitable_timer.hpp"
+#include "asio/bind_executor.hpp"
+#include "asio/buffer.hpp"
+#include "asio/buffered_read_stream_fwd.hpp"
+#include "asio/buffered_read_stream.hpp"
+#include "asio/buffered_stream_fwd.hpp"
+#include "asio/buffered_stream.hpp"
+#include "asio/buffered_write_stream_fwd.hpp"
+#include "asio/buffered_write_stream.hpp"
+#include "asio/buffers_iterator.hpp"
+#include "asio/co_spawn.hpp"
+#include "asio/completion_condition.hpp"
+#include "asio/compose.hpp"
+#include "asio/connect.hpp"
+#include "asio/coroutine.hpp"
+#include "asio/deadline_timer.hpp"
+#include "asio/defer.hpp"
+#include "asio/detached.hpp"
+#include "asio/dispatch.hpp"
+#include "asio/error.hpp"
+#include "asio/error_code.hpp"
+#include "asio/execution.hpp"
+#include "asio/execution/allocator.hpp"
+#include "asio/execution/any_executor.hpp"
+#include "asio/execution/blocking.hpp"
+#include "asio/execution/blocking_adaptation.hpp"
+#include "asio/execution/bulk_execute.hpp"
+#include "asio/execution/bulk_guarantee.hpp"
+#include "asio/execution/connect.hpp"
+#include "asio/execution/context.hpp"
+#include "asio/execution/context_as.hpp"
+#include "asio/execution/execute.hpp"
+#include "asio/execution/executor.hpp"
+#include "asio/execution/invocable_archetype.hpp"
+#include "asio/execution/mapping.hpp"
+#include "asio/execution/occupancy.hpp"
+#include "asio/execution/operation_state.hpp"
+#include "asio/execution/outstanding_work.hpp"
+#include "asio/execution/prefer_only.hpp"
+#include "asio/execution/receiver.hpp"
+#include "asio/execution/receiver_invocation_error.hpp"
+#include "asio/execution/relationship.hpp"
+#include "asio/execution/schedule.hpp"
+#include "asio/execution/scheduler.hpp"
+#include "asio/execution/sender.hpp"
+#include "asio/execution/set_done.hpp"
+#include "asio/execution/set_error.hpp"
+#include "asio/execution/set_value.hpp"
+#include "asio/execution/start.hpp"
+#include "asio/execution_context.hpp"
+#include "asio/executor.hpp"
+#include "asio/executor_work_guard.hpp"
+#include "asio/generic/basic_endpoint.hpp"
+#include "asio/generic/datagram_protocol.hpp"
+#include "asio/generic/raw_protocol.hpp"
+#include "asio/generic/seq_packet_protocol.hpp"
+#include "asio/generic/stream_protocol.hpp"
+#include "asio/handler_alloc_hook.hpp"
+#include "asio/handler_continuation_hook.hpp"
+#include "asio/handler_invoke_hook.hpp"
+#include "asio/high_resolution_timer.hpp"
+#include "asio/io_context.hpp"
+#include "asio/io_context_strand.hpp"
+#include "asio/io_service.hpp"
+#include "asio/io_service_strand.hpp"
+#include "asio/ip/address.hpp"
+#include "asio/ip/address_v4.hpp"
+#include "asio/ip/address_v4_iterator.hpp"
+#include "asio/ip/address_v4_range.hpp"
+#include "asio/ip/address_v6.hpp"
+#include "asio/ip/address_v6_iterator.hpp"
+#include "asio/ip/address_v6_range.hpp"
+#include "asio/ip/network_v4.hpp"
+#include "asio/ip/network_v6.hpp"
+#include "asio/ip/bad_address_cast.hpp"
+#include "asio/ip/basic_endpoint.hpp"
+#include "asio/ip/basic_resolver.hpp"
+#include "asio/ip/basic_resolver_entry.hpp"
+#include "asio/ip/basic_resolver_iterator.hpp"
+#include "asio/ip/basic_resolver_query.hpp"
+#include "asio/ip/host_name.hpp"
+#include "asio/ip/icmp.hpp"
+#include "asio/ip/multicast.hpp"
+#include "asio/ip/resolver_base.hpp"
+#include "asio/ip/resolver_query_base.hpp"
+#include "asio/ip/tcp.hpp"
+#include "asio/ip/udp.hpp"
+#include "asio/ip/unicast.hpp"
+#include "asio/ip/v6_only.hpp"
+#include "asio/is_applicable_property.hpp"
+#include "asio/is_executor.hpp"
+#include "asio/is_read_buffered.hpp"
+#include "asio/is_write_buffered.hpp"
+#include "asio/local/basic_endpoint.hpp"
+#include "asio/local/connect_pair.hpp"
+#include "asio/local/datagram_protocol.hpp"
+#include "asio/local/stream_protocol.hpp"
+#include "asio/multiple_exceptions.hpp"
+#include "asio/packaged_task.hpp"
+#include "asio/placeholders.hpp"
+#include "asio/posix/basic_descriptor.hpp"
+#include "asio/posix/basic_stream_descriptor.hpp"
+#include "asio/posix/descriptor.hpp"
+#include "asio/posix/descriptor_base.hpp"
+#include "asio/posix/stream_descriptor.hpp"
+#include "asio/post.hpp"
+#include "asio/prefer.hpp"
+#include "asio/query.hpp"
+#include "asio/read.hpp"
+#include "asio/read_at.hpp"
+#include "asio/read_until.hpp"
+#include "asio/redirect_error.hpp"
+#include "asio/require.hpp"
+#include "asio/require_concept.hpp"
+#include "asio/serial_port.hpp"
+#include "asio/serial_port_base.hpp"
+#include "asio/signal_set.hpp"
+#include "asio/socket_base.hpp"
+#include "asio/static_thread_pool.hpp"
+#include "asio/steady_timer.hpp"
+#include "asio/strand.hpp"
+#include "asio/streambuf.hpp"
+#include "asio/system_context.hpp"
+#include "asio/system_error.hpp"
+#include "asio/system_executor.hpp"
+#include "asio/system_timer.hpp"
+#include "asio/this_coro.hpp"
+#include "asio/thread.hpp"
+#include "asio/thread_pool.hpp"
+#include "asio/time_traits.hpp"
+#include "asio/use_awaitable.hpp"
+#include "asio/use_future.hpp"
+#include "asio/uses_executor.hpp"
+#include "asio/version.hpp"
+#include "asio/wait_traits.hpp"
+#include "asio/windows/basic_object_handle.hpp"
+#include "asio/windows/basic_overlapped_handle.hpp"
+#include "asio/windows/basic_random_access_handle.hpp"
+#include "asio/windows/basic_stream_handle.hpp"
+#include "asio/windows/object_handle.hpp"
+#include "asio/windows/overlapped_handle.hpp"
+#include "asio/windows/overlapped_ptr.hpp"
+#include "asio/windows/random_access_handle.hpp"
+#include "asio/windows/stream_handle.hpp"
+#include "asio/write.hpp"
+#include "asio/write_at.hpp"
+
+#endif // ASIO_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/any_io_executor.hpp b/link/modules/asio-standalone/asio/include/asio/any_io_executor.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/any_io_executor.hpp
@@ -0,0 +1,71 @@
+//
+// any_io_executor.hpp
+// ~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_ANY_IO_EXECUTOR_HPP
+#define ASIO_ANY_IO_EXECUTOR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#if defined(ASIO_USE_TS_EXECUTOR_AS_DEFAULT)
+# include "asio/executor.hpp"
+#else // defined(ASIO_USE_TS_EXECUTOR_AS_DEFAULT)
+# include "asio/execution.hpp"
+# include "asio/execution_context.hpp"
+#endif // defined(ASIO_USE_TS_EXECUTOR_AS_DEFAULT)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+#if defined(ASIO_USE_TS_EXECUTOR_AS_DEFAULT)
+
+typedef executor any_io_executor;
+
+#else // defined(ASIO_USE_TS_EXECUTOR_AS_DEFAULT)
+
+/// Polymorphic executor type for use with I/O objects.
+/**
+ * The @c any_io_executor type is a polymorphic executor that supports the set
+ * of properties required by I/O objects. It is defined as the
+ * execution::any_executor class template parameterised as follows:
+ * @code execution::any_executor<
+ *   execution::context_as_t<execution_context&>,
+ *   execution::blocking_t::never_t,
+ *   execution::prefer_only<execution::blocking_t::possibly_t>,
+ *   execution::prefer_only<execution::outstanding_work_t::tracked_t>,
+ *   execution::prefer_only<execution::outstanding_work_t::untracked_t>,
+ *   execution::prefer_only<execution::relationship_t::fork_t>,
+ *   execution::prefer_only<execution::relationship_t::continuation_t>
+ * > @endcode
+ */
+#if defined(GENERATING_DOCUMENTATION)
+typedef execution::any_executor<...> any_io_executor;
+#else // defined(GENERATING_DOCUMENTATION)
+typedef execution::any_executor<
+    execution::context_as_t<execution_context&>,
+    execution::blocking_t::never_t,
+    execution::prefer_only<execution::blocking_t::possibly_t>,
+    execution::prefer_only<execution::outstanding_work_t::tracked_t>,
+    execution::prefer_only<execution::outstanding_work_t::untracked_t>,
+    execution::prefer_only<execution::relationship_t::fork_t>,
+    execution::prefer_only<execution::relationship_t::continuation_t>
+  > any_io_executor;
+#endif // defined(GENERATING_DOCUMENTATION)
+
+#endif // defined(ASIO_USE_TS_EXECUTOR_AS_DEFAULT)
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_ANY_IO_EXECUTOR_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/associated_allocator.hpp b/link/modules/asio-standalone/asio/include/asio/associated_allocator.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/associated_allocator.hpp
@@ -0,0 +1,125 @@
+//
+// associated_allocator.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_ASSOCIATED_ALLOCATOR_HPP
+#define ASIO_ASSOCIATED_ALLOCATOR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <memory>
+#include "asio/detail/type_traits.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename T, typename E, typename = void>
+struct associated_allocator_impl
+{
+  typedef E type;
+
+  static type get(const T&, const E& e) ASIO_NOEXCEPT
+  {
+    return e;
+  }
+};
+
+template <typename T, typename E>
+struct associated_allocator_impl<T, E,
+  typename void_type<typename T::allocator_type>::type>
+{
+  typedef typename T::allocator_type type;
+
+  static type get(const T& t, const E&) ASIO_NOEXCEPT
+  {
+    return t.get_allocator();
+  }
+};
+
+} // namespace detail
+
+/// Traits type used to obtain the allocator associated with an object.
+/**
+ * A program may specialise this traits type if the @c T template parameter in
+ * the specialisation is a user-defined type. The template parameter @c
+ * Allocator shall be a type meeting the Allocator requirements.
+ *
+ * Specialisations shall meet the following requirements, where @c t is a const
+ * reference to an object of type @c T, and @c a is an object of type @c
+ * Allocator.
+ *
+ * @li Provide a nested typedef @c type that identifies a type meeting the
+ * Allocator requirements.
+ *
+ * @li Provide a noexcept static member function named @c get, callable as @c
+ * get(t) and with return type @c type.
+ *
+ * @li Provide a noexcept static member function named @c get, callable as @c
+ * get(t,a) and with return type @c type.
+ */
+template <typename T, typename Allocator = std::allocator<void> >
+struct associated_allocator
+{
+  /// If @c T has a nested type @c allocator_type, <tt>T::allocator_type</tt>.
+  /// Otherwise @c Allocator.
+#if defined(GENERATING_DOCUMENTATION)
+  typedef see_below type;
+#else // defined(GENERATING_DOCUMENTATION)
+  typedef typename detail::associated_allocator_impl<T, Allocator>::type type;
+#endif // defined(GENERATING_DOCUMENTATION)
+
+  /// If @c T has a nested type @c allocator_type, returns
+  /// <tt>t.get_allocator()</tt>. Otherwise returns @c a.
+  static type get(const T& t,
+      const Allocator& a = Allocator()) ASIO_NOEXCEPT
+  {
+    return detail::associated_allocator_impl<T, Allocator>::get(t, a);
+  }
+};
+
+/// Helper function to obtain an object's associated allocator.
+/**
+ * @returns <tt>associated_allocator<T>::get(t)</tt>
+ */
+template <typename T>
+inline typename associated_allocator<T>::type
+get_associated_allocator(const T& t) ASIO_NOEXCEPT
+{
+  return associated_allocator<T>::get(t);
+}
+
+/// Helper function to obtain an object's associated allocator.
+/**
+ * @returns <tt>associated_allocator<T, Allocator>::get(t, a)</tt>
+ */
+template <typename T, typename Allocator>
+inline typename associated_allocator<T, Allocator>::type
+get_associated_allocator(const T& t, const Allocator& a) ASIO_NOEXCEPT
+{
+  return associated_allocator<T, Allocator>::get(t, a);
+}
+
+#if defined(ASIO_HAS_ALIAS_TEMPLATES)
+
+template <typename T, typename Allocator = std::allocator<void> >
+using associated_allocator_t
+  = typename associated_allocator<T, Allocator>::type;
+
+#endif // defined(ASIO_HAS_ALIAS_TEMPLATES)
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_ASSOCIATED_ALLOCATOR_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/associated_executor.hpp b/link/modules/asio-standalone/asio/include/asio/associated_executor.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/associated_executor.hpp
@@ -0,0 +1,166 @@
+//
+// associated_executor.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_ASSOCIATED_EXECUTOR_HPP
+#define ASIO_ASSOCIATED_EXECUTOR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/type_traits.hpp"
+#include "asio/execution/executor.hpp"
+#include "asio/is_executor.hpp"
+#include "asio/system_executor.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename T, typename E, typename = void>
+struct associated_executor_impl
+{
+  typedef void asio_associated_executor_is_unspecialised;
+
+  typedef E type;
+
+  static type get(const T&, const E& e = E()) ASIO_NOEXCEPT
+  {
+    return e;
+  }
+};
+
+template <typename T, typename E>
+struct associated_executor_impl<T, E,
+  typename void_type<typename T::executor_type>::type>
+{
+  typedef typename T::executor_type type;
+
+  static type get(const T& t, const E& = E()) ASIO_NOEXCEPT
+  {
+    return t.get_executor();
+  }
+};
+
+} // namespace detail
+
+/// Traits type used to obtain the executor associated with an object.
+/**
+ * A program may specialise this traits type if the @c T template parameter in
+ * the specialisation is a user-defined type. The template parameter @c
+ * Executor shall be a type meeting the Executor requirements.
+ *
+ * Specialisations shall meet the following requirements, where @c t is a const
+ * reference to an object of type @c T, and @c e is an object of type @c
+ * Executor.
+ *
+ * @li Provide a nested typedef @c type that identifies a type meeting the
+ * Executor requirements.
+ *
+ * @li Provide a noexcept static member function named @c get, callable as @c
+ * get(t) and with return type @c type.
+ *
+ * @li Provide a noexcept static member function named @c get, callable as @c
+ * get(t,e) and with return type @c type.
+ */
+template <typename T, typename Executor = system_executor>
+struct associated_executor
+#if !defined(GENERATING_DOCUMENTATION)
+  : detail::associated_executor_impl<T, Executor>
+#endif // !defined(GENERATING_DOCUMENTATION)
+{
+#if defined(GENERATING_DOCUMENTATION)
+  /// If @c T has a nested type @c executor_type, <tt>T::executor_type</tt>.
+  /// Otherwise @c Executor.
+  typedef see_below type;
+
+  /// If @c T has a nested type @c executor_type, returns
+  /// <tt>t.get_executor()</tt>. Otherwise returns @c ex.
+  static type get(const T& t,
+      const Executor& ex = Executor()) ASIO_NOEXCEPT;
+#endif // defined(GENERATING_DOCUMENTATION)
+};
+
+/// Helper function to obtain an object's associated executor.
+/**
+ * @returns <tt>associated_executor<T>::get(t)</tt>
+ */
+template <typename T>
+inline typename associated_executor<T>::type
+get_associated_executor(const T& t) ASIO_NOEXCEPT
+{
+  return associated_executor<T>::get(t);
+}
+
+/// Helper function to obtain an object's associated executor.
+/**
+ * @returns <tt>associated_executor<T, Executor>::get(t, ex)</tt>
+ */
+template <typename T, typename Executor>
+inline typename associated_executor<T, Executor>::type
+get_associated_executor(const T& t, const Executor& ex,
+    typename enable_if<
+      is_executor<Executor>::value || execution::is_executor<Executor>::value
+    >::type* = 0) ASIO_NOEXCEPT
+{
+  return associated_executor<T, Executor>::get(t, ex);
+}
+
+/// Helper function to obtain an object's associated executor.
+/**
+ * @returns <tt>associated_executor<T, typename
+ * ExecutionContext::executor_type>::get(t, ctx.get_executor())</tt>
+ */
+template <typename T, typename ExecutionContext>
+inline typename associated_executor<T,
+  typename ExecutionContext::executor_type>::type
+get_associated_executor(const T& t, ExecutionContext& ctx,
+    typename enable_if<is_convertible<ExecutionContext&,
+      execution_context&>::value>::type* = 0) ASIO_NOEXCEPT
+{
+  return associated_executor<T,
+    typename ExecutionContext::executor_type>::get(t, ctx.get_executor());
+}
+
+#if defined(ASIO_HAS_ALIAS_TEMPLATES)
+
+template <typename T, typename Executor = system_executor>
+using associated_executor_t = typename associated_executor<T, Executor>::type;
+
+#endif // defined(ASIO_HAS_ALIAS_TEMPLATES)
+
+namespace detail {
+
+template <typename T, typename E, typename = void>
+struct associated_executor_forwarding_base
+{
+};
+
+template <typename T, typename E>
+struct associated_executor_forwarding_base<T, E,
+    typename enable_if<
+      is_same<
+        typename associated_executor<T,
+          E>::asio_associated_executor_is_unspecialised,
+        void
+      >::value
+    >::type>
+{
+  typedef void asio_associated_executor_is_unspecialised;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_ASSOCIATED_EXECUTOR_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/async_result.hpp b/link/modules/asio-standalone/asio/include/asio/async_result.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/async_result.hpp
@@ -0,0 +1,582 @@
+//
+// async_result.hpp
+// ~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_ASYNC_RESULT_HPP
+#define ASIO_ASYNC_RESULT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/type_traits.hpp"
+#include "asio/detail/variadic_templates.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+#if defined(ASIO_HAS_CONCEPTS) \
+  && defined(ASIO_HAS_VARIADIC_TEMPLATES) \
+  && defined(ASIO_HAS_DECLTYPE)
+
+namespace detail {
+
+template <typename T>
+struct is_completion_signature : false_type
+{
+};
+
+template <typename R, typename... Args>
+struct is_completion_signature<R(Args...)> : true_type
+{
+};
+
+template <typename T, typename... Args>
+ASIO_CONCEPT callable_with = requires(T t, Args&&... args)
+{
+  t(static_cast<Args&&>(args)...);
+};
+
+template <typename T, typename Signature>
+struct is_completion_handler_for : false_type
+{
+};
+
+template <typename T, typename R, typename... Args>
+struct is_completion_handler_for<T, R(Args...)>
+  : integral_constant<bool, (callable_with<T, Args...>)>
+{
+};
+
+} // namespace detail
+
+template <typename T>
+ASIO_CONCEPT completion_signature =
+  detail::is_completion_signature<T>::value;
+
+#define ASIO_COMPLETION_SIGNATURE \
+  ::asio::completion_signature
+
+template <typename T, typename Signature>
+ASIO_CONCEPT completion_handler_for =
+  detail::is_completion_signature<Signature>::value
+    && detail::is_completion_handler_for<T, Signature>::value;
+
+#define ASIO_COMPLETION_HANDLER_FOR(s) \
+  ::asio::completion_handler_for<s>
+
+#else // defined(ASIO_HAS_CONCEPTS)
+      //   && defined(ASIO_HAS_VARIADIC_TEMPLATES)
+      //   && defined(ASIO_HAS_DECLTYPE)
+
+#define ASIO_COMPLETION_SIGNATURE typename
+#define ASIO_COMPLETION_HANDLER_FOR(s) typename
+
+#endif // defined(ASIO_HAS_CONCEPTS)
+       //   && defined(ASIO_HAS_VARIADIC_TEMPLATES)
+       //   && defined(ASIO_HAS_DECLTYPE)
+
+/// An interface for customising the behaviour of an initiating function.
+/**
+ * The async_result traits class is used for determining:
+ *
+ * @li the concrete completion handler type to be called at the end of the
+ * asynchronous operation;
+ *
+ * @li the initiating function return type; and
+ *
+ * @li how the return value of the initiating function is obtained.
+ *
+ * The trait allows the handler and return types to be determined at the point
+ * where the specific completion handler signature is known.
+ *
+ * This template may be specialised for user-defined completion token types.
+ * The primary template assumes that the CompletionToken is the completion
+ * handler.
+ */
+template <typename CompletionToken, ASIO_COMPLETION_SIGNATURE Signature>
+class async_result
+{
+public:
+  /// The concrete completion handler type for the specific signature.
+  typedef CompletionToken completion_handler_type;
+
+  /// The return type of the initiating function.
+  typedef void return_type;
+
+  /// Construct an async result from a given handler.
+  /**
+   * When using a specalised async_result, the constructor has an opportunity
+   * to initialise some state associated with the completion handler, which is
+   * then returned from the initiating function.
+   */
+  explicit async_result(completion_handler_type& h)
+  {
+    (void)h;
+  }
+
+  /// Obtain the value to be returned from the initiating function.
+  return_type get()
+  {
+  }
+
+#if defined(GENERATING_DOCUMENTATION)
+
+  /// Initiate the asynchronous operation that will produce the result, and
+  /// obtain the value to be returned from the initiating function.
+  template <typename Initiation, typename RawCompletionToken, typename... Args>
+  static return_type initiate(
+      ASIO_MOVE_ARG(Initiation) initiation,
+      ASIO_MOVE_ARG(RawCompletionToken) token,
+      ASIO_MOVE_ARG(Args)... args);
+
+#elif defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+  template <typename Initiation,
+      ASIO_COMPLETION_HANDLER_FOR(Signature) RawCompletionToken,
+      typename... Args>
+  static return_type initiate(
+      ASIO_MOVE_ARG(Initiation) initiation,
+      ASIO_MOVE_ARG(RawCompletionToken) token,
+      ASIO_MOVE_ARG(Args)... args)
+  {
+    ASIO_MOVE_CAST(Initiation)(initiation)(
+        ASIO_MOVE_CAST(RawCompletionToken)(token),
+        ASIO_MOVE_CAST(Args)(args)...);
+  }
+
+#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+  template <typename Initiation,
+      ASIO_COMPLETION_HANDLER_FOR(Signature) RawCompletionToken>
+  static return_type initiate(
+      ASIO_MOVE_ARG(Initiation) initiation,
+      ASIO_MOVE_ARG(RawCompletionToken) token)
+  {
+    ASIO_MOVE_CAST(Initiation)(initiation)(
+        ASIO_MOVE_CAST(RawCompletionToken)(token));
+  }
+
+#define ASIO_PRIVATE_INITIATE_DEF(n) \
+  template <typename Initiation, \
+      ASIO_COMPLETION_HANDLER_FOR(Signature) RawCompletionToken, \
+      ASIO_VARIADIC_TPARAMS(n)> \
+  static return_type initiate( \
+      ASIO_MOVE_ARG(Initiation) initiation, \
+      ASIO_MOVE_ARG(RawCompletionToken) token, \
+      ASIO_VARIADIC_MOVE_PARAMS(n)) \
+  { \
+    ASIO_MOVE_CAST(Initiation)(initiation)( \
+        ASIO_MOVE_CAST(RawCompletionToken)(token), \
+        ASIO_VARIADIC_MOVE_ARGS(n)); \
+  } \
+  /**/
+  ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_INITIATE_DEF)
+#undef ASIO_PRIVATE_INITIATE_DEF
+
+#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+private:
+  async_result(const async_result&) ASIO_DELETED;
+  async_result& operator=(const async_result&) ASIO_DELETED;
+};
+
+#if !defined(GENERATING_DOCUMENTATION)
+
+template <ASIO_COMPLETION_SIGNATURE Signature>
+class async_result<void, Signature>
+{
+  // Empty.
+};
+
+#endif // !defined(GENERATING_DOCUMENTATION)
+
+/// Helper template to deduce the handler type from a CompletionToken, capture
+/// a local copy of the handler, and then create an async_result for the
+/// handler.
+template <typename CompletionToken, ASIO_COMPLETION_SIGNATURE Signature>
+struct async_completion
+{
+  /// The real handler type to be used for the asynchronous operation.
+  typedef typename asio::async_result<
+    typename decay<CompletionToken>::type,
+      Signature>::completion_handler_type completion_handler_type;
+
+#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+  /// Constructor.
+  /**
+   * The constructor creates the concrete completion handler and makes the link
+   * between the handler and the asynchronous result.
+   */
+  explicit async_completion(CompletionToken& token)
+    : completion_handler(static_cast<typename conditional<
+        is_same<CompletionToken, completion_handler_type>::value,
+        completion_handler_type&, CompletionToken&&>::type>(token)),
+      result(completion_handler)
+  {
+  }
+#else // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+  explicit async_completion(typename decay<CompletionToken>::type& token)
+    : completion_handler(token),
+      result(completion_handler)
+  {
+  }
+
+  explicit async_completion(const typename decay<CompletionToken>::type& token)
+    : completion_handler(token),
+      result(completion_handler)
+  {
+  }
+#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+
+  /// A copy of, or reference to, a real handler object.
+#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+  typename conditional<
+    is_same<CompletionToken, completion_handler_type>::value,
+    completion_handler_type&, completion_handler_type>::type completion_handler;
+#else // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+  completion_handler_type completion_handler;
+#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+
+  /// The result of the asynchronous operation's initiating function.
+  async_result<typename decay<CompletionToken>::type, Signature> result;
+};
+
+namespace detail {
+
+template <typename CompletionToken, typename Signature>
+struct async_result_helper
+  : async_result<typename decay<CompletionToken>::type, Signature>
+{
+};
+
+struct async_result_memfns_base
+{
+  void initiate();
+};
+
+template <typename T>
+struct async_result_memfns_derived
+  : T, async_result_memfns_base
+{
+};
+
+template <typename T, T>
+struct async_result_memfns_check
+{
+};
+
+template <typename>
+char (&async_result_initiate_memfn_helper(...))[2];
+
+template <typename T>
+char async_result_initiate_memfn_helper(
+    async_result_memfns_check<
+      void (async_result_memfns_base::*)(),
+      &async_result_memfns_derived<T>::initiate>*);
+
+template <typename CompletionToken, typename Signature>
+struct async_result_has_initiate_memfn
+  : integral_constant<bool, sizeof(async_result_initiate_memfn_helper<
+      async_result<typename decay<CompletionToken>::type, Signature>
+    >(0)) != 1>
+{
+};
+
+} // namespace detail
+
+#if defined(GENERATING_DOCUMENTATION)
+# define ASIO_INITFN_RESULT_TYPE(ct, sig) \
+  void_or_deduced
+#elif defined(_MSC_VER) && (_MSC_VER < 1500)
+# define ASIO_INITFN_RESULT_TYPE(ct, sig) \
+  typename ::asio::detail::async_result_helper< \
+    ct, sig>::return_type
+#define ASIO_HANDLER_TYPE(ct, sig) \
+  typename ::asio::detail::async_result_helper< \
+    ct, sig>::completion_handler_type
+#else
+# define ASIO_INITFN_RESULT_TYPE(ct, sig) \
+  typename ::asio::async_result< \
+    typename ::asio::decay<ct>::type, sig>::return_type
+#define ASIO_HANDLER_TYPE(ct, sig) \
+  typename ::asio::async_result< \
+    typename ::asio::decay<ct>::type, sig>::completion_handler_type
+#endif
+
+#if defined(GENERATION_DOCUMENTATION)
+# define ASIO_INITFN_AUTO_RESULT_TYPE(ct, sig) \
+  auto
+#elif defined(ASIO_HAS_RETURN_TYPE_DEDUCTION)
+# define ASIO_INITFN_AUTO_RESULT_TYPE(ct, sig) \
+  auto
+#else
+# define ASIO_INITFN_AUTO_RESULT_TYPE(ct, sig) \
+  ASIO_INITFN_RESULT_TYPE(ct, sig)
+#endif
+
+#if defined(GENERATION_DOCUMENTATION)
+# define ASIO_INITFN_DEDUCED_RESULT_TYPE(ct, sig, expr) \
+  void_or_deduced
+#elif defined(ASIO_HAS_DECLTYPE)
+# define ASIO_INITFN_DEDUCED_RESULT_TYPE(ct, sig, expr) \
+  decltype expr
+#else
+# define ASIO_INITFN_DEDUCED_RESULT_TYPE(ct, sig, expr) \
+  ASIO_INITFN_RESULT_TYPE(ct, sig)
+#endif
+
+#if defined(GENERATING_DOCUMENTATION)
+
+template <typename CompletionToken,
+    completion_signature Signature,
+    typename Initiation, typename... Args>
+void_or_deduced async_initiate(
+    ASIO_MOVE_ARG(Initiation) initiation,
+    ASIO_NONDEDUCED_MOVE_ARG(CompletionToken),
+    ASIO_MOVE_ARG(Args)... args);
+
+#elif defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+template <typename CompletionToken,
+    ASIO_COMPLETION_SIGNATURE Signature,
+    typename Initiation, typename... Args>
+inline typename enable_if<
+    detail::async_result_has_initiate_memfn<CompletionToken, Signature>::value,
+    ASIO_INITFN_DEDUCED_RESULT_TYPE(CompletionToken, Signature,
+      (async_result<typename decay<CompletionToken>::type,
+        Signature>::initiate(declval<ASIO_MOVE_ARG(Initiation)>(),
+          declval<ASIO_MOVE_ARG(CompletionToken)>(),
+          declval<ASIO_MOVE_ARG(Args)>()...)))>::type
+async_initiate(ASIO_MOVE_ARG(Initiation) initiation,
+    ASIO_NONDEDUCED_MOVE_ARG(CompletionToken) token,
+    ASIO_MOVE_ARG(Args)... args)
+{
+  return async_result<typename decay<CompletionToken>::type,
+    Signature>::initiate(ASIO_MOVE_CAST(Initiation)(initiation),
+      ASIO_MOVE_CAST(CompletionToken)(token),
+      ASIO_MOVE_CAST(Args)(args)...);
+}
+
+template <typename CompletionToken,
+    ASIO_COMPLETION_SIGNATURE Signature,
+    typename Initiation, typename... Args>
+inline typename enable_if<
+    !detail::async_result_has_initiate_memfn<CompletionToken, Signature>::value,
+    ASIO_INITFN_RESULT_TYPE(CompletionToken, Signature)>::type
+async_initiate(ASIO_MOVE_ARG(Initiation) initiation,
+    ASIO_NONDEDUCED_MOVE_ARG(CompletionToken) token,
+    ASIO_MOVE_ARG(Args)... args)
+{
+  async_completion<CompletionToken, Signature> completion(token);
+
+  ASIO_MOVE_CAST(Initiation)(initiation)(
+      ASIO_MOVE_CAST(ASIO_HANDLER_TYPE(CompletionToken,
+        Signature))(completion.completion_handler),
+      ASIO_MOVE_CAST(Args)(args)...);
+
+  return completion.result.get();
+}
+
+#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+template <typename CompletionToken,
+    ASIO_COMPLETION_SIGNATURE Signature,
+    typename Initiation>
+inline typename enable_if<
+    detail::async_result_has_initiate_memfn<CompletionToken, Signature>::value,
+    ASIO_INITFN_DEDUCED_RESULT_TYPE(CompletionToken, Signature,
+      (async_result<typename decay<CompletionToken>::type,
+        Signature>::initiate(declval<ASIO_MOVE_ARG(Initiation)>(),
+          declval<ASIO_MOVE_ARG(CompletionToken)>())))>::type
+async_initiate(ASIO_MOVE_ARG(Initiation) initiation,
+    ASIO_NONDEDUCED_MOVE_ARG(CompletionToken) token)
+{
+  return async_result<typename decay<CompletionToken>::type,
+    Signature>::initiate(ASIO_MOVE_CAST(Initiation)(initiation),
+      ASIO_MOVE_CAST(CompletionToken)(token));
+}
+
+template <typename CompletionToken,
+    ASIO_COMPLETION_SIGNATURE Signature,
+    typename Initiation>
+inline typename enable_if<
+    !detail::async_result_has_initiate_memfn<CompletionToken, Signature>::value,
+    ASIO_INITFN_RESULT_TYPE(CompletionToken, Signature)>::type
+async_initiate(ASIO_MOVE_ARG(Initiation) initiation,
+    ASIO_NONDEDUCED_MOVE_ARG(CompletionToken) token)
+{
+  async_completion<CompletionToken, Signature> completion(token);
+
+  ASIO_MOVE_CAST(Initiation)(initiation)(
+      ASIO_MOVE_CAST(ASIO_HANDLER_TYPE(CompletionToken,
+        Signature))(completion.completion_handler));
+
+  return completion.result.get();
+}
+
+#define ASIO_PRIVATE_INITIATE_DEF(n) \
+  template <typename CompletionToken, \
+      ASIO_COMPLETION_SIGNATURE Signature, \
+      typename Initiation, ASIO_VARIADIC_TPARAMS(n)> \
+  inline typename enable_if< \
+      detail::async_result_has_initiate_memfn< \
+        CompletionToken, Signature>::value, \
+      ASIO_INITFN_DEDUCED_RESULT_TYPE(CompletionToken, Signature, \
+        (async_result<typename decay<CompletionToken>::type, \
+          Signature>::initiate(declval<ASIO_MOVE_ARG(Initiation)>(), \
+            declval<ASIO_MOVE_ARG(CompletionToken)>(), \
+            ASIO_VARIADIC_MOVE_DECLVAL(n))))>::type \
+  async_initiate(ASIO_MOVE_ARG(Initiation) initiation, \
+      ASIO_NONDEDUCED_MOVE_ARG(CompletionToken) token, \
+      ASIO_VARIADIC_MOVE_PARAMS(n)) \
+  { \
+    return async_result<typename decay<CompletionToken>::type, \
+      Signature>::initiate(ASIO_MOVE_CAST(Initiation)(initiation), \
+        ASIO_MOVE_CAST(CompletionToken)(token), \
+        ASIO_VARIADIC_MOVE_ARGS(n)); \
+  } \
+  \
+  template <typename CompletionToken, \
+      ASIO_COMPLETION_SIGNATURE Signature, \
+      typename Initiation, ASIO_VARIADIC_TPARAMS(n)> \
+  inline typename enable_if< \
+      !detail::async_result_has_initiate_memfn< \
+        CompletionToken, Signature>::value, \
+      ASIO_INITFN_RESULT_TYPE(CompletionToken, Signature)>::type \
+  async_initiate(ASIO_MOVE_ARG(Initiation) initiation, \
+      ASIO_NONDEDUCED_MOVE_ARG(CompletionToken) token, \
+      ASIO_VARIADIC_MOVE_PARAMS(n)) \
+  { \
+    async_completion<CompletionToken, Signature> completion(token); \
+  \
+    ASIO_MOVE_CAST(Initiation)(initiation)( \
+        ASIO_MOVE_CAST(ASIO_HANDLER_TYPE(CompletionToken, \
+          Signature))(completion.completion_handler), \
+        ASIO_VARIADIC_MOVE_ARGS(n)); \
+  \
+    return completion.result.get(); \
+  } \
+  /**/
+  ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_INITIATE_DEF)
+#undef ASIO_PRIVATE_INITIATE_DEF
+
+#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+#if defined(ASIO_HAS_CONCEPTS) \
+  && defined(ASIO_HAS_VARIADIC_TEMPLATES) \
+  && defined(ASIO_HAS_DECLTYPE)
+
+namespace detail {
+
+template <typename Signature>
+struct initiation_archetype
+{
+  template <completion_handler_for<Signature> CompletionHandler>
+  void operator()(CompletionHandler&&) const
+  {
+  }
+};
+
+} // namespace detail
+
+template <typename T, typename Signature>
+ASIO_CONCEPT completion_token_for =
+  detail::is_completion_signature<Signature>::value
+  &&
+  requires(T&& t)
+  {
+    async_initiate<T, Signature>(detail::initiation_archetype<Signature>{}, t);
+  };
+
+#define ASIO_COMPLETION_TOKEN_FOR(s) \
+  ::asio::completion_token_for<s>
+
+#else // defined(ASIO_HAS_CONCEPTS)
+      //   && defined(ASIO_HAS_VARIADIC_TEMPLATES)
+      //   && defined(ASIO_HAS_DECLTYPE)
+
+#define ASIO_COMPLETION_TOKEN_FOR(s) typename
+
+#endif // defined(ASIO_HAS_CONCEPTS)
+       //   && defined(ASIO_HAS_VARIADIC_TEMPLATES)
+       //   && defined(ASIO_HAS_DECLTYPE)
+
+namespace detail {
+
+template <typename T, typename = void>
+struct default_completion_token_impl
+{
+  typedef void type;
+};
+
+template <typename T>
+struct default_completion_token_impl<T,
+  typename void_type<typename T::default_completion_token_type>::type>
+{
+  typedef typename T::default_completion_token_type type;
+};
+
+} // namespace detail
+
+#if defined(GENERATING_DOCUMENTATION)
+
+/// Traits type used to determine the default completion token type associated
+/// with a type (such as an executor).
+/**
+ * A program may specialise this traits type if the @c T template parameter in
+ * the specialisation is a user-defined type.
+ *
+ * Specialisations of this trait may provide a nested typedef @c type, which is
+ * a default-constructible completion token type.
+ */
+template <typename T>
+struct default_completion_token
+{
+  /// If @c T has a nested type @c default_completion_token_type,
+  /// <tt>T::default_completion_token_type</tt>. Otherwise the typedef @c type
+  /// is not defined.
+  typedef see_below type;
+};
+#else
+template <typename T>
+struct default_completion_token
+  : detail::default_completion_token_impl<T>
+{
+};
+#endif
+
+#if defined(ASIO_HAS_ALIAS_TEMPLATES)
+
+template <typename T>
+using default_completion_token_t = typename default_completion_token<T>::type;
+
+#endif // defined(ASIO_HAS_ALIAS_TEMPLATES)
+
+#if defined(ASIO_HAS_DEFAULT_FUNCTION_TEMPLATE_ARGUMENTS)
+
+#define ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(e) \
+  = typename ::asio::default_completion_token<e>::type
+#define ASIO_DEFAULT_COMPLETION_TOKEN(e) \
+  = typename ::asio::default_completion_token<e>::type()
+
+#else // defined(ASIO_HAS_DEFAULT_FUNCTION_TEMPLATE_ARGUMENTS)
+
+#define ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(e)
+#define ASIO_DEFAULT_COMPLETION_TOKEN(e)
+
+#endif // defined(ASIO_HAS_DEFAULT_FUNCTION_TEMPLATE_ARGUMENTS)
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_ASYNC_RESULT_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/awaitable.hpp b/link/modules/asio-standalone/asio/include/asio/awaitable.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/awaitable.hpp
@@ -0,0 +1,133 @@
+//
+// awaitable.hpp
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_AWAITABLE_HPP
+#define ASIO_AWAITABLE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_CO_AWAIT) || defined(GENERATING_DOCUMENTATION)
+
+#if defined(ASIO_HAS_STD_COROUTINE)
+# include <coroutine>
+#else // defined(ASIO_HAS_STD_COROUTINE)
+# include <experimental/coroutine>
+#endif // defined(ASIO_HAS_STD_COROUTINE)
+
+#include "asio/any_io_executor.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+#if defined(ASIO_HAS_STD_COROUTINE)
+using std::coroutine_handle;
+using std::suspend_always;
+#else // defined(ASIO_HAS_STD_COROUTINE)
+using std::experimental::coroutine_handle;
+using std::experimental::suspend_always;
+#endif // defined(ASIO_HAS_STD_COROUTINE)
+
+template <typename> class awaitable_thread;
+template <typename, typename> class awaitable_frame;
+
+} // namespace detail
+
+/// The return type of a coroutine or asynchronous operation.
+template <typename T, typename Executor = any_io_executor>
+class awaitable
+{
+public:
+  /// The type of the awaited value.
+  typedef T value_type;
+
+  /// The executor type that will be used for the coroutine.
+  typedef Executor executor_type;
+
+  /// Default constructor.
+  constexpr awaitable() noexcept
+    : frame_(nullptr)
+  {
+  }
+
+  /// Move constructor.
+  awaitable(awaitable&& other) noexcept
+    : frame_(std::exchange(other.frame_, nullptr))
+  {
+  }
+
+  /// Destructor
+  ~awaitable()
+  {
+    if (frame_)
+      frame_->destroy();
+  }
+
+  /// Checks if the awaitable refers to a future result.
+  bool valid() const noexcept
+  {
+    return !!frame_;
+  }
+
+#if !defined(GENERATING_DOCUMENTATION)
+
+  // Support for co_await keyword.
+  bool await_ready() const noexcept
+  {
+    return false;
+  }
+
+  // Support for co_await keyword.
+  template <class U>
+  void await_suspend(
+      detail::coroutine_handle<detail::awaitable_frame<U, Executor>> h)
+  {
+    frame_->push_frame(&h.promise());
+  }
+
+  // Support for co_await keyword.
+  T await_resume()
+  {
+    return awaitable(static_cast<awaitable&&>(*this)).frame_->get();
+  }
+
+#endif // !defined(GENERATING_DOCUMENTATION)
+
+private:
+  template <typename> friend class detail::awaitable_thread;
+  template <typename, typename> friend class detail::awaitable_frame;
+
+  // Not copy constructible or copy assignable.
+  awaitable(const awaitable&) = delete;
+  awaitable& operator=(const awaitable&) = delete;
+
+  // Construct the awaitable from a coroutine's frame object.
+  explicit awaitable(detail::awaitable_frame<T, Executor>* a)
+    : frame_(a)
+  {
+  }
+
+  detail::awaitable_frame<T, Executor>* frame_;
+};
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/impl/awaitable.hpp"
+
+#endif // defined(ASIO_HAS_CO_AWAIT) || defined(GENERATING_DOCUMENTATION)
+
+#endif // ASIO_AWAITABLE_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/basic_datagram_socket.hpp b/link/modules/asio-standalone/asio/include/asio/basic_datagram_socket.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/basic_datagram_socket.hpp
@@ -0,0 +1,1215 @@
+//
+// basic_datagram_socket.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_BASIC_DATAGRAM_SOCKET_HPP
+#define ASIO_BASIC_DATAGRAM_SOCKET_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <cstddef>
+#include "asio/basic_socket.hpp"
+#include "asio/detail/handler_type_requirements.hpp"
+#include "asio/detail/non_const_lvalue.hpp"
+#include "asio/detail/throw_error.hpp"
+#include "asio/detail/type_traits.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+#if !defined(ASIO_BASIC_DATAGRAM_SOCKET_FWD_DECL)
+#define ASIO_BASIC_DATAGRAM_SOCKET_FWD_DECL
+
+// Forward declaration with defaulted arguments.
+template <typename Protocol, typename Executor = any_io_executor>
+class basic_datagram_socket;
+
+#endif // !defined(ASIO_BASIC_DATAGRAM_SOCKET_FWD_DECL)
+
+/// Provides datagram-oriented socket functionality.
+/**
+ * The basic_datagram_socket class template provides asynchronous and blocking
+ * datagram-oriented socket functionality.
+ *
+ * @par Thread Safety
+ * @e Distinct @e objects: Safe.@n
+ * @e Shared @e objects: Unsafe.
+ */
+template <typename Protocol, typename Executor>
+class basic_datagram_socket
+  : public basic_socket<Protocol, Executor>
+{
+public:
+  /// The type of the executor associated with the object.
+  typedef Executor executor_type;
+
+  /// Rebinds the socket type to another executor.
+  template <typename Executor1>
+  struct rebind_executor
+  {
+    /// The socket type when rebound to the specified executor.
+    typedef basic_datagram_socket<Protocol, Executor1> other;
+  };
+
+  /// The native representation of a socket.
+#if defined(GENERATING_DOCUMENTATION)
+  typedef implementation_defined native_handle_type;
+#else
+  typedef typename basic_socket<Protocol,
+    Executor>::native_handle_type native_handle_type;
+#endif
+
+  /// The protocol type.
+  typedef Protocol protocol_type;
+
+  /// The endpoint type.
+  typedef typename Protocol::endpoint endpoint_type;
+
+  /// Construct a basic_datagram_socket without opening it.
+  /**
+   * This constructor creates a datagram socket without opening it. The open()
+   * function must be called before data can be sent or received on the socket.
+   *
+   * @param ex The I/O executor that the socket will use, by default, to
+   * dispatch handlers for any asynchronous operations performed on the socket.
+   */
+  explicit basic_datagram_socket(const executor_type& ex)
+    : basic_socket<Protocol, Executor>(ex)
+  {
+  }
+
+  /// Construct a basic_datagram_socket without opening it.
+  /**
+   * This constructor creates a datagram socket without opening it. The open()
+   * function must be called before data can be sent or received on the socket.
+   *
+   * @param context An execution context which provides the I/O executor that
+   * the socket will use, by default, to dispatch handlers for any asynchronous
+   * operations performed on the socket.
+   */
+  template <typename ExecutionContext>
+  explicit basic_datagram_socket(ExecutionContext& context,
+      typename enable_if<
+        is_convertible<ExecutionContext&, execution_context&>::value
+      >::type* = 0)
+    : basic_socket<Protocol, Executor>(context)
+  {
+  }
+
+  /// Construct and open a basic_datagram_socket.
+  /**
+   * This constructor creates and opens a datagram socket.
+   *
+   * @param ex The I/O executor that the socket will use, by default, to
+   * dispatch handlers for any asynchronous operations performed on the socket.
+   *
+   * @param protocol An object specifying protocol parameters to be used.
+   *
+   * @throws asio::system_error Thrown on failure.
+   */
+  basic_datagram_socket(const executor_type& ex, const protocol_type& protocol)
+    : basic_socket<Protocol, Executor>(ex, protocol)
+  {
+  }
+
+  /// Construct and open a basic_datagram_socket.
+  /**
+   * This constructor creates and opens a datagram socket.
+   *
+   * @param context An execution context which provides the I/O executor that
+   * the socket will use, by default, to dispatch handlers for any asynchronous
+   * operations performed on the socket.
+   *
+   * @param protocol An object specifying protocol parameters to be used.
+   *
+   * @throws asio::system_error Thrown on failure.
+   */
+  template <typename ExecutionContext>
+  basic_datagram_socket(ExecutionContext& context,
+      const protocol_type& protocol,
+      typename enable_if<
+        is_convertible<ExecutionContext&, execution_context&>::value
+      >::type* = 0)
+    : basic_socket<Protocol, Executor>(context, protocol)
+  {
+  }
+
+  /// Construct a basic_datagram_socket, opening it and binding it to the given
+  /// local endpoint.
+  /**
+   * This constructor creates a datagram socket and automatically opens it bound
+   * to the specified endpoint on the local machine. The protocol used is the
+   * protocol associated with the given endpoint.
+   *
+   * @param ex The I/O executor that the socket will use, by default, to
+   * dispatch handlers for any asynchronous operations performed on the socket.
+   *
+   * @param endpoint An endpoint on the local machine to which the datagram
+   * socket will be bound.
+   *
+   * @throws asio::system_error Thrown on failure.
+   */
+  basic_datagram_socket(const executor_type& ex, const endpoint_type& endpoint)
+    : basic_socket<Protocol, Executor>(ex, endpoint)
+  {
+  }
+
+  /// Construct a basic_datagram_socket, opening it and binding it to the given
+  /// local endpoint.
+  /**
+   * This constructor creates a datagram socket and automatically opens it bound
+   * to the specified endpoint on the local machine. The protocol used is the
+   * protocol associated with the given endpoint.
+   *
+   * @param context An execution context which provides the I/O executor that
+   * the socket will use, by default, to dispatch handlers for any asynchronous
+   * operations performed on the socket.
+   *
+   * @param endpoint An endpoint on the local machine to which the datagram
+   * socket will be bound.
+   *
+   * @throws asio::system_error Thrown on failure.
+   */
+  template <typename ExecutionContext>
+  basic_datagram_socket(ExecutionContext& context,
+      const endpoint_type& endpoint,
+      typename enable_if<
+        is_convertible<ExecutionContext&, execution_context&>::value
+      >::type* = 0)
+    : basic_socket<Protocol, Executor>(context, endpoint)
+  {
+  }
+
+  /// Construct a basic_datagram_socket on an existing native socket.
+  /**
+   * This constructor creates a datagram socket object to hold an existing
+   * native socket.
+   *
+   * @param ex The I/O executor that the socket will use, by default, to
+   * dispatch handlers for any asynchronous operations performed on the socket.
+   *
+   * @param protocol An object specifying protocol parameters to be used.
+   *
+   * @param native_socket The new underlying socket implementation.
+   *
+   * @throws asio::system_error Thrown on failure.
+   */
+  basic_datagram_socket(const executor_type& ex,
+      const protocol_type& protocol, const native_handle_type& native_socket)
+    : basic_socket<Protocol, Executor>(ex, protocol, native_socket)
+  {
+  }
+
+  /// Construct a basic_datagram_socket on an existing native socket.
+  /**
+   * This constructor creates a datagram socket object to hold an existing
+   * native socket.
+   *
+   * @param context An execution context which provides the I/O executor that
+   * the socket will use, by default, to dispatch handlers for any asynchronous
+   * operations performed on the socket.
+   *
+   * @param protocol An object specifying protocol parameters to be used.
+   *
+   * @param native_socket The new underlying socket implementation.
+   *
+   * @throws asio::system_error Thrown on failure.
+   */
+  template <typename ExecutionContext>
+  basic_datagram_socket(ExecutionContext& context,
+      const protocol_type& protocol, const native_handle_type& native_socket,
+      typename enable_if<
+        is_convertible<ExecutionContext&, execution_context&>::value
+      >::type* = 0)
+    : basic_socket<Protocol, Executor>(context, protocol, native_socket)
+  {
+  }
+
+#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+  /// Move-construct a basic_datagram_socket from another.
+  /**
+   * This constructor moves a datagram socket from one object to another.
+   *
+   * @param other The other basic_datagram_socket object from which the move
+   * will occur.
+   *
+   * @note Following the move, the moved-from object is in the same state as if
+   * constructed using the @c basic_datagram_socket(const executor_type&)
+   * constructor.
+   */
+  basic_datagram_socket(basic_datagram_socket&& other) ASIO_NOEXCEPT
+    : basic_socket<Protocol, Executor>(std::move(other))
+  {
+  }
+
+  /// Move-assign a basic_datagram_socket from another.
+  /**
+   * This assignment operator moves a datagram socket from one object to
+   * another.
+   *
+   * @param other The other basic_datagram_socket object from which the move
+   * will occur.
+   *
+   * @note Following the move, the moved-from object is in the same state as if
+   * constructed using the @c basic_datagram_socket(const executor_type&)
+   * constructor.
+   */
+  basic_datagram_socket& operator=(basic_datagram_socket&& other)
+  {
+    basic_socket<Protocol, Executor>::operator=(std::move(other));
+    return *this;
+  }
+
+  /// Move-construct a basic_datagram_socket from a socket of another protocol
+  /// type.
+  /**
+   * This constructor moves a datagram socket from one object to another.
+   *
+   * @param other The other basic_datagram_socket object from which the move
+   * will occur.
+   *
+   * @note Following the move, the moved-from object is in the same state as if
+   * constructed using the @c basic_datagram_socket(const executor_type&)
+   * constructor.
+   */
+  template <typename Protocol1, typename Executor1>
+  basic_datagram_socket(basic_datagram_socket<Protocol1, Executor1>&& other,
+      typename enable_if<
+        is_convertible<Protocol1, Protocol>::value
+          && is_convertible<Executor1, Executor>::value
+      >::type* = 0)
+    : basic_socket<Protocol, Executor>(std::move(other))
+  {
+  }
+
+  /// Move-assign a basic_datagram_socket from a socket of another protocol
+  /// type.
+  /**
+   * This assignment operator moves a datagram socket from one object to
+   * another.
+   *
+   * @param other The other basic_datagram_socket object from which the move
+   * will occur.
+   *
+   * @note Following the move, the moved-from object is in the same state as if
+   * constructed using the @c basic_datagram_socket(const executor_type&)
+   * constructor.
+   */
+  template <typename Protocol1, typename Executor1>
+  typename enable_if<
+    is_convertible<Protocol1, Protocol>::value
+      && is_convertible<Executor1, Executor>::value,
+    basic_datagram_socket&
+  >::type operator=(basic_datagram_socket<Protocol1, Executor1>&& other)
+  {
+    basic_socket<Protocol, Executor>::operator=(std::move(other));
+    return *this;
+  }
+#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+
+  /// Destroys the socket.
+  /**
+   * This function destroys the socket, cancelling any outstanding asynchronous
+   * operations associated with the socket as if by calling @c cancel.
+   */
+  ~basic_datagram_socket()
+  {
+  }
+
+  /// Send some data on a connected socket.
+  /**
+   * This function is used to send data on the datagram socket. The function
+   * call will block until the data has been sent successfully or an error
+   * occurs.
+   *
+   * @param buffers One ore more data buffers to be sent on the socket.
+   *
+   * @returns The number of bytes sent.
+   *
+   * @throws asio::system_error Thrown on failure.
+   *
+   * @note The send operation can only be used with a connected socket. Use
+   * the send_to function to send data on an unconnected datagram socket.
+   *
+   * @par Example
+   * To send a single data buffer use the @ref buffer function as follows:
+   * @code socket.send(asio::buffer(data, size)); @endcode
+   * See the @ref buffer documentation for information on sending multiple
+   * buffers in one go, and how to use it with arrays, boost::array or
+   * std::vector.
+   */
+  template <typename ConstBufferSequence>
+  std::size_t send(const ConstBufferSequence& buffers)
+  {
+    asio::error_code ec;
+    std::size_t s = this->impl_.get_service().send(
+        this->impl_.get_implementation(), buffers, 0, ec);
+    asio::detail::throw_error(ec, "send");
+    return s;
+  }
+
+  /// Send some data on a connected socket.
+  /**
+   * This function is used to send data on the datagram socket. The function
+   * call will block until the data has been sent successfully or an error
+   * occurs.
+   *
+   * @param buffers One ore more data buffers to be sent on the socket.
+   *
+   * @param flags Flags specifying how the send call is to be made.
+   *
+   * @returns The number of bytes sent.
+   *
+   * @throws asio::system_error Thrown on failure.
+   *
+   * @note The send operation can only be used with a connected socket. Use
+   * the send_to function to send data on an unconnected datagram socket.
+   */
+  template <typename ConstBufferSequence>
+  std::size_t send(const ConstBufferSequence& buffers,
+      socket_base::message_flags flags)
+  {
+    asio::error_code ec;
+    std::size_t s = this->impl_.get_service().send(
+        this->impl_.get_implementation(), buffers, flags, ec);
+    asio::detail::throw_error(ec, "send");
+    return s;
+  }
+
+  /// Send some data on a connected socket.
+  /**
+   * This function is used to send data on the datagram socket. The function
+   * call will block until the data has been sent successfully or an error
+   * occurs.
+   *
+   * @param buffers One or more data buffers to be sent on the socket.
+   *
+   * @param flags Flags specifying how the send call is to be made.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   *
+   * @returns The number of bytes sent.
+   *
+   * @note The send operation can only be used with a connected socket. Use
+   * the send_to function to send data on an unconnected datagram socket.
+   */
+  template <typename ConstBufferSequence>
+  std::size_t send(const ConstBufferSequence& buffers,
+      socket_base::message_flags flags, asio::error_code& ec)
+  {
+    return this->impl_.get_service().send(
+        this->impl_.get_implementation(), buffers, flags, ec);
+  }
+
+  /// Start an asynchronous send on a connected socket.
+  /**
+   * This function is used to asynchronously send data on the datagram socket.
+   * The function call always returns immediately.
+   *
+   * @param buffers One or more data buffers to be sent on the socket. Although
+   * the buffers object may be copied as necessary, ownership of the underlying
+   * memory blocks is retained by the caller, which must guarantee that they
+   * remain valid until the handler is called.
+   *
+   * @param handler The handler to be called when the send operation completes.
+   * Copies will be made of the handler as required. The function signature of
+   * the handler must be:
+   * @code void handler(
+   *   const asio::error_code& error, // Result of operation.
+   *   std::size_t bytes_transferred           // Number of bytes sent.
+   * ); @endcode
+   * Regardless of whether the asynchronous operation completes immediately or
+   * not, the handler will not be invoked from within this function. On
+   * immediate completion, invocation of the handler will be performed in a
+   * manner equivalent to using asio::post().
+   *
+   * @note The async_send operation can only be used with a connected socket.
+   * Use the async_send_to function to send data on an unconnected datagram
+   * socket.
+   *
+   * @par Example
+   * To send a single data buffer use the @ref buffer function as follows:
+   * @code
+   * socket.async_send(asio::buffer(data, size), handler);
+   * @endcode
+   * See the @ref buffer documentation for information on sending multiple
+   * buffers in one go, and how to use it with arrays, boost::array or
+   * std::vector.
+   */
+  template <typename ConstBufferSequence,
+      ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+        std::size_t)) WriteHandler
+          ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
+  ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,
+      void (asio::error_code, std::size_t))
+  async_send(const ConstBufferSequence& buffers,
+      ASIO_MOVE_ARG(WriteHandler) handler
+        ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
+  {
+    return async_initiate<WriteHandler,
+      void (asio::error_code, std::size_t)>(
+        initiate_async_send(this), handler,
+        buffers, socket_base::message_flags(0));
+  }
+
+  /// Start an asynchronous send on a connected socket.
+  /**
+   * This function is used to asynchronously send data on the datagram socket.
+   * The function call always returns immediately.
+   *
+   * @param buffers One or more data buffers to be sent on the socket. Although
+   * the buffers object may be copied as necessary, ownership of the underlying
+   * memory blocks is retained by the caller, which must guarantee that they
+   * remain valid until the handler is called.
+   *
+   * @param flags Flags specifying how the send call is to be made.
+   *
+   * @param handler The handler to be called when the send operation completes.
+   * Copies will be made of the handler as required. The function signature of
+   * the handler must be:
+   * @code void handler(
+   *   const asio::error_code& error, // Result of operation.
+   *   std::size_t bytes_transferred           // Number of bytes sent.
+   * ); @endcode
+   * Regardless of whether the asynchronous operation completes immediately or
+   * not, the handler will not be invoked from within this function. On
+   * immediate completion, invocation of the handler will be performed in a
+   * manner equivalent to using asio::post().
+   *
+   * @note The async_send operation can only be used with a connected socket.
+   * Use the async_send_to function to send data on an unconnected datagram
+   * socket.
+   */
+  template <typename ConstBufferSequence,
+      ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+        std::size_t)) WriteHandler
+          ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
+  ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,
+      void (asio::error_code, std::size_t))
+  async_send(const ConstBufferSequence& buffers,
+      socket_base::message_flags flags,
+      ASIO_MOVE_ARG(WriteHandler) handler
+        ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
+  {
+    return async_initiate<WriteHandler,
+      void (asio::error_code, std::size_t)>(
+        initiate_async_send(this), handler, buffers, flags);
+  }
+
+  /// Send a datagram to the specified endpoint.
+  /**
+   * This function is used to send a datagram to the specified remote endpoint.
+   * The function call will block until the data has been sent successfully or
+   * an error occurs.
+   *
+   * @param buffers One or more data buffers to be sent to the remote endpoint.
+   *
+   * @param destination The remote endpoint to which the data will be sent.
+   *
+   * @returns The number of bytes sent.
+   *
+   * @throws asio::system_error Thrown on failure.
+   *
+   * @par Example
+   * To send a single data buffer use the @ref buffer function as follows:
+   * @code
+   * asio::ip::udp::endpoint destination(
+   *     asio::ip::address::from_string("1.2.3.4"), 12345);
+   * socket.send_to(asio::buffer(data, size), destination);
+   * @endcode
+   * See the @ref buffer documentation for information on sending multiple
+   * buffers in one go, and how to use it with arrays, boost::array or
+   * std::vector.
+   */
+  template <typename ConstBufferSequence>
+  std::size_t send_to(const ConstBufferSequence& buffers,
+      const endpoint_type& destination)
+  {
+    asio::error_code ec;
+    std::size_t s = this->impl_.get_service().send_to(
+        this->impl_.get_implementation(), buffers, destination, 0, ec);
+    asio::detail::throw_error(ec, "send_to");
+    return s;
+  }
+
+  /// Send a datagram to the specified endpoint.
+  /**
+   * This function is used to send a datagram to the specified remote endpoint.
+   * The function call will block until the data has been sent successfully or
+   * an error occurs.
+   *
+   * @param buffers One or more data buffers to be sent to the remote endpoint.
+   *
+   * @param destination The remote endpoint to which the data will be sent.
+   *
+   * @param flags Flags specifying how the send call is to be made.
+   *
+   * @returns The number of bytes sent.
+   *
+   * @throws asio::system_error Thrown on failure.
+   */
+  template <typename ConstBufferSequence>
+  std::size_t send_to(const ConstBufferSequence& buffers,
+      const endpoint_type& destination, socket_base::message_flags flags)
+  {
+    asio::error_code ec;
+    std::size_t s = this->impl_.get_service().send_to(
+        this->impl_.get_implementation(), buffers, destination, flags, ec);
+    asio::detail::throw_error(ec, "send_to");
+    return s;
+  }
+
+  /// Send a datagram to the specified endpoint.
+  /**
+   * This function is used to send a datagram to the specified remote endpoint.
+   * The function call will block until the data has been sent successfully or
+   * an error occurs.
+   *
+   * @param buffers One or more data buffers to be sent to the remote endpoint.
+   *
+   * @param destination The remote endpoint to which the data will be sent.
+   *
+   * @param flags Flags specifying how the send call is to be made.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   *
+   * @returns The number of bytes sent.
+   */
+  template <typename ConstBufferSequence>
+  std::size_t send_to(const ConstBufferSequence& buffers,
+      const endpoint_type& destination, socket_base::message_flags flags,
+      asio::error_code& ec)
+  {
+    return this->impl_.get_service().send_to(this->impl_.get_implementation(),
+        buffers, destination, flags, ec);
+  }
+
+  /// Start an asynchronous send.
+  /**
+   * This function is used to asynchronously send a datagram to the specified
+   * remote endpoint. The function call always returns immediately.
+   *
+   * @param buffers One or more data buffers to be sent to the remote endpoint.
+   * Although the buffers object may be copied as necessary, ownership of the
+   * underlying memory blocks is retained by the caller, which must guarantee
+   * that they remain valid until the handler is called.
+   *
+   * @param destination The remote endpoint to which the data will be sent.
+   * Copies will be made of the endpoint as required.
+   *
+   * @param handler The handler to be called when the send operation completes.
+   * Copies will be made of the handler as required. The function signature of
+   * the handler must be:
+   * @code void handler(
+   *   const asio::error_code& error, // Result of operation.
+   *   std::size_t bytes_transferred           // Number of bytes sent.
+   * ); @endcode
+   * Regardless of whether the asynchronous operation completes immediately or
+   * not, the handler will not be invoked from within this function. On
+   * immediate completion, invocation of the handler will be performed in a
+   * manner equivalent to using asio::post().
+   *
+   * @par Example
+   * To send a single data buffer use the @ref buffer function as follows:
+   * @code
+   * asio::ip::udp::endpoint destination(
+   *     asio::ip::address::from_string("1.2.3.4"), 12345);
+   * socket.async_send_to(
+   *     asio::buffer(data, size), destination, handler);
+   * @endcode
+   * See the @ref buffer documentation for information on sending multiple
+   * buffers in one go, and how to use it with arrays, boost::array or
+   * std::vector.
+   */
+  template <typename ConstBufferSequence,
+      ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+        std::size_t)) WriteHandler
+          ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
+  ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,
+      void (asio::error_code, std::size_t))
+  async_send_to(const ConstBufferSequence& buffers,
+      const endpoint_type& destination,
+      ASIO_MOVE_ARG(WriteHandler) handler
+        ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
+  {
+    return async_initiate<WriteHandler,
+      void (asio::error_code, std::size_t)>(
+        initiate_async_send_to(this), handler, buffers,
+        destination, socket_base::message_flags(0));
+  }
+
+  /// Start an asynchronous send.
+  /**
+   * This function is used to asynchronously send a datagram to the specified
+   * remote endpoint. The function call always returns immediately.
+   *
+   * @param buffers One or more data buffers to be sent to the remote endpoint.
+   * Although the buffers object may be copied as necessary, ownership of the
+   * underlying memory blocks is retained by the caller, which must guarantee
+   * that they remain valid until the handler is called.
+   *
+   * @param flags Flags specifying how the send call is to be made.
+   *
+   * @param destination The remote endpoint to which the data will be sent.
+   * Copies will be made of the endpoint as required.
+   *
+   * @param handler The handler to be called when the send operation completes.
+   * Copies will be made of the handler as required. The function signature of
+   * the handler must be:
+   * @code void handler(
+   *   const asio::error_code& error, // Result of operation.
+   *   std::size_t bytes_transferred           // Number of bytes sent.
+   * ); @endcode
+   * Regardless of whether the asynchronous operation completes immediately or
+   * not, the handler will not be invoked from within this function. On
+   * immediate completion, invocation of the handler will be performed in a
+   * manner equivalent to using asio::post().
+   */
+  template <typename ConstBufferSequence,
+      ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+        std::size_t)) WriteHandler
+          ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
+  ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,
+      void (asio::error_code, std::size_t))
+  async_send_to(const ConstBufferSequence& buffers,
+      const endpoint_type& destination, socket_base::message_flags flags,
+      ASIO_MOVE_ARG(WriteHandler) handler
+        ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
+  {
+    return async_initiate<WriteHandler,
+      void (asio::error_code, std::size_t)>(
+        initiate_async_send_to(this), handler, buffers, destination, flags);
+  }
+
+  /// Receive some data on a connected socket.
+  /**
+   * This function is used to receive data on the datagram socket. The function
+   * call will block until data has been received successfully or an error
+   * occurs.
+   *
+   * @param buffers One or more buffers into which the data will be received.
+   *
+   * @returns The number of bytes received.
+   *
+   * @throws asio::system_error Thrown on failure.
+   *
+   * @note The receive operation can only be used with a connected socket. Use
+   * the receive_from function to receive data on an unconnected datagram
+   * socket.
+   *
+   * @par Example
+   * To receive into a single data buffer use the @ref buffer function as
+   * follows:
+   * @code socket.receive(asio::buffer(data, size)); @endcode
+   * See the @ref buffer documentation for information on receiving into
+   * multiple buffers in one go, and how to use it with arrays, boost::array or
+   * std::vector.
+   */
+  template <typename MutableBufferSequence>
+  std::size_t receive(const MutableBufferSequence& buffers)
+  {
+    asio::error_code ec;
+    std::size_t s = this->impl_.get_service().receive(
+        this->impl_.get_implementation(), buffers, 0, ec);
+    asio::detail::throw_error(ec, "receive");
+    return s;
+  }
+
+  /// Receive some data on a connected socket.
+  /**
+   * This function is used to receive data on the datagram socket. The function
+   * call will block until data has been received successfully or an error
+   * occurs.
+   *
+   * @param buffers One or more buffers into which the data will be received.
+   *
+   * @param flags Flags specifying how the receive call is to be made.
+   *
+   * @returns The number of bytes received.
+   *
+   * @throws asio::system_error Thrown on failure.
+   *
+   * @note The receive operation can only be used with a connected socket. Use
+   * the receive_from function to receive data on an unconnected datagram
+   * socket.
+   */
+  template <typename MutableBufferSequence>
+  std::size_t receive(const MutableBufferSequence& buffers,
+      socket_base::message_flags flags)
+  {
+    asio::error_code ec;
+    std::size_t s = this->impl_.get_service().receive(
+        this->impl_.get_implementation(), buffers, flags, ec);
+    asio::detail::throw_error(ec, "receive");
+    return s;
+  }
+
+  /// Receive some data on a connected socket.
+  /**
+   * This function is used to receive data on the datagram socket. The function
+   * call will block until data has been received successfully or an error
+   * occurs.
+   *
+   * @param buffers One or more buffers into which the data will be received.
+   *
+   * @param flags Flags specifying how the receive call is to be made.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   *
+   * @returns The number of bytes received.
+   *
+   * @note The receive operation can only be used with a connected socket. Use
+   * the receive_from function to receive data on an unconnected datagram
+   * socket.
+   */
+  template <typename MutableBufferSequence>
+  std::size_t receive(const MutableBufferSequence& buffers,
+      socket_base::message_flags flags, asio::error_code& ec)
+  {
+    return this->impl_.get_service().receive(
+        this->impl_.get_implementation(), buffers, flags, ec);
+  }
+
+  /// Start an asynchronous receive on a connected socket.
+  /**
+   * This function is used to asynchronously receive data from the datagram
+   * socket. The function call always returns immediately.
+   *
+   * @param buffers One or more buffers into which the data will be received.
+   * Although the buffers object may be copied as necessary, ownership of the
+   * underlying memory blocks is retained by the caller, which must guarantee
+   * that they remain valid until the handler is called.
+   *
+   * @param handler The handler to be called when the receive operation
+   * completes. Copies will be made of the handler as required. The function
+   * signature of the handler must be:
+   * @code void handler(
+   *   const asio::error_code& error, // Result of operation.
+   *   std::size_t bytes_transferred           // Number of bytes received.
+   * ); @endcode
+   * Regardless of whether the asynchronous operation completes immediately or
+   * not, the handler will not be invoked from within this function. On
+   * immediate completion, invocation of the handler will be performed in a
+   * manner equivalent to using asio::post().
+   *
+   * @note The async_receive operation can only be used with a connected socket.
+   * Use the async_receive_from function to receive data on an unconnected
+   * datagram socket.
+   *
+   * @par Example
+   * To receive into a single data buffer use the @ref buffer function as
+   * follows:
+   * @code
+   * socket.async_receive(asio::buffer(data, size), handler);
+   * @endcode
+   * See the @ref buffer documentation for information on receiving into
+   * multiple buffers in one go, and how to use it with arrays, boost::array or
+   * std::vector.
+   */
+  template <typename MutableBufferSequence,
+      ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+        std::size_t)) ReadHandler
+          ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
+  ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,
+      void (asio::error_code, std::size_t))
+  async_receive(const MutableBufferSequence& buffers,
+      ASIO_MOVE_ARG(ReadHandler) handler
+        ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
+  {
+    return async_initiate<ReadHandler,
+      void (asio::error_code, std::size_t)>(
+        initiate_async_receive(this), handler,
+        buffers, socket_base::message_flags(0));
+  }
+
+  /// Start an asynchronous receive on a connected socket.
+  /**
+   * This function is used to asynchronously receive data from the datagram
+   * socket. The function call always returns immediately.
+   *
+   * @param buffers One or more buffers into which the data will be received.
+   * Although the buffers object may be copied as necessary, ownership of the
+   * underlying memory blocks is retained by the caller, which must guarantee
+   * that they remain valid until the handler is called.
+   *
+   * @param flags Flags specifying how the receive call is to be made.
+   *
+   * @param handler The handler to be called when the receive operation
+   * completes. Copies will be made of the handler as required. The function
+   * signature of the handler must be:
+   * @code void handler(
+   *   const asio::error_code& error, // Result of operation.
+   *   std::size_t bytes_transferred           // Number of bytes received.
+   * ); @endcode
+   * Regardless of whether the asynchronous operation completes immediately or
+   * not, the handler will not be invoked from within this function. On
+   * immediate completion, invocation of the handler will be performed in a
+   * manner equivalent to using asio::post().
+   *
+   * @note The async_receive operation can only be used with a connected socket.
+   * Use the async_receive_from function to receive data on an unconnected
+   * datagram socket.
+   */
+  template <typename MutableBufferSequence,
+      ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+        std::size_t)) ReadHandler
+          ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
+  ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,
+      void (asio::error_code, std::size_t))
+  async_receive(const MutableBufferSequence& buffers,
+      socket_base::message_flags flags,
+      ASIO_MOVE_ARG(ReadHandler) handler
+        ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
+  {
+    return async_initiate<ReadHandler,
+      void (asio::error_code, std::size_t)>(
+        initiate_async_receive(this), handler, buffers, flags);
+  }
+
+  /// Receive a datagram with the endpoint of the sender.
+  /**
+   * This function is used to receive a datagram. The function call will block
+   * until data has been received successfully or an error occurs.
+   *
+   * @param buffers One or more buffers into which the data will be received.
+   *
+   * @param sender_endpoint An endpoint object that receives the endpoint of
+   * the remote sender of the datagram.
+   *
+   * @returns The number of bytes received.
+   *
+   * @throws asio::system_error Thrown on failure.
+   *
+   * @par Example
+   * To receive into a single data buffer use the @ref buffer function as
+   * follows:
+   * @code
+   * asio::ip::udp::endpoint sender_endpoint;
+   * socket.receive_from(
+   *     asio::buffer(data, size), sender_endpoint);
+   * @endcode
+   * See the @ref buffer documentation for information on receiving into
+   * multiple buffers in one go, and how to use it with arrays, boost::array or
+   * std::vector.
+   */
+  template <typename MutableBufferSequence>
+  std::size_t receive_from(const MutableBufferSequence& buffers,
+      endpoint_type& sender_endpoint)
+  {
+    asio::error_code ec;
+    std::size_t s = this->impl_.get_service().receive_from(
+        this->impl_.get_implementation(), buffers, sender_endpoint, 0, ec);
+    asio::detail::throw_error(ec, "receive_from");
+    return s;
+  }
+  
+  /// Receive a datagram with the endpoint of the sender.
+  /**
+   * This function is used to receive a datagram. The function call will block
+   * until data has been received successfully or an error occurs.
+   *
+   * @param buffers One or more buffers into which the data will be received.
+   *
+   * @param sender_endpoint An endpoint object that receives the endpoint of
+   * the remote sender of the datagram.
+   *
+   * @param flags Flags specifying how the receive call is to be made.
+   *
+   * @returns The number of bytes received.
+   *
+   * @throws asio::system_error Thrown on failure.
+   */
+  template <typename MutableBufferSequence>
+  std::size_t receive_from(const MutableBufferSequence& buffers,
+      endpoint_type& sender_endpoint, socket_base::message_flags flags)
+  {
+    asio::error_code ec;
+    std::size_t s = this->impl_.get_service().receive_from(
+        this->impl_.get_implementation(), buffers, sender_endpoint, flags, ec);
+    asio::detail::throw_error(ec, "receive_from");
+    return s;
+  }
+  
+  /// Receive a datagram with the endpoint of the sender.
+  /**
+   * This function is used to receive a datagram. The function call will block
+   * until data has been received successfully or an error occurs.
+   *
+   * @param buffers One or more buffers into which the data will be received.
+   *
+   * @param sender_endpoint An endpoint object that receives the endpoint of
+   * the remote sender of the datagram.
+   *
+   * @param flags Flags specifying how the receive call is to be made.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   *
+   * @returns The number of bytes received.
+   */
+  template <typename MutableBufferSequence>
+  std::size_t receive_from(const MutableBufferSequence& buffers,
+      endpoint_type& sender_endpoint, socket_base::message_flags flags,
+      asio::error_code& ec)
+  {
+    return this->impl_.get_service().receive_from(
+        this->impl_.get_implementation(), buffers, sender_endpoint, flags, ec);
+  }
+
+  /// Start an asynchronous receive.
+  /**
+   * This function is used to asynchronously receive a datagram. The function
+   * call always returns immediately.
+   *
+   * @param buffers One or more buffers into which the data will be received.
+   * Although the buffers object may be copied as necessary, ownership of the
+   * underlying memory blocks is retained by the caller, which must guarantee
+   * that they remain valid until the handler is called.
+   *
+   * @param sender_endpoint An endpoint object that receives the endpoint of
+   * the remote sender of the datagram. Ownership of the sender_endpoint object
+   * is retained by the caller, which must guarantee that it is valid until the
+   * handler is called.
+   *
+   * @param handler The handler to be called when the receive operation
+   * completes. Copies will be made of the handler as required. The function
+   * signature of the handler must be:
+   * @code void handler(
+   *   const asio::error_code& error, // Result of operation.
+   *   std::size_t bytes_transferred           // Number of bytes received.
+   * ); @endcode
+   * Regardless of whether the asynchronous operation completes immediately or
+   * not, the handler will not be invoked from within this function. On
+   * immediate completion, invocation of the handler will be performed in a
+   * manner equivalent to using asio::post().
+   *
+   * @par Example
+   * To receive into a single data buffer use the @ref buffer function as
+   * follows:
+   * @code socket.async_receive_from(
+   *     asio::buffer(data, size), sender_endpoint, handler); @endcode
+   * See the @ref buffer documentation for information on receiving into
+   * multiple buffers in one go, and how to use it with arrays, boost::array or
+   * std::vector.
+   */
+  template <typename MutableBufferSequence,
+      ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+        std::size_t)) ReadHandler
+          ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
+  ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,
+      void (asio::error_code, std::size_t))
+  async_receive_from(const MutableBufferSequence& buffers,
+      endpoint_type& sender_endpoint,
+      ASIO_MOVE_ARG(ReadHandler) handler
+        ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
+  {
+    return async_initiate<ReadHandler,
+      void (asio::error_code, std::size_t)>(
+        initiate_async_receive_from(this), handler, buffers,
+        &sender_endpoint, socket_base::message_flags(0));
+  }
+
+  /// Start an asynchronous receive.
+  /**
+   * This function is used to asynchronously receive a datagram. The function
+   * call always returns immediately.
+   *
+   * @param buffers One or more buffers into which the data will be received.
+   * Although the buffers object may be copied as necessary, ownership of the
+   * underlying memory blocks is retained by the caller, which must guarantee
+   * that they remain valid until the handler is called.
+   *
+   * @param sender_endpoint An endpoint object that receives the endpoint of
+   * the remote sender of the datagram. Ownership of the sender_endpoint object
+   * is retained by the caller, which must guarantee that it is valid until the
+   * handler is called.
+   *
+   * @param flags Flags specifying how the receive call is to be made.
+   *
+   * @param handler The handler to be called when the receive operation
+   * completes. Copies will be made of the handler as required. The function
+   * signature of the handler must be:
+   * @code void handler(
+   *   const asio::error_code& error, // Result of operation.
+   *   std::size_t bytes_transferred           // Number of bytes received.
+   * ); @endcode
+   * Regardless of whether the asynchronous operation completes immediately or
+   * not, the handler will not be invoked from within this function. On
+   * immediate completion, invocation of the handler will be performed in a
+   * manner equivalent to using asio::post().
+   */
+  template <typename MutableBufferSequence,
+      ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+        std::size_t)) ReadHandler
+          ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
+  ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,
+      void (asio::error_code, std::size_t))
+  async_receive_from(const MutableBufferSequence& buffers,
+      endpoint_type& sender_endpoint, socket_base::message_flags flags,
+      ASIO_MOVE_ARG(ReadHandler) handler
+        ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
+  {
+    return async_initiate<ReadHandler,
+      void (asio::error_code, std::size_t)>(
+        initiate_async_receive_from(this), handler,
+        buffers, &sender_endpoint, flags);
+  }
+
+private:
+  // Disallow copying and assignment.
+  basic_datagram_socket(const basic_datagram_socket&) ASIO_DELETED;
+  basic_datagram_socket& operator=(
+      const basic_datagram_socket&) ASIO_DELETED;
+
+  class initiate_async_send
+  { 
+  public:
+    typedef Executor executor_type;
+
+    explicit initiate_async_send(basic_datagram_socket* self)
+      : self_(self)
+    {
+    }
+
+    executor_type get_executor() const ASIO_NOEXCEPT
+    {
+      return self_->get_executor();
+    }
+
+    template <typename WriteHandler, typename ConstBufferSequence>
+    void operator()(ASIO_MOVE_ARG(WriteHandler) handler,
+        const ConstBufferSequence& buffers,
+        socket_base::message_flags flags) const
+    {
+      // If you get an error on the following line it means that your handler
+      // does not meet the documented type requirements for a WriteHandler.
+      ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check;
+
+      detail::non_const_lvalue<WriteHandler> handler2(handler);
+      self_->impl_.get_service().async_send(
+          self_->impl_.get_implementation(), buffers, flags,
+          handler2.value, self_->impl_.get_executor());
+    }
+
+  private:
+    basic_datagram_socket* self_;
+  };
+
+  class initiate_async_send_to
+  {
+  public:
+    typedef Executor executor_type;
+
+    explicit initiate_async_send_to(basic_datagram_socket* self)
+      : self_(self)
+    {
+    }
+
+    executor_type get_executor() const ASIO_NOEXCEPT
+    {
+      return self_->get_executor();
+    }
+
+    template <typename WriteHandler, typename ConstBufferSequence>
+    void operator()(ASIO_MOVE_ARG(WriteHandler) handler,
+        const ConstBufferSequence& buffers, const endpoint_type& destination,
+        socket_base::message_flags flags) const
+    {
+      // If you get an error on the following line it means that your handler
+      // does not meet the documented type requirements for a WriteHandler.
+      ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check;
+
+      detail::non_const_lvalue<WriteHandler> handler2(handler);
+      self_->impl_.get_service().async_send_to(
+          self_->impl_.get_implementation(), buffers, destination,
+          flags, handler2.value, self_->impl_.get_executor());
+    }
+
+  private:
+    basic_datagram_socket* self_;
+  };
+
+  class initiate_async_receive
+  {
+  public:
+    typedef Executor executor_type;
+
+    explicit initiate_async_receive(basic_datagram_socket* self)
+      : self_(self)
+    {
+    }
+
+    executor_type get_executor() const ASIO_NOEXCEPT
+    {
+      return self_->get_executor();
+    }
+
+    template <typename ReadHandler, typename MutableBufferSequence>
+    void operator()(ASIO_MOVE_ARG(ReadHandler) handler,
+        const MutableBufferSequence& buffers,
+        socket_base::message_flags flags) const
+    {
+      // If you get an error on the following line it means that your handler
+      // does not meet the documented type requirements for a ReadHandler.
+      ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
+
+      detail::non_const_lvalue<ReadHandler> handler2(handler);
+      self_->impl_.get_service().async_receive(
+          self_->impl_.get_implementation(), buffers, flags,
+          handler2.value, self_->impl_.get_executor());
+    }
+
+  private:
+    basic_datagram_socket* self_;
+  };
+
+  class initiate_async_receive_from
+  {
+  public:
+    typedef Executor executor_type;
+
+    explicit initiate_async_receive_from(basic_datagram_socket* self)
+      : self_(self)
+    {
+    }
+
+    executor_type get_executor() const ASIO_NOEXCEPT
+    {
+      return self_->get_executor();
+    }
+
+    template <typename ReadHandler, typename MutableBufferSequence>
+    void operator()(ASIO_MOVE_ARG(ReadHandler) handler,
+        const MutableBufferSequence& buffers, endpoint_type* sender_endpoint,
+        socket_base::message_flags flags) const
+    {
+      // If you get an error on the following line it means that your handler
+      // does not meet the documented type requirements for a ReadHandler.
+      ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
+
+      detail::non_const_lvalue<ReadHandler> handler2(handler);
+      self_->impl_.get_service().async_receive_from(
+          self_->impl_.get_implementation(), buffers, *sender_endpoint,
+          flags, handler2.value, self_->impl_.get_executor());
+    }
+
+  private:
+    basic_datagram_socket* self_;
+  };
+};
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_BASIC_DATAGRAM_SOCKET_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/basic_deadline_timer.hpp b/link/modules/asio-standalone/asio/include/asio/basic_deadline_timer.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/basic_deadline_timer.hpp
@@ -0,0 +1,693 @@
+//
+// basic_deadline_timer.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_BASIC_DEADLINE_TIMER_HPP
+#define ASIO_BASIC_DEADLINE_TIMER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_BOOST_DATE_TIME) \
+  || defined(GENERATING_DOCUMENTATION)
+
+#include <cstddef>
+#include "asio/any_io_executor.hpp"
+#include "asio/detail/deadline_timer_service.hpp"
+#include "asio/detail/handler_type_requirements.hpp"
+#include "asio/detail/io_object_impl.hpp"
+#include "asio/detail/non_const_lvalue.hpp"
+#include "asio/detail/throw_error.hpp"
+#include "asio/error.hpp"
+#include "asio/execution_context.hpp"
+#include "asio/time_traits.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+/// Provides waitable timer functionality.
+/**
+ * The basic_deadline_timer class template provides the ability to perform a
+ * blocking or asynchronous wait for a timer to expire.
+ *
+ * A deadline timer is always in one of two states: "expired" or "not expired".
+ * If the wait() or async_wait() function is called on an expired timer, the
+ * wait operation will complete immediately.
+ *
+ * Most applications will use the asio::deadline_timer typedef.
+ *
+ * @par Thread Safety
+ * @e Distinct @e objects: Safe.@n
+ * @e Shared @e objects: Unsafe.
+ *
+ * @par Examples
+ * Performing a blocking wait:
+ * @code
+ * // Construct a timer without setting an expiry time.
+ * asio::deadline_timer timer(my_context);
+ *
+ * // Set an expiry time relative to now.
+ * timer.expires_from_now(boost::posix_time::seconds(5));
+ *
+ * // Wait for the timer to expire.
+ * timer.wait();
+ * @endcode
+ *
+ * @par 
+ * Performing an asynchronous wait:
+ * @code
+ * void handler(const asio::error_code& error)
+ * {
+ *   if (!error)
+ *   {
+ *     // Timer expired.
+ *   }
+ * }
+ *
+ * ...
+ *
+ * // Construct a timer with an absolute expiry time.
+ * asio::deadline_timer timer(my_context,
+ *     boost::posix_time::time_from_string("2005-12-07 23:59:59.000"));
+ *
+ * // Start an asynchronous wait.
+ * timer.async_wait(handler);
+ * @endcode
+ *
+ * @par Changing an active deadline_timer's expiry time
+ *
+ * Changing the expiry time of a timer while there are pending asynchronous
+ * waits causes those wait operations to be cancelled. To ensure that the action
+ * associated with the timer is performed only once, use something like this:
+ * used:
+ *
+ * @code
+ * void on_some_event()
+ * {
+ *   if (my_timer.expires_from_now(seconds(5)) > 0)
+ *   {
+ *     // We managed to cancel the timer. Start new asynchronous wait.
+ *     my_timer.async_wait(on_timeout);
+ *   }
+ *   else
+ *   {
+ *     // Too late, timer has already expired!
+ *   }
+ * }
+ *
+ * void on_timeout(const asio::error_code& e)
+ * {
+ *   if (e != asio::error::operation_aborted)
+ *   {
+ *     // Timer was not cancelled, take necessary action.
+ *   }
+ * }
+ * @endcode
+ *
+ * @li The asio::basic_deadline_timer::expires_from_now() function
+ * cancels any pending asynchronous waits, and returns the number of
+ * asynchronous waits that were cancelled. If it returns 0 then you were too
+ * late and the wait handler has already been executed, or will soon be
+ * executed. If it returns 1 then the wait handler was successfully cancelled.
+ *
+ * @li If a wait handler is cancelled, the asio::error_code passed to
+ * it contains the value asio::error::operation_aborted.
+ */
+template <typename Time,
+    typename TimeTraits = asio::time_traits<Time>,
+    typename Executor = any_io_executor>
+class basic_deadline_timer
+{
+public:
+  /// The type of the executor associated with the object.
+  typedef Executor executor_type;
+
+  /// Rebinds the timer type to another executor.
+  template <typename Executor1>
+  struct rebind_executor
+  {
+    /// The timer type when rebound to the specified executor.
+    typedef basic_deadline_timer<Time, TimeTraits, Executor1> other;
+  };
+
+  /// The time traits type.
+  typedef TimeTraits traits_type;
+
+  /// The time type.
+  typedef typename traits_type::time_type time_type;
+
+  /// The duration type.
+  typedef typename traits_type::duration_type duration_type;
+
+  /// Constructor.
+  /**
+   * This constructor creates a timer without setting an expiry time. The
+   * expires_at() or expires_from_now() functions must be called to set an
+   * expiry time before the timer can be waited on.
+   *
+   * @param ex The I/O executor that the timer will use, by default, to
+   * dispatch handlers for any asynchronous operations performed on the timer.
+   */
+  explicit basic_deadline_timer(const executor_type& ex)
+    : impl_(ex)
+  {
+  }
+
+  /// Constructor.
+  /**
+   * This constructor creates a timer without setting an expiry time. The
+   * expires_at() or expires_from_now() functions must be called to set an
+   * expiry time before the timer can be waited on.
+   *
+   * @param context An execution context which provides the I/O executor that
+   * the timer will use, by default, to dispatch handlers for any asynchronous
+   * operations performed on the timer.
+   */
+  template <typename ExecutionContext>
+  explicit basic_deadline_timer(ExecutionContext& context,
+      typename enable_if<
+        is_convertible<ExecutionContext&, execution_context&>::value
+      >::type* = 0)
+    : impl_(context)
+  {
+  }
+
+  /// Constructor to set a particular expiry time as an absolute time.
+  /**
+   * This constructor creates a timer and sets the expiry time.
+   *
+   * @param ex The I/O executor that the timer will use, by default, to
+   * dispatch handlers for any asynchronous operations performed on the timer.
+   *
+   * @param expiry_time The expiry time to be used for the timer, expressed
+   * as an absolute time.
+   */
+  basic_deadline_timer(const executor_type& ex, const time_type& expiry_time)
+    : impl_(ex)
+  {
+    asio::error_code ec;
+    impl_.get_service().expires_at(impl_.get_implementation(), expiry_time, ec);
+    asio::detail::throw_error(ec, "expires_at");
+  }
+
+  /// Constructor to set a particular expiry time as an absolute time.
+  /**
+   * This constructor creates a timer and sets the expiry time.
+   *
+   * @param context An execution context which provides the I/O executor that
+   * the timer will use, by default, to dispatch handlers for any asynchronous
+   * operations performed on the timer.
+   *
+   * @param expiry_time The expiry time to be used for the timer, expressed
+   * as an absolute time.
+   */
+  template <typename ExecutionContext>
+  basic_deadline_timer(ExecutionContext& context, const time_type& expiry_time,
+      typename enable_if<
+        is_convertible<ExecutionContext&, execution_context&>::value
+      >::type* = 0)
+    : impl_(context)
+  {
+    asio::error_code ec;
+    impl_.get_service().expires_at(impl_.get_implementation(), expiry_time, ec);
+    asio::detail::throw_error(ec, "expires_at");
+  }
+
+  /// Constructor to set a particular expiry time relative to now.
+  /**
+   * This constructor creates a timer and sets the expiry time.
+   *
+   * @param ex The I/O executor that the timer will use, by default, to
+   * dispatch handlers for any asynchronous operations performed on the timer.
+   *
+   * @param expiry_time The expiry time to be used for the timer, relative to
+   * now.
+   */
+  basic_deadline_timer(const executor_type& ex,
+      const duration_type& expiry_time)
+    : impl_(ex)
+  {
+    asio::error_code ec;
+    impl_.get_service().expires_from_now(
+        impl_.get_implementation(), expiry_time, ec);
+    asio::detail::throw_error(ec, "expires_from_now");
+  }
+
+  /// Constructor to set a particular expiry time relative to now.
+  /**
+   * This constructor creates a timer and sets the expiry time.
+   *
+   * @param context An execution context which provides the I/O executor that
+   * the timer will use, by default, to dispatch handlers for any asynchronous
+   * operations performed on the timer.
+   *
+   * @param expiry_time The expiry time to be used for the timer, relative to
+   * now.
+   */
+  template <typename ExecutionContext>
+  basic_deadline_timer(ExecutionContext& context,
+      const duration_type& expiry_time,
+      typename enable_if<
+        is_convertible<ExecutionContext&, execution_context&>::value
+      >::type* = 0)
+    : impl_(context)
+  {
+    asio::error_code ec;
+    impl_.get_service().expires_from_now(
+        impl_.get_implementation(), expiry_time, ec);
+    asio::detail::throw_error(ec, "expires_from_now");
+  }
+
+#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+  /// Move-construct a basic_deadline_timer from another.
+  /**
+   * This constructor moves a timer from one object to another.
+   *
+   * @param other The other basic_deadline_timer object from which the move will
+   * occur.
+   *
+   * @note Following the move, the moved-from object is in the same state as if
+   * constructed using the @c basic_deadline_timer(const executor_type&)
+   * constructor.
+   */
+  basic_deadline_timer(basic_deadline_timer&& other)
+    : impl_(std::move(other.impl_))
+  {
+  }
+
+  /// Move-assign a basic_deadline_timer from another.
+  /**
+   * This assignment operator moves a timer from one object to another. Cancels
+   * any outstanding asynchronous operations associated with the target object.
+   *
+   * @param other The other basic_deadline_timer object from which the move will
+   * occur.
+   *
+   * @note Following the move, the moved-from object is in the same state as if
+   * constructed using the @c basic_deadline_timer(const executor_type&)
+   * constructor.
+   */
+  basic_deadline_timer& operator=(basic_deadline_timer&& other)
+  {
+    impl_ = std::move(other.impl_);
+    return *this;
+  }
+#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+
+  /// Destroys the timer.
+  /**
+   * This function destroys the timer, cancelling any outstanding asynchronous
+   * wait operations associated with the timer as if by calling @c cancel.
+   */
+  ~basic_deadline_timer()
+  {
+  }
+
+  /// Get the executor associated with the object.
+  executor_type get_executor() ASIO_NOEXCEPT
+  {
+    return impl_.get_executor();
+  }
+
+  /// Cancel any asynchronous operations that are waiting on the timer.
+  /**
+   * This function forces the completion of any pending asynchronous wait
+   * operations against the timer. The handler for each cancelled operation will
+   * be invoked with the asio::error::operation_aborted error code.
+   *
+   * Cancelling the timer does not change the expiry time.
+   *
+   * @return The number of asynchronous operations that were cancelled.
+   *
+   * @throws asio::system_error Thrown on failure.
+   *
+   * @note If the timer has already expired when cancel() is called, then the
+   * handlers for asynchronous wait operations will:
+   *
+   * @li have already been invoked; or
+   *
+   * @li have been queued for invocation in the near future.
+   *
+   * These handlers can no longer be cancelled, and therefore are passed an
+   * error code that indicates the successful completion of the wait operation.
+   */
+  std::size_t cancel()
+  {
+    asio::error_code ec;
+    std::size_t s = impl_.get_service().cancel(impl_.get_implementation(), ec);
+    asio::detail::throw_error(ec, "cancel");
+    return s;
+  }
+
+  /// Cancel any asynchronous operations that are waiting on the timer.
+  /**
+   * This function forces the completion of any pending asynchronous wait
+   * operations against the timer. The handler for each cancelled operation will
+   * be invoked with the asio::error::operation_aborted error code.
+   *
+   * Cancelling the timer does not change the expiry time.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   *
+   * @return The number of asynchronous operations that were cancelled.
+   *
+   * @note If the timer has already expired when cancel() is called, then the
+   * handlers for asynchronous wait operations will:
+   *
+   * @li have already been invoked; or
+   *
+   * @li have been queued for invocation in the near future.
+   *
+   * These handlers can no longer be cancelled, and therefore are passed an
+   * error code that indicates the successful completion of the wait operation.
+   */
+  std::size_t cancel(asio::error_code& ec)
+  {
+    return impl_.get_service().cancel(impl_.get_implementation(), ec);
+  }
+
+  /// Cancels one asynchronous operation that is waiting on the timer.
+  /**
+   * This function forces the completion of one pending asynchronous wait
+   * operation against the timer. Handlers are cancelled in FIFO order. The
+   * handler for the cancelled operation will be invoked with the
+   * asio::error::operation_aborted error code.
+   *
+   * Cancelling the timer does not change the expiry time.
+   *
+   * @return The number of asynchronous operations that were cancelled. That is,
+   * either 0 or 1.
+   *
+   * @throws asio::system_error Thrown on failure.
+   *
+   * @note If the timer has already expired when cancel_one() is called, then
+   * the handlers for asynchronous wait operations will:
+   *
+   * @li have already been invoked; or
+   *
+   * @li have been queued for invocation in the near future.
+   *
+   * These handlers can no longer be cancelled, and therefore are passed an
+   * error code that indicates the successful completion of the wait operation.
+   */
+  std::size_t cancel_one()
+  {
+    asio::error_code ec;
+    std::size_t s = impl_.get_service().cancel_one(
+        impl_.get_implementation(), ec);
+    asio::detail::throw_error(ec, "cancel_one");
+    return s;
+  }
+
+  /// Cancels one asynchronous operation that is waiting on the timer.
+  /**
+   * This function forces the completion of one pending asynchronous wait
+   * operation against the timer. Handlers are cancelled in FIFO order. The
+   * handler for the cancelled operation will be invoked with the
+   * asio::error::operation_aborted error code.
+   *
+   * Cancelling the timer does not change the expiry time.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   *
+   * @return The number of asynchronous operations that were cancelled. That is,
+   * either 0 or 1.
+   *
+   * @note If the timer has already expired when cancel_one() is called, then
+   * the handlers for asynchronous wait operations will:
+   *
+   * @li have already been invoked; or
+   *
+   * @li have been queued for invocation in the near future.
+   *
+   * These handlers can no longer be cancelled, and therefore are passed an
+   * error code that indicates the successful completion of the wait operation.
+   */
+  std::size_t cancel_one(asio::error_code& ec)
+  {
+    return impl_.get_service().cancel_one(impl_.get_implementation(), ec);
+  }
+
+  /// Get the timer's expiry time as an absolute time.
+  /**
+   * This function may be used to obtain the timer's current expiry time.
+   * Whether the timer has expired or not does not affect this value.
+   */
+  time_type expires_at() const
+  {
+    return impl_.get_service().expires_at(impl_.get_implementation());
+  }
+
+  /// Set the timer's expiry time as an absolute time.
+  /**
+   * This function sets the expiry time. Any pending asynchronous wait
+   * operations will be cancelled. The handler for each cancelled operation will
+   * be invoked with the asio::error::operation_aborted error code.
+   *
+   * @param expiry_time The expiry time to be used for the timer.
+   *
+   * @return The number of asynchronous operations that were cancelled.
+   *
+   * @throws asio::system_error Thrown on failure.
+   *
+   * @note If the timer has already expired when expires_at() is called, then
+   * the handlers for asynchronous wait operations will:
+   *
+   * @li have already been invoked; or
+   *
+   * @li have been queued for invocation in the near future.
+   *
+   * These handlers can no longer be cancelled, and therefore are passed an
+   * error code that indicates the successful completion of the wait operation.
+   */
+  std::size_t expires_at(const time_type& expiry_time)
+  {
+    asio::error_code ec;
+    std::size_t s = impl_.get_service().expires_at(
+        impl_.get_implementation(), expiry_time, ec);
+    asio::detail::throw_error(ec, "expires_at");
+    return s;
+  }
+
+  /// Set the timer's expiry time as an absolute time.
+  /**
+   * This function sets the expiry time. Any pending asynchronous wait
+   * operations will be cancelled. The handler for each cancelled operation will
+   * be invoked with the asio::error::operation_aborted error code.
+   *
+   * @param expiry_time The expiry time to be used for the timer.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   *
+   * @return The number of asynchronous operations that were cancelled.
+   *
+   * @note If the timer has already expired when expires_at() is called, then
+   * the handlers for asynchronous wait operations will:
+   *
+   * @li have already been invoked; or
+   *
+   * @li have been queued for invocation in the near future.
+   *
+   * These handlers can no longer be cancelled, and therefore are passed an
+   * error code that indicates the successful completion of the wait operation.
+   */
+  std::size_t expires_at(const time_type& expiry_time,
+      asio::error_code& ec)
+  {
+    return impl_.get_service().expires_at(
+        impl_.get_implementation(), expiry_time, ec);
+  }
+
+  /// Get the timer's expiry time relative to now.
+  /**
+   * This function may be used to obtain the timer's current expiry time.
+   * Whether the timer has expired or not does not affect this value.
+   */
+  duration_type expires_from_now() const
+  {
+    return impl_.get_service().expires_from_now(impl_.get_implementation());
+  }
+
+  /// Set the timer's expiry time relative to now.
+  /**
+   * This function sets the expiry time. Any pending asynchronous wait
+   * operations will be cancelled. The handler for each cancelled operation will
+   * be invoked with the asio::error::operation_aborted error code.
+   *
+   * @param expiry_time The expiry time to be used for the timer.
+   *
+   * @return The number of asynchronous operations that were cancelled.
+   *
+   * @throws asio::system_error Thrown on failure.
+   *
+   * @note If the timer has already expired when expires_from_now() is called,
+   * then the handlers for asynchronous wait operations will:
+   *
+   * @li have already been invoked; or
+   *
+   * @li have been queued for invocation in the near future.
+   *
+   * These handlers can no longer be cancelled, and therefore are passed an
+   * error code that indicates the successful completion of the wait operation.
+   */
+  std::size_t expires_from_now(const duration_type& expiry_time)
+  {
+    asio::error_code ec;
+    std::size_t s = impl_.get_service().expires_from_now(
+        impl_.get_implementation(), expiry_time, ec);
+    asio::detail::throw_error(ec, "expires_from_now");
+    return s;
+  }
+
+  /// Set the timer's expiry time relative to now.
+  /**
+   * This function sets the expiry time. Any pending asynchronous wait
+   * operations will be cancelled. The handler for each cancelled operation will
+   * be invoked with the asio::error::operation_aborted error code.
+   *
+   * @param expiry_time The expiry time to be used for the timer.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   *
+   * @return The number of asynchronous operations that were cancelled.
+   *
+   * @note If the timer has already expired when expires_from_now() is called,
+   * then the handlers for asynchronous wait operations will:
+   *
+   * @li have already been invoked; or
+   *
+   * @li have been queued for invocation in the near future.
+   *
+   * These handlers can no longer be cancelled, and therefore are passed an
+   * error code that indicates the successful completion of the wait operation.
+   */
+  std::size_t expires_from_now(const duration_type& expiry_time,
+      asio::error_code& ec)
+  {
+    return impl_.get_service().expires_from_now(
+        impl_.get_implementation(), expiry_time, ec);
+  }
+
+  /// Perform a blocking wait on the timer.
+  /**
+   * This function is used to wait for the timer to expire. This function
+   * blocks and does not return until the timer has expired.
+   *
+   * @throws asio::system_error Thrown on failure.
+   */
+  void wait()
+  {
+    asio::error_code ec;
+    impl_.get_service().wait(impl_.get_implementation(), ec);
+    asio::detail::throw_error(ec, "wait");
+  }
+
+  /// Perform a blocking wait on the timer.
+  /**
+   * This function is used to wait for the timer to expire. This function
+   * blocks and does not return until the timer has expired.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   */
+  void wait(asio::error_code& ec)
+  {
+    impl_.get_service().wait(impl_.get_implementation(), ec);
+  }
+
+  /// Start an asynchronous wait on the timer.
+  /**
+   * This function may be used to initiate an asynchronous wait against the
+   * timer. It always returns immediately.
+   *
+   * For each call to async_wait(), the supplied handler will be called exactly
+   * once. The handler will be called when:
+   *
+   * @li The timer has expired.
+   *
+   * @li The timer was cancelled, in which case the handler is passed the error
+   * code asio::error::operation_aborted.
+   *
+   * @param handler The handler to be called when the timer expires. Copies
+   * will be made of the handler as required. The function signature of the
+   * handler must be:
+   * @code void handler(
+   *   const asio::error_code& error // Result of operation.
+   * ); @endcode
+   * Regardless of whether the asynchronous operation completes immediately or
+   * not, the handler will not be invoked from within this function. On
+   * immediate completion, invocation of the handler will be performed in a
+   * manner equivalent to using asio::post().
+   */
+  template <
+      ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code))
+        WaitHandler ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
+  ASIO_INITFN_AUTO_RESULT_TYPE(WaitHandler,
+      void (asio::error_code))
+  async_wait(
+      ASIO_MOVE_ARG(WaitHandler) handler
+        ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
+  {
+    return async_initiate<WaitHandler, void (asio::error_code)>(
+        initiate_async_wait(this), handler);
+  }
+
+private:
+  // Disallow copying and assignment.
+  basic_deadline_timer(const basic_deadline_timer&) ASIO_DELETED;
+  basic_deadline_timer& operator=(
+      const basic_deadline_timer&) ASIO_DELETED;
+
+  class initiate_async_wait
+  {
+  public:
+    typedef Executor executor_type;
+
+    explicit initiate_async_wait(basic_deadline_timer* self)
+      : self_(self)
+    {
+    }
+
+    executor_type get_executor() const ASIO_NOEXCEPT
+    {
+      return self_->get_executor();
+    }
+
+    template <typename WaitHandler>
+    void operator()(ASIO_MOVE_ARG(WaitHandler) handler) const
+    {
+      // If you get an error on the following line it means that your handler
+      // does not meet the documented type requirements for a WaitHandler.
+      ASIO_WAIT_HANDLER_CHECK(WaitHandler, handler) type_check;
+
+      detail::non_const_lvalue<WaitHandler> handler2(handler);
+      self_->impl_.get_service().async_wait(
+          self_->impl_.get_implementation(),
+          handler2.value, self_->impl_.get_executor());
+    }
+
+  private:
+    basic_deadline_timer* self_;
+  };
+
+  detail::io_object_impl<
+    detail::deadline_timer_service<TimeTraits>, Executor> impl_;
+};
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_BOOST_DATE_TIME)
+       // || defined(GENERATING_DOCUMENTATION)
+
+#endif // ASIO_BASIC_DEADLINE_TIMER_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/basic_io_object.hpp b/link/modules/asio-standalone/asio/include/asio/basic_io_object.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/basic_io_object.hpp
@@ -0,0 +1,290 @@
+//
+// basic_io_object.hpp
+// ~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_BASIC_IO_OBJECT_HPP
+#define ASIO_BASIC_IO_OBJECT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/io_context.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+#if defined(ASIO_HAS_MOVE)
+namespace detail
+{
+  // Type trait used to determine whether a service supports move.
+  template <typename IoObjectService>
+  class service_has_move
+  {
+  private:
+    typedef IoObjectService service_type;
+    typedef typename service_type::implementation_type implementation_type;
+
+    template <typename T, typename U>
+    static auto asio_service_has_move_eval(T* t, U* u)
+      -> decltype(t->move_construct(*u, *u), char());
+    static char (&asio_service_has_move_eval(...))[2];
+
+  public:
+    static const bool value =
+      sizeof(asio_service_has_move_eval(
+        static_cast<service_type*>(0),
+        static_cast<implementation_type*>(0))) == 1;
+  };
+}
+#endif // defined(ASIO_HAS_MOVE)
+
+/// Base class for all I/O objects.
+/**
+ * @note All I/O objects are non-copyable. However, when using C++0x, certain
+ * I/O objects do support move construction and move assignment.
+ */
+#if !defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+template <typename IoObjectService>
+#else
+template <typename IoObjectService,
+    bool Movable = detail::service_has_move<IoObjectService>::value>
+#endif
+class basic_io_object
+{
+public:
+  /// The type of the service that will be used to provide I/O operations.
+  typedef IoObjectService service_type;
+
+  /// The underlying implementation type of I/O object.
+  typedef typename service_type::implementation_type implementation_type;
+
+#if !defined(ASIO_NO_DEPRECATED)
+  /// (Deprecated: Use get_executor().) Get the io_context associated with the
+  /// object.
+  /**
+   * This function may be used to obtain the io_context object that the I/O
+   * object uses to dispatch handlers for asynchronous operations.
+   *
+   * @return A reference to the io_context object that the I/O object will use
+   * to dispatch handlers. Ownership is not transferred to the caller.
+   */
+  asio::io_context& get_io_context()
+  {
+    return service_.get_io_context();
+  }
+
+  /// (Deprecated: Use get_executor().) Get the io_context associated with the
+  /// object.
+  /**
+   * This function may be used to obtain the io_context object that the I/O
+   * object uses to dispatch handlers for asynchronous operations.
+   *
+   * @return A reference to the io_context object that the I/O object will use
+   * to dispatch handlers. Ownership is not transferred to the caller.
+   */
+  asio::io_context& get_io_service()
+  {
+    return service_.get_io_context();
+  }
+#endif // !defined(ASIO_NO_DEPRECATED)
+
+  /// The type of the executor associated with the object.
+  typedef asio::io_context::executor_type executor_type;
+
+  /// Get the executor associated with the object.
+  executor_type get_executor() ASIO_NOEXCEPT
+  {
+    return service_.get_io_context().get_executor();
+  }
+
+protected:
+  /// Construct a basic_io_object.
+  /**
+   * Performs:
+   * @code get_service().construct(get_implementation()); @endcode
+   */
+  explicit basic_io_object(asio::io_context& io_context)
+    : service_(asio::use_service<IoObjectService>(io_context))
+  {
+    service_.construct(implementation_);
+  }
+
+#if defined(GENERATING_DOCUMENTATION)
+  /// Move-construct a basic_io_object.
+  /**
+   * Performs:
+   * @code get_service().move_construct(
+   *     get_implementation(), other.get_implementation()); @endcode
+   *
+   * @note Available only for services that support movability,
+   */
+  basic_io_object(basic_io_object&& other);
+
+  /// Move-assign a basic_io_object.
+  /**
+   * Performs:
+   * @code get_service().move_assign(get_implementation(),
+   *     other.get_service(), other.get_implementation()); @endcode
+   *
+   * @note Available only for services that support movability,
+   */
+  basic_io_object& operator=(basic_io_object&& other);
+
+  /// Perform a converting move-construction of a basic_io_object.
+  template <typename IoObjectService1>
+  basic_io_object(IoObjectService1& other_service,
+      typename IoObjectService1::implementation_type& other_implementation);
+#endif // defined(GENERATING_DOCUMENTATION)
+
+  /// Protected destructor to prevent deletion through this type.
+  /**
+   * Performs:
+   * @code get_service().destroy(get_implementation()); @endcode
+   */
+  ~basic_io_object()
+  {
+    service_.destroy(implementation_);
+  }
+
+  /// Get the service associated with the I/O object.
+  service_type& get_service()
+  {
+    return service_;
+  }
+
+  /// Get the service associated with the I/O object.
+  const service_type& get_service() const
+  {
+    return service_;
+  }
+
+  /// Get the underlying implementation of the I/O object.
+  implementation_type& get_implementation()
+  {
+    return implementation_;
+  }
+
+  /// Get the underlying implementation of the I/O object.
+  const implementation_type& get_implementation() const
+  {
+    return implementation_;
+  }
+
+private:
+  basic_io_object(const basic_io_object&);
+  basic_io_object& operator=(const basic_io_object&);
+
+  // The service associated with the I/O object.
+  service_type& service_;
+
+  /// The underlying implementation of the I/O object.
+  implementation_type implementation_;
+};
+
+#if defined(ASIO_HAS_MOVE)
+// Specialisation for movable objects.
+template <typename IoObjectService>
+class basic_io_object<IoObjectService, true>
+{
+public:
+  typedef IoObjectService service_type;
+  typedef typename service_type::implementation_type implementation_type;
+
+#if !defined(ASIO_NO_DEPRECATED)
+  asio::io_context& get_io_context()
+  {
+    return service_->get_io_context();
+  }
+
+  asio::io_context& get_io_service()
+  {
+    return service_->get_io_context();
+  }
+#endif // !defined(ASIO_NO_DEPRECATED)
+
+  typedef asio::io_context::executor_type executor_type;
+
+  executor_type get_executor() ASIO_NOEXCEPT
+  {
+    return service_->get_io_context().get_executor();
+  }
+
+protected:
+  explicit basic_io_object(asio::io_context& io_context)
+    : service_(&asio::use_service<IoObjectService>(io_context))
+  {
+    service_->construct(implementation_);
+  }
+
+  basic_io_object(basic_io_object&& other)
+    : service_(&other.get_service())
+  {
+    service_->move_construct(implementation_, other.implementation_);
+  }
+
+  template <typename IoObjectService1>
+  basic_io_object(IoObjectService1& other_service,
+      typename IoObjectService1::implementation_type& other_implementation)
+    : service_(&asio::use_service<IoObjectService>(
+          other_service.get_io_context()))
+  {
+    service_->converting_move_construct(implementation_,
+        other_service, other_implementation);
+  }
+
+  ~basic_io_object()
+  {
+    service_->destroy(implementation_);
+  }
+
+  basic_io_object& operator=(basic_io_object&& other)
+  {
+    service_->move_assign(implementation_,
+        *other.service_, other.implementation_);
+    service_ = other.service_;
+    return *this;
+  }
+
+  service_type& get_service()
+  {
+    return *service_;
+  }
+
+  const service_type& get_service() const
+  {
+    return *service_;
+  }
+
+  implementation_type& get_implementation()
+  {
+    return implementation_;
+  }
+
+  const implementation_type& get_implementation() const
+  {
+    return implementation_;
+  }
+
+private:
+  basic_io_object(const basic_io_object&);
+  void operator=(const basic_io_object&);
+
+  IoObjectService* service_;
+  implementation_type implementation_;
+};
+#endif // defined(ASIO_HAS_MOVE)
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_BASIC_IO_OBJECT_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/basic_raw_socket.hpp b/link/modules/asio-standalone/asio/include/asio/basic_raw_socket.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/basic_raw_socket.hpp
@@ -0,0 +1,1206 @@
+//
+// basic_raw_socket.hpp
+// ~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_BASIC_RAW_SOCKET_HPP
+#define ASIO_BASIC_RAW_SOCKET_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <cstddef>
+#include "asio/basic_socket.hpp"
+#include "asio/detail/handler_type_requirements.hpp"
+#include "asio/detail/non_const_lvalue.hpp"
+#include "asio/detail/throw_error.hpp"
+#include "asio/detail/type_traits.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+#if !defined(ASIO_BASIC_RAW_SOCKET_FWD_DECL)
+#define ASIO_BASIC_RAW_SOCKET_FWD_DECL
+
+// Forward declaration with defaulted arguments.
+template <typename Protocol, typename Executor = any_io_executor>
+class basic_raw_socket;
+
+#endif // !defined(ASIO_BASIC_RAW_SOCKET_FWD_DECL)
+
+/// Provides raw-oriented socket functionality.
+/**
+ * The basic_raw_socket class template provides asynchronous and blocking
+ * raw-oriented socket functionality.
+ *
+ * @par Thread Safety
+ * @e Distinct @e objects: Safe.@n
+ * @e Shared @e objects: Unsafe.
+ */
+template <typename Protocol, typename Executor>
+class basic_raw_socket
+  : public basic_socket<Protocol, Executor>
+{
+public:
+  /// The type of the executor associated with the object.
+  typedef Executor executor_type;
+
+  /// Rebinds the socket type to another executor.
+  template <typename Executor1>
+  struct rebind_executor
+  {
+    /// The socket type when rebound to the specified executor.
+    typedef basic_raw_socket<Protocol, Executor1> other;
+  };
+
+  /// The native representation of a socket.
+#if defined(GENERATING_DOCUMENTATION)
+  typedef implementation_defined native_handle_type;
+#else
+  typedef typename basic_socket<Protocol,
+    Executor>::native_handle_type native_handle_type;
+#endif
+
+  /// The protocol type.
+  typedef Protocol protocol_type;
+
+  /// The endpoint type.
+  typedef typename Protocol::endpoint endpoint_type;
+
+  /// Construct a basic_raw_socket without opening it.
+  /**
+   * This constructor creates a raw socket without opening it. The open()
+   * function must be called before data can be sent or received on the socket.
+   *
+   * @param ex The I/O executor that the socket will use, by default, to
+   * dispatch handlers for any asynchronous operations performed on the socket.
+   */
+  explicit basic_raw_socket(const executor_type& ex)
+    : basic_socket<Protocol, Executor>(ex)
+  {
+  }
+
+  /// Construct a basic_raw_socket without opening it.
+  /**
+   * This constructor creates a raw socket without opening it. The open()
+   * function must be called before data can be sent or received on the socket.
+   *
+   * @param context An execution context which provides the I/O executor that
+   * the socket will use, by default, to dispatch handlers for any asynchronous
+   * operations performed on the socket.
+   */
+  template <typename ExecutionContext>
+  explicit basic_raw_socket(ExecutionContext& context,
+      typename enable_if<
+        is_convertible<ExecutionContext&, execution_context&>::value
+      >::type* = 0)
+    : basic_socket<Protocol, Executor>(context)
+  {
+  }
+
+  /// Construct and open a basic_raw_socket.
+  /**
+   * This constructor creates and opens a raw socket.
+   *
+   * @param ex The I/O executor that the socket will use, by default, to
+   * dispatch handlers for any asynchronous operations performed on the socket.
+   *
+   * @param protocol An object specifying protocol parameters to be used.
+   *
+   * @throws asio::system_error Thrown on failure.
+   */
+  basic_raw_socket(const executor_type& ex, const protocol_type& protocol)
+    : basic_socket<Protocol, Executor>(ex, protocol)
+  {
+  }
+
+  /// Construct and open a basic_raw_socket.
+  /**
+   * This constructor creates and opens a raw socket.
+   *
+   * @param context An execution context which provides the I/O executor that
+   * the socket will use, by default, to dispatch handlers for any asynchronous
+   * operations performed on the socket.
+   *
+   * @param protocol An object specifying protocol parameters to be used.
+   *
+   * @throws asio::system_error Thrown on failure.
+   */
+  template <typename ExecutionContext>
+  basic_raw_socket(ExecutionContext& context, const protocol_type& protocol,
+      typename enable_if<
+        is_convertible<ExecutionContext&, execution_context&>::value
+      >::type* = 0)
+    : basic_socket<Protocol, Executor>(context, protocol)
+  {
+  }
+
+  /// Construct a basic_raw_socket, opening it and binding it to the given
+  /// local endpoint.
+  /**
+   * This constructor creates a raw socket and automatically opens it bound
+   * to the specified endpoint on the local machine. The protocol used is the
+   * protocol associated with the given endpoint.
+   *
+   * @param ex The I/O executor that the socket will use, by default, to
+   * dispatch handlers for any asynchronous operations performed on the socket.
+   *
+   * @param endpoint An endpoint on the local machine to which the raw
+   * socket will be bound.
+   *
+   * @throws asio::system_error Thrown on failure.
+   */
+  basic_raw_socket(const executor_type& ex, const endpoint_type& endpoint)
+    : basic_socket<Protocol, Executor>(ex, endpoint)
+  {
+  }
+
+  /// Construct a basic_raw_socket, opening it and binding it to the given
+  /// local endpoint.
+  /**
+   * This constructor creates a raw socket and automatically opens it bound
+   * to the specified endpoint on the local machine. The protocol used is the
+   * protocol associated with the given endpoint.
+   *
+   * @param context An execution context which provides the I/O executor that
+   * the socket will use, by default, to dispatch handlers for any asynchronous
+   * operations performed on the socket.
+   *
+   * @param endpoint An endpoint on the local machine to which the raw
+   * socket will be bound.
+   *
+   * @throws asio::system_error Thrown on failure.
+   */
+  template <typename ExecutionContext>
+  basic_raw_socket(ExecutionContext& context, const endpoint_type& endpoint,
+      typename enable_if<
+        is_convertible<ExecutionContext&, execution_context&>::value
+      >::type* = 0)
+    : basic_socket<Protocol, Executor>(context, endpoint)
+  {
+  }
+
+  /// Construct a basic_raw_socket on an existing native socket.
+  /**
+   * This constructor creates a raw socket object to hold an existing
+   * native socket.
+   *
+   * @param ex The I/O executor that the socket will use, by default, to
+   * dispatch handlers for any asynchronous operations performed on the socket.
+   *
+   * @param protocol An object specifying protocol parameters to be used.
+   *
+   * @param native_socket The new underlying socket implementation.
+   *
+   * @throws asio::system_error Thrown on failure.
+   */
+  basic_raw_socket(const executor_type& ex,
+      const protocol_type& protocol, const native_handle_type& native_socket)
+    : basic_socket<Protocol, Executor>(ex, protocol, native_socket)
+  {
+  }
+
+  /// Construct a basic_raw_socket on an existing native socket.
+  /**
+   * This constructor creates a raw socket object to hold an existing
+   * native socket.
+   *
+   * @param context An execution context which provides the I/O executor that
+   * the socket will use, by default, to dispatch handlers for any asynchronous
+   * operations performed on the socket.
+   *
+   * @param protocol An object specifying protocol parameters to be used.
+   *
+   * @param native_socket The new underlying socket implementation.
+   *
+   * @throws asio::system_error Thrown on failure.
+   */
+  template <typename ExecutionContext>
+  basic_raw_socket(ExecutionContext& context,
+      const protocol_type& protocol, const native_handle_type& native_socket,
+      typename enable_if<
+        is_convertible<ExecutionContext&, execution_context&>::value
+      >::type* = 0)
+    : basic_socket<Protocol, Executor>(context, protocol, native_socket)
+  {
+  }
+
+#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+  /// Move-construct a basic_raw_socket from another.
+  /**
+   * This constructor moves a raw socket from one object to another.
+   *
+   * @param other The other basic_raw_socket object from which the move
+   * will occur.
+   *
+   * @note Following the move, the moved-from object is in the same state as if
+   * constructed using the @c basic_raw_socket(const executor_type&)
+   * constructor.
+   */
+  basic_raw_socket(basic_raw_socket&& other) ASIO_NOEXCEPT
+    : basic_socket<Protocol, Executor>(std::move(other))
+  {
+  }
+
+  /// Move-assign a basic_raw_socket from another.
+  /**
+   * This assignment operator moves a raw socket from one object to another.
+   *
+   * @param other The other basic_raw_socket object from which the move
+   * will occur.
+   *
+   * @note Following the move, the moved-from object is in the same state as if
+   * constructed using the @c basic_raw_socket(const executor_type&)
+   * constructor.
+   */
+  basic_raw_socket& operator=(basic_raw_socket&& other)
+  {
+    basic_socket<Protocol, Executor>::operator=(std::move(other));
+    return *this;
+  }
+
+  /// Move-construct a basic_raw_socket from a socket of another protocol
+  /// type.
+  /**
+   * This constructor moves a raw socket from one object to another.
+   *
+   * @param other The other basic_raw_socket object from which the move
+   * will occur.
+   *
+   * @note Following the move, the moved-from object is in the same state as if
+   * constructed using the @c basic_raw_socket(const executor_type&)
+   * constructor.
+   */
+  template <typename Protocol1, typename Executor1>
+  basic_raw_socket(basic_raw_socket<Protocol1, Executor1>&& other,
+      typename enable_if<
+        is_convertible<Protocol1, Protocol>::value
+          && is_convertible<Executor1, Executor>::value
+      >::type* = 0)
+    : basic_socket<Protocol, Executor>(std::move(other))
+  {
+  }
+
+  /// Move-assign a basic_raw_socket from a socket of another protocol type.
+  /**
+   * This assignment operator moves a raw socket from one object to another.
+   *
+   * @param other The other basic_raw_socket object from which the move
+   * will occur.
+   *
+   * @note Following the move, the moved-from object is in the same state as if
+   * constructed using the @c basic_raw_socket(const executor_type&)
+   * constructor.
+   */
+  template <typename Protocol1, typename Executor1>
+  typename enable_if<
+    is_convertible<Protocol1, Protocol>::value
+      && is_convertible<Executor1, Executor>::value,
+    basic_raw_socket&
+  >::type operator=(basic_raw_socket<Protocol1, Executor1>&& other)
+  {
+    basic_socket<Protocol, Executor>::operator=(std::move(other));
+    return *this;
+  }
+#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+
+  /// Destroys the socket.
+  /**
+   * This function destroys the socket, cancelling any outstanding asynchronous
+   * operations associated with the socket as if by calling @c cancel.
+   */
+  ~basic_raw_socket()
+  {
+  }
+
+  /// Send some data on a connected socket.
+  /**
+   * This function is used to send data on the raw socket. The function call
+   * will block until the data has been sent successfully or an error occurs.
+   *
+   * @param buffers One ore more data buffers to be sent on the socket.
+   *
+   * @returns The number of bytes sent.
+   *
+   * @throws asio::system_error Thrown on failure.
+   *
+   * @note The send operation can only be used with a connected socket. Use
+   * the send_to function to send data on an unconnected raw socket.
+   *
+   * @par Example
+   * To send a single data buffer use the @ref buffer function as follows:
+   * @code socket.send(asio::buffer(data, size)); @endcode
+   * See the @ref buffer documentation for information on sending multiple
+   * buffers in one go, and how to use it with arrays, boost::array or
+   * std::vector.
+   */
+  template <typename ConstBufferSequence>
+  std::size_t send(const ConstBufferSequence& buffers)
+  {
+    asio::error_code ec;
+    std::size_t s = this->impl_.get_service().send(
+        this->impl_.get_implementation(), buffers, 0, ec);
+    asio::detail::throw_error(ec, "send");
+    return s;
+  }
+
+  /// Send some data on a connected socket.
+  /**
+   * This function is used to send data on the raw socket. The function call
+   * will block until the data has been sent successfully or an error occurs.
+   *
+   * @param buffers One ore more data buffers to be sent on the socket.
+   *
+   * @param flags Flags specifying how the send call is to be made.
+   *
+   * @returns The number of bytes sent.
+   *
+   * @throws asio::system_error Thrown on failure.
+   *
+   * @note The send operation can only be used with a connected socket. Use
+   * the send_to function to send data on an unconnected raw socket.
+   */
+  template <typename ConstBufferSequence>
+  std::size_t send(const ConstBufferSequence& buffers,
+      socket_base::message_flags flags)
+  {
+    asio::error_code ec;
+    std::size_t s = this->impl_.get_service().send(
+        this->impl_.get_implementation(), buffers, flags, ec);
+    asio::detail::throw_error(ec, "send");
+    return s;
+  }
+
+  /// Send some data on a connected socket.
+  /**
+   * This function is used to send data on the raw socket. The function call
+   * will block until the data has been sent successfully or an error occurs.
+   *
+   * @param buffers One or more data buffers to be sent on the socket.
+   *
+   * @param flags Flags specifying how the send call is to be made.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   *
+   * @returns The number of bytes sent.
+   *
+   * @note The send operation can only be used with a connected socket. Use
+   * the send_to function to send data on an unconnected raw socket.
+   */
+  template <typename ConstBufferSequence>
+  std::size_t send(const ConstBufferSequence& buffers,
+      socket_base::message_flags flags, asio::error_code& ec)
+  {
+    return this->impl_.get_service().send(
+        this->impl_.get_implementation(), buffers, flags, ec);
+  }
+
+  /// Start an asynchronous send on a connected socket.
+  /**
+   * This function is used to send data on the raw socket. The function call
+   * will block until the data has been sent successfully or an error occurs.
+   *
+   * @param buffers One or more data buffers to be sent on the socket. Although
+   * the buffers object may be copied as necessary, ownership of the underlying
+   * memory blocks is retained by the caller, which must guarantee that they
+   * remain valid until the handler is called.
+   *
+   * @param handler The handler to be called when the send operation completes.
+   * Copies will be made of the handler as required. The function signature of
+   * the handler must be:
+   * @code void handler(
+   *   const asio::error_code& error, // Result of operation.
+   *   std::size_t bytes_transferred           // Number of bytes sent.
+   * ); @endcode
+   * Regardless of whether the asynchronous operation completes immediately or
+   * not, the handler will not be invoked from within this function. On
+   * immediate completion, invocation of the handler will be performed in a
+   * manner equivalent to using asio::post().
+   *
+   * @note The async_send operation can only be used with a connected socket.
+   * Use the async_send_to function to send data on an unconnected raw
+   * socket.
+   *
+   * @par Example
+   * To send a single data buffer use the @ref buffer function as follows:
+   * @code
+   * socket.async_send(asio::buffer(data, size), handler);
+   * @endcode
+   * See the @ref buffer documentation for information on sending multiple
+   * buffers in one go, and how to use it with arrays, boost::array or
+   * std::vector.
+   */
+  template <typename ConstBufferSequence,
+      ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+        std::size_t)) WriteHandler
+          ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
+  ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,
+      void (asio::error_code, std::size_t))
+  async_send(const ConstBufferSequence& buffers,
+      ASIO_MOVE_ARG(WriteHandler) handler
+        ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
+  {
+    return async_initiate<WriteHandler,
+      void (asio::error_code, std::size_t)>(
+        initiate_async_send(this), handler,
+        buffers, socket_base::message_flags(0));
+  }
+
+  /// Start an asynchronous send on a connected socket.
+  /**
+   * This function is used to send data on the raw socket. The function call
+   * will block until the data has been sent successfully or an error occurs.
+   *
+   * @param buffers One or more data buffers to be sent on the socket. Although
+   * the buffers object may be copied as necessary, ownership of the underlying
+   * memory blocks is retained by the caller, which must guarantee that they
+   * remain valid until the handler is called.
+   *
+   * @param flags Flags specifying how the send call is to be made.
+   *
+   * @param handler The handler to be called when the send operation completes.
+   * Copies will be made of the handler as required. The function signature of
+   * the handler must be:
+   * @code void handler(
+   *   const asio::error_code& error, // Result of operation.
+   *   std::size_t bytes_transferred           // Number of bytes sent.
+   * ); @endcode
+   * Regardless of whether the asynchronous operation completes immediately or
+   * not, the handler will not be invoked from within this function. On
+   * immediate completion, invocation of the handler will be performed in a
+   * manner equivalent to using asio::post().
+   *
+   * @note The async_send operation can only be used with a connected socket.
+   * Use the async_send_to function to send data on an unconnected raw
+   * socket.
+   */
+  template <typename ConstBufferSequence,
+      ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+        std::size_t)) WriteHandler
+          ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
+  ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,
+      void (asio::error_code, std::size_t))
+  async_send(const ConstBufferSequence& buffers,
+      socket_base::message_flags flags,
+      ASIO_MOVE_ARG(WriteHandler) handler
+        ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
+  {
+    return async_initiate<WriteHandler,
+      void (asio::error_code, std::size_t)>(
+        initiate_async_send(this), handler, buffers, flags);
+  }
+
+  /// Send raw data to the specified endpoint.
+  /**
+   * This function is used to send raw data to the specified remote endpoint.
+   * The function call will block until the data has been sent successfully or
+   * an error occurs.
+   *
+   * @param buffers One or more data buffers to be sent to the remote endpoint.
+   *
+   * @param destination The remote endpoint to which the data will be sent.
+   *
+   * @returns The number of bytes sent.
+   *
+   * @throws asio::system_error Thrown on failure.
+   *
+   * @par Example
+   * To send a single data buffer use the @ref buffer function as follows:
+   * @code
+   * asio::ip::udp::endpoint destination(
+   *     asio::ip::address::from_string("1.2.3.4"), 12345);
+   * socket.send_to(asio::buffer(data, size), destination);
+   * @endcode
+   * See the @ref buffer documentation for information on sending multiple
+   * buffers in one go, and how to use it with arrays, boost::array or
+   * std::vector.
+   */
+  template <typename ConstBufferSequence>
+  std::size_t send_to(const ConstBufferSequence& buffers,
+      const endpoint_type& destination)
+  {
+    asio::error_code ec;
+    std::size_t s = this->impl_.get_service().send_to(
+        this->impl_.get_implementation(), buffers, destination, 0, ec);
+    asio::detail::throw_error(ec, "send_to");
+    return s;
+  }
+
+  /// Send raw data to the specified endpoint.
+  /**
+   * This function is used to send raw data to the specified remote endpoint.
+   * The function call will block until the data has been sent successfully or
+   * an error occurs.
+   *
+   * @param buffers One or more data buffers to be sent to the remote endpoint.
+   *
+   * @param destination The remote endpoint to which the data will be sent.
+   *
+   * @param flags Flags specifying how the send call is to be made.
+   *
+   * @returns The number of bytes sent.
+   *
+   * @throws asio::system_error Thrown on failure.
+   */
+  template <typename ConstBufferSequence>
+  std::size_t send_to(const ConstBufferSequence& buffers,
+      const endpoint_type& destination, socket_base::message_flags flags)
+  {
+    asio::error_code ec;
+    std::size_t s = this->impl_.get_service().send_to(
+        this->impl_.get_implementation(), buffers, destination, flags, ec);
+    asio::detail::throw_error(ec, "send_to");
+    return s;
+  }
+
+  /// Send raw data to the specified endpoint.
+  /**
+   * This function is used to send raw data to the specified remote endpoint.
+   * The function call will block until the data has been sent successfully or
+   * an error occurs.
+   *
+   * @param buffers One or more data buffers to be sent to the remote endpoint.
+   *
+   * @param destination The remote endpoint to which the data will be sent.
+   *
+   * @param flags Flags specifying how the send call is to be made.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   *
+   * @returns The number of bytes sent.
+   */
+  template <typename ConstBufferSequence>
+  std::size_t send_to(const ConstBufferSequence& buffers,
+      const endpoint_type& destination, socket_base::message_flags flags,
+      asio::error_code& ec)
+  {
+    return this->impl_.get_service().send_to(this->impl_.get_implementation(),
+        buffers, destination, flags, ec);
+  }
+
+  /// Start an asynchronous send.
+  /**
+   * This function is used to asynchronously send raw data to the specified
+   * remote endpoint. The function call always returns immediately.
+   *
+   * @param buffers One or more data buffers to be sent to the remote endpoint.
+   * Although the buffers object may be copied as necessary, ownership of the
+   * underlying memory blocks is retained by the caller, which must guarantee
+   * that they remain valid until the handler is called.
+   *
+   * @param destination The remote endpoint to which the data will be sent.
+   * Copies will be made of the endpoint as required.
+   *
+   * @param handler The handler to be called when the send operation completes.
+   * Copies will be made of the handler as required. The function signature of
+   * the handler must be:
+   * @code void handler(
+   *   const asio::error_code& error, // Result of operation.
+   *   std::size_t bytes_transferred           // Number of bytes sent.
+   * ); @endcode
+   * Regardless of whether the asynchronous operation completes immediately or
+   * not, the handler will not be invoked from within this function. On
+   * immediate completion, invocation of the handler will be performed in a
+   * manner equivalent to using asio::post().
+   *
+   * @par Example
+   * To send a single data buffer use the @ref buffer function as follows:
+   * @code
+   * asio::ip::udp::endpoint destination(
+   *     asio::ip::address::from_string("1.2.3.4"), 12345);
+   * socket.async_send_to(
+   *     asio::buffer(data, size), destination, handler);
+   * @endcode
+   * See the @ref buffer documentation for information on sending multiple
+   * buffers in one go, and how to use it with arrays, boost::array or
+   * std::vector.
+   */
+  template <typename ConstBufferSequence,
+      ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+        std::size_t)) WriteHandler
+          ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
+  ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,
+      void (asio::error_code, std::size_t))
+  async_send_to(const ConstBufferSequence& buffers,
+      const endpoint_type& destination,
+      ASIO_MOVE_ARG(WriteHandler) handler
+        ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
+  {
+    return async_initiate<WriteHandler,
+      void (asio::error_code, std::size_t)>(
+        initiate_async_send_to(this), handler, buffers,
+        destination, socket_base::message_flags(0));
+  }
+
+  /// Start an asynchronous send.
+  /**
+   * This function is used to asynchronously send raw data to the specified
+   * remote endpoint. The function call always returns immediately.
+   *
+   * @param buffers One or more data buffers to be sent to the remote endpoint.
+   * Although the buffers object may be copied as necessary, ownership of the
+   * underlying memory blocks is retained by the caller, which must guarantee
+   * that they remain valid until the handler is called.
+   *
+   * @param flags Flags specifying how the send call is to be made.
+   *
+   * @param destination The remote endpoint to which the data will be sent.
+   * Copies will be made of the endpoint as required.
+   *
+   * @param handler The handler to be called when the send operation completes.
+   * Copies will be made of the handler as required. The function signature of
+   * the handler must be:
+   * @code void handler(
+   *   const asio::error_code& error, // Result of operation.
+   *   std::size_t bytes_transferred           // Number of bytes sent.
+   * ); @endcode
+   * Regardless of whether the asynchronous operation completes immediately or
+   * not, the handler will not be invoked from within this function. On
+   * immediate completion, invocation of the handler will be performed in a
+   * manner equivalent to using asio::post().
+   */
+  template <typename ConstBufferSequence,
+      ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+        std::size_t)) WriteHandler
+          ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
+  ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,
+      void (asio::error_code, std::size_t))
+  async_send_to(const ConstBufferSequence& buffers,
+      const endpoint_type& destination, socket_base::message_flags flags,
+      ASIO_MOVE_ARG(WriteHandler) handler
+        ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
+  {
+    return async_initiate<WriteHandler,
+      void (asio::error_code, std::size_t)>(
+        initiate_async_send_to(this), handler, buffers, destination, flags);
+  }
+
+  /// Receive some data on a connected socket.
+  /**
+   * This function is used to receive data on the raw socket. The function
+   * call will block until data has been received successfully or an error
+   * occurs.
+   *
+   * @param buffers One or more buffers into which the data will be received.
+   *
+   * @returns The number of bytes received.
+   *
+   * @throws asio::system_error Thrown on failure.
+   *
+   * @note The receive operation can only be used with a connected socket. Use
+   * the receive_from function to receive data on an unconnected raw
+   * socket.
+   *
+   * @par Example
+   * To receive into a single data buffer use the @ref buffer function as
+   * follows:
+   * @code socket.receive(asio::buffer(data, size)); @endcode
+   * See the @ref buffer documentation for information on receiving into
+   * multiple buffers in one go, and how to use it with arrays, boost::array or
+   * std::vector.
+   */
+  template <typename MutableBufferSequence>
+  std::size_t receive(const MutableBufferSequence& buffers)
+  {
+    asio::error_code ec;
+    std::size_t s = this->impl_.get_service().receive(
+        this->impl_.get_implementation(), buffers, 0, ec);
+    asio::detail::throw_error(ec, "receive");
+    return s;
+  }
+
+  /// Receive some data on a connected socket.
+  /**
+   * This function is used to receive data on the raw socket. The function
+   * call will block until data has been received successfully or an error
+   * occurs.
+   *
+   * @param buffers One or more buffers into which the data will be received.
+   *
+   * @param flags Flags specifying how the receive call is to be made.
+   *
+   * @returns The number of bytes received.
+   *
+   * @throws asio::system_error Thrown on failure.
+   *
+   * @note The receive operation can only be used with a connected socket. Use
+   * the receive_from function to receive data on an unconnected raw
+   * socket.
+   */
+  template <typename MutableBufferSequence>
+  std::size_t receive(const MutableBufferSequence& buffers,
+      socket_base::message_flags flags)
+  {
+    asio::error_code ec;
+    std::size_t s = this->impl_.get_service().receive(
+        this->impl_.get_implementation(), buffers, flags, ec);
+    asio::detail::throw_error(ec, "receive");
+    return s;
+  }
+
+  /// Receive some data on a connected socket.
+  /**
+   * This function is used to receive data on the raw socket. The function
+   * call will block until data has been received successfully or an error
+   * occurs.
+   *
+   * @param buffers One or more buffers into which the data will be received.
+   *
+   * @param flags Flags specifying how the receive call is to be made.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   *
+   * @returns The number of bytes received.
+   *
+   * @note The receive operation can only be used with a connected socket. Use
+   * the receive_from function to receive data on an unconnected raw
+   * socket.
+   */
+  template <typename MutableBufferSequence>
+  std::size_t receive(const MutableBufferSequence& buffers,
+      socket_base::message_flags flags, asio::error_code& ec)
+  {
+    return this->impl_.get_service().receive(
+        this->impl_.get_implementation(), buffers, flags, ec);
+  }
+
+  /// Start an asynchronous receive on a connected socket.
+  /**
+   * This function is used to asynchronously receive data from the raw
+   * socket. The function call always returns immediately.
+   *
+   * @param buffers One or more buffers into which the data will be received.
+   * Although the buffers object may be copied as necessary, ownership of the
+   * underlying memory blocks is retained by the caller, which must guarantee
+   * that they remain valid until the handler is called.
+   *
+   * @param handler The handler to be called when the receive operation
+   * completes. Copies will be made of the handler as required. The function
+   * signature of the handler must be:
+   * @code void handler(
+   *   const asio::error_code& error, // Result of operation.
+   *   std::size_t bytes_transferred           // Number of bytes received.
+   * ); @endcode
+   * Regardless of whether the asynchronous operation completes immediately or
+   * not, the handler will not be invoked from within this function. On
+   * immediate completion, invocation of the handler will be performed in a
+   * manner equivalent to using asio::post().
+   *
+   * @note The async_receive operation can only be used with a connected socket.
+   * Use the async_receive_from function to receive data on an unconnected
+   * raw socket.
+   *
+   * @par Example
+   * To receive into a single data buffer use the @ref buffer function as
+   * follows:
+   * @code
+   * socket.async_receive(asio::buffer(data, size), handler);
+   * @endcode
+   * See the @ref buffer documentation for information on receiving into
+   * multiple buffers in one go, and how to use it with arrays, boost::array or
+   * std::vector.
+   */
+  template <typename MutableBufferSequence,
+      ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+        std::size_t)) ReadHandler
+          ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
+  ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,
+      void (asio::error_code, std::size_t))
+  async_receive(const MutableBufferSequence& buffers,
+      ASIO_MOVE_ARG(ReadHandler) handler
+        ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
+  {
+    return async_initiate<ReadHandler,
+      void (asio::error_code, std::size_t)>(
+        initiate_async_receive(this), handler,
+        buffers, socket_base::message_flags(0));
+  }
+
+  /// Start an asynchronous receive on a connected socket.
+  /**
+   * This function is used to asynchronously receive data from the raw
+   * socket. The function call always returns immediately.
+   *
+   * @param buffers One or more buffers into which the data will be received.
+   * Although the buffers object may be copied as necessary, ownership of the
+   * underlying memory blocks is retained by the caller, which must guarantee
+   * that they remain valid until the handler is called.
+   *
+   * @param flags Flags specifying how the receive call is to be made.
+   *
+   * @param handler The handler to be called when the receive operation
+   * completes. Copies will be made of the handler as required. The function
+   * signature of the handler must be:
+   * @code void handler(
+   *   const asio::error_code& error, // Result of operation.
+   *   std::size_t bytes_transferred           // Number of bytes received.
+   * ); @endcode
+   * Regardless of whether the asynchronous operation completes immediately or
+   * not, the handler will not be invoked from within this function. On
+   * immediate completion, invocation of the handler will be performed in a
+   * manner equivalent to using asio::post().
+   *
+   * @note The async_receive operation can only be used with a connected socket.
+   * Use the async_receive_from function to receive data on an unconnected
+   * raw socket.
+   */
+  template <typename MutableBufferSequence,
+      ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+        std::size_t)) ReadHandler
+          ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
+  ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,
+      void (asio::error_code, std::size_t))
+  async_receive(const MutableBufferSequence& buffers,
+      socket_base::message_flags flags,
+      ASIO_MOVE_ARG(ReadHandler) handler
+        ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
+  {
+    return async_initiate<ReadHandler,
+      void (asio::error_code, std::size_t)>(
+        initiate_async_receive(this), handler, buffers, flags);
+  }
+
+  /// Receive raw data with the endpoint of the sender.
+  /**
+   * This function is used to receive raw data. The function call will block
+   * until data has been received successfully or an error occurs.
+   *
+   * @param buffers One or more buffers into which the data will be received.
+   *
+   * @param sender_endpoint An endpoint object that receives the endpoint of
+   * the remote sender of the data.
+   *
+   * @returns The number of bytes received.
+   *
+   * @throws asio::system_error Thrown on failure.
+   *
+   * @par Example
+   * To receive into a single data buffer use the @ref buffer function as
+   * follows:
+   * @code
+   * asio::ip::udp::endpoint sender_endpoint;
+   * socket.receive_from(
+   *     asio::buffer(data, size), sender_endpoint);
+   * @endcode
+   * See the @ref buffer documentation for information on receiving into
+   * multiple buffers in one go, and how to use it with arrays, boost::array or
+   * std::vector.
+   */
+  template <typename MutableBufferSequence>
+  std::size_t receive_from(const MutableBufferSequence& buffers,
+      endpoint_type& sender_endpoint)
+  {
+    asio::error_code ec;
+    std::size_t s = this->impl_.get_service().receive_from(
+        this->impl_.get_implementation(), buffers, sender_endpoint, 0, ec);
+    asio::detail::throw_error(ec, "receive_from");
+    return s;
+  }
+  
+  /// Receive raw data with the endpoint of the sender.
+  /**
+   * This function is used to receive raw data. The function call will block
+   * until data has been received successfully or an error occurs.
+   *
+   * @param buffers One or more buffers into which the data will be received.
+   *
+   * @param sender_endpoint An endpoint object that receives the endpoint of
+   * the remote sender of the data.
+   *
+   * @param flags Flags specifying how the receive call is to be made.
+   *
+   * @returns The number of bytes received.
+   *
+   * @throws asio::system_error Thrown on failure.
+   */
+  template <typename MutableBufferSequence>
+  std::size_t receive_from(const MutableBufferSequence& buffers,
+      endpoint_type& sender_endpoint, socket_base::message_flags flags)
+  {
+    asio::error_code ec;
+    std::size_t s = this->impl_.get_service().receive_from(
+        this->impl_.get_implementation(), buffers, sender_endpoint, flags, ec);
+    asio::detail::throw_error(ec, "receive_from");
+    return s;
+  }
+  
+  /// Receive raw data with the endpoint of the sender.
+  /**
+   * This function is used to receive raw data. The function call will block
+   * until data has been received successfully or an error occurs.
+   *
+   * @param buffers One or more buffers into which the data will be received.
+   *
+   * @param sender_endpoint An endpoint object that receives the endpoint of
+   * the remote sender of the data.
+   *
+   * @param flags Flags specifying how the receive call is to be made.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   *
+   * @returns The number of bytes received.
+   */
+  template <typename MutableBufferSequence>
+  std::size_t receive_from(const MutableBufferSequence& buffers,
+      endpoint_type& sender_endpoint, socket_base::message_flags flags,
+      asio::error_code& ec)
+  {
+    return this->impl_.get_service().receive_from(
+        this->impl_.get_implementation(), buffers, sender_endpoint, flags, ec);
+  }
+
+  /// Start an asynchronous receive.
+  /**
+   * This function is used to asynchronously receive raw data. The function
+   * call always returns immediately.
+   *
+   * @param buffers One or more buffers into which the data will be received.
+   * Although the buffers object may be copied as necessary, ownership of the
+   * underlying memory blocks is retained by the caller, which must guarantee
+   * that they remain valid until the handler is called.
+   *
+   * @param sender_endpoint An endpoint object that receives the endpoint of
+   * the remote sender of the data. Ownership of the sender_endpoint object
+   * is retained by the caller, which must guarantee that it is valid until the
+   * handler is called.
+   *
+   * @param handler The handler to be called when the receive operation
+   * completes. Copies will be made of the handler as required. The function
+   * signature of the handler must be:
+   * @code void handler(
+   *   const asio::error_code& error, // Result of operation.
+   *   std::size_t bytes_transferred           // Number of bytes received.
+   * ); @endcode
+   * Regardless of whether the asynchronous operation completes immediately or
+   * not, the handler will not be invoked from within this function. On
+   * immediate completion, invocation of the handler will be performed in a
+   * manner equivalent to using asio::post().
+   *
+   * @par Example
+   * To receive into a single data buffer use the @ref buffer function as
+   * follows:
+   * @code socket.async_receive_from(
+   *     asio::buffer(data, size), 0, sender_endpoint, handler); @endcode
+   * See the @ref buffer documentation for information on receiving into
+   * multiple buffers in one go, and how to use it with arrays, boost::array or
+   * std::vector.
+   */
+  template <typename MutableBufferSequence,
+      ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+        std::size_t)) ReadHandler
+          ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
+  ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,
+      void (asio::error_code, std::size_t))
+  async_receive_from(const MutableBufferSequence& buffers,
+      endpoint_type& sender_endpoint,
+      ASIO_MOVE_ARG(ReadHandler) handler
+        ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
+  {
+    return async_initiate<ReadHandler,
+      void (asio::error_code, std::size_t)>(
+        initiate_async_receive_from(this), handler, buffers,
+        &sender_endpoint, socket_base::message_flags(0));
+  }
+
+  /// Start an asynchronous receive.
+  /**
+   * This function is used to asynchronously receive raw data. The function
+   * call always returns immediately.
+   *
+   * @param buffers One or more buffers into which the data will be received.
+   * Although the buffers object may be copied as necessary, ownership of the
+   * underlying memory blocks is retained by the caller, which must guarantee
+   * that they remain valid until the handler is called.
+   *
+   * @param sender_endpoint An endpoint object that receives the endpoint of
+   * the remote sender of the data. Ownership of the sender_endpoint object
+   * is retained by the caller, which must guarantee that it is valid until the
+   * handler is called.
+   *
+   * @param flags Flags specifying how the receive call is to be made.
+   *
+   * @param handler The handler to be called when the receive operation
+   * completes. Copies will be made of the handler as required. The function
+   * signature of the handler must be:
+   * @code void handler(
+   *   const asio::error_code& error, // Result of operation.
+   *   std::size_t bytes_transferred           // Number of bytes received.
+   * ); @endcode
+   * Regardless of whether the asynchronous operation completes immediately or
+   * not, the handler will not be invoked from within this function. On
+   * immediate completion, invocation of the handler will be performed in a
+   * manner equivalent to using asio::post().
+   */
+  template <typename MutableBufferSequence,
+      ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+        std::size_t)) ReadHandler
+          ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
+  ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,
+      void (asio::error_code, std::size_t))
+  async_receive_from(const MutableBufferSequence& buffers,
+      endpoint_type& sender_endpoint, socket_base::message_flags flags,
+      ASIO_MOVE_ARG(ReadHandler) handler
+        ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
+  {
+    return async_initiate<ReadHandler,
+      void (asio::error_code, std::size_t)>(
+        initiate_async_receive_from(this), handler,
+        buffers, &sender_endpoint, flags);
+  }
+
+private:
+  // Disallow copying and assignment.
+  basic_raw_socket(const basic_raw_socket&) ASIO_DELETED;
+  basic_raw_socket& operator=(const basic_raw_socket&) ASIO_DELETED;
+
+  class initiate_async_send
+  {
+  public:
+    typedef Executor executor_type;
+
+    explicit initiate_async_send(basic_raw_socket* self)
+      : self_(self)
+    {
+    }
+
+    executor_type get_executor() const ASIO_NOEXCEPT
+    {
+      return self_->get_executor();
+    }
+
+    template <typename WriteHandler, typename ConstBufferSequence>
+    void operator()(ASIO_MOVE_ARG(WriteHandler) handler,
+        const ConstBufferSequence& buffers,
+        socket_base::message_flags flags) const
+    {
+      // If you get an error on the following line it means that your handler
+      // does not meet the documented type requirements for a WriteHandler.
+      ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check;
+
+      detail::non_const_lvalue<WriteHandler> handler2(handler);
+      self_->impl_.get_service().async_send(
+          self_->impl_.get_implementation(), buffers, flags,
+          handler2.value, self_->impl_.get_executor());
+    }
+
+  private:
+    basic_raw_socket* self_;
+  };
+
+  class initiate_async_send_to
+  {
+  public:
+    typedef Executor executor_type;
+
+    explicit initiate_async_send_to(basic_raw_socket* self)
+      : self_(self)
+    {
+    }
+
+    executor_type get_executor() const ASIO_NOEXCEPT
+    {
+      return self_->get_executor();
+    }
+
+    template <typename WriteHandler, typename ConstBufferSequence>
+    void operator()(ASIO_MOVE_ARG(WriteHandler) handler,
+        const ConstBufferSequence& buffers, const endpoint_type& destination,
+        socket_base::message_flags flags) const
+    {
+      // If you get an error on the following line it means that your handler
+      // does not meet the documented type requirements for a WriteHandler.
+      ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check;
+
+      detail::non_const_lvalue<WriteHandler> handler2(handler);
+      self_->impl_.get_service().async_send_to(
+          self_->impl_.get_implementation(), buffers, destination,
+          flags, handler2.value, self_->impl_.get_executor());
+    }
+
+  private:
+    basic_raw_socket* self_;
+  };
+
+  class initiate_async_receive
+  {
+  public:
+    typedef Executor executor_type;
+
+    explicit initiate_async_receive(basic_raw_socket* self)
+      : self_(self)
+    {
+    }
+
+    executor_type get_executor() const ASIO_NOEXCEPT
+    {
+      return self_->get_executor();
+    }
+
+    template <typename ReadHandler, typename MutableBufferSequence>
+    void operator()(ASIO_MOVE_ARG(ReadHandler) handler,
+        const MutableBufferSequence& buffers,
+        socket_base::message_flags flags) const
+    {
+      // If you get an error on the following line it means that your handler
+      // does not meet the documented type requirements for a ReadHandler.
+      ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
+
+      detail::non_const_lvalue<ReadHandler> handler2(handler);
+      self_->impl_.get_service().async_receive(
+          self_->impl_.get_implementation(), buffers, flags,
+          handler2.value, self_->impl_.get_executor());
+    }
+
+  private:
+    basic_raw_socket* self_;
+  };
+
+  class initiate_async_receive_from
+  {
+  public:
+    typedef Executor executor_type;
+
+    explicit initiate_async_receive_from(basic_raw_socket* self)
+      : self_(self)
+    {
+    }
+
+    executor_type get_executor() const ASIO_NOEXCEPT
+    {
+      return self_->get_executor();
+    }
+
+    template <typename ReadHandler, typename MutableBufferSequence>
+    void operator()(ASIO_MOVE_ARG(ReadHandler) handler,
+        const MutableBufferSequence& buffers, endpoint_type* sender_endpoint,
+        socket_base::message_flags flags) const
+    {
+      // If you get an error on the following line it means that your handler
+      // does not meet the documented type requirements for a ReadHandler.
+      ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
+
+      detail::non_const_lvalue<ReadHandler> handler2(handler);
+      self_->impl_.get_service().async_receive_from(
+          self_->impl_.get_implementation(), buffers, *sender_endpoint,
+          flags, handler2.value, self_->impl_.get_executor());
+    }
+
+  private:
+    basic_raw_socket* self_;
+  };
+};
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_BASIC_RAW_SOCKET_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/basic_seq_packet_socket.hpp b/link/modules/asio-standalone/asio/include/asio/basic_seq_packet_socket.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/basic_seq_packet_socket.hpp
@@ -0,0 +1,761 @@
+//
+// basic_seq_packet_socket.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_BASIC_SEQ_PACKET_SOCKET_HPP
+#define ASIO_BASIC_SEQ_PACKET_SOCKET_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <cstddef>
+#include "asio/basic_socket.hpp"
+#include "asio/detail/handler_type_requirements.hpp"
+#include "asio/detail/throw_error.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+#if !defined(ASIO_BASIC_SEQ_PACKET_SOCKET_FWD_DECL)
+#define ASIO_BASIC_SEQ_PACKET_SOCKET_FWD_DECL
+
+// Forward declaration with defaulted arguments.
+template <typename Protocol, typename Executor = any_io_executor>
+class basic_seq_packet_socket;
+
+#endif // !defined(ASIO_BASIC_SEQ_PACKET_SOCKET_FWD_DECL)
+
+/// Provides sequenced packet socket functionality.
+/**
+ * The basic_seq_packet_socket class template provides asynchronous and blocking
+ * sequenced packet socket functionality.
+ *
+ * @par Thread Safety
+ * @e Distinct @e objects: Safe.@n
+ * @e Shared @e objects: Unsafe.
+ */
+template <typename Protocol, typename Executor>
+class basic_seq_packet_socket
+  : public basic_socket<Protocol, Executor>
+{
+public:
+  /// The type of the executor associated with the object.
+  typedef Executor executor_type;
+
+  /// Rebinds the socket type to another executor.
+  template <typename Executor1>
+  struct rebind_executor
+  {
+    /// The socket type when rebound to the specified executor.
+    typedef basic_seq_packet_socket<Protocol, Executor1> other;
+  };
+
+  /// The native representation of a socket.
+#if defined(GENERATING_DOCUMENTATION)
+  typedef implementation_defined native_handle_type;
+#else
+  typedef typename basic_socket<Protocol,
+    Executor>::native_handle_type native_handle_type;
+#endif
+
+  /// The protocol type.
+  typedef Protocol protocol_type;
+
+  /// The endpoint type.
+  typedef typename Protocol::endpoint endpoint_type;
+
+  /// Construct a basic_seq_packet_socket without opening it.
+  /**
+   * This constructor creates a sequenced packet socket without opening it. The
+   * socket needs to be opened and then connected or accepted before data can
+   * be sent or received on it.
+   *
+   * @param ex The I/O executor that the socket will use, by default, to
+   * dispatch handlers for any asynchronous operations performed on the socket.
+   */
+  explicit basic_seq_packet_socket(const executor_type& ex)
+    : basic_socket<Protocol, Executor>(ex)
+  {
+  }
+
+  /// Construct a basic_seq_packet_socket without opening it.
+  /**
+   * This constructor creates a sequenced packet socket without opening it. The
+   * socket needs to be opened and then connected or accepted before data can
+   * be sent or received on it.
+   *
+   * @param context An execution context which provides the I/O executor that
+   * the socket will use, by default, to dispatch handlers for any asynchronous
+   * operations performed on the socket.
+   */
+  template <typename ExecutionContext>
+  explicit basic_seq_packet_socket(ExecutionContext& context,
+      typename enable_if<
+        is_convertible<ExecutionContext&, execution_context&>::value
+      >::type* = 0)
+    : basic_socket<Protocol, Executor>(context)
+  {
+  }
+
+  /// Construct and open a basic_seq_packet_socket.
+  /**
+   * This constructor creates and opens a sequenced_packet socket. The socket
+   * needs to be connected or accepted before data can be sent or received on
+   * it.
+   *
+   * @param ex The I/O executor that the socket will use, by default, to
+   * dispatch handlers for any asynchronous operations performed on the socket.
+   *
+   * @param protocol An object specifying protocol parameters to be used.
+   *
+   * @throws asio::system_error Thrown on failure.
+   */
+  basic_seq_packet_socket(const executor_type& ex,
+      const protocol_type& protocol)
+    : basic_socket<Protocol, Executor>(ex, protocol)
+  {
+  }
+
+  /// Construct and open a basic_seq_packet_socket.
+  /**
+   * This constructor creates and opens a sequenced_packet socket. The socket
+   * needs to be connected or accepted before data can be sent or received on
+   * it.
+   *
+   * @param context An execution context which provides the I/O executor that
+   * the socket will use, by default, to dispatch handlers for any asynchronous
+   * operations performed on the socket.
+   *
+   * @param protocol An object specifying protocol parameters to be used.
+   *
+   * @throws asio::system_error Thrown on failure.
+   */
+  template <typename ExecutionContext>
+  basic_seq_packet_socket(ExecutionContext& context,
+      const protocol_type& protocol,
+      typename enable_if<
+        is_convertible<ExecutionContext&, execution_context&>::value
+      >::type* = 0)
+    : basic_socket<Protocol, Executor>(context, protocol)
+  {
+  }
+
+  /// Construct a basic_seq_packet_socket, opening it and binding it to the
+  /// given local endpoint.
+  /**
+   * This constructor creates a sequenced packet socket and automatically opens
+   * it bound to the specified endpoint on the local machine. The protocol used
+   * is the protocol associated with the given endpoint.
+   *
+   * @param ex The I/O executor that the socket will use, by default, to
+   * dispatch handlers for any asynchronous operations performed on the socket.
+   *
+   * @param endpoint An endpoint on the local machine to which the sequenced
+   * packet socket will be bound.
+   *
+   * @throws asio::system_error Thrown on failure.
+   */
+  basic_seq_packet_socket(const executor_type& ex,
+      const endpoint_type& endpoint)
+    : basic_socket<Protocol, Executor>(ex, endpoint)
+  {
+  }
+
+  /// Construct a basic_seq_packet_socket, opening it and binding it to the
+  /// given local endpoint.
+  /**
+   * This constructor creates a sequenced packet socket and automatically opens
+   * it bound to the specified endpoint on the local machine. The protocol used
+   * is the protocol associated with the given endpoint.
+   *
+   * @param context An execution context which provides the I/O executor that
+   * the socket will use, by default, to dispatch handlers for any asynchronous
+   * operations performed on the socket.
+   *
+   * @param endpoint An endpoint on the local machine to which the sequenced
+   * packet socket will be bound.
+   *
+   * @throws asio::system_error Thrown on failure.
+   */
+  template <typename ExecutionContext>
+  basic_seq_packet_socket(ExecutionContext& context,
+      const endpoint_type& endpoint,
+      typename enable_if<
+        is_convertible<ExecutionContext&, execution_context&>::value
+      >::type* = 0)
+    : basic_socket<Protocol, Executor>(context, endpoint)
+  {
+  }
+
+  /// Construct a basic_seq_packet_socket on an existing native socket.
+  /**
+   * This constructor creates a sequenced packet socket object to hold an
+   * existing native socket.
+   *
+   * @param ex The I/O executor that the socket will use, by default, to
+   * dispatch handlers for any asynchronous operations performed on the socket.
+   *
+   * @param protocol An object specifying protocol parameters to be used.
+   *
+   * @param native_socket The new underlying socket implementation.
+   *
+   * @throws asio::system_error Thrown on failure.
+   */
+  basic_seq_packet_socket(const executor_type& ex,
+      const protocol_type& protocol, const native_handle_type& native_socket)
+    : basic_socket<Protocol, Executor>(ex, protocol, native_socket)
+  {
+  }
+
+  /// Construct a basic_seq_packet_socket on an existing native socket.
+  /**
+   * This constructor creates a sequenced packet socket object to hold an
+   * existing native socket.
+   *
+   * @param context An execution context which provides the I/O executor that
+   * the socket will use, by default, to dispatch handlers for any asynchronous
+   * operations performed on the socket.
+   *
+   * @param protocol An object specifying protocol parameters to be used.
+   *
+   * @param native_socket The new underlying socket implementation.
+   *
+   * @throws asio::system_error Thrown on failure.
+   */
+  template <typename ExecutionContext>
+  basic_seq_packet_socket(ExecutionContext& context,
+      const protocol_type& protocol, const native_handle_type& native_socket,
+      typename enable_if<
+        is_convertible<ExecutionContext&, execution_context&>::value
+      >::type* = 0)
+    : basic_socket<Protocol, Executor>(context, protocol, native_socket)
+  {
+  }
+
+#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+  /// Move-construct a basic_seq_packet_socket from another.
+  /**
+   * This constructor moves a sequenced packet socket from one object to
+   * another.
+   *
+   * @param other The other basic_seq_packet_socket object from which the move
+   * will occur.
+   *
+   * @note Following the move, the moved-from object is in the same state as if
+   * constructed using the @c basic_seq_packet_socket(const executor_type&)
+   * constructor.
+   */
+  basic_seq_packet_socket(basic_seq_packet_socket&& other) ASIO_NOEXCEPT
+    : basic_socket<Protocol, Executor>(std::move(other))
+  {
+  }
+
+  /// Move-assign a basic_seq_packet_socket from another.
+  /**
+   * This assignment operator moves a sequenced packet socket from one object to
+   * another.
+   *
+   * @param other The other basic_seq_packet_socket object from which the move
+   * will occur.
+   *
+   * @note Following the move, the moved-from object is in the same state as if
+   * constructed using the @c basic_seq_packet_socket(const executor_type&)
+   * constructor.
+   */
+  basic_seq_packet_socket& operator=(basic_seq_packet_socket&& other)
+  {
+    basic_socket<Protocol, Executor>::operator=(std::move(other));
+    return *this;
+  }
+
+  /// Move-construct a basic_seq_packet_socket from a socket of another protocol
+  /// type.
+  /**
+   * This constructor moves a sequenced packet socket from one object to
+   * another.
+   *
+   * @param other The other basic_seq_packet_socket object from which the move
+   * will occur.
+   *
+   * @note Following the move, the moved-from object is in the same state as if
+   * constructed using the @c basic_seq_packet_socket(const executor_type&)
+   * constructor.
+   */
+  template <typename Protocol1, typename Executor1>
+  basic_seq_packet_socket(basic_seq_packet_socket<Protocol1, Executor1>&& other,
+      typename enable_if<
+        is_convertible<Protocol1, Protocol>::value
+          && is_convertible<Executor1, Executor>::value
+      >::type* = 0)
+    : basic_socket<Protocol, Executor>(std::move(other))
+  {
+  }
+
+  /// Move-assign a basic_seq_packet_socket from a socket of another protocol
+  /// type.
+  /**
+   * This assignment operator moves a sequenced packet socket from one object to
+   * another.
+   *
+   * @param other The other basic_seq_packet_socket object from which the move
+   * will occur.
+   *
+   * @note Following the move, the moved-from object is in the same state as if
+   * constructed using the @c basic_seq_packet_socket(const executor_type&)
+   * constructor.
+   */
+  template <typename Protocol1, typename Executor1>
+  typename enable_if<
+    is_convertible<Protocol1, Protocol>::value
+      && is_convertible<Executor1, Executor>::value,
+    basic_seq_packet_socket&
+  >::type operator=(basic_seq_packet_socket<Protocol1, Executor1>&& other)
+  {
+    basic_socket<Protocol, Executor>::operator=(std::move(other));
+    return *this;
+  }
+#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+
+  /// Destroys the socket.
+  /**
+   * This function destroys the socket, cancelling any outstanding asynchronous
+   * operations associated with the socket as if by calling @c cancel.
+   */
+  ~basic_seq_packet_socket()
+  {
+  }
+
+  /// Send some data on the socket.
+  /**
+   * This function is used to send data on the sequenced packet socket. The
+   * function call will block until the data has been sent successfully, or an
+   * until error occurs.
+   *
+   * @param buffers One or more data buffers to be sent on the socket.
+   *
+   * @param flags Flags specifying how the send call is to be made.
+   *
+   * @returns The number of bytes sent.
+   *
+   * @throws asio::system_error Thrown on failure.
+   *
+   * @par Example
+   * To send a single data buffer use the @ref buffer function as follows:
+   * @code
+   * socket.send(asio::buffer(data, size), 0);
+   * @endcode
+   * See the @ref buffer documentation for information on sending multiple
+   * buffers in one go, and how to use it with arrays, boost::array or
+   * std::vector.
+   */
+  template <typename ConstBufferSequence>
+  std::size_t send(const ConstBufferSequence& buffers,
+      socket_base::message_flags flags)
+  {
+    asio::error_code ec;
+    std::size_t s = this->impl_.get_service().send(
+        this->impl_.get_implementation(), buffers, flags, ec);
+    asio::detail::throw_error(ec, "send");
+    return s;
+  }
+
+  /// Send some data on the socket.
+  /**
+   * This function is used to send data on the sequenced packet socket. The
+   * function call will block the data has been sent successfully, or an until
+   * error occurs.
+   *
+   * @param buffers One or more data buffers to be sent on the socket.
+   *
+   * @param flags Flags specifying how the send call is to be made.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   *
+   * @returns The number of bytes sent. Returns 0 if an error occurred.
+   *
+   * @note The send operation may not transmit all of the data to the peer.
+   * Consider using the @ref write function if you need to ensure that all data
+   * is written before the blocking operation completes.
+   */
+  template <typename ConstBufferSequence>
+  std::size_t send(const ConstBufferSequence& buffers,
+      socket_base::message_flags flags, asio::error_code& ec)
+  {
+    return this->impl_.get_service().send(
+        this->impl_.get_implementation(), buffers, flags, ec);
+  }
+
+  /// Start an asynchronous send.
+  /**
+   * This function is used to asynchronously send data on the sequenced packet
+   * socket. The function call always returns immediately.
+   *
+   * @param buffers One or more data buffers to be sent on the socket. Although
+   * the buffers object may be copied as necessary, ownership of the underlying
+   * memory blocks is retained by the caller, which must guarantee that they
+   * remain valid until the handler is called.
+   *
+   * @param flags Flags specifying how the send call is to be made.
+   *
+   * @param handler The handler to be called when the send operation completes.
+   * Copies will be made of the handler as required. The function signature of
+   * the handler must be:
+   * @code void handler(
+   *   const asio::error_code& error, // Result of operation.
+   *   std::size_t bytes_transferred           // Number of bytes sent.
+   * ); @endcode
+   * Regardless of whether the asynchronous operation completes immediately or
+   * not, the handler will not be invoked from within this function. On
+   * immediate completion, invocation of the handler will be performed in a
+   * manner equivalent to using asio::post().
+   *
+   * @par Example
+   * To send a single data buffer use the @ref buffer function as follows:
+   * @code
+   * socket.async_send(asio::buffer(data, size), 0, handler);
+   * @endcode
+   * See the @ref buffer documentation for information on sending multiple
+   * buffers in one go, and how to use it with arrays, boost::array or
+   * std::vector.
+   */
+  template <typename ConstBufferSequence,
+      ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+        std::size_t)) WriteHandler
+          ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
+  ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,
+      void (asio::error_code, std::size_t))
+  async_send(const ConstBufferSequence& buffers,
+      socket_base::message_flags flags,
+      ASIO_MOVE_ARG(WriteHandler) handler
+        ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
+  {
+    return async_initiate<WriteHandler,
+      void (asio::error_code, std::size_t)>(
+        initiate_async_send(this), handler, buffers, flags);
+  }
+
+  /// Receive some data on the socket.
+  /**
+   * This function is used to receive data on the sequenced packet socket. The
+   * function call will block until data has been received successfully, or
+   * until an error occurs.
+   *
+   * @param buffers One or more buffers into which the data will be received.
+   *
+   * @param out_flags After the receive call completes, contains flags
+   * associated with the received data. For example, if the
+   * socket_base::message_end_of_record bit is set then the received data marks
+   * the end of a record.
+   *
+   * @returns The number of bytes received.
+   *
+   * @throws asio::system_error Thrown on failure. An error code of
+   * asio::error::eof indicates that the connection was closed by the
+   * peer.
+   *
+   * @par Example
+   * To receive into a single data buffer use the @ref buffer function as
+   * follows:
+   * @code
+   * socket.receive(asio::buffer(data, size), out_flags);
+   * @endcode
+   * See the @ref buffer documentation for information on receiving into
+   * multiple buffers in one go, and how to use it with arrays, boost::array or
+   * std::vector.
+   */
+  template <typename MutableBufferSequence>
+  std::size_t receive(const MutableBufferSequence& buffers,
+      socket_base::message_flags& out_flags)
+  {
+    asio::error_code ec;
+    std::size_t s = this->impl_.get_service().receive_with_flags(
+        this->impl_.get_implementation(), buffers, 0, out_flags, ec);
+    asio::detail::throw_error(ec, "receive");
+    return s;
+  }
+
+  /// Receive some data on the socket.
+  /**
+   * This function is used to receive data on the sequenced packet socket. The
+   * function call will block until data has been received successfully, or
+   * until an error occurs.
+   *
+   * @param buffers One or more buffers into which the data will be received.
+   *
+   * @param in_flags Flags specifying how the receive call is to be made.
+   *
+   * @param out_flags After the receive call completes, contains flags
+   * associated with the received data. For example, if the
+   * socket_base::message_end_of_record bit is set then the received data marks
+   * the end of a record.
+   *
+   * @returns The number of bytes received.
+   *
+   * @throws asio::system_error Thrown on failure. An error code of
+   * asio::error::eof indicates that the connection was closed by the
+   * peer.
+   *
+   * @note The receive operation may not receive all of the requested number of
+   * bytes. Consider using the @ref read function if you need to ensure that the
+   * requested amount of data is read before the blocking operation completes.
+   *
+   * @par Example
+   * To receive into a single data buffer use the @ref buffer function as
+   * follows:
+   * @code
+   * socket.receive(asio::buffer(data, size), 0, out_flags);
+   * @endcode
+   * See the @ref buffer documentation for information on receiving into
+   * multiple buffers in one go, and how to use it with arrays, boost::array or
+   * std::vector.
+   */
+  template <typename MutableBufferSequence>
+  std::size_t receive(const MutableBufferSequence& buffers,
+      socket_base::message_flags in_flags,
+      socket_base::message_flags& out_flags)
+  {
+    asio::error_code ec;
+    std::size_t s = this->impl_.get_service().receive_with_flags(
+        this->impl_.get_implementation(), buffers, in_flags, out_flags, ec);
+    asio::detail::throw_error(ec, "receive");
+    return s;
+  }
+
+  /// Receive some data on a connected socket.
+  /**
+   * This function is used to receive data on the sequenced packet socket. The
+   * function call will block until data has been received successfully, or
+   * until an error occurs.
+   *
+   * @param buffers One or more buffers into which the data will be received.
+   *
+   * @param in_flags Flags specifying how the receive call is to be made.
+   *
+   * @param out_flags After the receive call completes, contains flags
+   * associated with the received data. For example, if the
+   * socket_base::message_end_of_record bit is set then the received data marks
+   * the end of a record.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   *
+   * @returns The number of bytes received. Returns 0 if an error occurred.
+   *
+   * @note The receive operation may not receive all of the requested number of
+   * bytes. Consider using the @ref read function if you need to ensure that the
+   * requested amount of data is read before the blocking operation completes.
+   */
+  template <typename MutableBufferSequence>
+  std::size_t receive(const MutableBufferSequence& buffers,
+      socket_base::message_flags in_flags,
+      socket_base::message_flags& out_flags, asio::error_code& ec)
+  {
+    return this->impl_.get_service().receive_with_flags(
+        this->impl_.get_implementation(), buffers, in_flags, out_flags, ec);
+  }
+
+  /// Start an asynchronous receive.
+  /**
+   * This function is used to asynchronously receive data from the sequenced
+   * packet socket. The function call always returns immediately.
+   *
+   * @param buffers One or more buffers into which the data will be received.
+   * Although the buffers object may be copied as necessary, ownership of the
+   * underlying memory blocks is retained by the caller, which must guarantee
+   * that they remain valid until the handler is called.
+   *
+   * @param out_flags Once the asynchronous operation completes, contains flags
+   * associated with the received data. For example, if the
+   * socket_base::message_end_of_record bit is set then the received data marks
+   * the end of a record. The caller must guarantee that the referenced
+   * variable remains valid until the handler is called.
+   *
+   * @param handler The handler to be called when the receive operation
+   * completes. Copies will be made of the handler as required. The function
+   * signature of the handler must be:
+   * @code void handler(
+   *   const asio::error_code& error, // Result of operation.
+   *   std::size_t bytes_transferred           // Number of bytes received.
+   * ); @endcode
+   * Regardless of whether the asynchronous operation completes immediately or
+   * not, the handler will not be invoked from within this function. On
+   * immediate completion, invocation of the handler will be performed in a
+   * manner equivalent to using asio::post().
+   *
+   * @par Example
+   * To receive into a single data buffer use the @ref buffer function as
+   * follows:
+   * @code
+   * socket.async_receive(asio::buffer(data, size), out_flags, handler);
+   * @endcode
+   * See the @ref buffer documentation for information on receiving into
+   * multiple buffers in one go, and how to use it with arrays, boost::array or
+   * std::vector.
+   */
+  template <typename MutableBufferSequence,
+      ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+        std::size_t)) ReadHandler
+          ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
+  ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,
+      void (asio::error_code, std::size_t))
+  async_receive(const MutableBufferSequence& buffers,
+      socket_base::message_flags& out_flags,
+      ASIO_MOVE_ARG(ReadHandler) handler
+        ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
+  {
+    return async_initiate<ReadHandler,
+      void (asio::error_code, std::size_t)>(
+        initiate_async_receive_with_flags(this), handler,
+        buffers, socket_base::message_flags(0), &out_flags);
+  }
+
+  /// Start an asynchronous receive.
+  /**
+   * This function is used to asynchronously receive data from the sequenced
+   * data socket. The function call always returns immediately.
+   *
+   * @param buffers One or more buffers into which the data will be received.
+   * Although the buffers object may be copied as necessary, ownership of the
+   * underlying memory blocks is retained by the caller, which must guarantee
+   * that they remain valid until the handler is called.
+   *
+   * @param in_flags Flags specifying how the receive call is to be made.
+   *
+   * @param out_flags Once the asynchronous operation completes, contains flags
+   * associated with the received data. For example, if the
+   * socket_base::message_end_of_record bit is set then the received data marks
+   * the end of a record. The caller must guarantee that the referenced
+   * variable remains valid until the handler is called.
+   *
+   * @param handler The handler to be called when the receive operation
+   * completes. Copies will be made of the handler as required. The function
+   * signature of the handler must be:
+   * @code void handler(
+   *   const asio::error_code& error, // Result of operation.
+   *   std::size_t bytes_transferred           // Number of bytes received.
+   * ); @endcode
+   * Regardless of whether the asynchronous operation completes immediately or
+   * not, the handler will not be invoked from within this function. On
+   * immediate completion, invocation of the handler will be performed in a
+   * manner equivalent to using asio::post().
+   *
+   * @par Example
+   * To receive into a single data buffer use the @ref buffer function as
+   * follows:
+   * @code
+   * socket.async_receive(
+   *     asio::buffer(data, size),
+   *     0, out_flags, handler);
+   * @endcode
+   * See the @ref buffer documentation for information on receiving into
+   * multiple buffers in one go, and how to use it with arrays, boost::array or
+   * std::vector.
+   */
+  template <typename MutableBufferSequence,
+      ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+        std::size_t)) ReadHandler
+          ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
+  ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,
+      void (asio::error_code, std::size_t))
+  async_receive(const MutableBufferSequence& buffers,
+      socket_base::message_flags in_flags,
+      socket_base::message_flags& out_flags,
+      ASIO_MOVE_ARG(ReadHandler) handler
+        ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
+  {
+    return async_initiate<ReadHandler,
+      void (asio::error_code, std::size_t)>(
+        initiate_async_receive_with_flags(this),
+        handler, buffers, in_flags, &out_flags);
+  }
+
+private:
+  // Disallow copying and assignment.
+  basic_seq_packet_socket(const basic_seq_packet_socket&) ASIO_DELETED;
+  basic_seq_packet_socket& operator=(
+      const basic_seq_packet_socket&) ASIO_DELETED;
+
+  class initiate_async_send
+  {
+  public:
+    typedef Executor executor_type;
+
+    explicit initiate_async_send(basic_seq_packet_socket* self)
+      : self_(self)
+    {
+    }
+
+    executor_type get_executor() const ASIO_NOEXCEPT
+    {
+      return self_->get_executor();
+    }
+
+    template <typename WriteHandler, typename ConstBufferSequence>
+    void operator()(ASIO_MOVE_ARG(WriteHandler) handler,
+        const ConstBufferSequence& buffers,
+        socket_base::message_flags flags) const
+    {
+      // If you get an error on the following line it means that your handler
+      // does not meet the documented type requirements for a WriteHandler.
+      ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check;
+
+      detail::non_const_lvalue<WriteHandler> handler2(handler);
+      self_->impl_.get_service().async_send(
+          self_->impl_.get_implementation(), buffers, flags,
+          handler2.value, self_->impl_.get_executor());
+    }
+
+  private:
+    basic_seq_packet_socket* self_;
+  };
+
+  class initiate_async_receive_with_flags
+  {
+  public:
+    typedef Executor executor_type;
+
+    explicit initiate_async_receive_with_flags(basic_seq_packet_socket* self)
+      : self_(self)
+    {
+    }
+
+    executor_type get_executor() const ASIO_NOEXCEPT
+    {
+      return self_->get_executor();
+    }
+
+    template <typename ReadHandler, typename MutableBufferSequence>
+    void operator()(ASIO_MOVE_ARG(ReadHandler) handler,
+        const MutableBufferSequence& buffers,
+        socket_base::message_flags in_flags,
+        socket_base::message_flags* out_flags) const
+    {
+      // If you get an error on the following line it means that your handler
+      // does not meet the documented type requirements for a ReadHandler.
+      ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
+
+      detail::non_const_lvalue<ReadHandler> handler2(handler);
+      self_->impl_.get_service().async_receive_with_flags(
+          self_->impl_.get_implementation(), buffers, in_flags,
+          *out_flags, handler2.value, self_->impl_.get_executor());
+    }
+
+  private:
+    basic_seq_packet_socket* self_;
+  };
+};
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_BASIC_SEQ_PACKET_SOCKET_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/basic_serial_port.hpp b/link/modules/asio-standalone/asio/include/asio/basic_serial_port.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/basic_serial_port.hpp
@@ -0,0 +1,907 @@
+//
+// basic_serial_port.hpp
+// ~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.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 ASIO_BASIC_SERIAL_PORT_HPP
+#define ASIO_BASIC_SERIAL_PORT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_SERIAL_PORT) \
+  || defined(GENERATING_DOCUMENTATION)
+
+#include <string>
+#include "asio/any_io_executor.hpp"
+#include "asio/async_result.hpp"
+#include "asio/detail/handler_type_requirements.hpp"
+#include "asio/detail/io_object_impl.hpp"
+#include "asio/detail/non_const_lvalue.hpp"
+#include "asio/detail/throw_error.hpp"
+#include "asio/detail/type_traits.hpp"
+#include "asio/error.hpp"
+#include "asio/execution_context.hpp"
+#include "asio/serial_port_base.hpp"
+#if defined(ASIO_HAS_IOCP)
+# include "asio/detail/win_iocp_serial_port_service.hpp"
+#else
+# include "asio/detail/reactive_serial_port_service.hpp"
+#endif
+
+#if defined(ASIO_HAS_MOVE)
+# include <utility>
+#endif // defined(ASIO_HAS_MOVE)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+/// Provides serial port functionality.
+/**
+ * The basic_serial_port class provides a wrapper over serial port
+ * functionality.
+ *
+ * @par Thread Safety
+ * @e Distinct @e objects: Safe.@n
+ * @e Shared @e objects: Unsafe.
+ */
+template <typename Executor = any_io_executor>
+class basic_serial_port
+  : public serial_port_base
+{
+public:
+  /// The type of the executor associated with the object.
+  typedef Executor executor_type;
+
+  /// Rebinds the serial port type to another executor.
+  template <typename Executor1>
+  struct rebind_executor
+  {
+    /// The serial port type when rebound to the specified executor.
+    typedef basic_serial_port<Executor1> other;
+  };
+
+  /// The native representation of a serial port.
+#if defined(GENERATING_DOCUMENTATION)
+  typedef implementation_defined native_handle_type;
+#elif defined(ASIO_HAS_IOCP)
+  typedef detail::win_iocp_serial_port_service::native_handle_type
+    native_handle_type;
+#else
+  typedef detail::reactive_serial_port_service::native_handle_type
+    native_handle_type;
+#endif
+
+  /// A basic_basic_serial_port is always the lowest layer.
+  typedef basic_serial_port lowest_layer_type;
+
+  /// Construct a basic_serial_port without opening it.
+  /**
+   * This constructor creates a serial port without opening it.
+   *
+   * @param ex The I/O executor that the serial port will use, by default, to
+   * dispatch handlers for any asynchronous operations performed on the
+   * serial port.
+   */
+  explicit basic_serial_port(const executor_type& ex)
+    : impl_(ex)
+  {
+  }
+
+  /// Construct a basic_serial_port without opening it.
+  /**
+   * This constructor creates a serial port without opening it.
+   *
+   * @param context An execution context which provides the I/O executor that
+   * the serial port will use, by default, to dispatch handlers for any
+   * asynchronous operations performed on the serial port.
+   */
+  template <typename ExecutionContext>
+  explicit basic_serial_port(ExecutionContext& context,
+      typename enable_if<
+        is_convertible<ExecutionContext&, execution_context&>::value,
+        basic_serial_port
+      >::type* = 0)
+    : impl_(context)
+  {
+  }
+
+  /// Construct and open a basic_serial_port.
+  /**
+   * This constructor creates and opens a serial port for the specified device
+   * name.
+   *
+   * @param ex The I/O executor that the serial port will use, by default, to
+   * dispatch handlers for any asynchronous operations performed on the
+   * serial port.
+   *
+   * @param device The platform-specific device name for this serial
+   * port.
+   */
+  basic_serial_port(const executor_type& ex, const char* device)
+    : impl_(ex)
+  {
+    asio::error_code ec;
+    impl_.get_service().open(impl_.get_implementation(), device, ec);
+    asio::detail::throw_error(ec, "open");
+  }
+
+  /// Construct and open a basic_serial_port.
+  /**
+   * This constructor creates and opens a serial port for the specified device
+   * name.
+   *
+   * @param context An execution context which provides the I/O executor that
+   * the serial port will use, by default, to dispatch handlers for any
+   * asynchronous operations performed on the serial port.
+   *
+   * @param device The platform-specific device name for this serial
+   * port.
+   */
+  template <typename ExecutionContext>
+  basic_serial_port(ExecutionContext& context, const char* device,
+      typename enable_if<
+        is_convertible<ExecutionContext&, execution_context&>::value
+      >::type* = 0)
+    : impl_(context)
+  {
+    asio::error_code ec;
+    impl_.get_service().open(impl_.get_implementation(), device, ec);
+    asio::detail::throw_error(ec, "open");
+  }
+
+  /// Construct and open a basic_serial_port.
+  /**
+   * This constructor creates and opens a serial port for the specified device
+   * name.
+   *
+   * @param ex The I/O executor that the serial port will use, by default, to
+   * dispatch handlers for any asynchronous operations performed on the
+   * serial port.
+   *
+   * @param device The platform-specific device name for this serial
+   * port.
+   */
+  basic_serial_port(const executor_type& ex, const std::string& device)
+    : impl_(ex)
+  {
+    asio::error_code ec;
+    impl_.get_service().open(impl_.get_implementation(), device, ec);
+    asio::detail::throw_error(ec, "open");
+  }
+
+  /// Construct and open a basic_serial_port.
+  /**
+   * This constructor creates and opens a serial port for the specified device
+   * name.
+   *
+   * @param context An execution context which provides the I/O executor that
+   * the serial port will use, by default, to dispatch handlers for any
+   * asynchronous operations performed on the serial port.
+   *
+   * @param device The platform-specific device name for this serial
+   * port.
+   */
+  template <typename ExecutionContext>
+  basic_serial_port(ExecutionContext& context, const std::string& device,
+      typename enable_if<
+        is_convertible<ExecutionContext&, execution_context&>::value
+      >::type* = 0)
+    : impl_(context)
+  {
+    asio::error_code ec;
+    impl_.get_service().open(impl_.get_implementation(), device, ec);
+    asio::detail::throw_error(ec, "open");
+  }
+
+  /// Construct a basic_serial_port on an existing native serial port.
+  /**
+   * This constructor creates a serial port object to hold an existing native
+   * serial port.
+   *
+   * @param ex The I/O executor that the serial port will use, by default, to
+   * dispatch handlers for any asynchronous operations performed on the
+   * serial port.
+   *
+   * @param native_serial_port A native serial port.
+   *
+   * @throws asio::system_error Thrown on failure.
+   */
+  basic_serial_port(const executor_type& ex,
+      const native_handle_type& native_serial_port)
+    : impl_(ex)
+  {
+    asio::error_code ec;
+    impl_.get_service().assign(impl_.get_implementation(),
+        native_serial_port, ec);
+    asio::detail::throw_error(ec, "assign");
+  }
+
+  /// Construct a basic_serial_port on an existing native serial port.
+  /**
+   * This constructor creates a serial port object to hold an existing native
+   * serial port.
+   *
+   * @param context An execution context which provides the I/O executor that
+   * the serial port will use, by default, to dispatch handlers for any
+   * asynchronous operations performed on the serial port.
+   *
+   * @param native_serial_port A native serial port.
+   *
+   * @throws asio::system_error Thrown on failure.
+   */
+  template <typename ExecutionContext>
+  basic_serial_port(ExecutionContext& context,
+      const native_handle_type& native_serial_port,
+      typename enable_if<
+        is_convertible<ExecutionContext&, execution_context&>::value
+      >::type* = 0)
+    : impl_(context)
+  {
+    asio::error_code ec;
+    impl_.get_service().assign(impl_.get_implementation(),
+        native_serial_port, ec);
+    asio::detail::throw_error(ec, "assign");
+  }
+
+#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+  /// Move-construct a basic_serial_port from another.
+  /**
+   * This constructor moves a serial port from one object to another.
+   *
+   * @param other The other basic_serial_port object from which the move will
+   * occur.
+   *
+   * @note Following the move, the moved-from object is in the same state as if
+   * constructed using the @c basic_serial_port(const executor_type&)
+   * constructor.
+   */
+  basic_serial_port(basic_serial_port&& other)
+    : impl_(std::move(other.impl_))
+  {
+  }
+
+  /// Move-assign a basic_serial_port from another.
+  /**
+   * This assignment operator moves a serial port from one object to another.
+   *
+   * @param other The other basic_serial_port object from which the move will
+   * occur.
+   *
+   * @note Following the move, the moved-from object is in the same state as if
+   * constructed using the @c basic_serial_port(const executor_type&)
+   * constructor.
+   */
+  basic_serial_port& operator=(basic_serial_port&& other)
+  {
+    impl_ = std::move(other.impl_);
+    return *this;
+  }
+#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+
+  /// Destroys the serial port.
+  /**
+   * This function destroys the serial port, cancelling any outstanding
+   * asynchronous wait operations associated with the serial port as if by
+   * calling @c cancel.
+   */
+  ~basic_serial_port()
+  {
+  }
+
+  /// Get the executor associated with the object.
+  executor_type get_executor() ASIO_NOEXCEPT
+  {
+    return impl_.get_executor();
+  }
+
+  /// Get a reference to the lowest layer.
+  /**
+   * This function returns a reference to the lowest layer in a stack of
+   * layers. Since a basic_serial_port cannot contain any further layers, it
+   * simply returns a reference to itself.
+   *
+   * @return A reference to the lowest layer in the stack of layers. Ownership
+   * is not transferred to the caller.
+   */
+  lowest_layer_type& lowest_layer()
+  {
+    return *this;
+  }
+
+  /// Get a const reference to the lowest layer.
+  /**
+   * This function returns a const reference to the lowest layer in a stack of
+   * layers. Since a basic_serial_port cannot contain any further layers, it
+   * simply returns a reference to itself.
+   *
+   * @return A const reference to the lowest layer in the stack of layers.
+   * Ownership is not transferred to the caller.
+   */
+  const lowest_layer_type& lowest_layer() const
+  {
+    return *this;
+  }
+
+  /// Open the serial port using the specified device name.
+  /**
+   * This function opens the serial port for the specified device name.
+   *
+   * @param device The platform-specific device name.
+   *
+   * @throws asio::system_error Thrown on failure.
+   */
+  void open(const std::string& device)
+  {
+    asio::error_code ec;
+    impl_.get_service().open(impl_.get_implementation(), device, ec);
+    asio::detail::throw_error(ec, "open");
+  }
+
+  /// Open the serial port using the specified device name.
+  /**
+   * This function opens the serial port using the given platform-specific
+   * device name.
+   *
+   * @param device The platform-specific device name.
+   *
+   * @param ec Set the indicate what error occurred, if any.
+   */
+  ASIO_SYNC_OP_VOID open(const std::string& device,
+      asio::error_code& ec)
+  {
+    impl_.get_service().open(impl_.get_implementation(), device, ec);
+    ASIO_SYNC_OP_VOID_RETURN(ec);
+  }
+
+  /// Assign an existing native serial port to the serial port.
+  /*
+   * This function opens the serial port to hold an existing native serial port.
+   *
+   * @param native_serial_port A native serial port.
+   *
+   * @throws asio::system_error Thrown on failure.
+   */
+  void assign(const native_handle_type& native_serial_port)
+  {
+    asio::error_code ec;
+    impl_.get_service().assign(impl_.get_implementation(),
+        native_serial_port, ec);
+    asio::detail::throw_error(ec, "assign");
+  }
+
+  /// Assign an existing native serial port to the serial port.
+  /*
+   * This function opens the serial port to hold an existing native serial port.
+   *
+   * @param native_serial_port A native serial port.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   */
+  ASIO_SYNC_OP_VOID assign(const native_handle_type& native_serial_port,
+      asio::error_code& ec)
+  {
+    impl_.get_service().assign(impl_.get_implementation(),
+        native_serial_port, ec);
+    ASIO_SYNC_OP_VOID_RETURN(ec);
+  }
+
+  /// Determine whether the serial port is open.
+  bool is_open() const
+  {
+    return impl_.get_service().is_open(impl_.get_implementation());
+  }
+
+  /// Close the serial port.
+  /**
+   * This function is used to close the serial port. Any asynchronous read or
+   * write operations will be cancelled immediately, and will complete with the
+   * asio::error::operation_aborted error.
+   *
+   * @throws asio::system_error Thrown on failure.
+   */
+  void close()
+  {
+    asio::error_code ec;
+    impl_.get_service().close(impl_.get_implementation(), ec);
+    asio::detail::throw_error(ec, "close");
+  }
+
+  /// Close the serial port.
+  /**
+   * This function is used to close the serial port. Any asynchronous read or
+   * write operations will be cancelled immediately, and will complete with the
+   * asio::error::operation_aborted error.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   */
+  ASIO_SYNC_OP_VOID close(asio::error_code& ec)
+  {
+    impl_.get_service().close(impl_.get_implementation(), ec);
+    ASIO_SYNC_OP_VOID_RETURN(ec);
+  }
+
+  /// Get the native serial port representation.
+  /**
+   * This function may be used to obtain the underlying representation of the
+   * serial port. This is intended to allow access to native serial port
+   * functionality that is not otherwise provided.
+   */
+  native_handle_type native_handle()
+  {
+    return impl_.get_service().native_handle(impl_.get_implementation());
+  }
+
+  /// Cancel all asynchronous operations associated with the serial port.
+  /**
+   * This function causes all outstanding asynchronous read or write operations
+   * to finish immediately, and the handlers for cancelled operations will be
+   * passed the asio::error::operation_aborted error.
+   *
+   * @throws asio::system_error Thrown on failure.
+   */
+  void cancel()
+  {
+    asio::error_code ec;
+    impl_.get_service().cancel(impl_.get_implementation(), ec);
+    asio::detail::throw_error(ec, "cancel");
+  }
+
+  /// Cancel all asynchronous operations associated with the serial port.
+  /**
+   * This function causes all outstanding asynchronous read or write operations
+   * to finish immediately, and the handlers for cancelled operations will be
+   * passed the asio::error::operation_aborted error.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   */
+  ASIO_SYNC_OP_VOID cancel(asio::error_code& ec)
+  {
+    impl_.get_service().cancel(impl_.get_implementation(), ec);
+    ASIO_SYNC_OP_VOID_RETURN(ec);
+  }
+
+  /// Send a break sequence to the serial port.
+  /**
+   * This function causes a break sequence of platform-specific duration to be
+   * sent out the serial port.
+   *
+   * @throws asio::system_error Thrown on failure.
+   */
+  void send_break()
+  {
+    asio::error_code ec;
+    impl_.get_service().send_break(impl_.get_implementation(), ec);
+    asio::detail::throw_error(ec, "send_break");
+  }
+
+  /// Send a break sequence to the serial port.
+  /**
+   * This function causes a break sequence of platform-specific duration to be
+   * sent out the serial port.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   */
+  ASIO_SYNC_OP_VOID send_break(asio::error_code& ec)
+  {
+    impl_.get_service().send_break(impl_.get_implementation(), ec);
+    ASIO_SYNC_OP_VOID_RETURN(ec);
+  }
+
+  /// Set an option on the serial port.
+  /**
+   * This function is used to set an option on the serial port.
+   *
+   * @param option The option value to be set on the serial port.
+   *
+   * @throws asio::system_error Thrown on failure.
+   *
+   * @sa SettableSerialPortOption @n
+   * asio::serial_port_base::baud_rate @n
+   * asio::serial_port_base::flow_control @n
+   * asio::serial_port_base::parity @n
+   * asio::serial_port_base::stop_bits @n
+   * asio::serial_port_base::character_size
+   */
+  template <typename SettableSerialPortOption>
+  void set_option(const SettableSerialPortOption& option)
+  {
+    asio::error_code ec;
+    impl_.get_service().set_option(impl_.get_implementation(), option, ec);
+    asio::detail::throw_error(ec, "set_option");
+  }
+
+  /// Set an option on the serial port.
+  /**
+   * This function is used to set an option on the serial port.
+   *
+   * @param option The option value to be set on the serial port.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   *
+   * @sa SettableSerialPortOption @n
+   * asio::serial_port_base::baud_rate @n
+   * asio::serial_port_base::flow_control @n
+   * asio::serial_port_base::parity @n
+   * asio::serial_port_base::stop_bits @n
+   * asio::serial_port_base::character_size
+   */
+  template <typename SettableSerialPortOption>
+  ASIO_SYNC_OP_VOID set_option(const SettableSerialPortOption& option,
+      asio::error_code& ec)
+  {
+    impl_.get_service().set_option(impl_.get_implementation(), option, ec);
+    ASIO_SYNC_OP_VOID_RETURN(ec);
+  }
+
+  /// Get an option from the serial port.
+  /**
+   * This function is used to get the current value of an option on the serial
+   * port.
+   *
+   * @param option The option value to be obtained from the serial port.
+   *
+   * @throws asio::system_error Thrown on failure.
+   *
+   * @sa GettableSerialPortOption @n
+   * asio::serial_port_base::baud_rate @n
+   * asio::serial_port_base::flow_control @n
+   * asio::serial_port_base::parity @n
+   * asio::serial_port_base::stop_bits @n
+   * asio::serial_port_base::character_size
+   */
+  template <typename GettableSerialPortOption>
+  void get_option(GettableSerialPortOption& option) const
+  {
+    asio::error_code ec;
+    impl_.get_service().get_option(impl_.get_implementation(), option, ec);
+    asio::detail::throw_error(ec, "get_option");
+  }
+
+  /// Get an option from the serial port.
+  /**
+   * This function is used to get the current value of an option on the serial
+   * port.
+   *
+   * @param option The option value to be obtained from the serial port.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   *
+   * @sa GettableSerialPortOption @n
+   * asio::serial_port_base::baud_rate @n
+   * asio::serial_port_base::flow_control @n
+   * asio::serial_port_base::parity @n
+   * asio::serial_port_base::stop_bits @n
+   * asio::serial_port_base::character_size
+   */
+  template <typename GettableSerialPortOption>
+  ASIO_SYNC_OP_VOID get_option(GettableSerialPortOption& option,
+      asio::error_code& ec) const
+  {
+    impl_.get_service().get_option(impl_.get_implementation(), option, ec);
+    ASIO_SYNC_OP_VOID_RETURN(ec);
+  }
+
+  /// Write some data to the serial port.
+  /**
+   * This function is used to write data to the serial port. The function call
+   * will block until one or more bytes of the data has been written
+   * successfully, or until an error occurs.
+   *
+   * @param buffers One or more data buffers to be written to the serial port.
+   *
+   * @returns The number of bytes written.
+   *
+   * @throws asio::system_error Thrown on failure. An error code of
+   * asio::error::eof indicates that the connection was closed by the
+   * peer.
+   *
+   * @note The write_some operation may not transmit all of the data to the
+   * peer. Consider using the @ref write function if you need to ensure that
+   * all data is written before the blocking operation completes.
+   *
+   * @par Example
+   * To write a single data buffer use the @ref buffer function as follows:
+   * @code
+   * basic_serial_port.write_some(asio::buffer(data, size));
+   * @endcode
+   * See the @ref buffer documentation for information on writing multiple
+   * buffers in one go, and how to use it with arrays, boost::array or
+   * std::vector.
+   */
+  template <typename ConstBufferSequence>
+  std::size_t write_some(const ConstBufferSequence& buffers)
+  {
+    asio::error_code ec;
+    std::size_t s = impl_.get_service().write_some(
+        impl_.get_implementation(), buffers, ec);
+    asio::detail::throw_error(ec, "write_some");
+    return s;
+  }
+
+  /// Write some data to the serial port.
+  /**
+   * This function is used to write data to the serial port. The function call
+   * will block until one or more bytes of the data has been written
+   * successfully, or until an error occurs.
+   *
+   * @param buffers One or more data buffers to be written to the serial port.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   *
+   * @returns The number of bytes written. Returns 0 if an error occurred.
+   *
+   * @note The write_some operation may not transmit all of the data to the
+   * peer. Consider using the @ref write function if you need to ensure that
+   * all data is written before the blocking operation completes.
+   */
+  template <typename ConstBufferSequence>
+  std::size_t write_some(const ConstBufferSequence& buffers,
+      asio::error_code& ec)
+  {
+    return impl_.get_service().write_some(
+        impl_.get_implementation(), buffers, ec);
+  }
+
+  /// Start an asynchronous write.
+  /**
+   * This function is used to asynchronously write data to the serial port.
+   * The function call always returns immediately.
+   *
+   * @param buffers One or more data buffers to be written to the serial port.
+   * Although the buffers object may be copied as necessary, ownership of the
+   * underlying memory blocks is retained by the caller, which must guarantee
+   * that they remain valid until the handler is called.
+   *
+   * @param handler The handler to be called when the write operation completes.
+   * Copies will be made of the handler as required. The function signature of
+   * the handler must be:
+   * @code void handler(
+   *   const asio::error_code& error, // Result of operation.
+   *   std::size_t bytes_transferred           // Number of bytes written.
+   * ); @endcode
+   * Regardless of whether the asynchronous operation completes immediately or
+   * not, the handler will not be invoked from within this function. On
+   * immediate completion, invocation of the handler will be performed in a
+   * manner equivalent to using asio::post().
+   *
+   * @note The write operation may not transmit all of the data to the peer.
+   * Consider using the @ref async_write function if you need to ensure that all
+   * data is written before the asynchronous operation completes.
+   *
+   * @par Example
+   * To write a single data buffer use the @ref buffer function as follows:
+   * @code
+   * basic_serial_port.async_write_some(
+   *     asio::buffer(data, size), handler);
+   * @endcode
+   * See the @ref buffer documentation for information on writing multiple
+   * buffers in one go, and how to use it with arrays, boost::array or
+   * std::vector.
+   */
+  template <typename ConstBufferSequence,
+      ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+        std::size_t)) WriteHandler
+          ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
+  ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,
+      void (asio::error_code, std::size_t))
+  async_write_some(const ConstBufferSequence& buffers,
+      ASIO_MOVE_ARG(WriteHandler) handler
+        ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
+  {
+    return async_initiate<WriteHandler,
+      void (asio::error_code, std::size_t)>(
+        initiate_async_write_some(this), handler, buffers);
+  }
+
+  /// Read some data from the serial port.
+  /**
+   * This function is used to read data from the serial port. The function
+   * call will block until one or more bytes of data has been read successfully,
+   * or until an error occurs.
+   *
+   * @param buffers One or more buffers into which the data will be read.
+   *
+   * @returns The number of bytes read.
+   *
+   * @throws asio::system_error Thrown on failure. An error code of
+   * asio::error::eof indicates that the connection was closed by the
+   * peer.
+   *
+   * @note The read_some operation may not read all of the requested number of
+   * bytes. Consider using the @ref read function if you need to ensure that
+   * the requested amount of data is read before the blocking operation
+   * completes.
+   *
+   * @par Example
+   * To read into a single data buffer use the @ref buffer function as follows:
+   * @code
+   * basic_serial_port.read_some(asio::buffer(data, size));
+   * @endcode
+   * See the @ref buffer documentation for information on reading into multiple
+   * buffers in one go, and how to use it with arrays, boost::array or
+   * std::vector.
+   */
+  template <typename MutableBufferSequence>
+  std::size_t read_some(const MutableBufferSequence& buffers)
+  {
+    asio::error_code ec;
+    std::size_t s = impl_.get_service().read_some(
+        impl_.get_implementation(), buffers, ec);
+    asio::detail::throw_error(ec, "read_some");
+    return s;
+  }
+
+  /// Read some data from the serial port.
+  /**
+   * This function is used to read data from the serial port. The function
+   * call will block until one or more bytes of data has been read successfully,
+   * or until an error occurs.
+   *
+   * @param buffers One or more buffers into which the data will be read.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   *
+   * @returns The number of bytes read. Returns 0 if an error occurred.
+   *
+   * @note The read_some operation may not read all of the requested number of
+   * bytes. Consider using the @ref read function if you need to ensure that
+   * the requested amount of data is read before the blocking operation
+   * completes.
+   */
+  template <typename MutableBufferSequence>
+  std::size_t read_some(const MutableBufferSequence& buffers,
+      asio::error_code& ec)
+  {
+    return impl_.get_service().read_some(
+        impl_.get_implementation(), buffers, ec);
+  }
+
+  /// Start an asynchronous read.
+  /**
+   * This function is used to asynchronously read data from the serial port.
+   * The function call always returns immediately.
+   *
+   * @param buffers One or more buffers into which the data will be read.
+   * Although the buffers object may be copied as necessary, ownership of the
+   * underlying memory blocks is retained by the caller, which must guarantee
+   * that they remain valid until the handler is called.
+   *
+   * @param handler The handler to be called when the read operation completes.
+   * Copies will be made of the handler as required. The function signature of
+   * the handler must be:
+   * @code void handler(
+   *   const asio::error_code& error, // Result of operation.
+   *   std::size_t bytes_transferred           // Number of bytes read.
+   * ); @endcode
+   * Regardless of whether the asynchronous operation completes immediately or
+   * not, the handler will not be invoked from within this function. On
+   * immediate completion, invocation of the handler will be performed in a
+   * manner equivalent to using asio::post().
+   *
+   * @note The read operation may not read all of the requested number of bytes.
+   * Consider using the @ref async_read function if you need to ensure that the
+   * requested amount of data is read before the asynchronous operation
+   * completes.
+   *
+   * @par Example
+   * To read into a single data buffer use the @ref buffer function as follows:
+   * @code
+   * basic_serial_port.async_read_some(
+   *     asio::buffer(data, size), handler);
+   * @endcode
+   * See the @ref buffer documentation for information on reading into multiple
+   * buffers in one go, and how to use it with arrays, boost::array or
+   * std::vector.
+   */
+  template <typename MutableBufferSequence,
+      ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+        std::size_t)) ReadHandler
+          ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
+  ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,
+      void (asio::error_code, std::size_t))
+  async_read_some(const MutableBufferSequence& buffers,
+      ASIO_MOVE_ARG(ReadHandler) handler
+        ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
+  {
+    return async_initiate<ReadHandler,
+      void (asio::error_code, std::size_t)>(
+        initiate_async_read_some(this), handler, buffers);
+  }
+
+private:
+  // Disallow copying and assignment.
+  basic_serial_port(const basic_serial_port&) ASIO_DELETED;
+  basic_serial_port& operator=(const basic_serial_port&) ASIO_DELETED;
+
+  class initiate_async_write_some
+  {
+  public:
+    typedef Executor executor_type;
+
+    explicit initiate_async_write_some(basic_serial_port* self)
+      : self_(self)
+    {
+    }
+
+    executor_type get_executor() const ASIO_NOEXCEPT
+    {
+      return self_->get_executor();
+    }
+
+    template <typename WriteHandler, typename ConstBufferSequence>
+    void operator()(ASIO_MOVE_ARG(WriteHandler) handler,
+        const ConstBufferSequence& buffers) const
+    {
+      // If you get an error on the following line it means that your handler
+      // does not meet the documented type requirements for a WriteHandler.
+      ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check;
+
+      detail::non_const_lvalue<WriteHandler> handler2(handler);
+      self_->impl_.get_service().async_write_some(
+          self_->impl_.get_implementation(), buffers,
+          handler2.value, self_->impl_.get_executor());
+    }
+
+  private:
+    basic_serial_port* self_;
+  };
+
+  class initiate_async_read_some
+  {
+  public:
+    typedef Executor executor_type;
+
+    explicit initiate_async_read_some(basic_serial_port* self)
+      : self_(self)
+    {
+    }
+
+    executor_type get_executor() const ASIO_NOEXCEPT
+    {
+      return self_->get_executor();
+    }
+
+    template <typename ReadHandler, typename MutableBufferSequence>
+    void operator()(ASIO_MOVE_ARG(ReadHandler) handler,
+        const MutableBufferSequence& buffers) const
+    {
+      // If you get an error on the following line it means that your handler
+      // does not meet the documented type requirements for a ReadHandler.
+      ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
+
+      detail::non_const_lvalue<ReadHandler> handler2(handler);
+      self_->impl_.get_service().async_read_some(
+          self_->impl_.get_implementation(), buffers,
+          handler2.value, self_->impl_.get_executor());
+    }
+
+  private:
+    basic_serial_port* self_;
+  };
+
+#if defined(ASIO_HAS_IOCP)
+  detail::io_object_impl<detail::win_iocp_serial_port_service, Executor> impl_;
+#else
+  detail::io_object_impl<detail::reactive_serial_port_service, Executor> impl_;
+#endif
+};
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_SERIAL_PORT)
+       //   || defined(GENERATING_DOCUMENTATION)
+
+#endif // ASIO_BASIC_SERIAL_PORT_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/basic_signal_set.hpp b/link/modules/asio-standalone/asio/include/asio/basic_signal_set.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/basic_signal_set.hpp
@@ -0,0 +1,568 @@
+//
+// basic_signal_set.hpp
+// ~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_BASIC_SIGNAL_SET_HPP
+#define ASIO_BASIC_SIGNAL_SET_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#include "asio/any_io_executor.hpp"
+#include "asio/async_result.hpp"
+#include "asio/detail/handler_type_requirements.hpp"
+#include "asio/detail/io_object_impl.hpp"
+#include "asio/detail/non_const_lvalue.hpp"
+#include "asio/detail/signal_set_service.hpp"
+#include "asio/detail/throw_error.hpp"
+#include "asio/detail/type_traits.hpp"
+#include "asio/error.hpp"
+#include "asio/execution_context.hpp"
+
+namespace asio {
+
+/// Provides signal functionality.
+/**
+ * The basic_signal_set class provides the ability to perform an asynchronous
+ * wait for one or more signals to occur.
+ *
+ * @par Thread Safety
+ * @e Distinct @e objects: Safe.@n
+ * @e Shared @e objects: Unsafe.
+ *
+ * @par Example
+ * Performing an asynchronous wait:
+ * @code
+ * void handler(
+ *     const asio::error_code& error,
+ *     int signal_number)
+ * {
+ *   if (!error)
+ *   {
+ *     // A signal occurred.
+ *   }
+ * }
+ *
+ * ...
+ *
+ * // Construct a signal set registered for process termination.
+ * asio::signal_set signals(my_context, SIGINT, SIGTERM);
+ *
+ * // Start an asynchronous wait for one of the signals to occur.
+ * signals.async_wait(handler);
+ * @endcode
+ *
+ * @par Queueing of signal notifications
+ *
+ * If a signal is registered with a signal_set, and the signal occurs when
+ * there are no waiting handlers, then the signal notification is queued. The
+ * next async_wait operation on that signal_set will dequeue the notification.
+ * If multiple notifications are queued, subsequent async_wait operations
+ * dequeue them one at a time. Signal notifications are dequeued in order of
+ * ascending signal number.
+ *
+ * If a signal number is removed from a signal_set (using the @c remove or @c
+ * erase member functions) then any queued notifications for that signal are
+ * discarded.
+ *
+ * @par Multiple registration of signals
+ *
+ * The same signal number may be registered with different signal_set objects.
+ * When the signal occurs, one handler is called for each signal_set object.
+ *
+ * Note that multiple registration only works for signals that are registered
+ * using Asio. The application must not also register a signal handler using
+ * functions such as @c signal() or @c sigaction().
+ *
+ * @par Signal masking on POSIX platforms
+ *
+ * POSIX allows signals to be blocked using functions such as @c sigprocmask()
+ * and @c pthread_sigmask(). For signals to be delivered, programs must ensure
+ * that any signals registered using signal_set objects are unblocked in at
+ * least one thread.
+ */
+template <typename Executor = any_io_executor>
+class basic_signal_set
+{
+public:
+  /// The type of the executor associated with the object.
+  typedef Executor executor_type;
+
+  /// Rebinds the signal set type to another executor.
+  template <typename Executor1>
+  struct rebind_executor
+  {
+    /// The signal set type when rebound to the specified executor.
+    typedef basic_signal_set<Executor1> other;
+  };
+
+  /// Construct a signal set without adding any signals.
+  /**
+   * This constructor creates a signal set without registering for any signals.
+   *
+   * @param ex The I/O executor that the signal set will use, by default, to
+   * dispatch handlers for any asynchronous operations performed on the
+   * signal set.
+   */
+  explicit basic_signal_set(const executor_type& ex)
+    : impl_(ex)
+  {
+  }
+
+  /// Construct a signal set without adding any signals.
+  /**
+   * This constructor creates a signal set without registering for any signals.
+   *
+   * @param context An execution context which provides the I/O executor that
+   * the signal set will use, by default, to dispatch handlers for any
+   * asynchronous operations performed on the signal set.
+   */
+  template <typename ExecutionContext>
+  explicit basic_signal_set(ExecutionContext& context,
+      typename enable_if<
+        is_convertible<ExecutionContext&, execution_context&>::value
+      >::type* = 0)
+    : impl_(context)
+  {
+  }
+
+  /// Construct a signal set and add one signal.
+  /**
+   * This constructor creates a signal set and registers for one signal.
+   *
+   * @param ex The I/O executor that the signal set will use, by default, to
+   * dispatch handlers for any asynchronous operations performed on the
+   * signal set.
+   *
+   * @param signal_number_1 The signal number to be added.
+   *
+   * @note This constructor is equivalent to performing:
+   * @code asio::signal_set signals(ex);
+   * signals.add(signal_number_1); @endcode
+   */
+  basic_signal_set(const executor_type& ex, int signal_number_1)
+    : impl_(ex)
+  {
+    asio::error_code ec;
+    impl_.get_service().add(impl_.get_implementation(), signal_number_1, ec);
+    asio::detail::throw_error(ec, "add");
+  }
+
+  /// Construct a signal set and add one signal.
+  /**
+   * This constructor creates a signal set and registers for one signal.
+   *
+   * @param context An execution context which provides the I/O executor that
+   * the signal set will use, by default, to dispatch handlers for any
+   * asynchronous operations performed on the signal set.
+   *
+   * @param signal_number_1 The signal number to be added.
+   *
+   * @note This constructor is equivalent to performing:
+   * @code asio::signal_set signals(context);
+   * signals.add(signal_number_1); @endcode
+   */
+  template <typename ExecutionContext>
+  basic_signal_set(ExecutionContext& context, int signal_number_1,
+      typename enable_if<
+        is_convertible<ExecutionContext&, execution_context&>::value
+      >::type* = 0)
+    : impl_(context)
+  {
+    asio::error_code ec;
+    impl_.get_service().add(impl_.get_implementation(), signal_number_1, ec);
+    asio::detail::throw_error(ec, "add");
+  }
+
+  /// Construct a signal set and add two signals.
+  /**
+   * This constructor creates a signal set and registers for two signals.
+   *
+   * @param ex The I/O executor that the signal set will use, by default, to
+   * dispatch handlers for any asynchronous operations performed on the
+   * signal set.
+   *
+   * @param signal_number_1 The first signal number to be added.
+   *
+   * @param signal_number_2 The second signal number to be added.
+   *
+   * @note This constructor is equivalent to performing:
+   * @code asio::signal_set signals(ex);
+   * signals.add(signal_number_1);
+   * signals.add(signal_number_2); @endcode
+   */
+  basic_signal_set(const executor_type& ex, int signal_number_1,
+      int signal_number_2)
+    : impl_(ex)
+  {
+    asio::error_code ec;
+    impl_.get_service().add(impl_.get_implementation(), signal_number_1, ec);
+    asio::detail::throw_error(ec, "add");
+    impl_.get_service().add(impl_.get_implementation(), signal_number_2, ec);
+    asio::detail::throw_error(ec, "add");
+  }
+
+  /// Construct a signal set and add two signals.
+  /**
+   * This constructor creates a signal set and registers for two signals.
+   *
+   * @param context An execution context which provides the I/O executor that
+   * the signal set will use, by default, to dispatch handlers for any
+   * asynchronous operations performed on the signal set.
+   *
+   * @param signal_number_1 The first signal number to be added.
+   *
+   * @param signal_number_2 The second signal number to be added.
+   *
+   * @note This constructor is equivalent to performing:
+   * @code asio::signal_set signals(context);
+   * signals.add(signal_number_1);
+   * signals.add(signal_number_2); @endcode
+   */
+  template <typename ExecutionContext>
+  basic_signal_set(ExecutionContext& context, int signal_number_1,
+      int signal_number_2,
+      typename enable_if<
+        is_convertible<ExecutionContext&, execution_context&>::value
+      >::type* = 0)
+    : impl_(context)
+  {
+    asio::error_code ec;
+    impl_.get_service().add(impl_.get_implementation(), signal_number_1, ec);
+    asio::detail::throw_error(ec, "add");
+    impl_.get_service().add(impl_.get_implementation(), signal_number_2, ec);
+    asio::detail::throw_error(ec, "add");
+  }
+
+  /// Construct a signal set and add three signals.
+  /**
+   * This constructor creates a signal set and registers for three signals.
+   *
+   * @param ex The I/O executor that the signal set will use, by default, to
+   * dispatch handlers for any asynchronous operations performed on the
+   * signal set.
+   *
+   * @param signal_number_1 The first signal number to be added.
+   *
+   * @param signal_number_2 The second signal number to be added.
+   *
+   * @param signal_number_3 The third signal number to be added.
+   *
+   * @note This constructor is equivalent to performing:
+   * @code asio::signal_set signals(ex);
+   * signals.add(signal_number_1);
+   * signals.add(signal_number_2);
+   * signals.add(signal_number_3); @endcode
+   */
+  basic_signal_set(const executor_type& ex, int signal_number_1,
+      int signal_number_2, int signal_number_3)
+    : impl_(ex)
+  {
+    asio::error_code ec;
+    impl_.get_service().add(impl_.get_implementation(), signal_number_1, ec);
+    asio::detail::throw_error(ec, "add");
+    impl_.get_service().add(impl_.get_implementation(), signal_number_2, ec);
+    asio::detail::throw_error(ec, "add");
+    impl_.get_service().add(impl_.get_implementation(), signal_number_3, ec);
+    asio::detail::throw_error(ec, "add");
+  }
+
+  /// Construct a signal set and add three signals.
+  /**
+   * This constructor creates a signal set and registers for three signals.
+   *
+   * @param context An execution context which provides the I/O executor that
+   * the signal set will use, by default, to dispatch handlers for any
+   * asynchronous operations performed on the signal set.
+   *
+   * @param signal_number_1 The first signal number to be added.
+   *
+   * @param signal_number_2 The second signal number to be added.
+   *
+   * @param signal_number_3 The third signal number to be added.
+   *
+   * @note This constructor is equivalent to performing:
+   * @code asio::signal_set signals(context);
+   * signals.add(signal_number_1);
+   * signals.add(signal_number_2);
+   * signals.add(signal_number_3); @endcode
+   */
+  template <typename ExecutionContext>
+  basic_signal_set(ExecutionContext& context, int signal_number_1,
+      int signal_number_2, int signal_number_3,
+      typename enable_if<
+        is_convertible<ExecutionContext&, execution_context&>::value
+      >::type* = 0)
+    : impl_(context)
+  {
+    asio::error_code ec;
+    impl_.get_service().add(impl_.get_implementation(), signal_number_1, ec);
+    asio::detail::throw_error(ec, "add");
+    impl_.get_service().add(impl_.get_implementation(), signal_number_2, ec);
+    asio::detail::throw_error(ec, "add");
+    impl_.get_service().add(impl_.get_implementation(), signal_number_3, ec);
+    asio::detail::throw_error(ec, "add");
+  }
+
+  /// Destroys the signal set.
+  /**
+   * This function destroys the signal set, cancelling any outstanding
+   * asynchronous wait operations associated with the signal set as if by
+   * calling @c cancel.
+   */
+  ~basic_signal_set()
+  {
+  }
+
+  /// Get the executor associated with the object.
+  executor_type get_executor() ASIO_NOEXCEPT
+  {
+    return impl_.get_executor();
+  }
+
+  /// Add a signal to a signal_set.
+  /**
+   * This function adds the specified signal to the set. It has no effect if the
+   * signal is already in the set.
+   *
+   * @param signal_number The signal to be added to the set.
+   *
+   * @throws asio::system_error Thrown on failure.
+   */
+  void add(int signal_number)
+  {
+    asio::error_code ec;
+    impl_.get_service().add(impl_.get_implementation(), signal_number, ec);
+    asio::detail::throw_error(ec, "add");
+  }
+
+  /// Add a signal to a signal_set.
+  /**
+   * This function adds the specified signal to the set. It has no effect if the
+   * signal is already in the set.
+   *
+   * @param signal_number The signal to be added to the set.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   */
+  ASIO_SYNC_OP_VOID add(int signal_number,
+      asio::error_code& ec)
+  {
+    impl_.get_service().add(impl_.get_implementation(), signal_number, ec);
+    ASIO_SYNC_OP_VOID_RETURN(ec);
+  }
+
+  /// Remove a signal from a signal_set.
+  /**
+   * This function removes the specified signal from the set. It has no effect
+   * if the signal is not in the set.
+   *
+   * @param signal_number The signal to be removed from the set.
+   *
+   * @throws asio::system_error Thrown on failure.
+   *
+   * @note Removes any notifications that have been queued for the specified
+   * signal number.
+   */
+  void remove(int signal_number)
+  {
+    asio::error_code ec;
+    impl_.get_service().remove(impl_.get_implementation(), signal_number, ec);
+    asio::detail::throw_error(ec, "remove");
+  }
+
+  /// Remove a signal from a signal_set.
+  /**
+   * This function removes the specified signal from the set. It has no effect
+   * if the signal is not in the set.
+   *
+   * @param signal_number The signal to be removed from the set.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   *
+   * @note Removes any notifications that have been queued for the specified
+   * signal number.
+   */
+  ASIO_SYNC_OP_VOID remove(int signal_number,
+      asio::error_code& ec)
+  {
+    impl_.get_service().remove(impl_.get_implementation(), signal_number, ec);
+    ASIO_SYNC_OP_VOID_RETURN(ec);
+  }
+
+  /// Remove all signals from a signal_set.
+  /**
+   * This function removes all signals from the set. It has no effect if the set
+   * is already empty.
+   *
+   * @throws asio::system_error Thrown on failure.
+   *
+   * @note Removes all queued notifications.
+   */
+  void clear()
+  {
+    asio::error_code ec;
+    impl_.get_service().clear(impl_.get_implementation(), ec);
+    asio::detail::throw_error(ec, "clear");
+  }
+
+  /// Remove all signals from a signal_set.
+  /**
+   * This function removes all signals from the set. It has no effect if the set
+   * is already empty.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   *
+   * @note Removes all queued notifications.
+   */
+  ASIO_SYNC_OP_VOID clear(asio::error_code& ec)
+  {
+    impl_.get_service().clear(impl_.get_implementation(), ec);
+    ASIO_SYNC_OP_VOID_RETURN(ec);
+  }
+
+  /// Cancel all operations associated with the signal set.
+  /**
+   * This function forces the completion of any pending asynchronous wait
+   * operations against the signal set. The handler for each cancelled
+   * operation will be invoked with the asio::error::operation_aborted
+   * error code.
+   *
+   * Cancellation does not alter the set of registered signals.
+   *
+   * @throws asio::system_error Thrown on failure.
+   *
+   * @note If a registered signal occurred before cancel() is called, then the
+   * handlers for asynchronous wait operations will:
+   *
+   * @li have already been invoked; or
+   *
+   * @li have been queued for invocation in the near future.
+   *
+   * These handlers can no longer be cancelled, and therefore are passed an
+   * error code that indicates the successful completion of the wait operation.
+   */
+  void cancel()
+  {
+    asio::error_code ec;
+    impl_.get_service().cancel(impl_.get_implementation(), ec);
+    asio::detail::throw_error(ec, "cancel");
+  }
+
+  /// Cancel all operations associated with the signal set.
+  /**
+   * This function forces the completion of any pending asynchronous wait
+   * operations against the signal set. The handler for each cancelled
+   * operation will be invoked with the asio::error::operation_aborted
+   * error code.
+   *
+   * Cancellation does not alter the set of registered signals.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   *
+   * @note If a registered signal occurred before cancel() is called, then the
+   * handlers for asynchronous wait operations will:
+   *
+   * @li have already been invoked; or
+   *
+   * @li have been queued for invocation in the near future.
+   *
+   * These handlers can no longer be cancelled, and therefore are passed an
+   * error code that indicates the successful completion of the wait operation.
+   */
+  ASIO_SYNC_OP_VOID cancel(asio::error_code& ec)
+  {
+    impl_.get_service().cancel(impl_.get_implementation(), ec);
+    ASIO_SYNC_OP_VOID_RETURN(ec);
+  }
+
+  /// Start an asynchronous operation to wait for a signal to be delivered.
+  /**
+   * This function may be used to initiate an asynchronous wait against the
+   * signal set. It always returns immediately.
+   *
+   * For each call to async_wait(), the supplied handler will be called exactly
+   * once. The handler will be called when:
+   *
+   * @li One of the registered signals in the signal set occurs; or
+   *
+   * @li The signal set was cancelled, in which case the handler is passed the
+   * error code asio::error::operation_aborted.
+   *
+   * @param handler The handler to be called when the signal occurs. Copies
+   * will be made of the handler as required. The function signature of the
+   * handler must be:
+   * @code void handler(
+   *   const asio::error_code& error, // Result of operation.
+   *   int signal_number // Indicates which signal occurred.
+   * ); @endcode
+   * Regardless of whether the asynchronous operation completes immediately or
+   * not, the handler will not be invoked from within this function. On
+   * immediate completion, invocation of the handler will be performed in a
+   * manner equivalent to using asio::post().
+   */
+  template <
+    ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, int))
+      SignalHandler ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
+  ASIO_INITFN_AUTO_RESULT_TYPE(SignalHandler,
+      void (asio::error_code, int))
+  async_wait(
+      ASIO_MOVE_ARG(SignalHandler) handler
+        ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
+  {
+    return async_initiate<SignalHandler, void (asio::error_code, int)>(
+        initiate_async_wait(this), handler);
+  }
+
+private:
+  // Disallow copying and assignment.
+  basic_signal_set(const basic_signal_set&) ASIO_DELETED;
+  basic_signal_set& operator=(const basic_signal_set&) ASIO_DELETED;
+
+  class initiate_async_wait
+  {
+  public:
+    typedef Executor executor_type;
+
+    explicit initiate_async_wait(basic_signal_set* self)
+      : self_(self)
+    {
+    }
+
+    executor_type get_executor() const ASIO_NOEXCEPT
+    {
+      return self_->get_executor();
+    }
+
+    template <typename SignalHandler>
+    void operator()(ASIO_MOVE_ARG(SignalHandler) handler) const
+    {
+      // If you get an error on the following line it means that your handler
+      // does not meet the documented type requirements for a SignalHandler.
+      ASIO_SIGNAL_HANDLER_CHECK(SignalHandler, handler) type_check;
+
+      detail::non_const_lvalue<SignalHandler> handler2(handler);
+      self_->impl_.get_service().async_wait(
+          self_->impl_.get_implementation(),
+          handler2.value, self_->impl_.get_executor());
+    }
+
+  private:
+    basic_signal_set* self_;
+  };
+
+  detail::io_object_impl<detail::signal_set_service, Executor> impl_;
+};
+
+} // namespace asio
+
+#endif // ASIO_BASIC_SIGNAL_SET_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/basic_socket.hpp b/link/modules/asio-standalone/asio/include/asio/basic_socket.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/basic_socket.hpp
@@ -0,0 +1,1894 @@
+//
+// basic_socket.hpp
+// ~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_BASIC_SOCKET_HPP
+#define ASIO_BASIC_SOCKET_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/any_io_executor.hpp"
+#include "asio/detail/config.hpp"
+#include "asio/async_result.hpp"
+#include "asio/detail/handler_type_requirements.hpp"
+#include "asio/detail/io_object_impl.hpp"
+#include "asio/detail/non_const_lvalue.hpp"
+#include "asio/detail/throw_error.hpp"
+#include "asio/detail/type_traits.hpp"
+#include "asio/error.hpp"
+#include "asio/execution_context.hpp"
+#include "asio/post.hpp"
+#include "asio/socket_base.hpp"
+
+#if defined(ASIO_WINDOWS_RUNTIME)
+# include "asio/detail/null_socket_service.hpp"
+#elif defined(ASIO_HAS_IOCP)
+# include "asio/detail/win_iocp_socket_service.hpp"
+#else
+# include "asio/detail/reactive_socket_service.hpp"
+#endif
+
+#if defined(ASIO_HAS_MOVE)
+# include <utility>
+#endif // defined(ASIO_HAS_MOVE)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+#if !defined(ASIO_BASIC_SOCKET_FWD_DECL)
+#define ASIO_BASIC_SOCKET_FWD_DECL
+
+// Forward declaration with defaulted arguments.
+template <typename Protocol, typename Executor = any_io_executor>
+class basic_socket;
+
+#endif // !defined(ASIO_BASIC_SOCKET_FWD_DECL)
+
+/// Provides socket functionality.
+/**
+ * The basic_socket class template provides functionality that is common to both
+ * stream-oriented and datagram-oriented sockets.
+ *
+ * @par Thread Safety
+ * @e Distinct @e objects: Safe.@n
+ * @e Shared @e objects: Unsafe.
+ */
+template <typename Protocol, typename Executor>
+class basic_socket
+  : public socket_base
+{
+public:
+  /// The type of the executor associated with the object.
+  typedef Executor executor_type;
+
+  /// Rebinds the socket type to another executor.
+  template <typename Executor1>
+  struct rebind_executor
+  {
+    /// The socket type when rebound to the specified executor.
+    typedef basic_socket<Protocol, Executor1> other;
+  };
+
+  /// The native representation of a socket.
+#if defined(GENERATING_DOCUMENTATION)
+  typedef implementation_defined native_handle_type;
+#elif defined(ASIO_WINDOWS_RUNTIME)
+  typedef typename detail::null_socket_service<
+    Protocol>::native_handle_type native_handle_type;
+#elif defined(ASIO_HAS_IOCP)
+  typedef typename detail::win_iocp_socket_service<
+    Protocol>::native_handle_type native_handle_type;
+#else
+  typedef typename detail::reactive_socket_service<
+    Protocol>::native_handle_type native_handle_type;
+#endif
+
+  /// The protocol type.
+  typedef Protocol protocol_type;
+
+  /// The endpoint type.
+  typedef typename Protocol::endpoint endpoint_type;
+
+#if !defined(ASIO_NO_EXTENSIONS)
+  /// A basic_socket is always the lowest layer.
+  typedef basic_socket<Protocol, Executor> lowest_layer_type;
+#endif // !defined(ASIO_NO_EXTENSIONS)
+
+  /// Construct a basic_socket without opening it.
+  /**
+   * This constructor creates a socket without opening it.
+   *
+   * @param ex The I/O executor that the socket will use, by default, to
+   * dispatch handlers for any asynchronous operations performed on the socket.
+   */
+  explicit basic_socket(const executor_type& ex)
+    : impl_(ex)
+  {
+  }
+
+  /// Construct a basic_socket without opening it.
+  /**
+   * This constructor creates a socket without opening it.
+   *
+   * @param context An execution context which provides the I/O executor that
+   * the socket will use, by default, to dispatch handlers for any asynchronous
+   * operations performed on the socket.
+   */
+  template <typename ExecutionContext>
+  explicit basic_socket(ExecutionContext& context,
+      typename enable_if<
+        is_convertible<ExecutionContext&, execution_context&>::value
+      >::type* = 0)
+    : impl_(context)
+  {
+  }
+
+  /// Construct and open a basic_socket.
+  /**
+   * This constructor creates and opens a socket.
+   *
+   * @param ex The I/O executor that the socket will use, by default, to
+   * dispatch handlers for any asynchronous operations performed on the socket.
+   *
+   * @param protocol An object specifying protocol parameters to be used.
+   *
+   * @throws asio::system_error Thrown on failure.
+   */
+  basic_socket(const executor_type& ex, const protocol_type& protocol)
+    : impl_(ex)
+  {
+    asio::error_code ec;
+    impl_.get_service().open(impl_.get_implementation(), protocol, ec);
+    asio::detail::throw_error(ec, "open");
+  }
+
+  /// Construct and open a basic_socket.
+  /**
+   * This constructor creates and opens a socket.
+   *
+   * @param context An execution context which provides the I/O executor that
+   * the socket will use, by default, to dispatch handlers for any asynchronous
+   * operations performed on the socket.
+   *
+   * @param protocol An object specifying protocol parameters to be used.
+   *
+   * @throws asio::system_error Thrown on failure.
+   */
+  template <typename ExecutionContext>
+  basic_socket(ExecutionContext& context, const protocol_type& protocol,
+      typename enable_if<
+        is_convertible<ExecutionContext&, execution_context&>::value
+      >::type* = 0)
+    : impl_(context)
+  {
+    asio::error_code ec;
+    impl_.get_service().open(impl_.get_implementation(), protocol, ec);
+    asio::detail::throw_error(ec, "open");
+  }
+
+  /// Construct a basic_socket, opening it and binding it to the given local
+  /// endpoint.
+  /**
+   * This constructor creates a socket and automatically opens it bound to the
+   * specified endpoint on the local machine. The protocol used is the protocol
+   * associated with the given endpoint.
+   *
+   * @param ex The I/O executor that the socket will use, by default, to
+   * dispatch handlers for any asynchronous operations performed on the socket.
+   *
+   * @param endpoint An endpoint on the local machine to which the socket will
+   * be bound.
+   *
+   * @throws asio::system_error Thrown on failure.
+   */
+  basic_socket(const executor_type& ex, const endpoint_type& endpoint)
+    : impl_(ex)
+  {
+    asio::error_code ec;
+    const protocol_type protocol = endpoint.protocol();
+    impl_.get_service().open(impl_.get_implementation(), protocol, ec);
+    asio::detail::throw_error(ec, "open");
+    impl_.get_service().bind(impl_.get_implementation(), endpoint, ec);
+    asio::detail::throw_error(ec, "bind");
+  }
+
+  /// Construct a basic_socket, opening it and binding it to the given local
+  /// endpoint.
+  /**
+   * This constructor creates a socket and automatically opens it bound to the
+   * specified endpoint on the local machine. The protocol used is the protocol
+   * associated with the given endpoint.
+   *
+   * @param context An execution context which provides the I/O executor that
+   * the socket will use, by default, to dispatch handlers for any asynchronous
+   * operations performed on the socket.
+   *
+   * @param endpoint An endpoint on the local machine to which the socket will
+   * be bound.
+   *
+   * @throws asio::system_error Thrown on failure.
+   */
+  template <typename ExecutionContext>
+  basic_socket(ExecutionContext& context, const endpoint_type& endpoint,
+      typename enable_if<
+        is_convertible<ExecutionContext&, execution_context&>::value
+      >::type* = 0)
+    : impl_(context)
+  {
+    asio::error_code ec;
+    const protocol_type protocol = endpoint.protocol();
+    impl_.get_service().open(impl_.get_implementation(), protocol, ec);
+    asio::detail::throw_error(ec, "open");
+    impl_.get_service().bind(impl_.get_implementation(), endpoint, ec);
+    asio::detail::throw_error(ec, "bind");
+  }
+
+  /// Construct a basic_socket on an existing native socket.
+  /**
+   * This constructor creates a socket object to hold an existing native socket.
+   *
+   * @param ex The I/O executor that the socket will use, by default, to
+   * dispatch handlers for any asynchronous operations performed on the socket.
+   *
+   * @param protocol An object specifying protocol parameters to be used.
+   *
+   * @param native_socket A native socket.
+   *
+   * @throws asio::system_error Thrown on failure.
+   */
+  basic_socket(const executor_type& ex, const protocol_type& protocol,
+      const native_handle_type& native_socket)
+    : impl_(ex)
+  {
+    asio::error_code ec;
+    impl_.get_service().assign(impl_.get_implementation(),
+        protocol, native_socket, ec);
+    asio::detail::throw_error(ec, "assign");
+  }
+
+  /// Construct a basic_socket on an existing native socket.
+  /**
+   * This constructor creates a socket object to hold an existing native socket.
+   *
+   * @param context An execution context which provides the I/O executor that
+   * the socket will use, by default, to dispatch handlers for any asynchronous
+   * operations performed on the socket.
+   *
+   * @param protocol An object specifying protocol parameters to be used.
+   *
+   * @param native_socket A native socket.
+   *
+   * @throws asio::system_error Thrown on failure.
+   */
+  template <typename ExecutionContext>
+  basic_socket(ExecutionContext& context, const protocol_type& protocol,
+      const native_handle_type& native_socket,
+      typename enable_if<
+        is_convertible<ExecutionContext&, execution_context&>::value
+      >::type* = 0)
+    : impl_(context)
+  {
+    asio::error_code ec;
+    impl_.get_service().assign(impl_.get_implementation(),
+        protocol, native_socket, ec);
+    asio::detail::throw_error(ec, "assign");
+  }
+
+#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+  /// Move-construct a basic_socket from another.
+  /**
+   * This constructor moves a socket from one object to another.
+   *
+   * @param other The other basic_socket object from which the move will
+   * occur.
+   *
+   * @note Following the move, the moved-from object is in the same state as if
+   * constructed using the @c basic_socket(const executor_type&) constructor.
+   */
+  basic_socket(basic_socket&& other) ASIO_NOEXCEPT
+    : impl_(std::move(other.impl_))
+  {
+  }
+
+  /// Move-assign a basic_socket from another.
+  /**
+   * This assignment operator moves a socket from one object to another.
+   *
+   * @param other The other basic_socket object from which the move will
+   * occur.
+   *
+   * @note Following the move, the moved-from object is in the same state as if
+   * constructed using the @c basic_socket(const executor_type&) constructor.
+   */
+  basic_socket& operator=(basic_socket&& other)
+  {
+    impl_ = std::move(other.impl_);
+    return *this;
+  }
+
+  // All sockets have access to each other's implementations.
+  template <typename Protocol1, typename Executor1>
+  friend class basic_socket;
+
+  /// Move-construct a basic_socket from a socket of another protocol type.
+  /**
+   * This constructor moves a socket from one object to another.
+   *
+   * @param other The other basic_socket object from which the move will
+   * occur.
+   *
+   * @note Following the move, the moved-from object is in the same state as if
+   * constructed using the @c basic_socket(const executor_type&) constructor.
+   */
+  template <typename Protocol1, typename Executor1>
+  basic_socket(basic_socket<Protocol1, Executor1>&& other,
+      typename enable_if<
+        is_convertible<Protocol1, Protocol>::value
+          && is_convertible<Executor1, Executor>::value
+      >::type* = 0)
+    : impl_(std::move(other.impl_))
+  {
+  }
+
+  /// Move-assign a basic_socket from a socket of another protocol type.
+  /**
+   * This assignment operator moves a socket from one object to another.
+   *
+   * @param other The other basic_socket object from which the move will
+   * occur.
+   *
+   * @note Following the move, the moved-from object is in the same state as if
+   * constructed using the @c basic_socket(const executor_type&) constructor.
+   */
+  template <typename Protocol1, typename Executor1>
+  typename enable_if<
+    is_convertible<Protocol1, Protocol>::value
+      && is_convertible<Executor1, Executor>::value,
+    basic_socket&
+  >::type operator=(basic_socket<Protocol1, Executor1> && other)
+  {
+    basic_socket tmp(std::move(other));
+    impl_ = std::move(tmp.impl_);
+    return *this;
+  }
+#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+
+  /// Get the executor associated with the object.
+  executor_type get_executor() ASIO_NOEXCEPT
+  {
+    return impl_.get_executor();
+  }
+
+#if !defined(ASIO_NO_EXTENSIONS)
+  /// Get a reference to the lowest layer.
+  /**
+   * This function returns a reference to the lowest layer in a stack of
+   * layers. Since a basic_socket cannot contain any further layers, it simply
+   * returns a reference to itself.
+   *
+   * @return A reference to the lowest layer in the stack of layers. Ownership
+   * is not transferred to the caller.
+   */
+  lowest_layer_type& lowest_layer()
+  {
+    return *this;
+  }
+
+  /// Get a const reference to the lowest layer.
+  /**
+   * This function returns a const reference to the lowest layer in a stack of
+   * layers. Since a basic_socket cannot contain any further layers, it simply
+   * returns a reference to itself.
+   *
+   * @return A const reference to the lowest layer in the stack of layers.
+   * Ownership is not transferred to the caller.
+   */
+  const lowest_layer_type& lowest_layer() const
+  {
+    return *this;
+  }
+#endif // !defined(ASIO_NO_EXTENSIONS)
+
+  /// Open the socket using the specified protocol.
+  /**
+   * This function opens the socket so that it will use the specified protocol.
+   *
+   * @param protocol An object specifying protocol parameters to be used.
+   *
+   * @throws asio::system_error Thrown on failure.
+   *
+   * @par Example
+   * @code
+   * asio::ip::tcp::socket socket(my_context);
+   * socket.open(asio::ip::tcp::v4());
+   * @endcode
+   */
+  void open(const protocol_type& protocol = protocol_type())
+  {
+    asio::error_code ec;
+    impl_.get_service().open(impl_.get_implementation(), protocol, ec);
+    asio::detail::throw_error(ec, "open");
+  }
+
+  /// Open the socket using the specified protocol.
+  /**
+   * This function opens the socket so that it will use the specified protocol.
+   *
+   * @param protocol An object specifying which protocol is to be used.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   *
+   * @par Example
+   * @code
+   * asio::ip::tcp::socket socket(my_context);
+   * asio::error_code ec;
+   * socket.open(asio::ip::tcp::v4(), ec);
+   * if (ec)
+   * {
+   *   // An error occurred.
+   * }
+   * @endcode
+   */
+  ASIO_SYNC_OP_VOID open(const protocol_type& protocol,
+      asio::error_code& ec)
+  {
+    impl_.get_service().open(impl_.get_implementation(), protocol, ec);
+    ASIO_SYNC_OP_VOID_RETURN(ec);
+  }
+
+  /// Assign an existing native socket to the socket.
+  /*
+   * This function opens the socket to hold an existing native socket.
+   *
+   * @param protocol An object specifying which protocol is to be used.
+   *
+   * @param native_socket A native socket.
+   *
+   * @throws asio::system_error Thrown on failure.
+   */
+  void assign(const protocol_type& protocol,
+      const native_handle_type& native_socket)
+  {
+    asio::error_code ec;
+    impl_.get_service().assign(impl_.get_implementation(),
+        protocol, native_socket, ec);
+    asio::detail::throw_error(ec, "assign");
+  }
+
+  /// Assign an existing native socket to the socket.
+  /*
+   * This function opens the socket to hold an existing native socket.
+   *
+   * @param protocol An object specifying which protocol is to be used.
+   *
+   * @param native_socket A native socket.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   */
+  ASIO_SYNC_OP_VOID assign(const protocol_type& protocol,
+      const native_handle_type& native_socket, asio::error_code& ec)
+  {
+    impl_.get_service().assign(impl_.get_implementation(),
+        protocol, native_socket, ec);
+    ASIO_SYNC_OP_VOID_RETURN(ec);
+  }
+
+  /// Determine whether the socket is open.
+  bool is_open() const
+  {
+    return impl_.get_service().is_open(impl_.get_implementation());
+  }
+
+  /// Close the socket.
+  /**
+   * This function is used to close the socket. Any asynchronous send, receive
+   * or connect operations will be cancelled immediately, and will complete
+   * with the asio::error::operation_aborted error.
+   *
+   * @throws asio::system_error Thrown on failure. Note that, even if
+   * the function indicates an error, the underlying descriptor is closed.
+   *
+   * @note For portable behaviour with respect to graceful closure of a
+   * connected socket, call shutdown() before closing the socket.
+   */
+  void close()
+  {
+    asio::error_code ec;
+    impl_.get_service().close(impl_.get_implementation(), ec);
+    asio::detail::throw_error(ec, "close");
+  }
+
+  /// Close the socket.
+  /**
+   * This function is used to close the socket. Any asynchronous send, receive
+   * or connect operations will be cancelled immediately, and will complete
+   * with the asio::error::operation_aborted error.
+   *
+   * @param ec Set to indicate what error occurred, if any. Note that, even if
+   * the function indicates an error, the underlying descriptor is closed.
+   *
+   * @par Example
+   * @code
+   * asio::ip::tcp::socket socket(my_context);
+   * ...
+   * asio::error_code ec;
+   * socket.close(ec);
+   * if (ec)
+   * {
+   *   // An error occurred.
+   * }
+   * @endcode
+   *
+   * @note For portable behaviour with respect to graceful closure of a
+   * connected socket, call shutdown() before closing the socket.
+   */
+  ASIO_SYNC_OP_VOID close(asio::error_code& ec)
+  {
+    impl_.get_service().close(impl_.get_implementation(), ec);
+    ASIO_SYNC_OP_VOID_RETURN(ec);
+  }
+
+  /// Release ownership of the underlying native socket.
+  /**
+   * This function causes all outstanding asynchronous connect, send and receive
+   * operations to finish immediately, and the handlers for cancelled operations
+   * will be passed the asio::error::operation_aborted error. Ownership
+   * of the native socket is then transferred to the caller.
+   *
+   * @throws asio::system_error Thrown on failure.
+   *
+   * @note This function is unsupported on Windows versions prior to Windows
+   * 8.1, and will fail with asio::error::operation_not_supported on
+   * these platforms.
+   */
+#if defined(ASIO_MSVC) && (ASIO_MSVC >= 1400) \
+  && (!defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0603)
+  __declspec(deprecated("This function always fails with "
+        "operation_not_supported when used on Windows versions "
+        "prior to Windows 8.1."))
+#endif
+  native_handle_type release()
+  {
+    asio::error_code ec;
+    native_handle_type s = impl_.get_service().release(
+        impl_.get_implementation(), ec);
+    asio::detail::throw_error(ec, "release");
+    return s;
+  }
+
+  /// Release ownership of the underlying native socket.
+  /**
+   * This function causes all outstanding asynchronous connect, send and receive
+   * operations to finish immediately, and the handlers for cancelled operations
+   * will be passed the asio::error::operation_aborted error. Ownership
+   * of the native socket is then transferred to the caller.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   *
+   * @note This function is unsupported on Windows versions prior to Windows
+   * 8.1, and will fail with asio::error::operation_not_supported on
+   * these platforms.
+   */
+#if defined(ASIO_MSVC) && (ASIO_MSVC >= 1400) \
+  && (!defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0603)
+  __declspec(deprecated("This function always fails with "
+        "operation_not_supported when used on Windows versions "
+        "prior to Windows 8.1."))
+#endif
+  native_handle_type release(asio::error_code& ec)
+  {
+    return impl_.get_service().release(impl_.get_implementation(), ec);
+  }
+
+  /// Get the native socket representation.
+  /**
+   * This function may be used to obtain the underlying representation of the
+   * socket. This is intended to allow access to native socket functionality
+   * that is not otherwise provided.
+   */
+  native_handle_type native_handle()
+  {
+    return impl_.get_service().native_handle(impl_.get_implementation());
+  }
+
+  /// Cancel all asynchronous operations associated with the socket.
+  /**
+   * This function causes all outstanding asynchronous connect, send and receive
+   * operations to finish immediately, and the handlers for cancelled operations
+   * will be passed the asio::error::operation_aborted error.
+   *
+   * @throws asio::system_error Thrown on failure.
+   *
+   * @note Calls to cancel() will always fail with
+   * asio::error::operation_not_supported when run on Windows XP, Windows
+   * Server 2003, and earlier versions of Windows, unless
+   * ASIO_ENABLE_CANCELIO is defined. However, the CancelIo function has
+   * two issues that should be considered before enabling its use:
+   *
+   * @li It will only cancel asynchronous operations that were initiated in the
+   * current thread.
+   *
+   * @li It can appear to complete without error, but the request to cancel the
+   * unfinished operations may be silently ignored by the operating system.
+   * Whether it works or not seems to depend on the drivers that are installed.
+   *
+   * For portable cancellation, consider using one of the following
+   * alternatives:
+   *
+   * @li Disable asio's I/O completion port backend by defining
+   * ASIO_DISABLE_IOCP.
+   *
+   * @li Use the close() function to simultaneously cancel the outstanding
+   * operations and close the socket.
+   *
+   * When running on Windows Vista, Windows Server 2008, and later, the
+   * CancelIoEx function is always used. This function does not have the
+   * problems described above.
+   */
+#if defined(ASIO_MSVC) && (ASIO_MSVC >= 1400) \
+  && (!defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0600) \
+  && !defined(ASIO_ENABLE_CANCELIO)
+  __declspec(deprecated("By default, this function always fails with "
+        "operation_not_supported when used on Windows XP, Windows Server 2003, "
+        "or earlier. Consult documentation for details."))
+#endif
+  void cancel()
+  {
+    asio::error_code ec;
+    impl_.get_service().cancel(impl_.get_implementation(), ec);
+    asio::detail::throw_error(ec, "cancel");
+  }
+
+  /// Cancel all asynchronous operations associated with the socket.
+  /**
+   * This function causes all outstanding asynchronous connect, send and receive
+   * operations to finish immediately, and the handlers for cancelled operations
+   * will be passed the asio::error::operation_aborted error.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   *
+   * @note Calls to cancel() will always fail with
+   * asio::error::operation_not_supported when run on Windows XP, Windows
+   * Server 2003, and earlier versions of Windows, unless
+   * ASIO_ENABLE_CANCELIO is defined. However, the CancelIo function has
+   * two issues that should be considered before enabling its use:
+   *
+   * @li It will only cancel asynchronous operations that were initiated in the
+   * current thread.
+   *
+   * @li It can appear to complete without error, but the request to cancel the
+   * unfinished operations may be silently ignored by the operating system.
+   * Whether it works or not seems to depend on the drivers that are installed.
+   *
+   * For portable cancellation, consider using one of the following
+   * alternatives:
+   *
+   * @li Disable asio's I/O completion port backend by defining
+   * ASIO_DISABLE_IOCP.
+   *
+   * @li Use the close() function to simultaneously cancel the outstanding
+   * operations and close the socket.
+   *
+   * When running on Windows Vista, Windows Server 2008, and later, the
+   * CancelIoEx function is always used. This function does not have the
+   * problems described above.
+   */
+#if defined(ASIO_MSVC) && (ASIO_MSVC >= 1400) \
+  && (!defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0600) \
+  && !defined(ASIO_ENABLE_CANCELIO)
+  __declspec(deprecated("By default, this function always fails with "
+        "operation_not_supported when used on Windows XP, Windows Server 2003, "
+        "or earlier. Consult documentation for details."))
+#endif
+  ASIO_SYNC_OP_VOID cancel(asio::error_code& ec)
+  {
+    impl_.get_service().cancel(impl_.get_implementation(), ec);
+    ASIO_SYNC_OP_VOID_RETURN(ec);
+  }
+
+  /// Determine whether the socket is at the out-of-band data mark.
+  /**
+   * This function is used to check whether the socket input is currently
+   * positioned at the out-of-band data mark.
+   *
+   * @return A bool indicating whether the socket is at the out-of-band data
+   * mark.
+   *
+   * @throws asio::system_error Thrown on failure.
+   */
+  bool at_mark() const
+  {
+    asio::error_code ec;
+    bool b = impl_.get_service().at_mark(impl_.get_implementation(), ec);
+    asio::detail::throw_error(ec, "at_mark");
+    return b;
+  }
+
+  /// Determine whether the socket is at the out-of-band data mark.
+  /**
+   * This function is used to check whether the socket input is currently
+   * positioned at the out-of-band data mark.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   *
+   * @return A bool indicating whether the socket is at the out-of-band data
+   * mark.
+   */
+  bool at_mark(asio::error_code& ec) const
+  {
+    return impl_.get_service().at_mark(impl_.get_implementation(), ec);
+  }
+
+  /// Determine the number of bytes available for reading.
+  /**
+   * This function is used to determine the number of bytes that may be read
+   * without blocking.
+   *
+   * @return The number of bytes that may be read without blocking, or 0 if an
+   * error occurs.
+   *
+   * @throws asio::system_error Thrown on failure.
+   */
+  std::size_t available() const
+  {
+    asio::error_code ec;
+    std::size_t s = impl_.get_service().available(
+        impl_.get_implementation(), ec);
+    asio::detail::throw_error(ec, "available");
+    return s;
+  }
+
+  /// Determine the number of bytes available for reading.
+  /**
+   * This function is used to determine the number of bytes that may be read
+   * without blocking.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   *
+   * @return The number of bytes that may be read without blocking, or 0 if an
+   * error occurs.
+   */
+  std::size_t available(asio::error_code& ec) const
+  {
+    return impl_.get_service().available(impl_.get_implementation(), ec);
+  }
+
+  /// Bind the socket to the given local endpoint.
+  /**
+   * This function binds the socket to the specified endpoint on the local
+   * machine.
+   *
+   * @param endpoint An endpoint on the local machine to which the socket will
+   * be bound.
+   *
+   * @throws asio::system_error Thrown on failure.
+   *
+   * @par Example
+   * @code
+   * asio::ip::tcp::socket socket(my_context);
+   * socket.open(asio::ip::tcp::v4());
+   * socket.bind(asio::ip::tcp::endpoint(
+   *       asio::ip::tcp::v4(), 12345));
+   * @endcode
+   */
+  void bind(const endpoint_type& endpoint)
+  {
+    asio::error_code ec;
+    impl_.get_service().bind(impl_.get_implementation(), endpoint, ec);
+    asio::detail::throw_error(ec, "bind");
+  }
+
+  /// Bind the socket to the given local endpoint.
+  /**
+   * This function binds the socket to the specified endpoint on the local
+   * machine.
+   *
+   * @param endpoint An endpoint on the local machine to which the socket will
+   * be bound.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   *
+   * @par Example
+   * @code
+   * asio::ip::tcp::socket socket(my_context);
+   * socket.open(asio::ip::tcp::v4());
+   * asio::error_code ec;
+   * socket.bind(asio::ip::tcp::endpoint(
+   *       asio::ip::tcp::v4(), 12345), ec);
+   * if (ec)
+   * {
+   *   // An error occurred.
+   * }
+   * @endcode
+   */
+  ASIO_SYNC_OP_VOID bind(const endpoint_type& endpoint,
+      asio::error_code& ec)
+  {
+    impl_.get_service().bind(impl_.get_implementation(), endpoint, ec);
+    ASIO_SYNC_OP_VOID_RETURN(ec);
+  }
+
+  /// Connect the socket to the specified endpoint.
+  /**
+   * This function is used to connect a socket to the specified remote endpoint.
+   * The function call will block until the connection is successfully made or
+   * an error occurs.
+   *
+   * The socket is automatically opened if it is not already open. If the
+   * connect fails, and the socket was automatically opened, the socket is
+   * not returned to the closed state.
+   *
+   * @param peer_endpoint The remote endpoint to which the socket will be
+   * connected.
+   *
+   * @throws asio::system_error Thrown on failure.
+   *
+   * @par Example
+   * @code
+   * asio::ip::tcp::socket socket(my_context);
+   * asio::ip::tcp::endpoint endpoint(
+   *     asio::ip::address::from_string("1.2.3.4"), 12345);
+   * socket.connect(endpoint);
+   * @endcode
+   */
+  void connect(const endpoint_type& peer_endpoint)
+  {
+    asio::error_code ec;
+    if (!is_open())
+    {
+      impl_.get_service().open(impl_.get_implementation(),
+          peer_endpoint.protocol(), ec);
+      asio::detail::throw_error(ec, "connect");
+    }
+    impl_.get_service().connect(impl_.get_implementation(), peer_endpoint, ec);
+    asio::detail::throw_error(ec, "connect");
+  }
+
+  /// Connect the socket to the specified endpoint.
+  /**
+   * This function is used to connect a socket to the specified remote endpoint.
+   * The function call will block until the connection is successfully made or
+   * an error occurs.
+   *
+   * The socket is automatically opened if it is not already open. If the
+   * connect fails, and the socket was automatically opened, the socket is
+   * not returned to the closed state.
+   *
+   * @param peer_endpoint The remote endpoint to which the socket will be
+   * connected.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   *
+   * @par Example
+   * @code
+   * asio::ip::tcp::socket socket(my_context);
+   * asio::ip::tcp::endpoint endpoint(
+   *     asio::ip::address::from_string("1.2.3.4"), 12345);
+   * asio::error_code ec;
+   * socket.connect(endpoint, ec);
+   * if (ec)
+   * {
+   *   // An error occurred.
+   * }
+   * @endcode
+   */
+  ASIO_SYNC_OP_VOID connect(const endpoint_type& peer_endpoint,
+      asio::error_code& ec)
+  {
+    if (!is_open())
+    {
+      impl_.get_service().open(impl_.get_implementation(),
+            peer_endpoint.protocol(), ec);
+      if (ec)
+      {
+        ASIO_SYNC_OP_VOID_RETURN(ec);
+      }
+    }
+
+    impl_.get_service().connect(impl_.get_implementation(), peer_endpoint, ec);
+    ASIO_SYNC_OP_VOID_RETURN(ec);
+  }
+
+  /// Start an asynchronous connect.
+  /**
+   * This function is used to asynchronously connect a socket to the specified
+   * remote endpoint. The function call always returns immediately.
+   *
+   * The socket is automatically opened if it is not already open. If the
+   * connect fails, and the socket was automatically opened, the socket is
+   * not returned to the closed state.
+   *
+   * @param peer_endpoint The remote endpoint to which the socket will be
+   * connected. Copies will be made of the endpoint object as required.
+   *
+   * @param handler The handler to be called when the connection operation
+   * completes. Copies will be made of the handler as required. The function
+   * signature of the handler must be:
+   * @code void handler(
+   *   const asio::error_code& error // Result of operation
+   * ); @endcode
+   * Regardless of whether the asynchronous operation completes immediately or
+   * not, the handler will not be invoked from within this function. On
+   * immediate completion, invocation of the handler will be performed in a
+   * manner equivalent to using asio::post().
+   *
+   * @par Example
+   * @code
+   * void connect_handler(const asio::error_code& error)
+   * {
+   *   if (!error)
+   *   {
+   *     // Connect succeeded.
+   *   }
+   * }
+   *
+   * ...
+   *
+   * asio::ip::tcp::socket socket(my_context);
+   * asio::ip::tcp::endpoint endpoint(
+   *     asio::ip::address::from_string("1.2.3.4"), 12345);
+   * socket.async_connect(endpoint, connect_handler);
+   * @endcode
+   */
+  template <
+      ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code))
+        ConnectHandler ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
+  ASIO_INITFN_AUTO_RESULT_TYPE(ConnectHandler,
+      void (asio::error_code))
+  async_connect(const endpoint_type& peer_endpoint,
+      ASIO_MOVE_ARG(ConnectHandler) handler
+        ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
+  {
+    asio::error_code open_ec;
+    if (!is_open())
+    {
+      const protocol_type protocol = peer_endpoint.protocol();
+      impl_.get_service().open(impl_.get_implementation(), protocol, open_ec);
+    }
+
+    return async_initiate<ConnectHandler, void (asio::error_code)>(
+        initiate_async_connect(this), handler, peer_endpoint, open_ec);
+  }
+
+  /// Set an option on the socket.
+  /**
+   * This function is used to set an option on the socket.
+   *
+   * @param option The new option value to be set on the socket.
+   *
+   * @throws asio::system_error Thrown on failure.
+   *
+   * @sa SettableSocketOption @n
+   * asio::socket_base::broadcast @n
+   * asio::socket_base::do_not_route @n
+   * asio::socket_base::keep_alive @n
+   * asio::socket_base::linger @n
+   * asio::socket_base::receive_buffer_size @n
+   * asio::socket_base::receive_low_watermark @n
+   * asio::socket_base::reuse_address @n
+   * asio::socket_base::send_buffer_size @n
+   * asio::socket_base::send_low_watermark @n
+   * asio::ip::multicast::join_group @n
+   * asio::ip::multicast::leave_group @n
+   * asio::ip::multicast::enable_loopback @n
+   * asio::ip::multicast::outbound_interface @n
+   * asio::ip::multicast::hops @n
+   * asio::ip::tcp::no_delay
+   *
+   * @par Example
+   * Setting the IPPROTO_TCP/TCP_NODELAY option:
+   * @code
+   * asio::ip::tcp::socket socket(my_context);
+   * ...
+   * asio::ip::tcp::no_delay option(true);
+   * socket.set_option(option);
+   * @endcode
+   */
+  template <typename SettableSocketOption>
+  void set_option(const SettableSocketOption& option)
+  {
+    asio::error_code ec;
+    impl_.get_service().set_option(impl_.get_implementation(), option, ec);
+    asio::detail::throw_error(ec, "set_option");
+  }
+
+  /// Set an option on the socket.
+  /**
+   * This function is used to set an option on the socket.
+   *
+   * @param option The new option value to be set on the socket.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   *
+   * @sa SettableSocketOption @n
+   * asio::socket_base::broadcast @n
+   * asio::socket_base::do_not_route @n
+   * asio::socket_base::keep_alive @n
+   * asio::socket_base::linger @n
+   * asio::socket_base::receive_buffer_size @n
+   * asio::socket_base::receive_low_watermark @n
+   * asio::socket_base::reuse_address @n
+   * asio::socket_base::send_buffer_size @n
+   * asio::socket_base::send_low_watermark @n
+   * asio::ip::multicast::join_group @n
+   * asio::ip::multicast::leave_group @n
+   * asio::ip::multicast::enable_loopback @n
+   * asio::ip::multicast::outbound_interface @n
+   * asio::ip::multicast::hops @n
+   * asio::ip::tcp::no_delay
+   *
+   * @par Example
+   * Setting the IPPROTO_TCP/TCP_NODELAY option:
+   * @code
+   * asio::ip::tcp::socket socket(my_context);
+   * ...
+   * asio::ip::tcp::no_delay option(true);
+   * asio::error_code ec;
+   * socket.set_option(option, ec);
+   * if (ec)
+   * {
+   *   // An error occurred.
+   * }
+   * @endcode
+   */
+  template <typename SettableSocketOption>
+  ASIO_SYNC_OP_VOID set_option(const SettableSocketOption& option,
+      asio::error_code& ec)
+  {
+    impl_.get_service().set_option(impl_.get_implementation(), option, ec);
+    ASIO_SYNC_OP_VOID_RETURN(ec);
+  }
+
+  /// Get an option from the socket.
+  /**
+   * This function is used to get the current value of an option on the socket.
+   *
+   * @param option The option value to be obtained from the socket.
+   *
+   * @throws asio::system_error Thrown on failure.
+   *
+   * @sa GettableSocketOption @n
+   * asio::socket_base::broadcast @n
+   * asio::socket_base::do_not_route @n
+   * asio::socket_base::keep_alive @n
+   * asio::socket_base::linger @n
+   * asio::socket_base::receive_buffer_size @n
+   * asio::socket_base::receive_low_watermark @n
+   * asio::socket_base::reuse_address @n
+   * asio::socket_base::send_buffer_size @n
+   * asio::socket_base::send_low_watermark @n
+   * asio::ip::multicast::join_group @n
+   * asio::ip::multicast::leave_group @n
+   * asio::ip::multicast::enable_loopback @n
+   * asio::ip::multicast::outbound_interface @n
+   * asio::ip::multicast::hops @n
+   * asio::ip::tcp::no_delay
+   *
+   * @par Example
+   * Getting the value of the SOL_SOCKET/SO_KEEPALIVE option:
+   * @code
+   * asio::ip::tcp::socket socket(my_context);
+   * ...
+   * asio::ip::tcp::socket::keep_alive option;
+   * socket.get_option(option);
+   * bool is_set = option.value();
+   * @endcode
+   */
+  template <typename GettableSocketOption>
+  void get_option(GettableSocketOption& option) const
+  {
+    asio::error_code ec;
+    impl_.get_service().get_option(impl_.get_implementation(), option, ec);
+    asio::detail::throw_error(ec, "get_option");
+  }
+
+  /// Get an option from the socket.
+  /**
+   * This function is used to get the current value of an option on the socket.
+   *
+   * @param option The option value to be obtained from the socket.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   *
+   * @sa GettableSocketOption @n
+   * asio::socket_base::broadcast @n
+   * asio::socket_base::do_not_route @n
+   * asio::socket_base::keep_alive @n
+   * asio::socket_base::linger @n
+   * asio::socket_base::receive_buffer_size @n
+   * asio::socket_base::receive_low_watermark @n
+   * asio::socket_base::reuse_address @n
+   * asio::socket_base::send_buffer_size @n
+   * asio::socket_base::send_low_watermark @n
+   * asio::ip::multicast::join_group @n
+   * asio::ip::multicast::leave_group @n
+   * asio::ip::multicast::enable_loopback @n
+   * asio::ip::multicast::outbound_interface @n
+   * asio::ip::multicast::hops @n
+   * asio::ip::tcp::no_delay
+   *
+   * @par Example
+   * Getting the value of the SOL_SOCKET/SO_KEEPALIVE option:
+   * @code
+   * asio::ip::tcp::socket socket(my_context);
+   * ...
+   * asio::ip::tcp::socket::keep_alive option;
+   * asio::error_code ec;
+   * socket.get_option(option, ec);
+   * if (ec)
+   * {
+   *   // An error occurred.
+   * }
+   * bool is_set = option.value();
+   * @endcode
+   */
+  template <typename GettableSocketOption>
+  ASIO_SYNC_OP_VOID get_option(GettableSocketOption& option,
+      asio::error_code& ec) const
+  {
+    impl_.get_service().get_option(impl_.get_implementation(), option, ec);
+    ASIO_SYNC_OP_VOID_RETURN(ec);
+  }
+
+  /// Perform an IO control command on the socket.
+  /**
+   * This function is used to execute an IO control command on the socket.
+   *
+   * @param command The IO control command to be performed on the socket.
+   *
+   * @throws asio::system_error Thrown on failure.
+   *
+   * @sa IoControlCommand @n
+   * asio::socket_base::bytes_readable @n
+   * asio::socket_base::non_blocking_io
+   *
+   * @par Example
+   * Getting the number of bytes ready to read:
+   * @code
+   * asio::ip::tcp::socket socket(my_context);
+   * ...
+   * asio::ip::tcp::socket::bytes_readable command;
+   * socket.io_control(command);
+   * std::size_t bytes_readable = command.get();
+   * @endcode
+   */
+  template <typename IoControlCommand>
+  void io_control(IoControlCommand& command)
+  {
+    asio::error_code ec;
+    impl_.get_service().io_control(impl_.get_implementation(), command, ec);
+    asio::detail::throw_error(ec, "io_control");
+  }
+
+  /// Perform an IO control command on the socket.
+  /**
+   * This function is used to execute an IO control command on the socket.
+   *
+   * @param command The IO control command to be performed on the socket.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   *
+   * @sa IoControlCommand @n
+   * asio::socket_base::bytes_readable @n
+   * asio::socket_base::non_blocking_io
+   *
+   * @par Example
+   * Getting the number of bytes ready to read:
+   * @code
+   * asio::ip::tcp::socket socket(my_context);
+   * ...
+   * asio::ip::tcp::socket::bytes_readable command;
+   * asio::error_code ec;
+   * socket.io_control(command, ec);
+   * if (ec)
+   * {
+   *   // An error occurred.
+   * }
+   * std::size_t bytes_readable = command.get();
+   * @endcode
+   */
+  template <typename IoControlCommand>
+  ASIO_SYNC_OP_VOID io_control(IoControlCommand& command,
+      asio::error_code& ec)
+  {
+    impl_.get_service().io_control(impl_.get_implementation(), command, ec);
+    ASIO_SYNC_OP_VOID_RETURN(ec);
+  }
+
+  /// Gets the non-blocking mode of the socket.
+  /**
+   * @returns @c true if the socket's synchronous operations will fail with
+   * asio::error::would_block if they are unable to perform the requested
+   * operation immediately. If @c false, synchronous operations will block
+   * until complete.
+   *
+   * @note The non-blocking mode has no effect on the behaviour of asynchronous
+   * operations. Asynchronous operations will never fail with the error
+   * asio::error::would_block.
+   */
+  bool non_blocking() const
+  {
+    return impl_.get_service().non_blocking(impl_.get_implementation());
+  }
+
+  /// Sets the non-blocking mode of the socket.
+  /**
+   * @param mode If @c true, the socket's synchronous operations will fail with
+   * asio::error::would_block if they are unable to perform the requested
+   * operation immediately. If @c false, synchronous operations will block
+   * until complete.
+   *
+   * @throws asio::system_error Thrown on failure.
+   *
+   * @note The non-blocking mode has no effect on the behaviour of asynchronous
+   * operations. Asynchronous operations will never fail with the error
+   * asio::error::would_block.
+   */
+  void non_blocking(bool mode)
+  {
+    asio::error_code ec;
+    impl_.get_service().non_blocking(impl_.get_implementation(), mode, ec);
+    asio::detail::throw_error(ec, "non_blocking");
+  }
+
+  /// Sets the non-blocking mode of the socket.
+  /**
+   * @param mode If @c true, the socket's synchronous operations will fail with
+   * asio::error::would_block if they are unable to perform the requested
+   * operation immediately. If @c false, synchronous operations will block
+   * until complete.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   *
+   * @note The non-blocking mode has no effect on the behaviour of asynchronous
+   * operations. Asynchronous operations will never fail with the error
+   * asio::error::would_block.
+   */
+  ASIO_SYNC_OP_VOID non_blocking(
+      bool mode, asio::error_code& ec)
+  {
+    impl_.get_service().non_blocking(impl_.get_implementation(), mode, ec);
+    ASIO_SYNC_OP_VOID_RETURN(ec);
+  }
+
+  /// Gets the non-blocking mode of the native socket implementation.
+  /**
+   * This function is used to retrieve the non-blocking mode of the underlying
+   * native socket. This mode has no effect on the behaviour of the socket
+   * object's synchronous operations.
+   *
+   * @returns @c true if the underlying socket is in non-blocking mode and
+   * direct system calls may fail with asio::error::would_block (or the
+   * equivalent system error).
+   *
+   * @note The current non-blocking mode is cached by the socket object.
+   * Consequently, the return value may be incorrect if the non-blocking mode
+   * was set directly on the native socket.
+   *
+   * @par Example
+   * This function is intended to allow the encapsulation of arbitrary
+   * non-blocking system calls as asynchronous operations, in a way that is
+   * transparent to the user of the socket object. The following example
+   * illustrates how Linux's @c sendfile system call might be encapsulated:
+   * @code template <typename Handler>
+   * struct sendfile_op
+   * {
+   *   tcp::socket& sock_;
+   *   int fd_;
+   *   Handler handler_;
+   *   off_t offset_;
+   *   std::size_t total_bytes_transferred_;
+   *
+   *   // Function call operator meeting WriteHandler requirements.
+   *   // Used as the handler for the async_write_some operation.
+   *   void operator()(asio::error_code ec, std::size_t)
+   *   {
+   *     // Put the underlying socket into non-blocking mode.
+   *     if (!ec)
+   *       if (!sock_.native_non_blocking())
+   *         sock_.native_non_blocking(true, ec);
+   *
+   *     if (!ec)
+   *     {
+   *       for (;;)
+   *       {
+   *         // Try the system call.
+   *         errno = 0;
+   *         int n = ::sendfile(sock_.native_handle(), fd_, &offset_, 65536);
+   *         ec = asio::error_code(n < 0 ? errno : 0,
+   *             asio::error::get_system_category());
+   *         total_bytes_transferred_ += ec ? 0 : n;
+   *
+   *         // Retry operation immediately if interrupted by signal.
+   *         if (ec == asio::error::interrupted)
+   *           continue;
+   *
+   *         // Check if we need to run the operation again.
+   *         if (ec == asio::error::would_block
+   *             || ec == asio::error::try_again)
+   *         {
+   *           // We have to wait for the socket to become ready again.
+   *           sock_.async_wait(tcp::socket::wait_write, *this);
+   *           return;
+   *         }
+   *
+   *         if (ec || n == 0)
+   *         {
+   *           // An error occurred, or we have reached the end of the file.
+   *           // Either way we must exit the loop so we can call the handler.
+   *           break;
+   *         }
+   *
+   *         // Loop around to try calling sendfile again.
+   *       }
+   *     }
+   *
+   *     // Pass result back to user's handler.
+   *     handler_(ec, total_bytes_transferred_);
+   *   }
+   * };
+   *
+   * template <typename Handler>
+   * void async_sendfile(tcp::socket& sock, int fd, Handler h)
+   * {
+   *   sendfile_op<Handler> op = { sock, fd, h, 0, 0 };
+   *   sock.async_wait(tcp::socket::wait_write, op);
+   * } @endcode
+   */
+  bool native_non_blocking() const
+  {
+    return impl_.get_service().native_non_blocking(impl_.get_implementation());
+  }
+
+  /// Sets the non-blocking mode of the native socket implementation.
+  /**
+   * This function is used to modify the non-blocking mode of the underlying
+   * native socket. It has no effect on the behaviour of the socket object's
+   * synchronous operations.
+   *
+   * @param mode If @c true, the underlying socket is put into non-blocking
+   * mode and direct system calls may fail with asio::error::would_block
+   * (or the equivalent system error).
+   *
+   * @throws asio::system_error Thrown on failure. If the @c mode is
+   * @c false, but the current value of @c non_blocking() is @c true, this
+   * function fails with asio::error::invalid_argument, as the
+   * combination does not make sense.
+   *
+   * @par Example
+   * This function is intended to allow the encapsulation of arbitrary
+   * non-blocking system calls as asynchronous operations, in a way that is
+   * transparent to the user of the socket object. The following example
+   * illustrates how Linux's @c sendfile system call might be encapsulated:
+   * @code template <typename Handler>
+   * struct sendfile_op
+   * {
+   *   tcp::socket& sock_;
+   *   int fd_;
+   *   Handler handler_;
+   *   off_t offset_;
+   *   std::size_t total_bytes_transferred_;
+   *
+   *   // Function call operator meeting WriteHandler requirements.
+   *   // Used as the handler for the async_write_some operation.
+   *   void operator()(asio::error_code ec, std::size_t)
+   *   {
+   *     // Put the underlying socket into non-blocking mode.
+   *     if (!ec)
+   *       if (!sock_.native_non_blocking())
+   *         sock_.native_non_blocking(true, ec);
+   *
+   *     if (!ec)
+   *     {
+   *       for (;;)
+   *       {
+   *         // Try the system call.
+   *         errno = 0;
+   *         int n = ::sendfile(sock_.native_handle(), fd_, &offset_, 65536);
+   *         ec = asio::error_code(n < 0 ? errno : 0,
+   *             asio::error::get_system_category());
+   *         total_bytes_transferred_ += ec ? 0 : n;
+   *
+   *         // Retry operation immediately if interrupted by signal.
+   *         if (ec == asio::error::interrupted)
+   *           continue;
+   *
+   *         // Check if we need to run the operation again.
+   *         if (ec == asio::error::would_block
+   *             || ec == asio::error::try_again)
+   *         {
+   *           // We have to wait for the socket to become ready again.
+   *           sock_.async_wait(tcp::socket::wait_write, *this);
+   *           return;
+   *         }
+   *
+   *         if (ec || n == 0)
+   *         {
+   *           // An error occurred, or we have reached the end of the file.
+   *           // Either way we must exit the loop so we can call the handler.
+   *           break;
+   *         }
+   *
+   *         // Loop around to try calling sendfile again.
+   *       }
+   *     }
+   *
+   *     // Pass result back to user's handler.
+   *     handler_(ec, total_bytes_transferred_);
+   *   }
+   * };
+   *
+   * template <typename Handler>
+   * void async_sendfile(tcp::socket& sock, int fd, Handler h)
+   * {
+   *   sendfile_op<Handler> op = { sock, fd, h, 0, 0 };
+   *   sock.async_wait(tcp::socket::wait_write, op);
+   * } @endcode
+   */
+  void native_non_blocking(bool mode)
+  {
+    asio::error_code ec;
+    impl_.get_service().native_non_blocking(
+        impl_.get_implementation(), mode, ec);
+    asio::detail::throw_error(ec, "native_non_blocking");
+  }
+
+  /// Sets the non-blocking mode of the native socket implementation.
+  /**
+   * This function is used to modify the non-blocking mode of the underlying
+   * native socket. It has no effect on the behaviour of the socket object's
+   * synchronous operations.
+   *
+   * @param mode If @c true, the underlying socket is put into non-blocking
+   * mode and direct system calls may fail with asio::error::would_block
+   * (or the equivalent system error).
+   *
+   * @param ec Set to indicate what error occurred, if any. If the @c mode is
+   * @c false, but the current value of @c non_blocking() is @c true, this
+   * function fails with asio::error::invalid_argument, as the
+   * combination does not make sense.
+   *
+   * @par Example
+   * This function is intended to allow the encapsulation of arbitrary
+   * non-blocking system calls as asynchronous operations, in a way that is
+   * transparent to the user of the socket object. The following example
+   * illustrates how Linux's @c sendfile system call might be encapsulated:
+   * @code template <typename Handler>
+   * struct sendfile_op
+   * {
+   *   tcp::socket& sock_;
+   *   int fd_;
+   *   Handler handler_;
+   *   off_t offset_;
+   *   std::size_t total_bytes_transferred_;
+   *
+   *   // Function call operator meeting WriteHandler requirements.
+   *   // Used as the handler for the async_write_some operation.
+   *   void operator()(asio::error_code ec, std::size_t)
+   *   {
+   *     // Put the underlying socket into non-blocking mode.
+   *     if (!ec)
+   *       if (!sock_.native_non_blocking())
+   *         sock_.native_non_blocking(true, ec);
+   *
+   *     if (!ec)
+   *     {
+   *       for (;;)
+   *       {
+   *         // Try the system call.
+   *         errno = 0;
+   *         int n = ::sendfile(sock_.native_handle(), fd_, &offset_, 65536);
+   *         ec = asio::error_code(n < 0 ? errno : 0,
+   *             asio::error::get_system_category());
+   *         total_bytes_transferred_ += ec ? 0 : n;
+   *
+   *         // Retry operation immediately if interrupted by signal.
+   *         if (ec == asio::error::interrupted)
+   *           continue;
+   *
+   *         // Check if we need to run the operation again.
+   *         if (ec == asio::error::would_block
+   *             || ec == asio::error::try_again)
+   *         {
+   *           // We have to wait for the socket to become ready again.
+   *           sock_.async_wait(tcp::socket::wait_write, *this);
+   *           return;
+   *         }
+   *
+   *         if (ec || n == 0)
+   *         {
+   *           // An error occurred, or we have reached the end of the file.
+   *           // Either way we must exit the loop so we can call the handler.
+   *           break;
+   *         }
+   *
+   *         // Loop around to try calling sendfile again.
+   *       }
+   *     }
+   *
+   *     // Pass result back to user's handler.
+   *     handler_(ec, total_bytes_transferred_);
+   *   }
+   * };
+   *
+   * template <typename Handler>
+   * void async_sendfile(tcp::socket& sock, int fd, Handler h)
+   * {
+   *   sendfile_op<Handler> op = { sock, fd, h, 0, 0 };
+   *   sock.async_wait(tcp::socket::wait_write, op);
+   * } @endcode
+   */
+  ASIO_SYNC_OP_VOID native_non_blocking(
+      bool mode, asio::error_code& ec)
+  {
+    impl_.get_service().native_non_blocking(
+        impl_.get_implementation(), mode, ec);
+    ASIO_SYNC_OP_VOID_RETURN(ec);
+  }
+
+  /// Get the local endpoint of the socket.
+  /**
+   * This function is used to obtain the locally bound endpoint of the socket.
+   *
+   * @returns An object that represents the local endpoint of the socket.
+   *
+   * @throws asio::system_error Thrown on failure.
+   *
+   * @par Example
+   * @code
+   * asio::ip::tcp::socket socket(my_context);
+   * ...
+   * asio::ip::tcp::endpoint endpoint = socket.local_endpoint();
+   * @endcode
+   */
+  endpoint_type local_endpoint() const
+  {
+    asio::error_code ec;
+    endpoint_type ep = impl_.get_service().local_endpoint(
+        impl_.get_implementation(), ec);
+    asio::detail::throw_error(ec, "local_endpoint");
+    return ep;
+  }
+
+  /// Get the local endpoint of the socket.
+  /**
+   * This function is used to obtain the locally bound endpoint of the socket.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   *
+   * @returns An object that represents the local endpoint of the socket.
+   * Returns a default-constructed endpoint object if an error occurred.
+   *
+   * @par Example
+   * @code
+   * asio::ip::tcp::socket socket(my_context);
+   * ...
+   * asio::error_code ec;
+   * asio::ip::tcp::endpoint endpoint = socket.local_endpoint(ec);
+   * if (ec)
+   * {
+   *   // An error occurred.
+   * }
+   * @endcode
+   */
+  endpoint_type local_endpoint(asio::error_code& ec) const
+  {
+    return impl_.get_service().local_endpoint(impl_.get_implementation(), ec);
+  }
+
+  /// Get the remote endpoint of the socket.
+  /**
+   * This function is used to obtain the remote endpoint of the socket.
+   *
+   * @returns An object that represents the remote endpoint of the socket.
+   *
+   * @throws asio::system_error Thrown on failure.
+   *
+   * @par Example
+   * @code
+   * asio::ip::tcp::socket socket(my_context);
+   * ...
+   * asio::ip::tcp::endpoint endpoint = socket.remote_endpoint();
+   * @endcode
+   */
+  endpoint_type remote_endpoint() const
+  {
+    asio::error_code ec;
+    endpoint_type ep = impl_.get_service().remote_endpoint(
+        impl_.get_implementation(), ec);
+    asio::detail::throw_error(ec, "remote_endpoint");
+    return ep;
+  }
+
+  /// Get the remote endpoint of the socket.
+  /**
+   * This function is used to obtain the remote endpoint of the socket.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   *
+   * @returns An object that represents the remote endpoint of the socket.
+   * Returns a default-constructed endpoint object if an error occurred.
+   *
+   * @par Example
+   * @code
+   * asio::ip::tcp::socket socket(my_context);
+   * ...
+   * asio::error_code ec;
+   * asio::ip::tcp::endpoint endpoint = socket.remote_endpoint(ec);
+   * if (ec)
+   * {
+   *   // An error occurred.
+   * }
+   * @endcode
+   */
+  endpoint_type remote_endpoint(asio::error_code& ec) const
+  {
+    return impl_.get_service().remote_endpoint(impl_.get_implementation(), ec);
+  }
+
+  /// Disable sends or receives on the socket.
+  /**
+   * This function is used to disable send operations, receive operations, or
+   * both.
+   *
+   * @param what Determines what types of operation will no longer be allowed.
+   *
+   * @throws asio::system_error Thrown on failure.
+   *
+   * @par Example
+   * Shutting down the send side of the socket:
+   * @code
+   * asio::ip::tcp::socket socket(my_context);
+   * ...
+   * socket.shutdown(asio::ip::tcp::socket::shutdown_send);
+   * @endcode
+   */
+  void shutdown(shutdown_type what)
+  {
+    asio::error_code ec;
+    impl_.get_service().shutdown(impl_.get_implementation(), what, ec);
+    asio::detail::throw_error(ec, "shutdown");
+  }
+
+  /// Disable sends or receives on the socket.
+  /**
+   * This function is used to disable send operations, receive operations, or
+   * both.
+   *
+   * @param what Determines what types of operation will no longer be allowed.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   *
+   * @par Example
+   * Shutting down the send side of the socket:
+   * @code
+   * asio::ip::tcp::socket socket(my_context);
+   * ...
+   * asio::error_code ec;
+   * socket.shutdown(asio::ip::tcp::socket::shutdown_send, ec);
+   * if (ec)
+   * {
+   *   // An error occurred.
+   * }
+   * @endcode
+   */
+  ASIO_SYNC_OP_VOID shutdown(shutdown_type what,
+      asio::error_code& ec)
+  {
+    impl_.get_service().shutdown(impl_.get_implementation(), what, ec);
+    ASIO_SYNC_OP_VOID_RETURN(ec);
+  }
+
+  /// Wait for the socket to become ready to read, ready to write, or to have
+  /// pending error conditions.
+  /**
+   * This function is used to perform a blocking wait for a socket to enter
+   * a ready to read, write or error condition state.
+   *
+   * @param w Specifies the desired socket state.
+   *
+   * @par Example
+   * Waiting for a socket to become readable.
+   * @code
+   * asio::ip::tcp::socket socket(my_context);
+   * ...
+   * socket.wait(asio::ip::tcp::socket::wait_read);
+   * @endcode
+   */
+  void wait(wait_type w)
+  {
+    asio::error_code ec;
+    impl_.get_service().wait(impl_.get_implementation(), w, ec);
+    asio::detail::throw_error(ec, "wait");
+  }
+
+  /// Wait for the socket to become ready to read, ready to write, or to have
+  /// pending error conditions.
+  /**
+   * This function is used to perform a blocking wait for a socket to enter
+   * a ready to read, write or error condition state.
+   *
+   * @param w Specifies the desired socket state.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   *
+   * @par Example
+   * Waiting for a socket to become readable.
+   * @code
+   * asio::ip::tcp::socket socket(my_context);
+   * ...
+   * asio::error_code ec;
+   * socket.wait(asio::ip::tcp::socket::wait_read, ec);
+   * @endcode
+   */
+  ASIO_SYNC_OP_VOID wait(wait_type w, asio::error_code& ec)
+  {
+    impl_.get_service().wait(impl_.get_implementation(), w, ec);
+    ASIO_SYNC_OP_VOID_RETURN(ec);
+  }
+
+  /// Asynchronously wait for the socket to become ready to read, ready to
+  /// write, or to have pending error conditions.
+  /**
+   * This function is used to perform an asynchronous wait for a socket to enter
+   * a ready to read, write or error condition state.
+   *
+   * @param w Specifies the desired socket state.
+   *
+   * @param handler The handler to be called when the wait operation completes.
+   * Copies will be made of the handler as required. The function signature of
+   * the handler must be:
+   * @code void handler(
+   *   const asio::error_code& error // Result of operation
+   * ); @endcode
+   * Regardless of whether the asynchronous operation completes immediately or
+   * not, the handler will not be invoked from within this function. On
+   * immediate completion, invocation of the handler will be performed in a
+   * manner equivalent to using asio::post().
+   *
+   * @par Example
+   * @code
+   * void wait_handler(const asio::error_code& error)
+   * {
+   *   if (!error)
+   *   {
+   *     // Wait succeeded.
+   *   }
+   * }
+   *
+   * ...
+   *
+   * asio::ip::tcp::socket socket(my_context);
+   * ...
+   * socket.async_wait(asio::ip::tcp::socket::wait_read, wait_handler);
+   * @endcode
+   */
+  template <
+      ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code))
+        WaitHandler ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
+  ASIO_INITFN_AUTO_RESULT_TYPE(WaitHandler,
+      void (asio::error_code))
+  async_wait(wait_type w,
+      ASIO_MOVE_ARG(WaitHandler) handler
+        ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
+  {
+    return async_initiate<WaitHandler, void (asio::error_code)>(
+        initiate_async_wait(this), handler, w);
+  }
+
+protected:
+  /// Protected destructor to prevent deletion through this type.
+  /**
+   * This function destroys the socket, cancelling any outstanding asynchronous
+   * operations associated with the socket as if by calling @c cancel.
+   */
+  ~basic_socket()
+  {
+  }
+
+#if defined(ASIO_WINDOWS_RUNTIME)
+  detail::io_object_impl<
+    detail::null_socket_service<Protocol>, Executor> impl_;
+#elif defined(ASIO_HAS_IOCP)
+  detail::io_object_impl<
+    detail::win_iocp_socket_service<Protocol>, Executor> impl_;
+#else
+  detail::io_object_impl<
+    detail::reactive_socket_service<Protocol>, Executor> impl_;
+#endif
+
+private:
+  // Disallow copying and assignment.
+  basic_socket(const basic_socket&) ASIO_DELETED;
+  basic_socket& operator=(const basic_socket&) ASIO_DELETED;
+
+  class initiate_async_connect
+  {
+  public:
+    typedef Executor executor_type;
+
+    explicit initiate_async_connect(basic_socket* self)
+      : self_(self)
+    {
+    }
+
+    executor_type get_executor() const ASIO_NOEXCEPT
+    {
+      return self_->get_executor();
+    }
+
+    template <typename ConnectHandler>
+    void operator()(ASIO_MOVE_ARG(ConnectHandler) handler,
+        const endpoint_type& peer_endpoint,
+        const asio::error_code& open_ec) const
+    {
+      // If you get an error on the following line it means that your handler
+      // does not meet the documented type requirements for a ConnectHandler.
+      ASIO_CONNECT_HANDLER_CHECK(ConnectHandler, handler) type_check;
+
+      if (open_ec)
+      {
+          asio::post(self_->impl_.get_executor(),
+              asio::detail::bind_handler(
+                ASIO_MOVE_CAST(ConnectHandler)(handler), open_ec));
+      }
+      else
+      {
+        detail::non_const_lvalue<ConnectHandler> handler2(handler);
+        self_->impl_.get_service().async_connect(
+            self_->impl_.get_implementation(), peer_endpoint,
+            handler2.value, self_->impl_.get_executor());
+      }
+    }
+
+  private:
+    basic_socket* self_;
+  };
+
+  class initiate_async_wait
+  {
+  public:
+    typedef Executor executor_type;
+
+    explicit initiate_async_wait(basic_socket* self)
+      : self_(self)
+    {
+    }
+
+    executor_type get_executor() const ASIO_NOEXCEPT
+    {
+      return self_->get_executor();
+    }
+
+    template <typename WaitHandler>
+    void operator()(ASIO_MOVE_ARG(WaitHandler) handler, wait_type w) const
+    {
+      // If you get an error on the following line it means that your handler
+      // does not meet the documented type requirements for a WaitHandler.
+      ASIO_WAIT_HANDLER_CHECK(WaitHandler, handler) type_check;
+
+      detail::non_const_lvalue<WaitHandler> handler2(handler);
+      self_->impl_.get_service().async_wait(
+          self_->impl_.get_implementation(), w,
+          handler2.value, self_->impl_.get_executor());
+    }
+
+  private:
+    basic_socket* self_;
+  };
+};
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_BASIC_SOCKET_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/basic_socket_acceptor.hpp b/link/modules/asio-standalone/asio/include/asio/basic_socket_acceptor.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/basic_socket_acceptor.hpp
@@ -0,0 +1,2501 @@
+//
+// basic_socket_acceptor.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_BASIC_SOCKET_ACCEPTOR_HPP
+#define ASIO_BASIC_SOCKET_ACCEPTOR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/any_io_executor.hpp"
+#include "asio/basic_socket.hpp"
+#include "asio/detail/handler_type_requirements.hpp"
+#include "asio/detail/io_object_impl.hpp"
+#include "asio/detail/non_const_lvalue.hpp"
+#include "asio/detail/throw_error.hpp"
+#include "asio/detail/type_traits.hpp"
+#include "asio/error.hpp"
+#include "asio/execution_context.hpp"
+#include "asio/socket_base.hpp"
+
+#if defined(ASIO_WINDOWS_RUNTIME)
+# include "asio/detail/null_socket_service.hpp"
+#elif defined(ASIO_HAS_IOCP)
+# include "asio/detail/win_iocp_socket_service.hpp"
+#else
+# include "asio/detail/reactive_socket_service.hpp"
+#endif
+
+#if defined(ASIO_HAS_MOVE)
+# include <utility>
+#endif // defined(ASIO_HAS_MOVE)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+#if !defined(ASIO_BASIC_SOCKET_ACCEPTOR_FWD_DECL)
+#define ASIO_BASIC_SOCKET_ACCEPTOR_FWD_DECL
+
+// Forward declaration with defaulted arguments.
+template <typename Protocol, typename Executor = any_io_executor>
+class basic_socket_acceptor;
+
+#endif // !defined(ASIO_BASIC_SOCKET_ACCEPTOR_FWD_DECL)
+
+/// Provides the ability to accept new connections.
+/**
+ * The basic_socket_acceptor class template is used for accepting new socket
+ * connections.
+ *
+ * @par Thread Safety
+ * @e Distinct @e objects: Safe.@n
+ * @e Shared @e objects: Unsafe.
+ *
+ * @par Example
+ * Opening a socket acceptor with the SO_REUSEADDR option enabled:
+ * @code
+ * asio::ip::tcp::acceptor acceptor(my_context);
+ * asio::ip::tcp::endpoint endpoint(asio::ip::tcp::v4(), port);
+ * acceptor.open(endpoint.protocol());
+ * acceptor.set_option(asio::ip::tcp::acceptor::reuse_address(true));
+ * acceptor.bind(endpoint);
+ * acceptor.listen();
+ * @endcode
+ */
+template <typename Protocol, typename Executor>
+class basic_socket_acceptor
+  : public socket_base
+{
+public:
+  /// The type of the executor associated with the object.
+  typedef Executor executor_type;
+
+  /// Rebinds the acceptor type to another executor.
+  template <typename Executor1>
+  struct rebind_executor
+  {
+    /// The socket type when rebound to the specified executor.
+    typedef basic_socket_acceptor<Protocol, Executor1> other;
+  };
+
+  /// The native representation of an acceptor.
+#if defined(GENERATING_DOCUMENTATION)
+  typedef implementation_defined native_handle_type;
+#elif defined(ASIO_WINDOWS_RUNTIME)
+  typedef typename detail::null_socket_service<
+    Protocol>::native_handle_type native_handle_type;
+#elif defined(ASIO_HAS_IOCP)
+  typedef typename detail::win_iocp_socket_service<
+    Protocol>::native_handle_type native_handle_type;
+#else
+  typedef typename detail::reactive_socket_service<
+    Protocol>::native_handle_type native_handle_type;
+#endif
+
+  /// The protocol type.
+  typedef Protocol protocol_type;
+
+  /// The endpoint type.
+  typedef typename Protocol::endpoint endpoint_type;
+
+  /// Construct an acceptor without opening it.
+  /**
+   * This constructor creates an acceptor without opening it to listen for new
+   * connections. The open() function must be called before the acceptor can
+   * accept new socket connections.
+   *
+   * @param ex The I/O executor that the acceptor will use, by default, to
+   * dispatch handlers for any asynchronous operations performed on the
+   * acceptor.
+   */
+  explicit basic_socket_acceptor(const executor_type& ex)
+    : impl_(ex)
+  {
+  }
+
+  /// Construct an acceptor without opening it.
+  /**
+   * This constructor creates an acceptor without opening it to listen for new
+   * connections. The open() function must be called before the acceptor can
+   * accept new socket connections.
+   *
+   * @param context An execution context which provides the I/O executor that
+   * the acceptor will use, by default, to dispatch handlers for any
+   * asynchronous operations performed on the acceptor.
+   */
+  template <typename ExecutionContext>
+  explicit basic_socket_acceptor(ExecutionContext& context,
+      typename enable_if<
+        is_convertible<ExecutionContext&, execution_context&>::value
+      >::type* = 0)
+    : impl_(context)
+  {
+  }
+
+  /// Construct an open acceptor.
+  /**
+   * This constructor creates an acceptor and automatically opens it.
+   *
+   * @param ex The I/O executor that the acceptor will use, by default, to
+   * dispatch handlers for any asynchronous operations performed on the
+   * acceptor.
+   *
+   * @param protocol An object specifying protocol parameters to be used.
+   *
+   * @throws asio::system_error Thrown on failure.
+   */
+  basic_socket_acceptor(const executor_type& ex, const protocol_type& protocol)
+    : impl_(ex)
+  {
+    asio::error_code ec;
+    impl_.get_service().open(impl_.get_implementation(), protocol, ec);
+    asio::detail::throw_error(ec, "open");
+  }
+
+  /// Construct an open acceptor.
+  /**
+   * This constructor creates an acceptor and automatically opens it.
+   *
+   * @param context An execution context which provides the I/O executor that
+   * the acceptor will use, by default, to dispatch handlers for any
+   * asynchronous operations performed on the acceptor.
+   *
+   * @param protocol An object specifying protocol parameters to be used.
+   *
+   * @throws asio::system_error Thrown on failure.
+   */
+  template <typename ExecutionContext>
+  basic_socket_acceptor(ExecutionContext& context,
+      const protocol_type& protocol,
+      typename enable_if<
+        is_convertible<ExecutionContext&, execution_context&>::value
+      >::type* = 0)
+    : impl_(context)
+  {
+    asio::error_code ec;
+    impl_.get_service().open(impl_.get_implementation(), protocol, ec);
+    asio::detail::throw_error(ec, "open");
+  }
+
+  /// Construct an acceptor opened on the given endpoint.
+  /**
+   * This constructor creates an acceptor and automatically opens it to listen
+   * for new connections on the specified endpoint.
+   *
+   * @param ex The I/O executor that the acceptor will use, by default, to
+   * dispatch handlers for any asynchronous operations performed on the
+   * acceptor.
+   *
+   * @param endpoint An endpoint on the local machine on which the acceptor
+   * will listen for new connections.
+   *
+   * @param reuse_addr Whether the constructor should set the socket option
+   * socket_base::reuse_address.
+   *
+   * @throws asio::system_error Thrown on failure.
+   *
+   * @note This constructor is equivalent to the following code:
+   * @code
+   * basic_socket_acceptor<Protocol> acceptor(my_context);
+   * acceptor.open(endpoint.protocol());
+   * if (reuse_addr)
+   *   acceptor.set_option(socket_base::reuse_address(true));
+   * acceptor.bind(endpoint);
+   * acceptor.listen();
+   * @endcode
+   */
+  basic_socket_acceptor(const executor_type& ex,
+      const endpoint_type& endpoint, bool reuse_addr = true)
+    : impl_(ex)
+  {
+    asio::error_code ec;
+    const protocol_type protocol = endpoint.protocol();
+    impl_.get_service().open(impl_.get_implementation(), protocol, ec);
+    asio::detail::throw_error(ec, "open");
+    if (reuse_addr)
+    {
+      impl_.get_service().set_option(impl_.get_implementation(),
+          socket_base::reuse_address(true), ec);
+      asio::detail::throw_error(ec, "set_option");
+    }
+    impl_.get_service().bind(impl_.get_implementation(), endpoint, ec);
+    asio::detail::throw_error(ec, "bind");
+    impl_.get_service().listen(impl_.get_implementation(),
+        socket_base::max_listen_connections, ec);
+    asio::detail::throw_error(ec, "listen");
+  }
+
+  /// Construct an acceptor opened on the given endpoint.
+  /**
+   * This constructor creates an acceptor and automatically opens it to listen
+   * for new connections on the specified endpoint.
+   *
+   * @param context An execution context which provides the I/O executor that
+   * the acceptor will use, by default, to dispatch handlers for any
+   * asynchronous operations performed on the acceptor.
+   *
+   * @param endpoint An endpoint on the local machine on which the acceptor
+   * will listen for new connections.
+   *
+   * @param reuse_addr Whether the constructor should set the socket option
+   * socket_base::reuse_address.
+   *
+   * @throws asio::system_error Thrown on failure.
+   *
+   * @note This constructor is equivalent to the following code:
+   * @code
+   * basic_socket_acceptor<Protocol> acceptor(my_context);
+   * acceptor.open(endpoint.protocol());
+   * if (reuse_addr)
+   *   acceptor.set_option(socket_base::reuse_address(true));
+   * acceptor.bind(endpoint);
+   * acceptor.listen();
+   * @endcode
+   */
+  template <typename ExecutionContext>
+  basic_socket_acceptor(ExecutionContext& context,
+      const endpoint_type& endpoint, bool reuse_addr = true,
+      typename enable_if<
+        is_convertible<ExecutionContext&, execution_context&>::value
+      >::type* = 0)
+    : impl_(context)
+  {
+    asio::error_code ec;
+    const protocol_type protocol = endpoint.protocol();
+    impl_.get_service().open(impl_.get_implementation(), protocol, ec);
+    asio::detail::throw_error(ec, "open");
+    if (reuse_addr)
+    {
+      impl_.get_service().set_option(impl_.get_implementation(),
+          socket_base::reuse_address(true), ec);
+      asio::detail::throw_error(ec, "set_option");
+    }
+    impl_.get_service().bind(impl_.get_implementation(), endpoint, ec);
+    asio::detail::throw_error(ec, "bind");
+    impl_.get_service().listen(impl_.get_implementation(),
+        socket_base::max_listen_connections, ec);
+    asio::detail::throw_error(ec, "listen");
+  }
+
+  /// Construct a basic_socket_acceptor on an existing native acceptor.
+  /**
+   * This constructor creates an acceptor object to hold an existing native
+   * acceptor.
+   *
+   * @param ex The I/O executor that the acceptor will use, by default, to
+   * dispatch handlers for any asynchronous operations performed on the
+   * acceptor.
+   *
+   * @param protocol An object specifying protocol parameters to be used.
+   *
+   * @param native_acceptor A native acceptor.
+   *
+   * @throws asio::system_error Thrown on failure.
+   */
+  basic_socket_acceptor(const executor_type& ex,
+      const protocol_type& protocol, const native_handle_type& native_acceptor)
+    : impl_(ex)
+  {
+    asio::error_code ec;
+    impl_.get_service().assign(impl_.get_implementation(),
+        protocol, native_acceptor, ec);
+    asio::detail::throw_error(ec, "assign");
+  }
+
+  /// Construct a basic_socket_acceptor on an existing native acceptor.
+  /**
+   * This constructor creates an acceptor object to hold an existing native
+   * acceptor.
+   *
+   * @param context An execution context which provides the I/O executor that
+   * the acceptor will use, by default, to dispatch handlers for any
+   * asynchronous operations performed on the acceptor.
+   *
+   * @param protocol An object specifying protocol parameters to be used.
+   *
+   * @param native_acceptor A native acceptor.
+   *
+   * @throws asio::system_error Thrown on failure.
+   */
+  template <typename ExecutionContext>
+  basic_socket_acceptor(ExecutionContext& context,
+      const protocol_type& protocol, const native_handle_type& native_acceptor,
+      typename enable_if<
+        is_convertible<ExecutionContext&, execution_context&>::value
+      >::type* = 0)
+    : impl_(context)
+  {
+    asio::error_code ec;
+    impl_.get_service().assign(impl_.get_implementation(),
+        protocol, native_acceptor, ec);
+    asio::detail::throw_error(ec, "assign");
+  }
+
+#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+  /// Move-construct a basic_socket_acceptor from another.
+  /**
+   * This constructor moves an acceptor from one object to another.
+   *
+   * @param other The other basic_socket_acceptor object from which the move
+   * will occur.
+   *
+   * @note Following the move, the moved-from object is in the same state as if
+   * constructed using the @c basic_socket_acceptor(const executor_type&)
+   * constructor.
+   */
+  basic_socket_acceptor(basic_socket_acceptor&& other) ASIO_NOEXCEPT
+    : impl_(std::move(other.impl_))
+  {
+  }
+
+  /// Move-assign a basic_socket_acceptor from another.
+  /**
+   * This assignment operator moves an acceptor from one object to another.
+   *
+   * @param other The other basic_socket_acceptor object from which the move
+   * will occur.
+   *
+   * @note Following the move, the moved-from object is in the same state as if
+   * constructed using the @c basic_socket_acceptor(const executor_type&)
+   * constructor.
+   */
+  basic_socket_acceptor& operator=(basic_socket_acceptor&& other)
+  {
+    impl_ = std::move(other.impl_);
+    return *this;
+  }
+
+  // All socket acceptors have access to each other's implementations.
+  template <typename Protocol1, typename Executor1>
+  friend class basic_socket_acceptor;
+
+  /// Move-construct a basic_socket_acceptor from an acceptor of another
+  /// protocol type.
+  /**
+   * This constructor moves an acceptor from one object to another.
+   *
+   * @param other The other basic_socket_acceptor object from which the move
+   * will occur.
+   *
+   * @note Following the move, the moved-from object is in the same state as if
+   * constructed using the @c basic_socket_acceptor(const executor_type&)
+   * constructor.
+   */
+  template <typename Protocol1, typename Executor1>
+  basic_socket_acceptor(basic_socket_acceptor<Protocol1, Executor1>&& other,
+      typename enable_if<
+        is_convertible<Protocol1, Protocol>::value
+          && is_convertible<Executor1, Executor>::value
+      >::type* = 0)
+    : impl_(std::move(other.impl_))
+  {
+  }
+
+  /// Move-assign a basic_socket_acceptor from an acceptor of another protocol
+  /// type.
+  /**
+   * This assignment operator moves an acceptor from one object to another.
+   *
+   * @param other The other basic_socket_acceptor object from which the move
+   * will occur.
+   *
+   * @note Following the move, the moved-from object is in the same state as if
+   * constructed using the @c basic_socket_acceptor(const executor_type&)
+   * constructor.
+   */
+  template <typename Protocol1, typename Executor1>
+  typename enable_if<
+    is_convertible<Protocol1, Protocol>::value
+      && is_convertible<Executor1, Executor>::value,
+    basic_socket_acceptor&
+  >::type operator=(basic_socket_acceptor<Protocol1, Executor1>&& other)
+  {
+    basic_socket_acceptor tmp(std::move(other));
+    impl_ = std::move(tmp.impl_);
+    return *this;
+  }
+#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+
+  /// Destroys the acceptor.
+  /**
+   * This function destroys the acceptor, cancelling any outstanding
+   * asynchronous operations associated with the acceptor as if by calling
+   * @c cancel.
+   */
+  ~basic_socket_acceptor()
+  {
+  }
+
+  /// Get the executor associated with the object.
+  executor_type get_executor() ASIO_NOEXCEPT
+  {
+    return impl_.get_executor();
+  }
+
+  /// Open the acceptor using the specified protocol.
+  /**
+   * This function opens the socket acceptor so that it will use the specified
+   * protocol.
+   *
+   * @param protocol An object specifying which protocol is to be used.
+   *
+   * @throws asio::system_error Thrown on failure.
+   *
+   * @par Example
+   * @code
+   * asio::ip::tcp::acceptor acceptor(my_context);
+   * acceptor.open(asio::ip::tcp::v4());
+   * @endcode
+   */
+  void open(const protocol_type& protocol = protocol_type())
+  {
+    asio::error_code ec;
+    impl_.get_service().open(impl_.get_implementation(), protocol, ec);
+    asio::detail::throw_error(ec, "open");
+  }
+
+  /// Open the acceptor using the specified protocol.
+  /**
+   * This function opens the socket acceptor so that it will use the specified
+   * protocol.
+   *
+   * @param protocol An object specifying which protocol is to be used.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   *
+   * @par Example
+   * @code
+   * asio::ip::tcp::acceptor acceptor(my_context);
+   * asio::error_code ec;
+   * acceptor.open(asio::ip::tcp::v4(), ec);
+   * if (ec)
+   * {
+   *   // An error occurred.
+   * }
+   * @endcode
+   */
+  ASIO_SYNC_OP_VOID open(const protocol_type& protocol,
+      asio::error_code& ec)
+  {
+    impl_.get_service().open(impl_.get_implementation(), protocol, ec);
+    ASIO_SYNC_OP_VOID_RETURN(ec);
+  }
+
+  /// Assigns an existing native acceptor to the acceptor.
+  /*
+   * This function opens the acceptor to hold an existing native acceptor.
+   *
+   * @param protocol An object specifying which protocol is to be used.
+   *
+   * @param native_acceptor A native acceptor.
+   *
+   * @throws asio::system_error Thrown on failure.
+   */
+  void assign(const protocol_type& protocol,
+      const native_handle_type& native_acceptor)
+  {
+    asio::error_code ec;
+    impl_.get_service().assign(impl_.get_implementation(),
+        protocol, native_acceptor, ec);
+    asio::detail::throw_error(ec, "assign");
+  }
+
+  /// Assigns an existing native acceptor to the acceptor.
+  /*
+   * This function opens the acceptor to hold an existing native acceptor.
+   *
+   * @param protocol An object specifying which protocol is to be used.
+   *
+   * @param native_acceptor A native acceptor.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   */
+  ASIO_SYNC_OP_VOID assign(const protocol_type& protocol,
+      const native_handle_type& native_acceptor, asio::error_code& ec)
+  {
+    impl_.get_service().assign(impl_.get_implementation(),
+        protocol, native_acceptor, ec);
+    ASIO_SYNC_OP_VOID_RETURN(ec);
+  }
+
+  /// Determine whether the acceptor is open.
+  bool is_open() const
+  {
+    return impl_.get_service().is_open(impl_.get_implementation());
+  }
+
+  /// Bind the acceptor to the given local endpoint.
+  /**
+   * This function binds the socket acceptor to the specified endpoint on the
+   * local machine.
+   *
+   * @param endpoint An endpoint on the local machine to which the socket
+   * acceptor will be bound.
+   *
+   * @throws asio::system_error Thrown on failure.
+   *
+   * @par Example
+   * @code
+   * asio::ip::tcp::acceptor acceptor(my_context);
+   * asio::ip::tcp::endpoint endpoint(asio::ip::tcp::v4(), 12345);
+   * acceptor.open(endpoint.protocol());
+   * acceptor.bind(endpoint);
+   * @endcode
+   */
+  void bind(const endpoint_type& endpoint)
+  {
+    asio::error_code ec;
+    impl_.get_service().bind(impl_.get_implementation(), endpoint, ec);
+    asio::detail::throw_error(ec, "bind");
+  }
+
+  /// Bind the acceptor to the given local endpoint.
+  /**
+   * This function binds the socket acceptor to the specified endpoint on the
+   * local machine.
+   *
+   * @param endpoint An endpoint on the local machine to which the socket
+   * acceptor will be bound.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   *
+   * @par Example
+   * @code
+   * asio::ip::tcp::acceptor acceptor(my_context);
+   * asio::ip::tcp::endpoint endpoint(asio::ip::tcp::v4(), 12345);
+   * acceptor.open(endpoint.protocol());
+   * asio::error_code ec;
+   * acceptor.bind(endpoint, ec);
+   * if (ec)
+   * {
+   *   // An error occurred.
+   * }
+   * @endcode
+   */
+  ASIO_SYNC_OP_VOID bind(const endpoint_type& endpoint,
+      asio::error_code& ec)
+  {
+    impl_.get_service().bind(impl_.get_implementation(), endpoint, ec);
+    ASIO_SYNC_OP_VOID_RETURN(ec);
+  }
+
+  /// Place the acceptor into the state where it will listen for new
+  /// connections.
+  /**
+   * This function puts the socket acceptor into the state where it may accept
+   * new connections.
+   *
+   * @param backlog The maximum length of the queue of pending connections.
+   *
+   * @throws asio::system_error Thrown on failure.
+   */
+  void listen(int backlog = socket_base::max_listen_connections)
+  {
+    asio::error_code ec;
+    impl_.get_service().listen(impl_.get_implementation(), backlog, ec);
+    asio::detail::throw_error(ec, "listen");
+  }
+
+  /// Place the acceptor into the state where it will listen for new
+  /// connections.
+  /**
+   * This function puts the socket acceptor into the state where it may accept
+   * new connections.
+   *
+   * @param backlog The maximum length of the queue of pending connections.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   *
+   * @par Example
+   * @code
+   * asio::ip::tcp::acceptor acceptor(my_context);
+   * ...
+   * asio::error_code ec;
+   * acceptor.listen(asio::socket_base::max_listen_connections, ec);
+   * if (ec)
+   * {
+   *   // An error occurred.
+   * }
+   * @endcode
+   */
+  ASIO_SYNC_OP_VOID listen(int backlog, asio::error_code& ec)
+  {
+    impl_.get_service().listen(impl_.get_implementation(), backlog, ec);
+    ASIO_SYNC_OP_VOID_RETURN(ec);
+  }
+
+  /// Close the acceptor.
+  /**
+   * This function is used to close the acceptor. Any asynchronous accept
+   * operations will be cancelled immediately.
+   *
+   * A subsequent call to open() is required before the acceptor can again be
+   * used to again perform socket accept operations.
+   *
+   * @throws asio::system_error Thrown on failure.
+   */
+  void close()
+  {
+    asio::error_code ec;
+    impl_.get_service().close(impl_.get_implementation(), ec);
+    asio::detail::throw_error(ec, "close");
+  }
+
+  /// Close the acceptor.
+  /**
+   * This function is used to close the acceptor. Any asynchronous accept
+   * operations will be cancelled immediately.
+   *
+   * A subsequent call to open() is required before the acceptor can again be
+   * used to again perform socket accept operations.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   *
+   * @par Example
+   * @code
+   * asio::ip::tcp::acceptor acceptor(my_context);
+   * ...
+   * asio::error_code ec;
+   * acceptor.close(ec);
+   * if (ec)
+   * {
+   *   // An error occurred.
+   * }
+   * @endcode
+   */
+  ASIO_SYNC_OP_VOID close(asio::error_code& ec)
+  {
+    impl_.get_service().close(impl_.get_implementation(), ec);
+    ASIO_SYNC_OP_VOID_RETURN(ec);
+  }
+
+  /// Release ownership of the underlying native acceptor.
+  /**
+   * This function causes all outstanding asynchronous accept operations to
+   * finish immediately, and the handlers for cancelled operations will be
+   * passed the asio::error::operation_aborted error. Ownership of the
+   * native acceptor is then transferred to the caller.
+   *
+   * @throws asio::system_error Thrown on failure.
+   *
+   * @note This function is unsupported on Windows versions prior to Windows
+   * 8.1, and will fail with asio::error::operation_not_supported on
+   * these platforms.
+   */
+#if defined(ASIO_MSVC) && (ASIO_MSVC >= 1400) \
+  && (!defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0603)
+  __declspec(deprecated("This function always fails with "
+        "operation_not_supported when used on Windows versions "
+        "prior to Windows 8.1."))
+#endif
+  native_handle_type release()
+  {
+    asio::error_code ec;
+    native_handle_type s = impl_.get_service().release(
+        impl_.get_implementation(), ec);
+    asio::detail::throw_error(ec, "release");
+    return s;
+  }
+
+  /// Release ownership of the underlying native acceptor.
+  /**
+   * This function causes all outstanding asynchronous accept operations to
+   * finish immediately, and the handlers for cancelled operations will be
+   * passed the asio::error::operation_aborted error. Ownership of the
+   * native acceptor is then transferred to the caller.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   *
+   * @note This function is unsupported on Windows versions prior to Windows
+   * 8.1, and will fail with asio::error::operation_not_supported on
+   * these platforms.
+   */
+#if defined(ASIO_MSVC) && (ASIO_MSVC >= 1400) \
+  && (!defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0603)
+  __declspec(deprecated("This function always fails with "
+        "operation_not_supported when used on Windows versions "
+        "prior to Windows 8.1."))
+#endif
+  native_handle_type release(asio::error_code& ec)
+  {
+    return impl_.get_service().release(impl_.get_implementation(), ec);
+  }
+
+  /// Get the native acceptor representation.
+  /**
+   * This function may be used to obtain the underlying representation of the
+   * acceptor. This is intended to allow access to native acceptor functionality
+   * that is not otherwise provided.
+   */
+  native_handle_type native_handle()
+  {
+    return impl_.get_service().native_handle(impl_.get_implementation());
+  }
+
+  /// Cancel all asynchronous operations associated with the acceptor.
+  /**
+   * This function causes all outstanding asynchronous connect, send and receive
+   * operations to finish immediately, and the handlers for cancelled operations
+   * will be passed the asio::error::operation_aborted error.
+   *
+   * @throws asio::system_error Thrown on failure.
+   */
+  void cancel()
+  {
+    asio::error_code ec;
+    impl_.get_service().cancel(impl_.get_implementation(), ec);
+    asio::detail::throw_error(ec, "cancel");
+  }
+
+  /// Cancel all asynchronous operations associated with the acceptor.
+  /**
+   * This function causes all outstanding asynchronous connect, send and receive
+   * operations to finish immediately, and the handlers for cancelled operations
+   * will be passed the asio::error::operation_aborted error.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   */
+  ASIO_SYNC_OP_VOID cancel(asio::error_code& ec)
+  {
+    impl_.get_service().cancel(impl_.get_implementation(), ec);
+    ASIO_SYNC_OP_VOID_RETURN(ec);
+  }
+
+  /// Set an option on the acceptor.
+  /**
+   * This function is used to set an option on the acceptor.
+   *
+   * @param option The new option value to be set on the acceptor.
+   *
+   * @throws asio::system_error Thrown on failure.
+   *
+   * @sa SettableSocketOption @n
+   * asio::socket_base::reuse_address
+   * asio::socket_base::enable_connection_aborted
+   *
+   * @par Example
+   * Setting the SOL_SOCKET/SO_REUSEADDR option:
+   * @code
+   * asio::ip::tcp::acceptor acceptor(my_context);
+   * ...
+   * asio::ip::tcp::acceptor::reuse_address option(true);
+   * acceptor.set_option(option);
+   * @endcode
+   */
+  template <typename SettableSocketOption>
+  void set_option(const SettableSocketOption& option)
+  {
+    asio::error_code ec;
+    impl_.get_service().set_option(impl_.get_implementation(), option, ec);
+    asio::detail::throw_error(ec, "set_option");
+  }
+
+  /// Set an option on the acceptor.
+  /**
+   * This function is used to set an option on the acceptor.
+   *
+   * @param option The new option value to be set on the acceptor.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   *
+   * @sa SettableSocketOption @n
+   * asio::socket_base::reuse_address
+   * asio::socket_base::enable_connection_aborted
+   *
+   * @par Example
+   * Setting the SOL_SOCKET/SO_REUSEADDR option:
+   * @code
+   * asio::ip::tcp::acceptor acceptor(my_context);
+   * ...
+   * asio::ip::tcp::acceptor::reuse_address option(true);
+   * asio::error_code ec;
+   * acceptor.set_option(option, ec);
+   * if (ec)
+   * {
+   *   // An error occurred.
+   * }
+   * @endcode
+   */
+  template <typename SettableSocketOption>
+  ASIO_SYNC_OP_VOID set_option(const SettableSocketOption& option,
+      asio::error_code& ec)
+  {
+    impl_.get_service().set_option(impl_.get_implementation(), option, ec);
+    ASIO_SYNC_OP_VOID_RETURN(ec);
+  }
+
+  /// Get an option from the acceptor.
+  /**
+   * This function is used to get the current value of an option on the
+   * acceptor.
+   *
+   * @param option The option value to be obtained from the acceptor.
+   *
+   * @throws asio::system_error Thrown on failure.
+   *
+   * @sa GettableSocketOption @n
+   * asio::socket_base::reuse_address
+   *
+   * @par Example
+   * Getting the value of the SOL_SOCKET/SO_REUSEADDR option:
+   * @code
+   * asio::ip::tcp::acceptor acceptor(my_context);
+   * ...
+   * asio::ip::tcp::acceptor::reuse_address option;
+   * acceptor.get_option(option);
+   * bool is_set = option.get();
+   * @endcode
+   */
+  template <typename GettableSocketOption>
+  void get_option(GettableSocketOption& option) const
+  {
+    asio::error_code ec;
+    impl_.get_service().get_option(impl_.get_implementation(), option, ec);
+    asio::detail::throw_error(ec, "get_option");
+  }
+
+  /// Get an option from the acceptor.
+  /**
+   * This function is used to get the current value of an option on the
+   * acceptor.
+   *
+   * @param option The option value to be obtained from the acceptor.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   *
+   * @sa GettableSocketOption @n
+   * asio::socket_base::reuse_address
+   *
+   * @par Example
+   * Getting the value of the SOL_SOCKET/SO_REUSEADDR option:
+   * @code
+   * asio::ip::tcp::acceptor acceptor(my_context);
+   * ...
+   * asio::ip::tcp::acceptor::reuse_address option;
+   * asio::error_code ec;
+   * acceptor.get_option(option, ec);
+   * if (ec)
+   * {
+   *   // An error occurred.
+   * }
+   * bool is_set = option.get();
+   * @endcode
+   */
+  template <typename GettableSocketOption>
+  ASIO_SYNC_OP_VOID get_option(GettableSocketOption& option,
+      asio::error_code& ec) const
+  {
+    impl_.get_service().get_option(impl_.get_implementation(), option, ec);
+    ASIO_SYNC_OP_VOID_RETURN(ec);
+  }
+
+  /// Perform an IO control command on the acceptor.
+  /**
+   * This function is used to execute an IO control command on the acceptor.
+   *
+   * @param command The IO control command to be performed on the acceptor.
+   *
+   * @throws asio::system_error Thrown on failure.
+   *
+   * @sa IoControlCommand @n
+   * asio::socket_base::non_blocking_io
+   *
+   * @par Example
+   * Getting the number of bytes ready to read:
+   * @code
+   * asio::ip::tcp::acceptor acceptor(my_context);
+   * ...
+   * asio::ip::tcp::acceptor::non_blocking_io command(true);
+   * socket.io_control(command);
+   * @endcode
+   */
+  template <typename IoControlCommand>
+  void io_control(IoControlCommand& command)
+  {
+    asio::error_code ec;
+    impl_.get_service().io_control(impl_.get_implementation(), command, ec);
+    asio::detail::throw_error(ec, "io_control");
+  }
+
+  /// Perform an IO control command on the acceptor.
+  /**
+   * This function is used to execute an IO control command on the acceptor.
+   *
+   * @param command The IO control command to be performed on the acceptor.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   *
+   * @sa IoControlCommand @n
+   * asio::socket_base::non_blocking_io
+   *
+   * @par Example
+   * Getting the number of bytes ready to read:
+   * @code
+   * asio::ip::tcp::acceptor acceptor(my_context);
+   * ...
+   * asio::ip::tcp::acceptor::non_blocking_io command(true);
+   * asio::error_code ec;
+   * socket.io_control(command, ec);
+   * if (ec)
+   * {
+   *   // An error occurred.
+   * }
+   * @endcode
+   */
+  template <typename IoControlCommand>
+  ASIO_SYNC_OP_VOID io_control(IoControlCommand& command,
+      asio::error_code& ec)
+  {
+    impl_.get_service().io_control(impl_.get_implementation(), command, ec);
+    ASIO_SYNC_OP_VOID_RETURN(ec);
+  }
+
+  /// Gets the non-blocking mode of the acceptor.
+  /**
+   * @returns @c true if the acceptor's synchronous operations will fail with
+   * asio::error::would_block if they are unable to perform the requested
+   * operation immediately. If @c false, synchronous operations will block
+   * until complete.
+   *
+   * @note The non-blocking mode has no effect on the behaviour of asynchronous
+   * operations. Asynchronous operations will never fail with the error
+   * asio::error::would_block.
+   */
+  bool non_blocking() const
+  {
+    return impl_.get_service().non_blocking(impl_.get_implementation());
+  }
+
+  /// Sets the non-blocking mode of the acceptor.
+  /**
+   * @param mode If @c true, the acceptor's synchronous operations will fail
+   * with asio::error::would_block if they are unable to perform the
+   * requested operation immediately. If @c false, synchronous operations will
+   * block until complete.
+   *
+   * @throws asio::system_error Thrown on failure.
+   *
+   * @note The non-blocking mode has no effect on the behaviour of asynchronous
+   * operations. Asynchronous operations will never fail with the error
+   * asio::error::would_block.
+   */
+  void non_blocking(bool mode)
+  {
+    asio::error_code ec;
+    impl_.get_service().non_blocking(impl_.get_implementation(), mode, ec);
+    asio::detail::throw_error(ec, "non_blocking");
+  }
+
+  /// Sets the non-blocking mode of the acceptor.
+  /**
+   * @param mode If @c true, the acceptor's synchronous operations will fail
+   * with asio::error::would_block if they are unable to perform the
+   * requested operation immediately. If @c false, synchronous operations will
+   * block until complete.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   *
+   * @note The non-blocking mode has no effect on the behaviour of asynchronous
+   * operations. Asynchronous operations will never fail with the error
+   * asio::error::would_block.
+   */
+  ASIO_SYNC_OP_VOID non_blocking(
+      bool mode, asio::error_code& ec)
+  {
+    impl_.get_service().non_blocking(impl_.get_implementation(), mode, ec);
+    ASIO_SYNC_OP_VOID_RETURN(ec);
+  }
+
+  /// Gets the non-blocking mode of the native acceptor implementation.
+  /**
+   * This function is used to retrieve the non-blocking mode of the underlying
+   * native acceptor. This mode has no effect on the behaviour of the acceptor
+   * object's synchronous operations.
+   *
+   * @returns @c true if the underlying acceptor is in non-blocking mode and
+   * direct system calls may fail with asio::error::would_block (or the
+   * equivalent system error).
+   *
+   * @note The current non-blocking mode is cached by the acceptor object.
+   * Consequently, the return value may be incorrect if the non-blocking mode
+   * was set directly on the native acceptor.
+   */
+  bool native_non_blocking() const
+  {
+    return impl_.get_service().native_non_blocking(impl_.get_implementation());
+  }
+
+  /// Sets the non-blocking mode of the native acceptor implementation.
+  /**
+   * This function is used to modify the non-blocking mode of the underlying
+   * native acceptor. It has no effect on the behaviour of the acceptor object's
+   * synchronous operations.
+   *
+   * @param mode If @c true, the underlying acceptor is put into non-blocking
+   * mode and direct system calls may fail with asio::error::would_block
+   * (or the equivalent system error).
+   *
+   * @throws asio::system_error Thrown on failure. If the @c mode is
+   * @c false, but the current value of @c non_blocking() is @c true, this
+   * function fails with asio::error::invalid_argument, as the
+   * combination does not make sense.
+   */
+  void native_non_blocking(bool mode)
+  {
+    asio::error_code ec;
+    impl_.get_service().native_non_blocking(
+        impl_.get_implementation(), mode, ec);
+    asio::detail::throw_error(ec, "native_non_blocking");
+  }
+
+  /// Sets the non-blocking mode of the native acceptor implementation.
+  /**
+   * This function is used to modify the non-blocking mode of the underlying
+   * native acceptor. It has no effect on the behaviour of the acceptor object's
+   * synchronous operations.
+   *
+   * @param mode If @c true, the underlying acceptor is put into non-blocking
+   * mode and direct system calls may fail with asio::error::would_block
+   * (or the equivalent system error).
+   *
+   * @param ec Set to indicate what error occurred, if any. If the @c mode is
+   * @c false, but the current value of @c non_blocking() is @c true, this
+   * function fails with asio::error::invalid_argument, as the
+   * combination does not make sense.
+   */
+  ASIO_SYNC_OP_VOID native_non_blocking(
+      bool mode, asio::error_code& ec)
+  {
+    impl_.get_service().native_non_blocking(
+        impl_.get_implementation(), mode, ec);
+    ASIO_SYNC_OP_VOID_RETURN(ec);
+  }
+
+  /// Get the local endpoint of the acceptor.
+  /**
+   * This function is used to obtain the locally bound endpoint of the acceptor.
+   *
+   * @returns An object that represents the local endpoint of the acceptor.
+   *
+   * @throws asio::system_error Thrown on failure.
+   *
+   * @par Example
+   * @code
+   * asio::ip::tcp::acceptor acceptor(my_context);
+   * ...
+   * asio::ip::tcp::endpoint endpoint = acceptor.local_endpoint();
+   * @endcode
+   */
+  endpoint_type local_endpoint() const
+  {
+    asio::error_code ec;
+    endpoint_type ep = impl_.get_service().local_endpoint(
+        impl_.get_implementation(), ec);
+    asio::detail::throw_error(ec, "local_endpoint");
+    return ep;
+  }
+
+  /// Get the local endpoint of the acceptor.
+  /**
+   * This function is used to obtain the locally bound endpoint of the acceptor.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   *
+   * @returns An object that represents the local endpoint of the acceptor.
+   * Returns a default-constructed endpoint object if an error occurred and the
+   * error handler did not throw an exception.
+   *
+   * @par Example
+   * @code
+   * asio::ip::tcp::acceptor acceptor(my_context);
+   * ...
+   * asio::error_code ec;
+   * asio::ip::tcp::endpoint endpoint = acceptor.local_endpoint(ec);
+   * if (ec)
+   * {
+   *   // An error occurred.
+   * }
+   * @endcode
+   */
+  endpoint_type local_endpoint(asio::error_code& ec) const
+  {
+    return impl_.get_service().local_endpoint(impl_.get_implementation(), ec);
+  }
+
+  /// Wait for the acceptor to become ready to read, ready to write, or to have
+  /// pending error conditions.
+  /**
+   * This function is used to perform a blocking wait for an acceptor to enter
+   * a ready to read, write or error condition state.
+   *
+   * @param w Specifies the desired acceptor state.
+   *
+   * @par Example
+   * Waiting for an acceptor to become readable.
+   * @code
+   * asio::ip::tcp::acceptor acceptor(my_context);
+   * ...
+   * acceptor.wait(asio::ip::tcp::acceptor::wait_read);
+   * @endcode
+   */
+  void wait(wait_type w)
+  {
+    asio::error_code ec;
+    impl_.get_service().wait(impl_.get_implementation(), w, ec);
+    asio::detail::throw_error(ec, "wait");
+  }
+
+  /// Wait for the acceptor to become ready to read, ready to write, or to have
+  /// pending error conditions.
+  /**
+   * This function is used to perform a blocking wait for an acceptor to enter
+   * a ready to read, write or error condition state.
+   *
+   * @param w Specifies the desired acceptor state.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   *
+   * @par Example
+   * Waiting for an acceptor to become readable.
+   * @code
+   * asio::ip::tcp::acceptor acceptor(my_context);
+   * ...
+   * asio::error_code ec;
+   * acceptor.wait(asio::ip::tcp::acceptor::wait_read, ec);
+   * @endcode
+   */
+  ASIO_SYNC_OP_VOID wait(wait_type w, asio::error_code& ec)
+  {
+    impl_.get_service().wait(impl_.get_implementation(), w, ec);
+    ASIO_SYNC_OP_VOID_RETURN(ec);
+  }
+
+  /// Asynchronously wait for the acceptor to become ready to read, ready to
+  /// write, or to have pending error conditions.
+  /**
+   * This function is used to perform an asynchronous wait for an acceptor to
+   * enter a ready to read, write or error condition state.
+   *
+   * @param w Specifies the desired acceptor state.
+   *
+   * @param handler The handler to be called when the wait operation completes.
+   * Copies will be made of the handler as required. The function signature of
+   * the handler must be:
+   * @code void handler(
+   *   const asio::error_code& error // Result of operation
+   * ); @endcode
+   * Regardless of whether the asynchronous operation completes immediately or
+   * not, the handler will not be invoked from within this function. On
+   * immediate completion, invocation of the handler will be performed in a
+   * manner equivalent to using asio::post().
+   *
+   * @par Example
+   * @code
+   * void wait_handler(const asio::error_code& error)
+   * {
+   *   if (!error)
+   *   {
+   *     // Wait succeeded.
+   *   }
+   * }
+   *
+   * ...
+   *
+   * asio::ip::tcp::acceptor acceptor(my_context);
+   * ...
+   * acceptor.async_wait(
+   *     asio::ip::tcp::acceptor::wait_read,
+   *     wait_handler);
+   * @endcode
+   */
+  template <
+      ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code))
+        WaitHandler ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
+  ASIO_INITFN_AUTO_RESULT_TYPE(WaitHandler,
+      void (asio::error_code))
+  async_wait(wait_type w,
+      ASIO_MOVE_ARG(WaitHandler) handler
+        ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
+  {
+    return async_initiate<WaitHandler, void (asio::error_code)>(
+        initiate_async_wait(this), handler, w);
+  }
+
+#if !defined(ASIO_NO_EXTENSIONS)
+  /// Accept a new connection.
+  /**
+   * This function is used to accept a new connection from a peer into the
+   * given socket. The function call will block until a new connection has been
+   * accepted successfully or an error occurs.
+   *
+   * @param peer The socket into which the new connection will be accepted.
+   *
+   * @throws asio::system_error Thrown on failure.
+   *
+   * @par Example
+   * @code
+   * asio::ip::tcp::acceptor acceptor(my_context);
+   * ...
+   * asio::ip::tcp::socket socket(my_context);
+   * acceptor.accept(socket);
+   * @endcode
+   */
+  template <typename Protocol1, typename Executor1>
+  void accept(basic_socket<Protocol1, Executor1>& peer,
+      typename enable_if<
+        is_convertible<Protocol, Protocol1>::value
+      >::type* = 0)
+  {
+    asio::error_code ec;
+    impl_.get_service().accept(impl_.get_implementation(),
+        peer, static_cast<endpoint_type*>(0), ec);
+    asio::detail::throw_error(ec, "accept");
+  }
+
+  /// Accept a new connection.
+  /**
+   * This function is used to accept a new connection from a peer into the
+   * given socket. The function call will block until a new connection has been
+   * accepted successfully or an error occurs.
+   *
+   * @param peer The socket into which the new connection will be accepted.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   *
+   * @par Example
+   * @code
+   * asio::ip::tcp::acceptor acceptor(my_context);
+   * ...
+   * asio::ip::tcp::socket socket(my_context);
+   * asio::error_code ec;
+   * acceptor.accept(socket, ec);
+   * if (ec)
+   * {
+   *   // An error occurred.
+   * }
+   * @endcode
+   */
+  template <typename Protocol1, typename Executor1>
+  ASIO_SYNC_OP_VOID accept(
+      basic_socket<Protocol1, Executor1>& peer, asio::error_code& ec,
+      typename enable_if<
+        is_convertible<Protocol, Protocol1>::value
+      >::type* = 0)
+  {
+    impl_.get_service().accept(impl_.get_implementation(),
+        peer, static_cast<endpoint_type*>(0), ec);
+    ASIO_SYNC_OP_VOID_RETURN(ec);
+  }
+
+  /// Start an asynchronous accept.
+  /**
+   * This function is used to asynchronously accept a new connection into a
+   * socket. The function call always returns immediately.
+   *
+   * @param peer The socket into which the new connection will be accepted.
+   * Ownership of the peer object is retained by the caller, which must
+   * guarantee that it is valid until the handler is called.
+   *
+   * @param handler The handler to be called when the accept operation
+   * completes. Copies will be made of the handler as required. The function
+   * signature of the handler must be:
+   * @code void handler(
+   *   const asio::error_code& error // Result of operation.
+   * ); @endcode
+   * Regardless of whether the asynchronous operation completes immediately or
+   * not, the handler will not be invoked from within this function. On
+   * immediate completion, invocation of the handler will be performed in a
+   * manner equivalent to using asio::post().
+   *
+   * @par Example
+   * @code
+   * void accept_handler(const asio::error_code& error)
+   * {
+   *   if (!error)
+   *   {
+   *     // Accept succeeded.
+   *   }
+   * }
+   *
+   * ...
+   *
+   * asio::ip::tcp::acceptor acceptor(my_context);
+   * ...
+   * asio::ip::tcp::socket socket(my_context);
+   * acceptor.async_accept(socket, accept_handler);
+   * @endcode
+   */
+  template <typename Protocol1, typename Executor1,
+      ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code))
+        AcceptHandler ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
+  ASIO_INITFN_AUTO_RESULT_TYPE(AcceptHandler,
+      void (asio::error_code))
+  async_accept(basic_socket<Protocol1, Executor1>& peer,
+      ASIO_MOVE_ARG(AcceptHandler) handler
+        ASIO_DEFAULT_COMPLETION_TOKEN(executor_type),
+      typename enable_if<
+        is_convertible<Protocol, Protocol1>::value
+      >::type* = 0)
+  {
+    return async_initiate<AcceptHandler, void (asio::error_code)>(
+        initiate_async_accept(this), handler,
+        &peer, static_cast<endpoint_type*>(0));
+  }
+
+  /// Accept a new connection and obtain the endpoint of the peer
+  /**
+   * This function is used to accept a new connection from a peer into the
+   * given socket, and additionally provide the endpoint of the remote peer.
+   * The function call will block until a new connection has been accepted
+   * successfully or an error occurs.
+   *
+   * @param peer The socket into which the new connection will be accepted.
+   *
+   * @param peer_endpoint An endpoint object which will receive the endpoint of
+   * the remote peer.
+   *
+   * @throws asio::system_error Thrown on failure.
+   *
+   * @par Example
+   * @code
+   * asio::ip::tcp::acceptor acceptor(my_context);
+   * ...
+   * asio::ip::tcp::socket socket(my_context);
+   * asio::ip::tcp::endpoint endpoint;
+   * acceptor.accept(socket, endpoint);
+   * @endcode
+   */
+  template <typename Executor1>
+  void accept(basic_socket<protocol_type, Executor1>& peer,
+      endpoint_type& peer_endpoint)
+  {
+    asio::error_code ec;
+    impl_.get_service().accept(impl_.get_implementation(),
+        peer, &peer_endpoint, ec);
+    asio::detail::throw_error(ec, "accept");
+  }
+
+  /// Accept a new connection and obtain the endpoint of the peer
+  /**
+   * This function is used to accept a new connection from a peer into the
+   * given socket, and additionally provide the endpoint of the remote peer.
+   * The function call will block until a new connection has been accepted
+   * successfully or an error occurs.
+   *
+   * @param peer The socket into which the new connection will be accepted.
+   *
+   * @param peer_endpoint An endpoint object which will receive the endpoint of
+   * the remote peer.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   *
+   * @par Example
+   * @code
+   * asio::ip::tcp::acceptor acceptor(my_context);
+   * ...
+   * asio::ip::tcp::socket socket(my_context);
+   * asio::ip::tcp::endpoint endpoint;
+   * asio::error_code ec;
+   * acceptor.accept(socket, endpoint, ec);
+   * if (ec)
+   * {
+   *   // An error occurred.
+   * }
+   * @endcode
+   */
+  template <typename Executor1>
+  ASIO_SYNC_OP_VOID accept(basic_socket<protocol_type, Executor1>& peer,
+      endpoint_type& peer_endpoint, asio::error_code& ec)
+  {
+    impl_.get_service().accept(
+        impl_.get_implementation(), peer, &peer_endpoint, ec);
+    ASIO_SYNC_OP_VOID_RETURN(ec);
+  }
+
+  /// Start an asynchronous accept.
+  /**
+   * This function is used to asynchronously accept a new connection into a
+   * socket, and additionally obtain the endpoint of the remote peer. The
+   * function call always returns immediately.
+   *
+   * @param peer The socket into which the new connection will be accepted.
+   * Ownership of the peer object is retained by the caller, which must
+   * guarantee that it is valid until the handler is called.
+   *
+   * @param peer_endpoint An endpoint object into which the endpoint of the
+   * remote peer will be written. Ownership of the peer_endpoint object is
+   * retained by the caller, which must guarantee that it is valid until the
+   * handler is called.
+   *
+   * @param handler The handler to be called when the accept operation
+   * completes. Copies will be made of the handler as required. The function
+   * signature of the handler must be:
+   * @code void handler(
+   *   const asio::error_code& error // Result of operation.
+   * ); @endcode
+   * Regardless of whether the asynchronous operation completes immediately or
+   * not, the handler will not be invoked from within this function. On
+   * immediate completion, invocation of the handler will be performed in a
+   * manner equivalent to using asio::post().
+   */
+  template <typename Executor1,
+      ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code))
+        AcceptHandler ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
+  ASIO_INITFN_AUTO_RESULT_TYPE(AcceptHandler,
+      void (asio::error_code))
+  async_accept(basic_socket<protocol_type, Executor1>& peer,
+      endpoint_type& peer_endpoint,
+      ASIO_MOVE_ARG(AcceptHandler) handler
+        ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
+  {
+    return async_initiate<AcceptHandler, void (asio::error_code)>(
+        initiate_async_accept(this), handler, &peer, &peer_endpoint);
+  }
+#endif // !defined(ASIO_NO_EXTENSIONS)
+
+#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+  /// Accept a new connection.
+  /**
+   * This function is used to accept a new connection from a peer. The function
+   * call will block until a new connection has been accepted successfully or
+   * an error occurs.
+   *
+   * This overload requires that the Protocol template parameter satisfy the
+   * AcceptableProtocol type requirements.
+   *
+   * @returns A socket object representing the newly accepted connection.
+   *
+   * @throws asio::system_error Thrown on failure.
+   *
+   * @par Example
+   * @code
+   * asio::ip::tcp::acceptor acceptor(my_context);
+   * ...
+   * asio::ip::tcp::socket socket(acceptor.accept());
+   * @endcode
+   */
+  typename Protocol::socket::template rebind_executor<executor_type>::other
+  accept()
+  {
+    asio::error_code ec;
+    typename Protocol::socket::template rebind_executor<
+      executor_type>::other peer(impl_.get_executor());
+    impl_.get_service().accept(impl_.get_implementation(), peer, 0, ec);
+    asio::detail::throw_error(ec, "accept");
+    return peer;
+  }
+
+  /// Accept a new connection.
+  /**
+   * This function is used to accept a new connection from a peer. The function
+   * call will block until a new connection has been accepted successfully or
+   * an error occurs.
+   *
+   * This overload requires that the Protocol template parameter satisfy the
+   * AcceptableProtocol type requirements.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   *
+   * @returns On success, a socket object representing the newly accepted
+   * connection. On error, a socket object where is_open() is false.
+   *
+   * @par Example
+   * @code
+   * asio::ip::tcp::acceptor acceptor(my_context);
+   * ...
+   * asio::ip::tcp::socket socket(acceptor.accept(ec));
+   * if (ec)
+   * {
+   *   // An error occurred.
+   * }
+   * @endcode
+   */
+  typename Protocol::socket::template rebind_executor<executor_type>::other
+  accept(asio::error_code& ec)
+  {
+    typename Protocol::socket::template rebind_executor<
+      executor_type>::other peer(impl_.get_executor());
+    impl_.get_service().accept(impl_.get_implementation(), peer, 0, ec);
+    return peer;
+  }
+
+  /// Start an asynchronous accept.
+  /**
+   * This function is used to asynchronously accept a new connection. The
+   * function call always returns immediately.
+   *
+   * This overload requires that the Protocol template parameter satisfy the
+   * AcceptableProtocol type requirements.
+   *
+   * @param handler The handler to be called when the accept operation
+   * completes. Copies will be made of the handler as required. The function
+   * signature of the handler must be:
+   * @code void handler(
+   *   // Result of operation.
+   *   const asio::error_code& error,
+   *   // On success, the newly accepted socket.
+   *   typename Protocol::socket::template
+   *     rebind_executor<executor_type>::other peer
+   * ); @endcode
+   * Regardless of whether the asynchronous operation completes immediately or
+   * not, the handler will not be invoked from within this function. On
+   * immediate completion, invocation of the handler will be performed in a
+   * manner equivalent to using asio::post().
+   *
+   * @par Example
+   * @code
+   * void accept_handler(const asio::error_code& error,
+   *     asio::ip::tcp::socket peer)
+   * {
+   *   if (!error)
+   *   {
+   *     // Accept succeeded.
+   *   }
+   * }
+   *
+   * ...
+   *
+   * asio::ip::tcp::acceptor acceptor(my_context);
+   * ...
+   * acceptor.async_accept(accept_handler);
+   * @endcode
+   */
+  template <
+      ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+        typename Protocol::socket::template rebind_executor<
+          executor_type>::other)) MoveAcceptHandler
+            ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
+  ASIO_INITFN_AUTO_RESULT_TYPE(MoveAcceptHandler,
+      void (asio::error_code,
+        typename Protocol::socket::template
+          rebind_executor<executor_type>::other))
+  async_accept(
+      ASIO_MOVE_ARG(MoveAcceptHandler) handler
+        ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
+  {
+    return async_initiate<MoveAcceptHandler,
+      void (asio::error_code, typename Protocol::socket::template
+        rebind_executor<executor_type>::other)>(
+          initiate_async_move_accept(this), handler,
+          impl_.get_executor(), static_cast<endpoint_type*>(0),
+          static_cast<typename Protocol::socket::template
+            rebind_executor<executor_type>::other*>(0));
+  }
+
+  /// Accept a new connection.
+  /**
+   * This function is used to accept a new connection from a peer. The function
+   * call will block until a new connection has been accepted successfully or
+   * an error occurs.
+   *
+   * This overload requires that the Protocol template parameter satisfy the
+   * AcceptableProtocol type requirements.
+   *
+   * @param ex The I/O executor object to be used for the newly
+   * accepted socket.
+   *
+   * @returns A socket object representing the newly accepted connection.
+   *
+   * @throws asio::system_error Thrown on failure.
+   *
+   * @par Example
+   * @code
+   * asio::ip::tcp::acceptor acceptor(my_context);
+   * ...
+   * asio::ip::tcp::socket socket(acceptor.accept());
+   * @endcode
+   */
+  template <typename Executor1>
+  typename Protocol::socket::template rebind_executor<Executor1>::other
+  accept(const Executor1& ex,
+      typename enable_if<
+        is_executor<Executor1>::value
+          || execution::is_executor<Executor1>::value
+      >::type* = 0)
+  {
+    asio::error_code ec;
+    typename Protocol::socket::template
+      rebind_executor<Executor1>::other peer(ex);
+    impl_.get_service().accept(impl_.get_implementation(), peer, 0, ec);
+    asio::detail::throw_error(ec, "accept");
+    return peer;
+  }
+
+  /// Accept a new connection.
+  /**
+   * This function is used to accept a new connection from a peer. The function
+   * call will block until a new connection has been accepted successfully or
+   * an error occurs.
+   *
+   * This overload requires that the Protocol template parameter satisfy the
+   * AcceptableProtocol type requirements.
+   *
+   * @param context The I/O execution context object to be used for the newly
+   * accepted socket.
+   *
+   * @returns A socket object representing the newly accepted connection.
+   *
+   * @throws asio::system_error Thrown on failure.
+   *
+   * @par Example
+   * @code
+   * asio::ip::tcp::acceptor acceptor(my_context);
+   * ...
+   * asio::ip::tcp::socket socket(acceptor.accept());
+   * @endcode
+   */
+  template <typename ExecutionContext>
+  typename Protocol::socket::template rebind_executor<
+      typename ExecutionContext::executor_type>::other
+  accept(ExecutionContext& context,
+      typename enable_if<
+        is_convertible<ExecutionContext&, execution_context&>::value
+      >::type* = 0)
+  {
+    asio::error_code ec;
+    typename Protocol::socket::template rebind_executor<
+        typename ExecutionContext::executor_type>::other peer(context);
+    impl_.get_service().accept(impl_.get_implementation(), peer, 0, ec);
+    asio::detail::throw_error(ec, "accept");
+    return peer;
+  }
+
+  /// Accept a new connection.
+  /**
+   * This function is used to accept a new connection from a peer. The function
+   * call will block until a new connection has been accepted successfully or
+   * an error occurs.
+   *
+   * This overload requires that the Protocol template parameter satisfy the
+   * AcceptableProtocol type requirements.
+   *
+   * @param ex The I/O executor object to be used for the newly accepted
+   * socket.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   *
+   * @returns On success, a socket object representing the newly accepted
+   * connection. On error, a socket object where is_open() is false.
+   *
+   * @par Example
+   * @code
+   * asio::ip::tcp::acceptor acceptor(my_context);
+   * ...
+   * asio::ip::tcp::socket socket(acceptor.accept(my_context2, ec));
+   * if (ec)
+   * {
+   *   // An error occurred.
+   * }
+   * @endcode
+   */
+  template <typename Executor1>
+  typename Protocol::socket::template rebind_executor<Executor1>::other
+  accept(const Executor1& ex, asio::error_code& ec,
+      typename enable_if<
+        is_executor<Executor1>::value
+          || execution::is_executor<Executor1>::value
+      >::type* = 0)
+  {
+    typename Protocol::socket::template
+      rebind_executor<Executor1>::other peer(ex);
+    impl_.get_service().accept(impl_.get_implementation(), peer, 0, ec);
+    return peer;
+  }
+
+  /// Accept a new connection.
+  /**
+   * This function is used to accept a new connection from a peer. The function
+   * call will block until a new connection has been accepted successfully or
+   * an error occurs.
+   *
+   * This overload requires that the Protocol template parameter satisfy the
+   * AcceptableProtocol type requirements.
+   *
+   * @param context The I/O execution context object to be used for the newly
+   * accepted socket.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   *
+   * @returns On success, a socket object representing the newly accepted
+   * connection. On error, a socket object where is_open() is false.
+   *
+   * @par Example
+   * @code
+   * asio::ip::tcp::acceptor acceptor(my_context);
+   * ...
+   * asio::ip::tcp::socket socket(acceptor.accept(my_context2, ec));
+   * if (ec)
+   * {
+   *   // An error occurred.
+   * }
+   * @endcode
+   */
+  template <typename ExecutionContext>
+  typename Protocol::socket::template rebind_executor<
+      typename ExecutionContext::executor_type>::other
+  accept(ExecutionContext& context, asio::error_code& ec,
+      typename enable_if<
+        is_convertible<ExecutionContext&, execution_context&>::value
+      >::type* = 0)
+  {
+    typename Protocol::socket::template rebind_executor<
+        typename ExecutionContext::executor_type>::other peer(context);
+    impl_.get_service().accept(impl_.get_implementation(), peer, 0, ec);
+    return peer;
+  }
+
+  /// Start an asynchronous accept.
+  /**
+   * This function is used to asynchronously accept a new connection. The
+   * function call always returns immediately.
+   *
+   * This overload requires that the Protocol template parameter satisfy the
+   * AcceptableProtocol type requirements.
+   *
+   * @param ex The I/O executor object to be used for the newly accepted
+   * socket.
+   *
+   * @param handler The handler to be called when the accept operation
+   * completes. Copies will be made of the handler as required. The function
+   * signature of the handler must be:
+   * @code void handler(
+   *   const asio::error_code& error, // Result of operation.
+   *   typename Protocol::socket::template rebind_executor<
+   *     Executor1>::other peer // On success, the newly accepted socket.
+   * ); @endcode
+   * Regardless of whether the asynchronous operation completes immediately or
+   * not, the handler will not be invoked from within this function. On
+   * immediate completion, invocation of the handler will be performed in a
+   * manner equivalent to using asio::post().
+   *
+   * @par Example
+   * @code
+   * void accept_handler(const asio::error_code& error,
+   *     asio::ip::tcp::socket peer)
+   * {
+   *   if (!error)
+   *   {
+   *     // Accept succeeded.
+   *   }
+   * }
+   *
+   * ...
+   *
+   * asio::ip::tcp::acceptor acceptor(my_context);
+   * ...
+   * acceptor.async_accept(my_context2, accept_handler);
+   * @endcode
+   */
+  template <typename Executor1,
+      ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+        typename Protocol::socket::template rebind_executor<
+          Executor1>::other)) MoveAcceptHandler
+            ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
+  ASIO_INITFN_AUTO_RESULT_TYPE(MoveAcceptHandler,
+      void (asio::error_code,
+        typename Protocol::socket::template rebind_executor<
+          Executor1>::other))
+  async_accept(const Executor1& ex,
+      ASIO_MOVE_ARG(MoveAcceptHandler) handler
+        ASIO_DEFAULT_COMPLETION_TOKEN(executor_type),
+      typename enable_if<
+        is_executor<Executor1>::value
+          || execution::is_executor<Executor1>::value
+      >::type* = 0)
+  {
+    typedef typename Protocol::socket::template rebind_executor<
+      Executor1>::other other_socket_type;
+
+    return async_initiate<MoveAcceptHandler,
+      void (asio::error_code, other_socket_type)>(
+        initiate_async_move_accept(this), handler,
+        ex, static_cast<endpoint_type*>(0),
+        static_cast<other_socket_type*>(0));
+  }
+
+  /// Start an asynchronous accept.
+  /**
+   * This function is used to asynchronously accept a new connection. The
+   * function call always returns immediately.
+   *
+   * This overload requires that the Protocol template parameter satisfy the
+   * AcceptableProtocol type requirements.
+   *
+   * @param context The I/O execution context object to be used for the newly
+   * accepted socket.
+   *
+   * @param handler The handler to be called when the accept operation
+   * completes. Copies will be made of the handler as required. The function
+   * signature of the handler must be:
+   * @code void handler(
+   *   const asio::error_code& error, // Result of operation.
+   *   typename Protocol::socket::template rebind_executor<
+   *     typename ExecutionContext::executor_type>::other peer
+   *       // On success, the newly accepted socket.
+   * ); @endcode
+   * Regardless of whether the asynchronous operation completes immediately or
+   * not, the handler will not be invoked from within this function. On
+   * immediate completion, invocation of the handler will be performed in a
+   * manner equivalent to using asio::post().
+   *
+   * @par Example
+   * @code
+   * void accept_handler(const asio::error_code& error,
+   *     asio::ip::tcp::socket peer)
+   * {
+   *   if (!error)
+   *   {
+   *     // Accept succeeded.
+   *   }
+   * }
+   *
+   * ...
+   *
+   * asio::ip::tcp::acceptor acceptor(my_context);
+   * ...
+   * acceptor.async_accept(my_context2, accept_handler);
+   * @endcode
+   */
+  template <typename ExecutionContext,
+      ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+        typename Protocol::socket::template rebind_executor<
+          typename ExecutionContext::executor_type>::other)) MoveAcceptHandler
+            ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
+  ASIO_INITFN_AUTO_RESULT_TYPE(MoveAcceptHandler,
+      void (asio::error_code,
+        typename Protocol::socket::template rebind_executor<
+          typename ExecutionContext::executor_type>::other))
+  async_accept(ExecutionContext& context,
+      ASIO_MOVE_ARG(MoveAcceptHandler) handler
+        ASIO_DEFAULT_COMPLETION_TOKEN(executor_type),
+      typename enable_if<
+        is_convertible<ExecutionContext&, execution_context&>::value
+      >::type* = 0)
+  {
+    typedef typename Protocol::socket::template rebind_executor<
+      typename ExecutionContext::executor_type>::other other_socket_type;
+
+    return async_initiate<MoveAcceptHandler,
+      void (asio::error_code, other_socket_type)>(
+        initiate_async_move_accept(this), handler,
+        context.get_executor(), static_cast<endpoint_type*>(0),
+        static_cast<other_socket_type*>(0));
+  }
+
+  /// Accept a new connection.
+  /**
+   * This function is used to accept a new connection from a peer. The function
+   * call will block until a new connection has been accepted successfully or
+   * an error occurs.
+   *
+   * This overload requires that the Protocol template parameter satisfy the
+   * AcceptableProtocol type requirements.
+   *
+   * @param peer_endpoint An endpoint object into which the endpoint of the
+   * remote peer will be written.
+   *
+   * @returns A socket object representing the newly accepted connection.
+   *
+   * @throws asio::system_error Thrown on failure.
+   *
+   * @par Example
+   * @code
+   * asio::ip::tcp::acceptor acceptor(my_context);
+   * ...
+   * asio::ip::tcp::endpoint endpoint;
+   * asio::ip::tcp::socket socket(acceptor.accept(endpoint));
+   * @endcode
+   */
+  typename Protocol::socket::template rebind_executor<executor_type>::other
+  accept(endpoint_type& peer_endpoint)
+  {
+    asio::error_code ec;
+    typename Protocol::socket::template rebind_executor<
+      executor_type>::other peer(impl_.get_executor());
+    impl_.get_service().accept(impl_.get_implementation(),
+        peer, &peer_endpoint, ec);
+    asio::detail::throw_error(ec, "accept");
+    return peer;
+  }
+
+  /// Accept a new connection.
+  /**
+   * This function is used to accept a new connection from a peer. The function
+   * call will block until a new connection has been accepted successfully or
+   * an error occurs.
+   *
+   * This overload requires that the Protocol template parameter satisfy the
+   * AcceptableProtocol type requirements.
+   *
+   * @param peer_endpoint An endpoint object into which the endpoint of the
+   * remote peer will be written.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   *
+   * @returns On success, a socket object representing the newly accepted
+   * connection. On error, a socket object where is_open() is false.
+   *
+   * @par Example
+   * @code
+   * asio::ip::tcp::acceptor acceptor(my_context);
+   * ...
+   * asio::ip::tcp::endpoint endpoint;
+   * asio::ip::tcp::socket socket(acceptor.accept(endpoint, ec));
+   * if (ec)
+   * {
+   *   // An error occurred.
+   * }
+   * @endcode
+   */
+  typename Protocol::socket::template rebind_executor<executor_type>::other
+  accept(endpoint_type& peer_endpoint, asio::error_code& ec)
+  {
+    typename Protocol::socket::template rebind_executor<
+      executor_type>::other peer(impl_.get_executor());
+    impl_.get_service().accept(impl_.get_implementation(),
+        peer, &peer_endpoint, ec);
+    return peer;
+  }
+
+  /// Start an asynchronous accept.
+  /**
+   * This function is used to asynchronously accept a new connection. The
+   * function call always returns immediately.
+   *
+   * This overload requires that the Protocol template parameter satisfy the
+   * AcceptableProtocol type requirements.
+   *
+   * @param peer_endpoint An endpoint object into which the endpoint of the
+   * remote peer will be written. Ownership of the peer_endpoint object is
+   * retained by the caller, which must guarantee that it is valid until the
+   * handler is called.
+   *
+   * @param handler The handler to be called when the accept operation
+   * completes. Copies will be made of the handler as required. The function
+   * signature of the handler must be:
+   * @code void handler(
+   *   // Result of operation.
+   *   const asio::error_code& error,
+   *   // On success, the newly accepted socket.
+   *   typename Protocol::socket::template
+   *     rebind_executor<executor_type>::other peer
+   * ); @endcode
+   * Regardless of whether the asynchronous operation completes immediately or
+   * not, the handler will not be invoked from within this function. On
+   * immediate completion, invocation of the handler will be performed in a
+   * manner equivalent to using asio::post().
+   *
+   * @par Example
+   * @code
+   * void accept_handler(const asio::error_code& error,
+   *     asio::ip::tcp::socket peer)
+   * {
+   *   if (!error)
+   *   {
+   *     // Accept succeeded.
+   *   }
+   * }
+   *
+   * ...
+   *
+   * asio::ip::tcp::acceptor acceptor(my_context);
+   * ...
+   * asio::ip::tcp::endpoint endpoint;
+   * acceptor.async_accept(endpoint, accept_handler);
+   * @endcode
+   */
+  template <
+      ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+        typename Protocol::socket::template rebind_executor<
+          executor_type>::other)) MoveAcceptHandler
+            ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
+  ASIO_INITFN_AUTO_RESULT_TYPE(MoveAcceptHandler,
+      void (asio::error_code,
+        typename Protocol::socket::template
+          rebind_executor<executor_type>::other))
+  async_accept(endpoint_type& peer_endpoint,
+      ASIO_MOVE_ARG(MoveAcceptHandler) handler
+        ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
+  {
+    return async_initiate<MoveAcceptHandler,
+      void (asio::error_code, typename Protocol::socket::template
+        rebind_executor<executor_type>::other)>(
+          initiate_async_move_accept(this), handler,
+          impl_.get_executor(), &peer_endpoint,
+          static_cast<typename Protocol::socket::template
+            rebind_executor<executor_type>::other*>(0));
+  }
+
+  /// Accept a new connection.
+  /**
+   * This function is used to accept a new connection from a peer. The function
+   * call will block until a new connection has been accepted successfully or
+   * an error occurs.
+   *
+   * This overload requires that the Protocol template parameter satisfy the
+   * AcceptableProtocol type requirements.
+   *
+   * @param ex The I/O executor object to be used for the newly accepted
+   * socket.
+   *
+   * @param peer_endpoint An endpoint object into which the endpoint of the
+   * remote peer will be written.
+   *
+   * @returns A socket object representing the newly accepted connection.
+   *
+   * @throws asio::system_error Thrown on failure.
+   *
+   * @par Example
+   * @code
+   * asio::ip::tcp::acceptor acceptor(my_context);
+   * ...
+   * asio::ip::tcp::endpoint endpoint;
+   * asio::ip::tcp::socket socket(
+   *     acceptor.accept(my_context2, endpoint));
+   * @endcode
+   */
+  template <typename Executor1>
+  typename Protocol::socket::template rebind_executor<Executor1>::other
+  accept(const Executor1& ex, endpoint_type& peer_endpoint,
+      typename enable_if<
+        is_executor<Executor1>::value
+          || execution::is_executor<Executor1>::value
+      >::type* = 0)
+  {
+    asio::error_code ec;
+    typename Protocol::socket::template
+        rebind_executor<Executor1>::other peer(ex);
+    impl_.get_service().accept(impl_.get_implementation(),
+        peer, &peer_endpoint, ec);
+    asio::detail::throw_error(ec, "accept");
+    return peer;
+  }
+
+  /// Accept a new connection.
+  /**
+   * This function is used to accept a new connection from a peer. The function
+   * call will block until a new connection has been accepted successfully or
+   * an error occurs.
+   *
+   * This overload requires that the Protocol template parameter satisfy the
+   * AcceptableProtocol type requirements.
+   *
+   * @param context The I/O execution context object to be used for the newly
+   * accepted socket.
+   *
+   * @param peer_endpoint An endpoint object into which the endpoint of the
+   * remote peer will be written.
+   *
+   * @returns A socket object representing the newly accepted connection.
+   *
+   * @throws asio::system_error Thrown on failure.
+   *
+   * @par Example
+   * @code
+   * asio::ip::tcp::acceptor acceptor(my_context);
+   * ...
+   * asio::ip::tcp::endpoint endpoint;
+   * asio::ip::tcp::socket socket(
+   *     acceptor.accept(my_context2, endpoint));
+   * @endcode
+   */
+  template <typename ExecutionContext>
+  typename Protocol::socket::template rebind_executor<
+      typename ExecutionContext::executor_type>::other
+  accept(ExecutionContext& context, endpoint_type& peer_endpoint,
+      typename enable_if<
+        is_convertible<ExecutionContext&, execution_context&>::value
+      >::type* = 0)
+  {
+    asio::error_code ec;
+    typename Protocol::socket::template rebind_executor<
+        typename ExecutionContext::executor_type>::other peer(context);
+    impl_.get_service().accept(impl_.get_implementation(),
+        peer, &peer_endpoint, ec);
+    asio::detail::throw_error(ec, "accept");
+    return peer;
+  }
+
+  /// Accept a new connection.
+  /**
+   * This function is used to accept a new connection from a peer. The function
+   * call will block until a new connection has been accepted successfully or
+   * an error occurs.
+   *
+   * This overload requires that the Protocol template parameter satisfy the
+   * AcceptableProtocol type requirements.
+   *
+   * @param ex The I/O executor object to be used for the newly accepted
+   * socket.
+   *
+   * @param peer_endpoint An endpoint object into which the endpoint of the
+   * remote peer will be written.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   *
+   * @returns On success, a socket object representing the newly accepted
+   * connection. On error, a socket object where is_open() is false.
+   *
+   * @par Example
+   * @code
+   * asio::ip::tcp::acceptor acceptor(my_context);
+   * ...
+   * asio::ip::tcp::endpoint endpoint;
+   * asio::ip::tcp::socket socket(
+   *     acceptor.accept(my_context2, endpoint, ec));
+   * if (ec)
+   * {
+   *   // An error occurred.
+   * }
+   * @endcode
+   */
+  template <typename Executor1>
+  typename Protocol::socket::template rebind_executor<Executor1>::other
+  accept(const executor_type& ex,
+      endpoint_type& peer_endpoint, asio::error_code& ec,
+      typename enable_if<
+        is_executor<Executor1>::value
+          || execution::is_executor<Executor1>::value
+      >::type* = 0)
+  {
+    typename Protocol::socket::template
+      rebind_executor<Executor1>::other peer(ex);
+    impl_.get_service().accept(impl_.get_implementation(),
+        peer, &peer_endpoint, ec);
+    return peer;
+  }
+
+  /// Accept a new connection.
+  /**
+   * This function is used to accept a new connection from a peer. The function
+   * call will block until a new connection has been accepted successfully or
+   * an error occurs.
+   *
+   * This overload requires that the Protocol template parameter satisfy the
+   * AcceptableProtocol type requirements.
+   *
+   * @param context The I/O execution context object to be used for the newly
+   * accepted socket.
+   *
+   * @param peer_endpoint An endpoint object into which the endpoint of the
+   * remote peer will be written.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   *
+   * @returns On success, a socket object representing the newly accepted
+   * connection. On error, a socket object where is_open() is false.
+   *
+   * @par Example
+   * @code
+   * asio::ip::tcp::acceptor acceptor(my_context);
+   * ...
+   * asio::ip::tcp::endpoint endpoint;
+   * asio::ip::tcp::socket socket(
+   *     acceptor.accept(my_context2, endpoint, ec));
+   * if (ec)
+   * {
+   *   // An error occurred.
+   * }
+   * @endcode
+   */
+  template <typename ExecutionContext>
+  typename Protocol::socket::template rebind_executor<
+      typename ExecutionContext::executor_type>::other
+  accept(ExecutionContext& context,
+      endpoint_type& peer_endpoint, asio::error_code& ec,
+      typename enable_if<
+        is_convertible<ExecutionContext&, execution_context&>::value
+      >::type* = 0)
+  {
+    typename Protocol::socket::template rebind_executor<
+        typename ExecutionContext::executor_type>::other peer(context);
+    impl_.get_service().accept(impl_.get_implementation(),
+        peer, &peer_endpoint, ec);
+    return peer;
+  }
+
+  /// Start an asynchronous accept.
+  /**
+   * This function is used to asynchronously accept a new connection. The
+   * function call always returns immediately.
+   *
+   * This overload requires that the Protocol template parameter satisfy the
+   * AcceptableProtocol type requirements.
+   *
+   * @param ex The I/O executor object to be used for the newly accepted
+   * socket.
+   *
+   * @param peer_endpoint An endpoint object into which the endpoint of the
+   * remote peer will be written. Ownership of the peer_endpoint object is
+   * retained by the caller, which must guarantee that it is valid until the
+   * handler is called.
+   *
+   * @param handler The handler to be called when the accept operation
+   * completes. Copies will be made of the handler as required. The function
+   * signature of the handler must be:
+   * @code void handler(
+   *   const asio::error_code& error, // Result of operation.
+   *   typename Protocol::socket::template rebind_executor<
+   *     Executor1>::other peer // On success, the newly accepted socket.
+   * ); @endcode
+   * Regardless of whether the asynchronous operation completes immediately or
+   * not, the handler will not be invoked from within this function. On
+   * immediate completion, invocation of the handler will be performed in a
+   * manner equivalent to using asio::post().
+   *
+   * @par Example
+   * @code
+   * void accept_handler(const asio::error_code& error,
+   *     asio::ip::tcp::socket peer)
+   * {
+   *   if (!error)
+   *   {
+   *     // Accept succeeded.
+   *   }
+   * }
+   *
+   * ...
+   *
+   * asio::ip::tcp::acceptor acceptor(my_context);
+   * ...
+   * asio::ip::tcp::endpoint endpoint;
+   * acceptor.async_accept(my_context2, endpoint, accept_handler);
+   * @endcode
+   */
+  template <typename Executor1,
+      ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+        typename Protocol::socket::template rebind_executor<
+          Executor1>::other)) MoveAcceptHandler
+            ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
+  ASIO_INITFN_AUTO_RESULT_TYPE(MoveAcceptHandler,
+      void (asio::error_code,
+        typename Protocol::socket::template rebind_executor<
+          Executor1>::other))
+  async_accept(const Executor1& ex, endpoint_type& peer_endpoint,
+      ASIO_MOVE_ARG(MoveAcceptHandler) handler
+        ASIO_DEFAULT_COMPLETION_TOKEN(executor_type),
+      typename enable_if<
+        is_executor<Executor1>::value
+          || execution::is_executor<Executor1>::value
+      >::type* = 0)
+  {
+    typedef typename Protocol::socket::template rebind_executor<
+      Executor1>::other other_socket_type;
+
+    return async_initiate<MoveAcceptHandler,
+      void (asio::error_code, other_socket_type)>(
+        initiate_async_move_accept(this), handler,
+        ex, &peer_endpoint,
+        static_cast<other_socket_type*>(0));
+  }
+
+  /// Start an asynchronous accept.
+  /**
+   * This function is used to asynchronously accept a new connection. The
+   * function call always returns immediately.
+   *
+   * This overload requires that the Protocol template parameter satisfy the
+   * AcceptableProtocol type requirements.
+   *
+   * @param context The I/O execution context object to be used for the newly
+   * accepted socket.
+   *
+   * @param peer_endpoint An endpoint object into which the endpoint of the
+   * remote peer will be written. Ownership of the peer_endpoint object is
+   * retained by the caller, which must guarantee that it is valid until the
+   * handler is called.
+   *
+   * @param handler The handler to be called when the accept operation
+   * completes. Copies will be made of the handler as required. The function
+   * signature of the handler must be:
+   * @code void handler(
+   *   const asio::error_code& error, // Result of operation.
+   *   typename Protocol::socket::template rebind_executor<
+   *     typename ExecutionContext::executor_type>::other peer
+   *       // On success, the newly accepted socket.
+   * ); @endcode
+   * Regardless of whether the asynchronous operation completes immediately or
+   * not, the handler will not be invoked from within this function. On
+   * immediate completion, invocation of the handler will be performed in a
+   * manner equivalent to using asio::post().
+   *
+   * @par Example
+   * @code
+   * void accept_handler(const asio::error_code& error,
+   *     asio::ip::tcp::socket peer)
+   * {
+   *   if (!error)
+   *   {
+   *     // Accept succeeded.
+   *   }
+   * }
+   *
+   * ...
+   *
+   * asio::ip::tcp::acceptor acceptor(my_context);
+   * ...
+   * asio::ip::tcp::endpoint endpoint;
+   * acceptor.async_accept(my_context2, endpoint, accept_handler);
+   * @endcode
+   */
+  template <typename ExecutionContext,
+      ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+        typename Protocol::socket::template rebind_executor<
+          typename ExecutionContext::executor_type>::other)) MoveAcceptHandler
+            ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
+  ASIO_INITFN_AUTO_RESULT_TYPE(MoveAcceptHandler,
+      void (asio::error_code,
+        typename Protocol::socket::template rebind_executor<
+          typename ExecutionContext::executor_type>::other))
+  async_accept(ExecutionContext& context,
+      endpoint_type& peer_endpoint,
+      ASIO_MOVE_ARG(MoveAcceptHandler) handler
+        ASIO_DEFAULT_COMPLETION_TOKEN(executor_type),
+      typename enable_if<
+        is_convertible<ExecutionContext&, execution_context&>::value
+      >::type* = 0)
+  {
+    typedef typename Protocol::socket::template rebind_executor<
+      typename ExecutionContext::executor_type>::other other_socket_type;
+
+    return async_initiate<MoveAcceptHandler,
+      void (asio::error_code, other_socket_type)>(
+        initiate_async_move_accept(this), handler,
+        context.get_executor(), &peer_endpoint,
+        static_cast<other_socket_type*>(0));
+  }
+#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+
+private:
+  // Disallow copying and assignment.
+  basic_socket_acceptor(const basic_socket_acceptor&) ASIO_DELETED;
+  basic_socket_acceptor& operator=(
+      const basic_socket_acceptor&) ASIO_DELETED;
+
+  class initiate_async_wait
+  {
+  public:
+    typedef Executor executor_type;
+
+    explicit initiate_async_wait(basic_socket_acceptor* self)
+      : self_(self)
+    {
+    }
+
+    executor_type get_executor() const ASIO_NOEXCEPT
+    {
+      return self_->get_executor();
+    }
+
+    template <typename WaitHandler>
+    void operator()(ASIO_MOVE_ARG(WaitHandler) handler, wait_type w) const
+    {
+      // If you get an error on the following line it means that your handler
+      // does not meet the documented type requirements for a WaitHandler.
+      ASIO_WAIT_HANDLER_CHECK(WaitHandler, handler) type_check;
+
+      detail::non_const_lvalue<WaitHandler> handler2(handler);
+      self_->impl_.get_service().async_wait(
+          self_->impl_.get_implementation(), w,
+          handler2.value, self_->impl_.get_executor());
+    }
+
+  private:
+    basic_socket_acceptor* self_;
+  };
+
+  class initiate_async_accept
+  {
+  public:
+    typedef Executor executor_type;
+
+    explicit initiate_async_accept(basic_socket_acceptor* self)
+      : self_(self)
+    {
+    }
+
+    executor_type get_executor() const ASIO_NOEXCEPT
+    {
+      return self_->get_executor();
+    }
+
+    template <typename AcceptHandler, typename Protocol1, typename Executor1>
+    void operator()(ASIO_MOVE_ARG(AcceptHandler) handler,
+        basic_socket<Protocol1, Executor1>* peer,
+        endpoint_type* peer_endpoint) const
+    {
+      // If you get an error on the following line it means that your handler
+      // does not meet the documented type requirements for a AcceptHandler.
+      ASIO_ACCEPT_HANDLER_CHECK(AcceptHandler, handler) type_check;
+
+      detail::non_const_lvalue<AcceptHandler> handler2(handler);
+      self_->impl_.get_service().async_accept(
+          self_->impl_.get_implementation(), *peer, peer_endpoint,
+          handler2.value, self_->impl_.get_executor());
+    }
+
+  private:
+    basic_socket_acceptor* self_;
+  };
+
+  class initiate_async_move_accept
+  {
+  public:
+    typedef Executor executor_type;
+
+    explicit initiate_async_move_accept(basic_socket_acceptor* self)
+      : self_(self)
+    {
+    }
+
+    executor_type get_executor() const ASIO_NOEXCEPT
+    {
+      return self_->get_executor();
+    }
+
+    template <typename MoveAcceptHandler, typename Executor1, typename Socket>
+    void operator()(ASIO_MOVE_ARG(MoveAcceptHandler) handler,
+        const Executor1& peer_ex, endpoint_type* peer_endpoint, Socket*) const
+    {
+      // If you get an error on the following line it means that your handler
+      // does not meet the documented type requirements for a MoveAcceptHandler.
+      ASIO_MOVE_ACCEPT_HANDLER_CHECK(
+          MoveAcceptHandler, handler, Socket) type_check;
+
+      detail::non_const_lvalue<MoveAcceptHandler> handler2(handler);
+      self_->impl_.get_service().async_move_accept(
+          self_->impl_.get_implementation(), peer_ex, peer_endpoint,
+          handler2.value, self_->impl_.get_executor());
+    }
+
+  private:
+    basic_socket_acceptor* self_;
+  };
+
+#if defined(ASIO_WINDOWS_RUNTIME)
+  detail::io_object_impl<
+    detail::null_socket_service<Protocol>, Executor> impl_;
+#elif defined(ASIO_HAS_IOCP)
+  detail::io_object_impl<
+    detail::win_iocp_socket_service<Protocol>, Executor> impl_;
+#else
+  detail::io_object_impl<
+    detail::reactive_socket_service<Protocol>, Executor> impl_;
+#endif
+};
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_BASIC_SOCKET_ACCEPTOR_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/basic_socket_iostream.hpp b/link/modules/asio-standalone/asio/include/asio/basic_socket_iostream.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/basic_socket_iostream.hpp
@@ -0,0 +1,407 @@
+//
+// basic_socket_iostream.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_BASIC_SOCKET_IOSTREAM_HPP
+#define ASIO_BASIC_SOCKET_IOSTREAM_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if !defined(ASIO_NO_IOSTREAM)
+
+#include <istream>
+#include <ostream>
+#include "asio/basic_socket_streambuf.hpp"
+
+#if !defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+# include "asio/detail/variadic_templates.hpp"
+
+// A macro that should expand to:
+//   template <typename T1, ..., typename Tn>
+//   explicit basic_socket_iostream(T1 x1, ..., Tn xn)
+//     : std::basic_iostream<char>(
+//         &this->detail::socket_iostream_base<
+//           Protocol, Clock, WaitTraits>::streambuf_)
+//   {
+//     if (rdbuf()->connect(x1, ..., xn) == 0)
+//       this->setstate(std::ios_base::failbit);
+//   }
+// This macro should only persist within this file.
+
+# define ASIO_PRIVATE_CTR_DEF(n) \
+  template <ASIO_VARIADIC_TPARAMS(n)> \
+  explicit basic_socket_iostream(ASIO_VARIADIC_BYVAL_PARAMS(n)) \
+    : std::basic_iostream<char>( \
+        &this->detail::socket_iostream_base< \
+          Protocol, Clock, WaitTraits>::streambuf_) \
+  { \
+    this->setf(std::ios_base::unitbuf); \
+    if (rdbuf()->connect(ASIO_VARIADIC_BYVAL_ARGS(n)) == 0) \
+      this->setstate(std::ios_base::failbit); \
+  } \
+  /**/
+
+// A macro that should expand to:
+//   template <typename T1, ..., typename Tn>
+//   void connect(T1 x1, ..., Tn xn)
+//   {
+//     if (rdbuf()->connect(x1, ..., xn) == 0)
+//       this->setstate(std::ios_base::failbit);
+//   }
+// This macro should only persist within this file.
+
+# define ASIO_PRIVATE_CONNECT_DEF(n) \
+  template <ASIO_VARIADIC_TPARAMS(n)> \
+  void connect(ASIO_VARIADIC_BYVAL_PARAMS(n)) \
+  { \
+    if (rdbuf()->connect(ASIO_VARIADIC_BYVAL_ARGS(n)) == 0) \
+      this->setstate(std::ios_base::failbit); \
+  } \
+  /**/
+
+#endif // !defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+// A separate base class is used to ensure that the streambuf is initialised
+// prior to the basic_socket_iostream's basic_iostream base class.
+template <typename Protocol, typename Clock, typename WaitTraits>
+class socket_iostream_base
+{
+protected:
+  socket_iostream_base()
+  {
+  }
+
+#if defined(ASIO_HAS_MOVE)
+  socket_iostream_base(socket_iostream_base&& other)
+    : streambuf_(std::move(other.streambuf_))
+  {
+  }
+
+  socket_iostream_base(basic_stream_socket<Protocol> s)
+    : streambuf_(std::move(s))
+  {
+  }
+
+  socket_iostream_base& operator=(socket_iostream_base&& other)
+  {
+    streambuf_ = std::move(other.streambuf_);
+    return *this;
+  }
+#endif // defined(ASIO_HAS_MOVE)
+
+  basic_socket_streambuf<Protocol, Clock, WaitTraits> streambuf_;
+};
+
+} // namespace detail
+
+#if !defined(ASIO_BASIC_SOCKET_IOSTREAM_FWD_DECL)
+#define ASIO_BASIC_SOCKET_IOSTREAM_FWD_DECL
+
+// Forward declaration with defaulted arguments.
+template <typename Protocol,
+#if defined(ASIO_HAS_BOOST_DATE_TIME) \
+  && defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM)
+    typename Clock = boost::posix_time::ptime,
+    typename WaitTraits = time_traits<Clock> >
+#else // defined(ASIO_HAS_BOOST_DATE_TIME)
+      // && defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM)
+    typename Clock = chrono::steady_clock,
+    typename WaitTraits = wait_traits<Clock> >
+#endif // defined(ASIO_HAS_BOOST_DATE_TIME)
+       // && defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM)
+class basic_socket_iostream;
+
+#endif // !defined(ASIO_BASIC_SOCKET_IOSTREAM_FWD_DECL)
+
+/// Iostream interface for a socket.
+#if defined(GENERATING_DOCUMENTATION)
+template <typename Protocol,
+    typename Clock = chrono::steady_clock,
+    typename WaitTraits = wait_traits<Clock> >
+#else // defined(GENERATING_DOCUMENTATION)
+template <typename Protocol, typename Clock, typename WaitTraits>
+#endif // defined(GENERATING_DOCUMENTATION)
+class basic_socket_iostream
+  : private detail::socket_iostream_base<Protocol, Clock, WaitTraits>,
+    public std::basic_iostream<char>
+{
+private:
+  // These typedefs are intended keep this class's implementation independent
+  // of whether it's using Boost.DateClock, Boost.Chrono or std::chrono.
+#if defined(ASIO_HAS_BOOST_DATE_TIME) \
+  && defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM)
+  typedef WaitTraits traits_helper;
+#else // defined(ASIO_HAS_BOOST_DATE_TIME)
+      // && defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM)
+  typedef detail::chrono_time_traits<Clock, WaitTraits> traits_helper;
+#endif // defined(ASIO_HAS_BOOST_DATE_TIME)
+       // && defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM)
+
+public:
+  /// The protocol type.
+  typedef Protocol protocol_type;
+
+  /// The endpoint type.
+  typedef typename Protocol::endpoint endpoint_type;
+
+  /// The clock type.
+  typedef Clock clock_type;
+
+#if defined(GENERATING_DOCUMENTATION)
+  /// (Deprecated: Use time_point.) The time type.
+  typedef typename WaitTraits::time_type time_type;
+
+  /// The time type.
+  typedef typename WaitTraits::time_point time_point;
+
+  /// (Deprecated: Use duration.) The duration type.
+  typedef typename WaitTraits::duration_type duration_type;
+
+  /// The duration type.
+  typedef typename WaitTraits::duration duration;
+#else
+# if !defined(ASIO_NO_DEPRECATED)
+  typedef typename traits_helper::time_type time_type;
+  typedef typename traits_helper::duration_type duration_type;
+# endif // !defined(ASIO_NO_DEPRECATED)
+  typedef typename traits_helper::time_type time_point;
+  typedef typename traits_helper::duration_type duration;
+#endif
+
+  /// Construct a basic_socket_iostream without establishing a connection.
+  basic_socket_iostream()
+    : std::basic_iostream<char>(
+        &this->detail::socket_iostream_base<
+          Protocol, Clock, WaitTraits>::streambuf_)
+  {
+    this->setf(std::ios_base::unitbuf);
+  }
+
+#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+  /// Construct a basic_socket_iostream from the supplied socket.
+  explicit basic_socket_iostream(basic_stream_socket<protocol_type> s)
+    : detail::socket_iostream_base<
+        Protocol, Clock, WaitTraits>(std::move(s)),
+      std::basic_iostream<char>(
+        &this->detail::socket_iostream_base<
+          Protocol, Clock, WaitTraits>::streambuf_)
+  {
+    this->setf(std::ios_base::unitbuf);
+  }
+
+#if defined(ASIO_HAS_STD_IOSTREAM_MOVE) \
+  || defined(GENERATING_DOCUMENTATION)
+  /// Move-construct a basic_socket_iostream from another.
+  basic_socket_iostream(basic_socket_iostream&& other)
+    : detail::socket_iostream_base<
+        Protocol, Clock, WaitTraits>(std::move(other)),
+      std::basic_iostream<char>(std::move(other))
+  {
+    this->set_rdbuf(&this->detail::socket_iostream_base<
+          Protocol, Clock, WaitTraits>::streambuf_);
+  }
+
+  /// Move-assign a basic_socket_iostream from another.
+  basic_socket_iostream& operator=(basic_socket_iostream&& other)
+  {
+    std::basic_iostream<char>::operator=(std::move(other));
+    detail::socket_iostream_base<
+        Protocol, Clock, WaitTraits>::operator=(std::move(other));
+    return *this;
+  }
+#endif // defined(ASIO_HAS_STD_IOSTREAM_MOVE)
+       //   || defined(GENERATING_DOCUMENTATION)
+#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+
+#if defined(GENERATING_DOCUMENTATION)
+  /// Establish a connection to an endpoint corresponding to a resolver query.
+  /**
+   * This constructor automatically establishes a connection based on the
+   * supplied resolver query parameters. The arguments are used to construct
+   * a resolver query object.
+   */
+  template <typename T1, ..., typename TN>
+  explicit basic_socket_iostream(T1 t1, ..., TN tn);
+#elif defined(ASIO_HAS_VARIADIC_TEMPLATES)
+  template <typename... T>
+  explicit basic_socket_iostream(T... x)
+    : std::basic_iostream<char>(
+        &this->detail::socket_iostream_base<
+          Protocol, Clock, WaitTraits>::streambuf_)
+  {
+    this->setf(std::ios_base::unitbuf);
+    if (rdbuf()->connect(x...) == 0)
+      this->setstate(std::ios_base::failbit);
+  }
+#else
+  ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_CTR_DEF)
+#endif
+
+#if defined(GENERATING_DOCUMENTATION)
+  /// Establish a connection to an endpoint corresponding to a resolver query.
+  /**
+   * This function automatically establishes a connection based on the supplied
+   * resolver query parameters. The arguments are used to construct a resolver
+   * query object.
+   */
+  template <typename T1, ..., typename TN>
+  void connect(T1 t1, ..., TN tn);
+#elif defined(ASIO_HAS_VARIADIC_TEMPLATES)
+  template <typename... T>
+  void connect(T... x)
+  {
+    if (rdbuf()->connect(x...) == 0)
+      this->setstate(std::ios_base::failbit);
+  }
+#else
+  ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_CONNECT_DEF)
+#endif
+
+  /// Close the connection.
+  void close()
+  {
+    if (rdbuf()->close() == 0)
+      this->setstate(std::ios_base::failbit);
+  }
+
+  /// Return a pointer to the underlying streambuf.
+  basic_socket_streambuf<Protocol, Clock, WaitTraits>* rdbuf() const
+  {
+    return const_cast<basic_socket_streambuf<Protocol, Clock, WaitTraits>*>(
+        &this->detail::socket_iostream_base<
+          Protocol, Clock, WaitTraits>::streambuf_);
+  }
+
+  /// Get a reference to the underlying socket.
+  basic_socket<Protocol>& socket()
+  {
+    return rdbuf()->socket();
+  }
+
+  /// Get the last error associated with the stream.
+  /**
+   * @return An \c error_code corresponding to the last error from the stream.
+   *
+   * @par Example
+   * To print the error associated with a failure to establish a connection:
+   * @code tcp::iostream s("www.boost.org", "http");
+   * if (!s)
+   * {
+   *   std::cout << "Error: " << s.error().message() << std::endl;
+   * } @endcode
+   */
+  const asio::error_code& error() const
+  {
+    return rdbuf()->error();
+  }
+
+#if !defined(ASIO_NO_DEPRECATED)
+  /// (Deprecated: Use expiry().) Get the stream's expiry time as an absolute
+  /// time.
+  /**
+   * @return An absolute time value representing the stream's expiry time.
+   */
+  time_point expires_at() const
+  {
+    return rdbuf()->expires_at();
+  }
+#endif // !defined(ASIO_NO_DEPRECATED)
+
+  /// Get the stream's expiry time as an absolute time.
+  /**
+   * @return An absolute time value representing the stream's expiry time.
+   */
+  time_point expiry() const
+  {
+    return rdbuf()->expiry();
+  }
+
+  /// Set the stream's expiry time as an absolute time.
+  /**
+   * This function sets the expiry time associated with the stream. Stream
+   * operations performed after this time (where the operations cannot be
+   * completed using the internal buffers) will fail with the error
+   * asio::error::operation_aborted.
+   *
+   * @param expiry_time The expiry time to be used for the stream.
+   */
+  void expires_at(const time_point& expiry_time)
+  {
+    rdbuf()->expires_at(expiry_time);
+  }
+
+  /// Set the stream's expiry time relative to now.
+  /**
+   * This function sets the expiry time associated with the stream. Stream
+   * operations performed after this time (where the operations cannot be
+   * completed using the internal buffers) will fail with the error
+   * asio::error::operation_aborted.
+   *
+   * @param expiry_time The expiry time to be used for the timer.
+   */
+  void expires_after(const duration& expiry_time)
+  {
+    rdbuf()->expires_after(expiry_time);
+  }
+
+#if !defined(ASIO_NO_DEPRECATED)
+  /// (Deprecated: Use expiry().) Get the stream's expiry time relative to now.
+  /**
+   * @return A relative time value representing the stream's expiry time.
+   */
+  duration expires_from_now() const
+  {
+    return rdbuf()->expires_from_now();
+  }
+
+  /// (Deprecated: Use expires_after().) Set the stream's expiry time relative
+  /// to now.
+  /**
+   * This function sets the expiry time associated with the stream. Stream
+   * operations performed after this time (where the operations cannot be
+   * completed using the internal buffers) will fail with the error
+   * asio::error::operation_aborted.
+   *
+   * @param expiry_time The expiry time to be used for the timer.
+   */
+  void expires_from_now(const duration& expiry_time)
+  {
+    rdbuf()->expires_from_now(expiry_time);
+  }
+#endif // !defined(ASIO_NO_DEPRECATED)
+
+private:
+  // Disallow copying and assignment.
+  basic_socket_iostream(const basic_socket_iostream&) ASIO_DELETED;
+  basic_socket_iostream& operator=(
+      const basic_socket_iostream&) ASIO_DELETED;
+};
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#if !defined(ASIO_HAS_VARIADIC_TEMPLATES)
+# undef ASIO_PRIVATE_CTR_DEF
+# undef ASIO_PRIVATE_CONNECT_DEF
+#endif // !defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+#endif // !defined(ASIO_NO_IOSTREAM)
+
+#endif // ASIO_BASIC_SOCKET_IOSTREAM_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/basic_socket_streambuf.hpp b/link/modules/asio-standalone/asio/include/asio/basic_socket_streambuf.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/basic_socket_streambuf.hpp
@@ -0,0 +1,687 @@
+//
+// basic_socket_streambuf.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_BASIC_SOCKET_STREAMBUF_HPP
+#define ASIO_BASIC_SOCKET_STREAMBUF_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if !defined(ASIO_NO_IOSTREAM)
+
+#include <streambuf>
+#include <vector>
+#include "asio/basic_socket.hpp"
+#include "asio/basic_stream_socket.hpp"
+#include "asio/detail/buffer_sequence_adapter.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/detail/throw_error.hpp"
+#include "asio/io_context.hpp"
+
+#if defined(ASIO_HAS_BOOST_DATE_TIME) \
+  && defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM)
+# include "asio/detail/deadline_timer_service.hpp"
+#else // defined(ASIO_HAS_BOOST_DATE_TIME)
+      // && defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM)
+# include "asio/steady_timer.hpp"
+#endif // defined(ASIO_HAS_BOOST_DATE_TIME)
+       // && defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM)
+
+#if !defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+# include "asio/detail/variadic_templates.hpp"
+
+// A macro that should expand to:
+//   template <typename T1, ..., typename Tn>
+//   basic_socket_streambuf* connect(T1 x1, ..., Tn xn)
+//   {
+//     init_buffers();
+//     typedef typename Protocol::resolver resolver_type;
+//     resolver_type resolver(socket().get_executor());
+//     connect_to_endpoints(
+//         resolver.resolve(x1, ..., xn, ec_));
+//     return !ec_ ? this : 0;
+//   }
+// This macro should only persist within this file.
+
+# define ASIO_PRIVATE_CONNECT_DEF(n) \
+  template <ASIO_VARIADIC_TPARAMS(n)> \
+  basic_socket_streambuf* connect(ASIO_VARIADIC_BYVAL_PARAMS(n)) \
+  { \
+    init_buffers(); \
+    typedef typename Protocol::resolver resolver_type; \
+    resolver_type resolver(socket().get_executor()); \
+    connect_to_endpoints( \
+        resolver.resolve(ASIO_VARIADIC_BYVAL_ARGS(n), ec_)); \
+    return !ec_ ? this : 0; \
+  } \
+  /**/
+
+#endif // !defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+// A separate base class is used to ensure that the io_context member is
+// initialised prior to the basic_socket_streambuf's basic_socket base class.
+class socket_streambuf_io_context
+{
+protected:
+  socket_streambuf_io_context(io_context* ctx)
+    : default_io_context_(ctx)
+  {
+  }
+
+  shared_ptr<io_context> default_io_context_;
+};
+
+// A separate base class is used to ensure that the dynamically allocated
+// buffers are constructed prior to the basic_socket_streambuf's basic_socket
+// base class. This makes moving the socket is the last potentially throwing
+// step in the streambuf's move constructor, giving the constructor a strong
+// exception safety guarantee.
+class socket_streambuf_buffers
+{
+protected:
+  socket_streambuf_buffers()
+    : get_buffer_(buffer_size),
+      put_buffer_(buffer_size)
+  {
+  }
+
+  enum { buffer_size = 512 };
+  std::vector<char> get_buffer_;
+  std::vector<char> put_buffer_;
+};
+
+} // namespace detail
+
+#if !defined(ASIO_BASIC_SOCKET_STREAMBUF_FWD_DECL)
+#define ASIO_BASIC_SOCKET_STREAMBUF_FWD_DECL
+
+// Forward declaration with defaulted arguments.
+template <typename Protocol,
+#if defined(ASIO_HAS_BOOST_DATE_TIME) \
+  && defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM)
+    typename Clock = boost::posix_time::ptime,
+    typename WaitTraits = time_traits<Clock> >
+#else // defined(ASIO_HAS_BOOST_DATE_TIME)
+      // && defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM)
+    typename Clock = chrono::steady_clock,
+    typename WaitTraits = wait_traits<Clock> >
+#endif // defined(ASIO_HAS_BOOST_DATE_TIME)
+       // && defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM)
+class basic_socket_streambuf;
+
+#endif // !defined(ASIO_BASIC_SOCKET_STREAMBUF_FWD_DECL)
+
+/// Iostream streambuf for a socket.
+#if defined(GENERATING_DOCUMENTATION)
+template <typename Protocol,
+    typename Clock = chrono::steady_clock,
+    typename WaitTraits = wait_traits<Clock> >
+#else // defined(GENERATING_DOCUMENTATION)
+template <typename Protocol, typename Clock, typename WaitTraits>
+#endif // defined(GENERATING_DOCUMENTATION)
+class basic_socket_streambuf
+  : public std::streambuf,
+    private detail::socket_streambuf_io_context,
+    private detail::socket_streambuf_buffers,
+#if defined(ASIO_NO_DEPRECATED) || defined(GENERATING_DOCUMENTATION)
+    private basic_socket<Protocol>
+#else // defined(ASIO_NO_DEPRECATED) || defined(GENERATING_DOCUMENTATION)
+    public basic_socket<Protocol>
+#endif // defined(ASIO_NO_DEPRECATED) || defined(GENERATING_DOCUMENTATION)
+{
+private:
+  // These typedefs are intended keep this class's implementation independent
+  // of whether it's using Boost.DateClock, Boost.Chrono or std::chrono.
+#if defined(ASIO_HAS_BOOST_DATE_TIME) \
+  && defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM)
+  typedef WaitTraits traits_helper;
+#else // defined(ASIO_HAS_BOOST_DATE_TIME)
+      // && defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM)
+  typedef detail::chrono_time_traits<Clock, WaitTraits> traits_helper;
+#endif // defined(ASIO_HAS_BOOST_DATE_TIME)
+       // && defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM)
+
+public:
+  /// The protocol type.
+  typedef Protocol protocol_type;
+
+  /// The endpoint type.
+  typedef typename Protocol::endpoint endpoint_type;
+
+  /// The clock type.
+  typedef Clock clock_type;
+
+#if defined(GENERATING_DOCUMENTATION)
+  /// (Deprecated: Use time_point.) The time type.
+  typedef typename WaitTraits::time_type time_type;
+
+  /// The time type.
+  typedef typename WaitTraits::time_point time_point;
+
+  /// (Deprecated: Use duration.) The duration type.
+  typedef typename WaitTraits::duration_type duration_type;
+
+  /// The duration type.
+  typedef typename WaitTraits::duration duration;
+#else
+# if !defined(ASIO_NO_DEPRECATED)
+  typedef typename traits_helper::time_type time_type;
+  typedef typename traits_helper::duration_type duration_type;
+# endif // !defined(ASIO_NO_DEPRECATED)
+  typedef typename traits_helper::time_type time_point;
+  typedef typename traits_helper::duration_type duration;
+#endif
+
+  /// Construct a basic_socket_streambuf without establishing a connection.
+  basic_socket_streambuf()
+    : detail::socket_streambuf_io_context(new io_context),
+      basic_socket<Protocol>(*default_io_context_),
+      expiry_time_(max_expiry_time())
+  {
+    init_buffers();
+  }
+
+#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+  /// Construct a basic_socket_streambuf from the supplied socket.
+  explicit basic_socket_streambuf(basic_stream_socket<protocol_type> s)
+    : detail::socket_streambuf_io_context(0),
+      basic_socket<Protocol>(std::move(s)),
+      expiry_time_(max_expiry_time())
+  {
+    init_buffers();
+  }
+
+  /// Move-construct a basic_socket_streambuf from another.
+  basic_socket_streambuf(basic_socket_streambuf&& other)
+    : detail::socket_streambuf_io_context(other),
+      basic_socket<Protocol>(std::move(other.socket())),
+      ec_(other.ec_),
+      expiry_time_(other.expiry_time_)
+  {
+    get_buffer_.swap(other.get_buffer_);
+    put_buffer_.swap(other.put_buffer_);
+    setg(other.eback(), other.gptr(), other.egptr());
+    setp(other.pptr(), other.epptr());
+    other.ec_ = asio::error_code();
+    other.expiry_time_ = max_expiry_time();
+    other.init_buffers();
+  }
+
+  /// Move-assign a basic_socket_streambuf from another.
+  basic_socket_streambuf& operator=(basic_socket_streambuf&& other)
+  {
+    this->close();
+    socket() = std::move(other.socket());
+    detail::socket_streambuf_io_context::operator=(other);
+    ec_ = other.ec_;
+    expiry_time_ = other.expiry_time_;
+    get_buffer_.swap(other.get_buffer_);
+    put_buffer_.swap(other.put_buffer_);
+    setg(other.eback(), other.gptr(), other.egptr());
+    setp(other.pptr(), other.epptr());
+    other.ec_ = asio::error_code();
+    other.expiry_time_ = max_expiry_time();
+    other.put_buffer_.resize(buffer_size);
+    other.init_buffers();
+    return *this;
+  }
+#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+
+  /// Destructor flushes buffered data.
+  virtual ~basic_socket_streambuf()
+  {
+    if (pptr() != pbase())
+      overflow(traits_type::eof());
+  }
+
+  /// Establish a connection.
+  /**
+   * This function establishes a connection to the specified endpoint.
+   *
+   * @return \c this if a connection was successfully established, a null
+   * pointer otherwise.
+   */
+  basic_socket_streambuf* connect(const endpoint_type& endpoint)
+  {
+    init_buffers();
+    ec_ = asio::error_code();
+    this->connect_to_endpoints(&endpoint, &endpoint + 1);
+    return !ec_ ? this : 0;
+  }
+
+#if defined(GENERATING_DOCUMENTATION)
+  /// Establish a connection.
+  /**
+   * This function automatically establishes a connection based on the supplied
+   * resolver query parameters. The arguments are used to construct a resolver
+   * query object.
+   *
+   * @return \c this if a connection was successfully established, a null
+   * pointer otherwise.
+   */
+  template <typename T1, ..., typename TN>
+  basic_socket_streambuf* connect(T1 t1, ..., TN tn);
+#elif defined(ASIO_HAS_VARIADIC_TEMPLATES)
+  template <typename... T>
+  basic_socket_streambuf* connect(T... x)
+  {
+    init_buffers();
+    typedef typename Protocol::resolver resolver_type;
+    resolver_type resolver(socket().get_executor());
+    connect_to_endpoints(resolver.resolve(x..., ec_));
+    return !ec_ ? this : 0;
+  }
+#else
+  ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_CONNECT_DEF)
+#endif
+
+  /// Close the connection.
+  /**
+   * @return \c this if a connection was successfully established, a null
+   * pointer otherwise.
+   */
+  basic_socket_streambuf* close()
+  {
+    sync();
+    socket().close(ec_);
+    if (!ec_)
+      init_buffers();
+    return !ec_ ? this : 0;
+  }
+
+  /// Get a reference to the underlying socket.
+  basic_socket<Protocol>& socket()
+  {
+    return *this;
+  }
+
+  /// Get the last error associated with the stream buffer.
+  /**
+   * @return An \c error_code corresponding to the last error from the stream
+   * buffer.
+   */
+  const asio::error_code& error() const
+  {
+    return ec_;
+  }
+
+#if !defined(ASIO_NO_DEPRECATED)
+  /// (Deprecated: Use error().) Get the last error associated with the stream
+  /// buffer.
+  /**
+   * @return An \c error_code corresponding to the last error from the stream
+   * buffer.
+   */
+  const asio::error_code& puberror() const
+  {
+    return error();
+  }
+
+  /// (Deprecated: Use expiry().) Get the stream buffer's expiry time as an
+  /// absolute time.
+  /**
+   * @return An absolute time value representing the stream buffer's expiry
+   * time.
+   */
+  time_point expires_at() const
+  {
+    return expiry_time_;
+  }
+#endif // !defined(ASIO_NO_DEPRECATED)
+
+  /// Get the stream buffer's expiry time as an absolute time.
+  /**
+   * @return An absolute time value representing the stream buffer's expiry
+   * time.
+   */
+  time_point expiry() const
+  {
+    return expiry_time_;
+  }
+
+  /// Set the stream buffer's expiry time as an absolute time.
+  /**
+   * This function sets the expiry time associated with the stream. Stream
+   * operations performed after this time (where the operations cannot be
+   * completed using the internal buffers) will fail with the error
+   * asio::error::operation_aborted.
+   *
+   * @param expiry_time The expiry time to be used for the stream.
+   */
+  void expires_at(const time_point& expiry_time)
+  {
+    expiry_time_ = expiry_time;
+  }
+
+  /// Set the stream buffer's expiry time relative to now.
+  /**
+   * This function sets the expiry time associated with the stream. Stream
+   * operations performed after this time (where the operations cannot be
+   * completed using the internal buffers) will fail with the error
+   * asio::error::operation_aborted.
+   *
+   * @param expiry_time The expiry time to be used for the timer.
+   */
+  void expires_after(const duration& expiry_time)
+  {
+    expiry_time_ = traits_helper::add(traits_helper::now(), expiry_time);
+  }
+
+#if !defined(ASIO_NO_DEPRECATED)
+  /// (Deprecated: Use expiry().) Get the stream buffer's expiry time relative
+  /// to now.
+  /**
+   * @return A relative time value representing the stream buffer's expiry time.
+   */
+  duration expires_from_now() const
+  {
+    return traits_helper::subtract(expires_at(), traits_helper::now());
+  }
+
+  /// (Deprecated: Use expires_after().) Set the stream buffer's expiry time
+  /// relative to now.
+  /**
+   * This function sets the expiry time associated with the stream. Stream
+   * operations performed after this time (where the operations cannot be
+   * completed using the internal buffers) will fail with the error
+   * asio::error::operation_aborted.
+   *
+   * @param expiry_time The expiry time to be used for the timer.
+   */
+  void expires_from_now(const duration& expiry_time)
+  {
+    expiry_time_ = traits_helper::add(traits_helper::now(), expiry_time);
+  }
+#endif // !defined(ASIO_NO_DEPRECATED)
+
+protected:
+  int_type underflow()
+  {
+#if defined(ASIO_WINDOWS_RUNTIME)
+    ec_ = asio::error::operation_not_supported;
+    return traits_type::eof();
+#else // defined(ASIO_WINDOWS_RUNTIME)
+    if (gptr() != egptr())
+      return traits_type::eof();
+
+    for (;;)
+    {
+      // Check if we are past the expiry time.
+      if (traits_helper::less_than(expiry_time_, traits_helper::now()))
+      {
+        ec_ = asio::error::timed_out;
+        return traits_type::eof();
+      }
+
+      // Try to complete the operation without blocking.
+      if (!socket().native_non_blocking())
+        socket().native_non_blocking(true, ec_);
+      detail::buffer_sequence_adapter<mutable_buffer, mutable_buffer>
+        bufs(asio::buffer(get_buffer_) + putback_max);
+      detail::signed_size_type bytes = detail::socket_ops::recv(
+          socket().native_handle(), bufs.buffers(), bufs.count(), 0, ec_);
+
+      // Check if operation succeeded.
+      if (bytes > 0)
+      {
+        setg(&get_buffer_[0], &get_buffer_[0] + putback_max,
+            &get_buffer_[0] + putback_max + bytes);
+        return traits_type::to_int_type(*gptr());
+      }
+
+      // Check for EOF.
+      if (bytes == 0)
+      {
+        ec_ = asio::error::eof;
+        return traits_type::eof();
+      }
+
+      // Operation failed.
+      if (ec_ != asio::error::would_block
+          && ec_ != asio::error::try_again)
+        return traits_type::eof();
+
+      // Wait for socket to become ready.
+      if (detail::socket_ops::poll_read(
+            socket().native_handle(), 0, timeout(), ec_) < 0)
+        return traits_type::eof();
+    }
+#endif // defined(ASIO_WINDOWS_RUNTIME)
+  }
+
+  int_type overflow(int_type c)
+  {
+#if defined(ASIO_WINDOWS_RUNTIME)
+    ec_ = asio::error::operation_not_supported;
+    return traits_type::eof();
+#else // defined(ASIO_WINDOWS_RUNTIME)
+    char_type ch = traits_type::to_char_type(c);
+
+    // Determine what needs to be sent.
+    const_buffer output_buffer;
+    if (put_buffer_.empty())
+    {
+      if (traits_type::eq_int_type(c, traits_type::eof()))
+        return traits_type::not_eof(c); // Nothing to do.
+      output_buffer = asio::buffer(&ch, sizeof(char_type));
+    }
+    else
+    {
+      output_buffer = asio::buffer(pbase(),
+          (pptr() - pbase()) * sizeof(char_type));
+    }
+
+    while (output_buffer.size() > 0)
+    {
+      // Check if we are past the expiry time.
+      if (traits_helper::less_than(expiry_time_, traits_helper::now()))
+      {
+        ec_ = asio::error::timed_out;
+        return traits_type::eof();
+      }
+
+      // Try to complete the operation without blocking.
+      if (!socket().native_non_blocking())
+        socket().native_non_blocking(true, ec_);
+      detail::buffer_sequence_adapter<
+        const_buffer, const_buffer> bufs(output_buffer);
+      detail::signed_size_type bytes = detail::socket_ops::send(
+          socket().native_handle(), bufs.buffers(), bufs.count(), 0, ec_);
+
+      // Check if operation succeeded.
+      if (bytes > 0)
+      {
+        output_buffer += static_cast<std::size_t>(bytes);
+        continue;
+      }
+
+      // Operation failed.
+      if (ec_ != asio::error::would_block
+          && ec_ != asio::error::try_again)
+        return traits_type::eof();
+
+      // Wait for socket to become ready.
+      if (detail::socket_ops::poll_write(
+            socket().native_handle(), 0, timeout(), ec_) < 0)
+        return traits_type::eof();
+    }
+
+    if (!put_buffer_.empty())
+    {
+      setp(&put_buffer_[0], &put_buffer_[0] + put_buffer_.size());
+
+      // If the new character is eof then our work here is done.
+      if (traits_type::eq_int_type(c, traits_type::eof()))
+        return traits_type::not_eof(c);
+
+      // Add the new character to the output buffer.
+      *pptr() = ch;
+      pbump(1);
+    }
+
+    return c;
+#endif // defined(ASIO_WINDOWS_RUNTIME)
+  }
+
+  int sync()
+  {
+    return overflow(traits_type::eof());
+  }
+
+  std::streambuf* setbuf(char_type* s, std::streamsize n)
+  {
+    if (pptr() == pbase() && s == 0 && n == 0)
+    {
+      put_buffer_.clear();
+      setp(0, 0);
+      sync();
+      return this;
+    }
+
+    return 0;
+  }
+
+private:
+  // Disallow copying and assignment.
+  basic_socket_streambuf(const basic_socket_streambuf&) ASIO_DELETED;
+  basic_socket_streambuf& operator=(
+      const basic_socket_streambuf&) ASIO_DELETED;
+
+  void init_buffers()
+  {
+    setg(&get_buffer_[0],
+        &get_buffer_[0] + putback_max,
+        &get_buffer_[0] + putback_max);
+
+    if (put_buffer_.empty())
+      setp(0, 0);
+    else
+      setp(&put_buffer_[0], &put_buffer_[0] + put_buffer_.size());
+  }
+
+  int timeout() const
+  {
+    int64_t msec = traits_helper::to_posix_duration(
+        traits_helper::subtract(expiry_time_,
+          traits_helper::now())).total_milliseconds();
+    if (msec > (std::numeric_limits<int>::max)())
+      msec = (std::numeric_limits<int>::max)();
+    else if (msec < 0)
+      msec = 0;
+    return static_cast<int>(msec);
+  }
+
+  template <typename EndpointSequence>
+  void connect_to_endpoints(const EndpointSequence& endpoints)
+  {
+    this->connect_to_endpoints(endpoints.begin(), endpoints.end());
+  }
+
+  template <typename EndpointIterator>
+  void connect_to_endpoints(EndpointIterator begin, EndpointIterator end)
+  {
+#if defined(ASIO_WINDOWS_RUNTIME)
+    ec_ = asio::error::operation_not_supported;
+#else // defined(ASIO_WINDOWS_RUNTIME)
+    if (ec_)
+      return;
+
+    ec_ = asio::error::not_found;
+    for (EndpointIterator i = begin; i != end; ++i)
+    {
+      // Check if we are past the expiry time.
+      if (traits_helper::less_than(expiry_time_, traits_helper::now()))
+      {
+        ec_ = asio::error::timed_out;
+        return;
+      }
+
+      // Close and reopen the socket.
+      typename Protocol::endpoint ep(*i);
+      socket().close(ec_);
+      socket().open(ep.protocol(), ec_);
+      if (ec_)
+        continue;
+
+      // Try to complete the operation without blocking.
+      if (!socket().native_non_blocking())
+        socket().native_non_blocking(true, ec_);
+      detail::socket_ops::connect(socket().native_handle(),
+          ep.data(), ep.size(), ec_);
+
+      // Check if operation succeeded.
+      if (!ec_)
+        return;
+
+      // Operation failed.
+      if (ec_ != asio::error::in_progress
+          && ec_ != asio::error::would_block)
+        continue;
+
+      // Wait for socket to become ready.
+      if (detail::socket_ops::poll_connect(
+            socket().native_handle(), timeout(), ec_) < 0)
+        continue;
+
+      // Get the error code from the connect operation.
+      int connect_error = 0;
+      size_t connect_error_len = sizeof(connect_error);
+      if (detail::socket_ops::getsockopt(socket().native_handle(), 0,
+            SOL_SOCKET, SO_ERROR, &connect_error, &connect_error_len, ec_)
+          == detail::socket_error_retval)
+        return;
+
+      // Check the result of the connect operation.
+      ec_ = asio::error_code(connect_error,
+          asio::error::get_system_category());
+      if (!ec_)
+        return;
+    }
+#endif // defined(ASIO_WINDOWS_RUNTIME)
+  }
+
+  // Helper function to get the maximum expiry time.
+  static time_point max_expiry_time()
+  {
+#if defined(ASIO_HAS_BOOST_DATE_TIME) \
+  && defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM)
+    return boost::posix_time::pos_infin;
+#else // defined(ASIO_HAS_BOOST_DATE_TIME)
+      // && defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM)
+    return (time_point::max)();
+#endif // defined(ASIO_HAS_BOOST_DATE_TIME)
+       // && defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM)
+  }
+
+  enum { putback_max = 8 };
+  asio::error_code ec_;
+  time_point expiry_time_;
+};
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#if !defined(ASIO_HAS_VARIADIC_TEMPLATES)
+# undef ASIO_PRIVATE_CONNECT_DEF
+#endif // !defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+#endif // !defined(ASIO_NO_IOSTREAM)
+
+#endif // ASIO_BASIC_SOCKET_STREAMBUF_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/basic_stream_socket.hpp b/link/modules/asio-standalone/asio/include/asio/basic_stream_socket.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/basic_stream_socket.hpp
@@ -0,0 +1,1053 @@
+//
+// basic_stream_socket.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_BASIC_STREAM_SOCKET_HPP
+#define ASIO_BASIC_STREAM_SOCKET_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <cstddef>
+#include "asio/async_result.hpp"
+#include "asio/basic_socket.hpp"
+#include "asio/detail/handler_type_requirements.hpp"
+#include "asio/detail/non_const_lvalue.hpp"
+#include "asio/detail/throw_error.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+#if !defined(ASIO_BASIC_STREAM_SOCKET_FWD_DECL)
+#define ASIO_BASIC_STREAM_SOCKET_FWD_DECL
+
+// Forward declaration with defaulted arguments.
+template <typename Protocol, typename Executor = any_io_executor>
+class basic_stream_socket;
+
+#endif // !defined(ASIO_BASIC_STREAM_SOCKET_FWD_DECL)
+
+/// Provides stream-oriented socket functionality.
+/**
+ * The basic_stream_socket class template provides asynchronous and blocking
+ * stream-oriented socket functionality.
+ *
+ * @par Thread Safety
+ * @e Distinct @e objects: Safe.@n
+ * @e Shared @e objects: Unsafe.
+ *
+ * @par Concepts:
+ * AsyncReadStream, AsyncWriteStream, Stream, SyncReadStream, SyncWriteStream.
+ */
+template <typename Protocol, typename Executor>
+class basic_stream_socket
+  : public basic_socket<Protocol, Executor>
+{
+public:
+  /// The type of the executor associated with the object.
+  typedef Executor executor_type;
+
+  /// Rebinds the socket type to another executor.
+  template <typename Executor1>
+  struct rebind_executor
+  {
+    /// The socket type when rebound to the specified executor.
+    typedef basic_stream_socket<Protocol, Executor1> other;
+  };
+
+  /// The native representation of a socket.
+#if defined(GENERATING_DOCUMENTATION)
+  typedef implementation_defined native_handle_type;
+#else
+  typedef typename basic_socket<Protocol,
+    Executor>::native_handle_type native_handle_type;
+#endif
+
+  /// The protocol type.
+  typedef Protocol protocol_type;
+
+  /// The endpoint type.
+  typedef typename Protocol::endpoint endpoint_type;
+
+  /// Construct a basic_stream_socket without opening it.
+  /**
+   * This constructor creates a stream socket without opening it. The socket
+   * needs to be opened and then connected or accepted before data can be sent
+   * or received on it.
+   *
+   * @param ex The I/O executor that the socket will use, by default, to
+   * dispatch handlers for any asynchronous operations performed on the socket.
+   */
+  explicit basic_stream_socket(const executor_type& ex)
+    : basic_socket<Protocol, Executor>(ex)
+  {
+  }
+
+  /// Construct a basic_stream_socket without opening it.
+  /**
+   * This constructor creates a stream socket without opening it. The socket
+   * needs to be opened and then connected or accepted before data can be sent
+   * or received on it.
+   *
+   * @param context An execution context which provides the I/O executor that
+   * the socket will use, by default, to dispatch handlers for any asynchronous
+   * operations performed on the socket.
+   */
+  template <typename ExecutionContext>
+  explicit basic_stream_socket(ExecutionContext& context,
+      typename enable_if<
+        is_convertible<ExecutionContext&, execution_context&>::value
+      >::type* = 0)
+    : basic_socket<Protocol, Executor>(context)
+  {
+  }
+
+  /// Construct and open a basic_stream_socket.
+  /**
+   * This constructor creates and opens a stream socket. The socket needs to be
+   * connected or accepted before data can be sent or received on it.
+   *
+   * @param ex The I/O executor that the socket will use, by default, to
+   * dispatch handlers for any asynchronous operations performed on the socket.
+   *
+   * @param protocol An object specifying protocol parameters to be used.
+   *
+   * @throws asio::system_error Thrown on failure.
+   */
+  basic_stream_socket(const executor_type& ex, const protocol_type& protocol)
+    : basic_socket<Protocol, Executor>(ex, protocol)
+  {
+  }
+
+  /// Construct and open a basic_stream_socket.
+  /**
+   * This constructor creates and opens a stream socket. The socket needs to be
+   * connected or accepted before data can be sent or received on it.
+   *
+   * @param context An execution context which provides the I/O executor that
+   * the socket will use, by default, to dispatch handlers for any asynchronous
+   * operations performed on the socket.
+   *
+   * @param protocol An object specifying protocol parameters to be used.
+   *
+   * @throws asio::system_error Thrown on failure.
+   */
+  template <typename ExecutionContext>
+  basic_stream_socket(ExecutionContext& context, const protocol_type& protocol,
+      typename enable_if<
+        is_convertible<ExecutionContext&, execution_context&>::value
+      >::type* = 0)
+    : basic_socket<Protocol, Executor>(context, protocol)
+  {
+  }
+
+  /// Construct a basic_stream_socket, opening it and binding it to the given
+  /// local endpoint.
+  /**
+   * This constructor creates a stream socket and automatically opens it bound
+   * to the specified endpoint on the local machine. The protocol used is the
+   * protocol associated with the given endpoint.
+   *
+   * @param ex The I/O executor that the socket will use, by default, to
+   * dispatch handlers for any asynchronous operations performed on the socket.
+   *
+   * @param endpoint An endpoint on the local machine to which the stream
+   * socket will be bound.
+   *
+   * @throws asio::system_error Thrown on failure.
+   */
+  basic_stream_socket(const executor_type& ex, const endpoint_type& endpoint)
+    : basic_socket<Protocol, Executor>(ex, endpoint)
+  {
+  }
+
+  /// Construct a basic_stream_socket, opening it and binding it to the given
+  /// local endpoint.
+  /**
+   * This constructor creates a stream socket and automatically opens it bound
+   * to the specified endpoint on the local machine. The protocol used is the
+   * protocol associated with the given endpoint.
+   *
+   * @param context An execution context which provides the I/O executor that
+   * the socket will use, by default, to dispatch handlers for any asynchronous
+   * operations performed on the socket.
+   *
+   * @param endpoint An endpoint on the local machine to which the stream
+   * socket will be bound.
+   *
+   * @throws asio::system_error Thrown on failure.
+   */
+  template <typename ExecutionContext>
+  basic_stream_socket(ExecutionContext& context, const endpoint_type& endpoint,
+      typename enable_if<
+        is_convertible<ExecutionContext&, execution_context&>::value
+      >::type* = 0)
+    : basic_socket<Protocol, Executor>(context, endpoint)
+  {
+  }
+
+  /// Construct a basic_stream_socket on an existing native socket.
+  /**
+   * This constructor creates a stream socket object to hold an existing native
+   * socket.
+   *
+   * @param ex The I/O executor that the socket will use, by default, to
+   * dispatch handlers for any asynchronous operations performed on the socket.
+   *
+   * @param protocol An object specifying protocol parameters to be used.
+   *
+   * @param native_socket The new underlying socket implementation.
+   *
+   * @throws asio::system_error Thrown on failure.
+   */
+  basic_stream_socket(const executor_type& ex,
+      const protocol_type& protocol, const native_handle_type& native_socket)
+    : basic_socket<Protocol, Executor>(ex, protocol, native_socket)
+  {
+  }
+
+  /// Construct a basic_stream_socket on an existing native socket.
+  /**
+   * This constructor creates a stream socket object to hold an existing native
+   * socket.
+   *
+   * @param context An execution context which provides the I/O executor that
+   * the socket will use, by default, to dispatch handlers for any asynchronous
+   * operations performed on the socket.
+   *
+   * @param protocol An object specifying protocol parameters to be used.
+   *
+   * @param native_socket The new underlying socket implementation.
+   *
+   * @throws asio::system_error Thrown on failure.
+   */
+  template <typename ExecutionContext>
+  basic_stream_socket(ExecutionContext& context,
+      const protocol_type& protocol, const native_handle_type& native_socket,
+      typename enable_if<
+        is_convertible<ExecutionContext&, execution_context&>::value
+      >::type* = 0)
+    : basic_socket<Protocol, Executor>(context, protocol, native_socket)
+  {
+  }
+
+#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+  /// Move-construct a basic_stream_socket from another.
+  /**
+   * This constructor moves a stream socket from one object to another.
+   *
+   * @param other The other basic_stream_socket object from which the move
+   * will occur.
+   *
+   * @note Following the move, the moved-from object is in the same state as if
+   * constructed using the @c basic_stream_socket(const executor_type&)
+   * constructor.
+   */
+  basic_stream_socket(basic_stream_socket&& other) ASIO_NOEXCEPT
+    : basic_socket<Protocol, Executor>(std::move(other))
+  {
+  }
+
+  /// Move-assign a basic_stream_socket from another.
+  /**
+   * This assignment operator moves a stream socket from one object to another.
+   *
+   * @param other The other basic_stream_socket object from which the move
+   * will occur.
+   *
+   * @note Following the move, the moved-from object is in the same state as if
+   * constructed using the @c basic_stream_socket(const executor_type&)
+   * constructor.
+   */
+  basic_stream_socket& operator=(basic_stream_socket&& other)
+  {
+    basic_socket<Protocol, Executor>::operator=(std::move(other));
+    return *this;
+  }
+
+  /// Move-construct a basic_stream_socket from a socket of another protocol
+  /// type.
+  /**
+   * This constructor moves a stream socket from one object to another.
+   *
+   * @param other The other basic_stream_socket object from which the move
+   * will occur.
+   *
+   * @note Following the move, the moved-from object is in the same state as if
+   * constructed using the @c basic_stream_socket(const executor_type&)
+   * constructor.
+   */
+  template <typename Protocol1, typename Executor1>
+  basic_stream_socket(basic_stream_socket<Protocol1, Executor1>&& other,
+      typename enable_if<
+        is_convertible<Protocol1, Protocol>::value
+          && is_convertible<Executor1, Executor>::value
+      >::type* = 0)
+    : basic_socket<Protocol, Executor>(std::move(other))
+  {
+  }
+
+  /// Move-assign a basic_stream_socket from a socket of another protocol type.
+  /**
+   * This assignment operator moves a stream socket from one object to another.
+   *
+   * @param other The other basic_stream_socket object from which the move
+   * will occur.
+   *
+   * @note Following the move, the moved-from object is in the same state as if
+   * constructed using the @c basic_stream_socket(const executor_type&)
+   * constructor.
+   */
+  template <typename Protocol1, typename Executor1>
+  typename enable_if<
+    is_convertible<Protocol1, Protocol>::value
+      && is_convertible<Executor1, Executor>::value,
+    basic_stream_socket&
+  >::type operator=(basic_stream_socket<Protocol1, Executor1>&& other)
+  {
+    basic_socket<Protocol, Executor>::operator=(std::move(other));
+    return *this;
+  }
+#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+
+  /// Destroys the socket.
+  /**
+   * This function destroys the socket, cancelling any outstanding asynchronous
+   * operations associated with the socket as if by calling @c cancel.
+   */
+  ~basic_stream_socket()
+  {
+  }
+
+  /// Send some data on the socket.
+  /**
+   * This function is used to send data on the stream socket. The function
+   * call will block until one or more bytes of the data has been sent
+   * successfully, or an until error occurs.
+   *
+   * @param buffers One or more data buffers to be sent on the socket.
+   *
+   * @returns The number of bytes sent.
+   *
+   * @throws asio::system_error Thrown on failure.
+   *
+   * @note The send operation may not transmit all of the data to the peer.
+   * Consider using the @ref write function if you need to ensure that all data
+   * is written before the blocking operation completes.
+   *
+   * @par Example
+   * To send a single data buffer use the @ref buffer function as follows:
+   * @code
+   * socket.send(asio::buffer(data, size));
+   * @endcode
+   * See the @ref buffer documentation for information on sending multiple
+   * buffers in one go, and how to use it with arrays, boost::array or
+   * std::vector.
+   */
+  template <typename ConstBufferSequence>
+  std::size_t send(const ConstBufferSequence& buffers)
+  {
+    asio::error_code ec;
+    std::size_t s = this->impl_.get_service().send(
+        this->impl_.get_implementation(), buffers, 0, ec);
+    asio::detail::throw_error(ec, "send");
+    return s;
+  }
+
+  /// Send some data on the socket.
+  /**
+   * This function is used to send data on the stream socket. The function
+   * call will block until one or more bytes of the data has been sent
+   * successfully, or an until error occurs.
+   *
+   * @param buffers One or more data buffers to be sent on the socket.
+   *
+   * @param flags Flags specifying how the send call is to be made.
+   *
+   * @returns The number of bytes sent.
+   *
+   * @throws asio::system_error Thrown on failure.
+   *
+   * @note The send operation may not transmit all of the data to the peer.
+   * Consider using the @ref write function if you need to ensure that all data
+   * is written before the blocking operation completes.
+   *
+   * @par Example
+   * To send a single data buffer use the @ref buffer function as follows:
+   * @code
+   * socket.send(asio::buffer(data, size), 0);
+   * @endcode
+   * See the @ref buffer documentation for information on sending multiple
+   * buffers in one go, and how to use it with arrays, boost::array or
+   * std::vector.
+   */
+  template <typename ConstBufferSequence>
+  std::size_t send(const ConstBufferSequence& buffers,
+      socket_base::message_flags flags)
+  {
+    asio::error_code ec;
+    std::size_t s = this->impl_.get_service().send(
+        this->impl_.get_implementation(), buffers, flags, ec);
+    asio::detail::throw_error(ec, "send");
+    return s;
+  }
+
+  /// Send some data on the socket.
+  /**
+   * This function is used to send data on the stream socket. The function
+   * call will block until one or more bytes of the data has been sent
+   * successfully, or an until error occurs.
+   *
+   * @param buffers One or more data buffers to be sent on the socket.
+   *
+   * @param flags Flags specifying how the send call is to be made.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   *
+   * @returns The number of bytes sent. Returns 0 if an error occurred.
+   *
+   * @note The send operation may not transmit all of the data to the peer.
+   * Consider using the @ref write function if you need to ensure that all data
+   * is written before the blocking operation completes.
+   */
+  template <typename ConstBufferSequence>
+  std::size_t send(const ConstBufferSequence& buffers,
+      socket_base::message_flags flags, asio::error_code& ec)
+  {
+    return this->impl_.get_service().send(
+        this->impl_.get_implementation(), buffers, flags, ec);
+  }
+
+  /// Start an asynchronous send.
+  /**
+   * This function is used to asynchronously send data on the stream socket.
+   * The function call always returns immediately.
+   *
+   * @param buffers One or more data buffers to be sent on the socket. Although
+   * the buffers object may be copied as necessary, ownership of the underlying
+   * memory blocks is retained by the caller, which must guarantee that they
+   * remain valid until the handler is called.
+   *
+   * @param handler The handler to be called when the send operation completes.
+   * Copies will be made of the handler as required. The function signature of
+   * the handler must be:
+   * @code void handler(
+   *   const asio::error_code& error, // Result of operation.
+   *   std::size_t bytes_transferred           // Number of bytes sent.
+   * ); @endcode
+   * Regardless of whether the asynchronous operation completes immediately or
+   * not, the handler will not be invoked from within this function. On
+   * immediate completion, invocation of the handler will be performed in a
+   * manner equivalent to using asio::post().
+   *
+   * @note The send operation may not transmit all of the data to the peer.
+   * Consider using the @ref async_write function if you need to ensure that all
+   * data is written before the asynchronous operation completes.
+   *
+   * @par Example
+   * To send a single data buffer use the @ref buffer function as follows:
+   * @code
+   * socket.async_send(asio::buffer(data, size), handler);
+   * @endcode
+   * See the @ref buffer documentation for information on sending multiple
+   * buffers in one go, and how to use it with arrays, boost::array or
+   * std::vector.
+   */
+  template <typename ConstBufferSequence,
+      ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+        std::size_t)) WriteHandler
+          ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
+  ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,
+      void (asio::error_code, std::size_t))
+  async_send(const ConstBufferSequence& buffers,
+      ASIO_MOVE_ARG(WriteHandler) handler
+        ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
+  {
+    return async_initiate<WriteHandler,
+      void (asio::error_code, std::size_t)>(
+        initiate_async_send(this), handler,
+        buffers, socket_base::message_flags(0));
+  }
+
+  /// Start an asynchronous send.
+  /**
+   * This function is used to asynchronously send data on the stream socket.
+   * The function call always returns immediately.
+   *
+   * @param buffers One or more data buffers to be sent on the socket. Although
+   * the buffers object may be copied as necessary, ownership of the underlying
+   * memory blocks is retained by the caller, which must guarantee that they
+   * remain valid until the handler is called.
+   *
+   * @param flags Flags specifying how the send call is to be made.
+   *
+   * @param handler The handler to be called when the send operation completes.
+   * Copies will be made of the handler as required. The function signature of
+   * the handler must be:
+   * @code void handler(
+   *   const asio::error_code& error, // Result of operation.
+   *   std::size_t bytes_transferred           // Number of bytes sent.
+   * ); @endcode
+   * Regardless of whether the asynchronous operation completes immediately or
+   * not, the handler will not be invoked from within this function. On
+   * immediate completion, invocation of the handler will be performed in a
+   * manner equivalent to using asio::post().
+   *
+   * @note The send operation may not transmit all of the data to the peer.
+   * Consider using the @ref async_write function if you need to ensure that all
+   * data is written before the asynchronous operation completes.
+   *
+   * @par Example
+   * To send a single data buffer use the @ref buffer function as follows:
+   * @code
+   * socket.async_send(asio::buffer(data, size), 0, handler);
+   * @endcode
+   * See the @ref buffer documentation for information on sending multiple
+   * buffers in one go, and how to use it with arrays, boost::array or
+   * std::vector.
+   */
+  template <typename ConstBufferSequence,
+      ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+        std::size_t)) WriteHandler
+          ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
+  ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,
+      void (asio::error_code, std::size_t))
+  async_send(const ConstBufferSequence& buffers,
+      socket_base::message_flags flags,
+      ASIO_MOVE_ARG(WriteHandler) handler
+        ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
+  {
+    return async_initiate<WriteHandler,
+      void (asio::error_code, std::size_t)>(
+        initiate_async_send(this), handler, buffers, flags);
+  }
+
+  /// Receive some data on the socket.
+  /**
+   * This function is used to receive data on the stream socket. The function
+   * call will block until one or more bytes of data has been received
+   * successfully, or until an error occurs.
+   *
+   * @param buffers One or more buffers into which the data will be received.
+   *
+   * @returns The number of bytes received.
+   *
+   * @throws asio::system_error Thrown on failure. An error code of
+   * asio::error::eof indicates that the connection was closed by the
+   * peer.
+   *
+   * @note The receive operation may not receive all of the requested number of
+   * bytes. Consider using the @ref read function if you need to ensure that the
+   * requested amount of data is read before the blocking operation completes.
+   *
+   * @par Example
+   * To receive into a single data buffer use the @ref buffer function as
+   * follows:
+   * @code
+   * socket.receive(asio::buffer(data, size));
+   * @endcode
+   * See the @ref buffer documentation for information on receiving into
+   * multiple buffers in one go, and how to use it with arrays, boost::array or
+   * std::vector.
+   */
+  template <typename MutableBufferSequence>
+  std::size_t receive(const MutableBufferSequence& buffers)
+  {
+    asio::error_code ec;
+    std::size_t s = this->impl_.get_service().receive(
+        this->impl_.get_implementation(), buffers, 0, ec);
+    asio::detail::throw_error(ec, "receive");
+    return s;
+  }
+
+  /// Receive some data on the socket.
+  /**
+   * This function is used to receive data on the stream socket. The function
+   * call will block until one or more bytes of data has been received
+   * successfully, or until an error occurs.
+   *
+   * @param buffers One or more buffers into which the data will be received.
+   *
+   * @param flags Flags specifying how the receive call is to be made.
+   *
+   * @returns The number of bytes received.
+   *
+   * @throws asio::system_error Thrown on failure. An error code of
+   * asio::error::eof indicates that the connection was closed by the
+   * peer.
+   *
+   * @note The receive operation may not receive all of the requested number of
+   * bytes. Consider using the @ref read function if you need to ensure that the
+   * requested amount of data is read before the blocking operation completes.
+   *
+   * @par Example
+   * To receive into a single data buffer use the @ref buffer function as
+   * follows:
+   * @code
+   * socket.receive(asio::buffer(data, size), 0);
+   * @endcode
+   * See the @ref buffer documentation for information on receiving into
+   * multiple buffers in one go, and how to use it with arrays, boost::array or
+   * std::vector.
+   */
+  template <typename MutableBufferSequence>
+  std::size_t receive(const MutableBufferSequence& buffers,
+      socket_base::message_flags flags)
+  {
+    asio::error_code ec;
+    std::size_t s = this->impl_.get_service().receive(
+        this->impl_.get_implementation(), buffers, flags, ec);
+    asio::detail::throw_error(ec, "receive");
+    return s;
+  }
+
+  /// Receive some data on a connected socket.
+  /**
+   * This function is used to receive data on the stream socket. The function
+   * call will block until one or more bytes of data has been received
+   * successfully, or until an error occurs.
+   *
+   * @param buffers One or more buffers into which the data will be received.
+   *
+   * @param flags Flags specifying how the receive call is to be made.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   *
+   * @returns The number of bytes received. Returns 0 if an error occurred.
+   *
+   * @note The receive operation may not receive all of the requested number of
+   * bytes. Consider using the @ref read function if you need to ensure that the
+   * requested amount of data is read before the blocking operation completes.
+   */
+  template <typename MutableBufferSequence>
+  std::size_t receive(const MutableBufferSequence& buffers,
+      socket_base::message_flags flags, asio::error_code& ec)
+  {
+    return this->impl_.get_service().receive(
+        this->impl_.get_implementation(), buffers, flags, ec);
+  }
+
+  /// Start an asynchronous receive.
+  /**
+   * This function is used to asynchronously receive data from the stream
+   * socket. The function call always returns immediately.
+   *
+   * @param buffers One or more buffers into which the data will be received.
+   * Although the buffers object may be copied as necessary, ownership of the
+   * underlying memory blocks is retained by the caller, which must guarantee
+   * that they remain valid until the handler is called.
+   *
+   * @param handler The handler to be called when the receive operation
+   * completes. Copies will be made of the handler as required. The function
+   * signature of the handler must be:
+   * @code void handler(
+   *   const asio::error_code& error, // Result of operation.
+   *   std::size_t bytes_transferred           // Number of bytes received.
+   * ); @endcode
+   * Regardless of whether the asynchronous operation completes immediately or
+   * not, the handler will not be invoked from within this function. On
+   * immediate completion, invocation of the handler will be performed in a
+   * manner equivalent to using asio::post().
+   *
+   * @note The receive operation may not receive all of the requested number of
+   * bytes. Consider using the @ref async_read function if you need to ensure
+   * that the requested amount of data is received before the asynchronous
+   * operation completes.
+   *
+   * @par Example
+   * To receive into a single data buffer use the @ref buffer function as
+   * follows:
+   * @code
+   * socket.async_receive(asio::buffer(data, size), handler);
+   * @endcode
+   * See the @ref buffer documentation for information on receiving into
+   * multiple buffers in one go, and how to use it with arrays, boost::array or
+   * std::vector.
+   */
+  template <typename MutableBufferSequence,
+      ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+        std::size_t)) ReadHandler
+          ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
+  ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,
+      void (asio::error_code, std::size_t))
+  async_receive(const MutableBufferSequence& buffers,
+      ASIO_MOVE_ARG(ReadHandler) handler
+        ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
+  {
+    return async_initiate<ReadHandler,
+      void (asio::error_code, std::size_t)>(
+        initiate_async_receive(this), handler,
+        buffers, socket_base::message_flags(0));
+  }
+
+  /// Start an asynchronous receive.
+  /**
+   * This function is used to asynchronously receive data from the stream
+   * socket. The function call always returns immediately.
+   *
+   * @param buffers One or more buffers into which the data will be received.
+   * Although the buffers object may be copied as necessary, ownership of the
+   * underlying memory blocks is retained by the caller, which must guarantee
+   * that they remain valid until the handler is called.
+   *
+   * @param flags Flags specifying how the receive call is to be made.
+   *
+   * @param handler The handler to be called when the receive operation
+   * completes. Copies will be made of the handler as required. The function
+   * signature of the handler must be:
+   * @code void handler(
+   *   const asio::error_code& error, // Result of operation.
+   *   std::size_t bytes_transferred           // Number of bytes received.
+   * ); @endcode
+   * Regardless of whether the asynchronous operation completes immediately or
+   * not, the handler will not be invoked from within this function. On
+   * immediate completion, invocation of the handler will be performed in a
+   * manner equivalent to using asio::post().
+   *
+   * @note The receive operation may not receive all of the requested number of
+   * bytes. Consider using the @ref async_read function if you need to ensure
+   * that the requested amount of data is received before the asynchronous
+   * operation completes.
+   *
+   * @par Example
+   * To receive into a single data buffer use the @ref buffer function as
+   * follows:
+   * @code
+   * socket.async_receive(asio::buffer(data, size), 0, handler);
+   * @endcode
+   * See the @ref buffer documentation for information on receiving into
+   * multiple buffers in one go, and how to use it with arrays, boost::array or
+   * std::vector.
+   */
+  template <typename MutableBufferSequence,
+      ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+        std::size_t)) ReadHandler
+          ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
+  ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,
+      void (asio::error_code, std::size_t))
+  async_receive(const MutableBufferSequence& buffers,
+      socket_base::message_flags flags,
+      ASIO_MOVE_ARG(ReadHandler) handler
+        ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
+  {
+    return async_initiate<ReadHandler,
+      void (asio::error_code, std::size_t)>(
+        initiate_async_receive(this), handler, buffers, flags);
+  }
+
+  /// Write some data to the socket.
+  /**
+   * This function is used to write data to the stream socket. The function call
+   * will block until one or more bytes of the data has been written
+   * successfully, or until an error occurs.
+   *
+   * @param buffers One or more data buffers to be written to the socket.
+   *
+   * @returns The number of bytes written.
+   *
+   * @throws asio::system_error Thrown on failure. An error code of
+   * asio::error::eof indicates that the connection was closed by the
+   * peer.
+   *
+   * @note The write_some operation may not transmit all of the data to the
+   * peer. Consider using the @ref write function if you need to ensure that
+   * all data is written before the blocking operation completes.
+   *
+   * @par Example
+   * To write a single data buffer use the @ref buffer function as follows:
+   * @code
+   * socket.write_some(asio::buffer(data, size));
+   * @endcode
+   * See the @ref buffer documentation for information on writing multiple
+   * buffers in one go, and how to use it with arrays, boost::array or
+   * std::vector.
+   */
+  template <typename ConstBufferSequence>
+  std::size_t write_some(const ConstBufferSequence& buffers)
+  {
+    asio::error_code ec;
+    std::size_t s = this->impl_.get_service().send(
+        this->impl_.get_implementation(), buffers, 0, ec);
+    asio::detail::throw_error(ec, "write_some");
+    return s;
+  }
+
+  /// Write some data to the socket.
+  /**
+   * This function is used to write data to the stream socket. The function call
+   * will block until one or more bytes of the data has been written
+   * successfully, or until an error occurs.
+   *
+   * @param buffers One or more data buffers to be written to the socket.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   *
+   * @returns The number of bytes written. Returns 0 if an error occurred.
+   *
+   * @note The write_some operation may not transmit all of the data to the
+   * peer. Consider using the @ref write function if you need to ensure that
+   * all data is written before the blocking operation completes.
+   */
+  template <typename ConstBufferSequence>
+  std::size_t write_some(const ConstBufferSequence& buffers,
+      asio::error_code& ec)
+  {
+    return this->impl_.get_service().send(
+        this->impl_.get_implementation(), buffers, 0, ec);
+  }
+
+  /// Start an asynchronous write.
+  /**
+   * This function is used to asynchronously write data to the stream socket.
+   * The function call always returns immediately.
+   *
+   * @param buffers One or more data buffers to be written to the socket.
+   * Although the buffers object may be copied as necessary, ownership of the
+   * underlying memory blocks is retained by the caller, which must guarantee
+   * that they remain valid until the handler is called.
+   *
+   * @param handler The handler to be called when the write operation completes.
+   * Copies will be made of the handler as required. The function signature of
+   * the handler must be:
+   * @code void handler(
+   *   const asio::error_code& error, // Result of operation.
+   *   std::size_t bytes_transferred           // Number of bytes written.
+   * ); @endcode
+   * Regardless of whether the asynchronous operation completes immediately or
+   * not, the handler will not be invoked from within this function. On
+   * immediate completion, invocation of the handler will be performed in a
+   * manner equivalent to using asio::post().
+   *
+   * @note The write operation may not transmit all of the data to the peer.
+   * Consider using the @ref async_write function if you need to ensure that all
+   * data is written before the asynchronous operation completes.
+   *
+   * @par Example
+   * To write a single data buffer use the @ref buffer function as follows:
+   * @code
+   * socket.async_write_some(asio::buffer(data, size), handler);
+   * @endcode
+   * See the @ref buffer documentation for information on writing multiple
+   * buffers in one go, and how to use it with arrays, boost::array or
+   * std::vector.
+   */
+  template <typename ConstBufferSequence,
+      ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+        std::size_t)) WriteHandler
+          ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
+  ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,
+      void (asio::error_code, std::size_t))
+  async_write_some(const ConstBufferSequence& buffers,
+      ASIO_MOVE_ARG(WriteHandler) handler
+        ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
+  {
+    return async_initiate<WriteHandler,
+      void (asio::error_code, std::size_t)>(
+        initiate_async_send(this), handler,
+        buffers, socket_base::message_flags(0));
+  }
+
+  /// Read some data from the socket.
+  /**
+   * This function is used to read data from the stream socket. The function
+   * call will block until one or more bytes of data has been read successfully,
+   * or until an error occurs.
+   *
+   * @param buffers One or more buffers into which the data will be read.
+   *
+   * @returns The number of bytes read.
+   *
+   * @throws asio::system_error Thrown on failure. An error code of
+   * asio::error::eof indicates that the connection was closed by the
+   * peer.
+   *
+   * @note The read_some operation may not read all of the requested number of
+   * bytes. Consider using the @ref read function if you need to ensure that
+   * the requested amount of data is read before the blocking operation
+   * completes.
+   *
+   * @par Example
+   * To read into a single data buffer use the @ref buffer function as follows:
+   * @code
+   * socket.read_some(asio::buffer(data, size));
+   * @endcode
+   * See the @ref buffer documentation for information on reading into multiple
+   * buffers in one go, and how to use it with arrays, boost::array or
+   * std::vector.
+   */
+  template <typename MutableBufferSequence>
+  std::size_t read_some(const MutableBufferSequence& buffers)
+  {
+    asio::error_code ec;
+    std::size_t s = this->impl_.get_service().receive(
+        this->impl_.get_implementation(), buffers, 0, ec);
+    asio::detail::throw_error(ec, "read_some");
+    return s;
+  }
+
+  /// Read some data from the socket.
+  /**
+   * This function is used to read data from the stream socket. The function
+   * call will block until one or more bytes of data has been read successfully,
+   * or until an error occurs.
+   *
+   * @param buffers One or more buffers into which the data will be read.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   *
+   * @returns The number of bytes read. Returns 0 if an error occurred.
+   *
+   * @note The read_some operation may not read all of the requested number of
+   * bytes. Consider using the @ref read function if you need to ensure that
+   * the requested amount of data is read before the blocking operation
+   * completes.
+   */
+  template <typename MutableBufferSequence>
+  std::size_t read_some(const MutableBufferSequence& buffers,
+      asio::error_code& ec)
+  {
+    return this->impl_.get_service().receive(
+        this->impl_.get_implementation(), buffers, 0, ec);
+  }
+
+  /// Start an asynchronous read.
+  /**
+   * This function is used to asynchronously read data from the stream socket.
+   * The function call always returns immediately.
+   *
+   * @param buffers One or more buffers into which the data will be read.
+   * Although the buffers object may be copied as necessary, ownership of the
+   * underlying memory blocks is retained by the caller, which must guarantee
+   * that they remain valid until the handler is called.
+   *
+   * @param handler The handler to be called when the read operation completes.
+   * Copies will be made of the handler as required. The function signature of
+   * the handler must be:
+   * @code void handler(
+   *   const asio::error_code& error, // Result of operation.
+   *   std::size_t bytes_transferred           // Number of bytes read.
+   * ); @endcode
+   * Regardless of whether the asynchronous operation completes immediately or
+   * not, the handler will not be invoked from within this function. On
+   * immediate completion, invocation of the handler will be performed in a
+   * manner equivalent to using asio::post().
+   *
+   * @note The read operation may not read all of the requested number of bytes.
+   * Consider using the @ref async_read function if you need to ensure that the
+   * requested amount of data is read before the asynchronous operation
+   * completes.
+   *
+   * @par Example
+   * To read into a single data buffer use the @ref buffer function as follows:
+   * @code
+   * socket.async_read_some(asio::buffer(data, size), handler);
+   * @endcode
+   * See the @ref buffer documentation for information on reading into multiple
+   * buffers in one go, and how to use it with arrays, boost::array or
+   * std::vector.
+   */
+  template <typename MutableBufferSequence,
+      ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+        std::size_t)) ReadHandler
+          ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
+  ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,
+      void (asio::error_code, std::size_t))
+  async_read_some(const MutableBufferSequence& buffers,
+      ASIO_MOVE_ARG(ReadHandler) handler
+        ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
+  {
+    return async_initiate<ReadHandler,
+      void (asio::error_code, std::size_t)>(
+        initiate_async_receive(this), handler,
+        buffers, socket_base::message_flags(0));
+  }
+
+private:
+  // Disallow copying and assignment.
+  basic_stream_socket(const basic_stream_socket&) ASIO_DELETED;
+  basic_stream_socket& operator=(const basic_stream_socket&) ASIO_DELETED;
+
+  class initiate_async_send
+  {
+  public:
+    typedef Executor executor_type;
+
+    explicit initiate_async_send(basic_stream_socket* self)
+      : self_(self)
+    {
+    }
+
+    executor_type get_executor() const ASIO_NOEXCEPT
+    {
+      return self_->get_executor();
+    }
+
+    template <typename WriteHandler, typename ConstBufferSequence>
+    void operator()(ASIO_MOVE_ARG(WriteHandler) handler,
+        const ConstBufferSequence& buffers,
+        socket_base::message_flags flags) const
+    {
+      // If you get an error on the following line it means that your handler
+      // does not meet the documented type requirements for a WriteHandler.
+      ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check;
+
+      detail::non_const_lvalue<WriteHandler> handler2(handler);
+      self_->impl_.get_service().async_send(
+          self_->impl_.get_implementation(), buffers, flags,
+          handler2.value, self_->impl_.get_executor());
+    }
+
+  private:
+    basic_stream_socket* self_;
+  };
+
+  class initiate_async_receive
+  {
+  public:
+    typedef Executor executor_type;
+
+    explicit initiate_async_receive(basic_stream_socket* self)
+      : self_(self)
+    {
+    }
+
+    executor_type get_executor() const ASIO_NOEXCEPT
+    {
+      return self_->get_executor();
+    }
+
+    template <typename ReadHandler, typename MutableBufferSequence>
+    void operator()(ASIO_MOVE_ARG(ReadHandler) handler,
+        const MutableBufferSequence& buffers,
+        socket_base::message_flags flags) const
+    {
+      // If you get an error on the following line it means that your handler
+      // does not meet the documented type requirements for a ReadHandler.
+      ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
+
+      detail::non_const_lvalue<ReadHandler> handler2(handler);
+      self_->impl_.get_service().async_receive(
+          self_->impl_.get_implementation(), buffers, flags,
+          handler2.value, self_->impl_.get_executor());
+    }
+
+  private:
+    basic_stream_socket* self_;
+  };
+};
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_BASIC_STREAM_SOCKET_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/basic_streambuf.hpp b/link/modules/asio-standalone/asio/include/asio/basic_streambuf.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/basic_streambuf.hpp
@@ -0,0 +1,452 @@
+//
+// basic_streambuf.hpp
+// ~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_BASIC_STREAMBUF_HPP
+#define ASIO_BASIC_STREAMBUF_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if !defined(ASIO_NO_IOSTREAM)
+
+#include <algorithm>
+#include <cstring>
+#include <stdexcept>
+#include <streambuf>
+#include <vector>
+#include "asio/basic_streambuf_fwd.hpp"
+#include "asio/buffer.hpp"
+#include "asio/detail/limits.hpp"
+#include "asio/detail/noncopyable.hpp"
+#include "asio/detail/throw_exception.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+/// Automatically resizable buffer class based on std::streambuf.
+/**
+ * The @c basic_streambuf class is derived from @c std::streambuf to associate
+ * the streambuf's input and output sequences with one or more character
+ * arrays. These character arrays are internal to the @c basic_streambuf
+ * object, but direct access to the array elements is provided to permit them
+ * to be used efficiently with I/O operations. Characters written to the output
+ * sequence of a @c basic_streambuf object are appended to the input sequence
+ * of the same object.
+ *
+ * The @c basic_streambuf class's public interface is intended to permit the
+ * following implementation strategies:
+ *
+ * @li A single contiguous character array, which is reallocated as necessary
+ * to accommodate changes in the size of the character sequence. This is the
+ * implementation approach currently used in Asio.
+ *
+ * @li A sequence of one or more character arrays, where each array is of the
+ * same size. Additional character array objects are appended to the sequence
+ * to accommodate changes in the size of the character sequence.
+ *
+ * @li A sequence of one or more character arrays of varying sizes. Additional
+ * character array objects are appended to the sequence to accommodate changes
+ * in the size of the character sequence.
+ *
+ * The constructor for basic_streambuf accepts a @c size_t argument specifying
+ * the maximum of the sum of the sizes of the input sequence and output
+ * sequence. During the lifetime of the @c basic_streambuf object, the following
+ * invariant holds:
+ * @code size() <= max_size()@endcode
+ * Any member function that would, if successful, cause the invariant to be
+ * violated shall throw an exception of class @c std::length_error.
+ *
+ * The constructor for @c basic_streambuf takes an Allocator argument. A copy
+ * of this argument is used for any memory allocation performed, by the
+ * constructor and by all member functions, during the lifetime of each @c
+ * basic_streambuf object.
+ *
+ * @par Examples
+ * Writing directly from an streambuf to a socket:
+ * @code
+ * asio::streambuf b;
+ * std::ostream os(&b);
+ * os << "Hello, World!\n";
+ *
+ * // try sending some data in input sequence
+ * size_t n = sock.send(b.data());
+ *
+ * b.consume(n); // sent data is removed from input sequence
+ * @endcode
+ *
+ * Reading from a socket directly into a streambuf:
+ * @code
+ * asio::streambuf b;
+ *
+ * // reserve 512 bytes in output sequence
+ * asio::streambuf::mutable_buffers_type bufs = b.prepare(512);
+ *
+ * size_t n = sock.receive(bufs);
+ *
+ * // received data is "committed" from output sequence to input sequence
+ * b.commit(n);
+ *
+ * std::istream is(&b);
+ * std::string s;
+ * is >> s;
+ * @endcode
+ */
+#if defined(GENERATING_DOCUMENTATION)
+template <typename Allocator = std::allocator<char> >
+#else
+template <typename Allocator>
+#endif
+class basic_streambuf
+  : public std::streambuf,
+    private noncopyable
+{
+public:
+#if defined(GENERATING_DOCUMENTATION)
+  /// The type used to represent the input sequence as a list of buffers.
+  typedef implementation_defined const_buffers_type;
+
+  /// The type used to represent the output sequence as a list of buffers.
+  typedef implementation_defined mutable_buffers_type;
+#else
+  typedef ASIO_CONST_BUFFER const_buffers_type;
+  typedef ASIO_MUTABLE_BUFFER mutable_buffers_type;
+#endif
+
+  /// Construct a basic_streambuf object.
+  /**
+   * Constructs a streambuf with the specified maximum size. The initial size
+   * of the streambuf's input sequence is 0.
+   */
+  explicit basic_streambuf(
+      std::size_t maximum_size = (std::numeric_limits<std::size_t>::max)(),
+      const Allocator& allocator = Allocator())
+    : max_size_(maximum_size),
+      buffer_(allocator)
+  {
+    std::size_t pend = (std::min<std::size_t>)(max_size_, buffer_delta);
+    buffer_.resize((std::max<std::size_t>)(pend, 1));
+    setg(&buffer_[0], &buffer_[0], &buffer_[0]);
+    setp(&buffer_[0], &buffer_[0] + pend);
+  }
+
+  /// Get the size of the input sequence.
+  /**
+   * @returns The size of the input sequence. The value is equal to that
+   * calculated for @c s in the following code:
+   * @code
+   * size_t s = 0;
+   * const_buffers_type bufs = data();
+   * const_buffers_type::const_iterator i = bufs.begin();
+   * while (i != bufs.end())
+   * {
+   *   const_buffer buf(*i++);
+   *   s += buf.size();
+   * }
+   * @endcode
+   */
+  std::size_t size() const ASIO_NOEXCEPT
+  {
+    return pptr() - gptr();
+  }
+
+  /// Get the maximum size of the basic_streambuf.
+  /**
+   * @returns The allowed maximum of the sum of the sizes of the input sequence
+   * and output sequence.
+   */
+  std::size_t max_size() const ASIO_NOEXCEPT
+  {
+    return max_size_;
+  }
+
+  /// Get the current capacity of the basic_streambuf.
+  /**
+   * @returns The current total capacity of the streambuf, i.e. for both the
+   * input sequence and output sequence.
+   */
+  std::size_t capacity() const ASIO_NOEXCEPT
+  {
+    return buffer_.capacity();
+  }
+
+  /// Get a list of buffers that represents the input sequence.
+  /**
+   * @returns An object of type @c const_buffers_type that satisfies
+   * ConstBufferSequence requirements, representing all character arrays in the
+   * input sequence.
+   *
+   * @note The returned object is invalidated by any @c basic_streambuf member
+   * function that modifies the input sequence or output sequence.
+   */
+  const_buffers_type data() const ASIO_NOEXCEPT
+  {
+    return asio::buffer(asio::const_buffer(gptr(),
+          (pptr() - gptr()) * sizeof(char_type)));
+  }
+
+  /// Get a list of buffers that represents the output sequence, with the given
+  /// size.
+  /**
+   * Ensures that the output sequence can accommodate @c n characters,
+   * reallocating character array objects as necessary.
+   *
+   * @returns An object of type @c mutable_buffers_type that satisfies
+   * MutableBufferSequence requirements, representing character array objects
+   * at the start of the output sequence such that the sum of the buffer sizes
+   * is @c n.
+   *
+   * @throws std::length_error If <tt>size() + n > max_size()</tt>.
+   *
+   * @note The returned object is invalidated by any @c basic_streambuf member
+   * function that modifies the input sequence or output sequence.
+   */
+  mutable_buffers_type prepare(std::size_t n)
+  {
+    reserve(n);
+    return asio::buffer(asio::mutable_buffer(
+          pptr(), n * sizeof(char_type)));
+  }
+
+  /// Move characters from the output sequence to the input sequence.
+  /**
+   * Appends @c n characters from the start of the output sequence to the input
+   * sequence. The beginning of the output sequence is advanced by @c n
+   * characters.
+   *
+   * Requires a preceding call <tt>prepare(x)</tt> where <tt>x >= n</tt>, and
+   * no intervening operations that modify the input or output sequence.
+   *
+   * @note If @c n is greater than the size of the output sequence, the entire
+   * output sequence is moved to the input sequence and no error is issued.
+   */
+  void commit(std::size_t n)
+  {
+    n = std::min<std::size_t>(n, epptr() - pptr());
+    pbump(static_cast<int>(n));
+    setg(eback(), gptr(), pptr());
+  }
+
+  /// Remove characters from the input sequence.
+  /**
+   * Removes @c n characters from the beginning of the input sequence.
+   *
+   * @note If @c n is greater than the size of the input sequence, the entire
+   * input sequence is consumed and no error is issued.
+   */
+  void consume(std::size_t n)
+  {
+    if (egptr() < pptr())
+      setg(&buffer_[0], gptr(), pptr());
+    if (gptr() + n > pptr())
+      n = pptr() - gptr();
+    gbump(static_cast<int>(n));
+  }
+
+protected:
+  enum { buffer_delta = 128 };
+
+  /// Override std::streambuf behaviour.
+  /**
+   * Behaves according to the specification of @c std::streambuf::underflow().
+   */
+  int_type underflow()
+  {
+    if (gptr() < pptr())
+    {
+      setg(&buffer_[0], gptr(), pptr());
+      return traits_type::to_int_type(*gptr());
+    }
+    else
+    {
+      return traits_type::eof();
+    }
+  }
+
+  /// Override std::streambuf behaviour.
+  /**
+   * Behaves according to the specification of @c std::streambuf::overflow(),
+   * with the specialisation that @c std::length_error is thrown if appending
+   * the character to the input sequence would require the condition
+   * <tt>size() > max_size()</tt> to be true.
+   */
+  int_type overflow(int_type c)
+  {
+    if (!traits_type::eq_int_type(c, traits_type::eof()))
+    {
+      if (pptr() == epptr())
+      {
+        std::size_t buffer_size = pptr() - gptr();
+        if (buffer_size < max_size_ && max_size_ - buffer_size < buffer_delta)
+        {
+          reserve(max_size_ - buffer_size);
+        }
+        else
+        {
+          reserve(buffer_delta);
+        }
+      }
+
+      *pptr() = traits_type::to_char_type(c);
+      pbump(1);
+      return c;
+    }
+
+    return traits_type::not_eof(c);
+  }
+
+  void reserve(std::size_t n)
+  {
+    // Get current stream positions as offsets.
+    std::size_t gnext = gptr() - &buffer_[0];
+    std::size_t pnext = pptr() - &buffer_[0];
+    std::size_t pend = epptr() - &buffer_[0];
+
+    // Check if there is already enough space in the put area.
+    if (n <= pend - pnext)
+    {
+      return;
+    }
+
+    // Shift existing contents of get area to start of buffer.
+    if (gnext > 0)
+    {
+      pnext -= gnext;
+      std::memmove(&buffer_[0], &buffer_[0] + gnext, pnext);
+    }
+
+    // Ensure buffer is large enough to hold at least the specified size.
+    if (n > pend - pnext)
+    {
+      if (n <= max_size_ && pnext <= max_size_ - n)
+      {
+        pend = pnext + n;
+        buffer_.resize((std::max<std::size_t>)(pend, 1));
+      }
+      else
+      {
+        std::length_error ex("asio::streambuf too long");
+        asio::detail::throw_exception(ex);
+      }
+    }
+
+    // Update stream positions.
+    setg(&buffer_[0], &buffer_[0], &buffer_[0] + pnext);
+    setp(&buffer_[0] + pnext, &buffer_[0] + pend);
+  }
+
+private:
+  std::size_t max_size_;
+  std::vector<char_type, Allocator> buffer_;
+
+  // Helper function to get the preferred size for reading data.
+  friend std::size_t read_size_helper(
+      basic_streambuf& sb, std::size_t max_size)
+  {
+    return std::min<std::size_t>(
+        std::max<std::size_t>(512, sb.buffer_.capacity() - sb.size()),
+        std::min<std::size_t>(max_size, sb.max_size() - sb.size()));
+  }
+};
+
+/// Adapts basic_streambuf to the dynamic buffer sequence type requirements.
+#if defined(GENERATING_DOCUMENTATION)
+template <typename Allocator = std::allocator<char> >
+#else
+template <typename Allocator>
+#endif
+class basic_streambuf_ref
+{
+public:
+  /// The type used to represent the input sequence as a list of buffers.
+  typedef typename basic_streambuf<Allocator>::const_buffers_type
+    const_buffers_type;
+
+  /// The type used to represent the output sequence as a list of buffers.
+  typedef typename basic_streambuf<Allocator>::mutable_buffers_type
+    mutable_buffers_type;
+
+  /// Construct a basic_streambuf_ref for the given basic_streambuf object.
+  explicit basic_streambuf_ref(basic_streambuf<Allocator>& sb)
+    : sb_(sb)
+  {
+  }
+
+  /// Copy construct a basic_streambuf_ref.
+  basic_streambuf_ref(const basic_streambuf_ref& other) ASIO_NOEXCEPT
+    : sb_(other.sb_)
+  {
+  }
+
+#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+  /// Move construct a basic_streambuf_ref.
+  basic_streambuf_ref(basic_streambuf_ref&& other) ASIO_NOEXCEPT
+    : sb_(other.sb_)
+  {
+  }
+#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+
+  /// Get the size of the input sequence.
+  std::size_t size() const ASIO_NOEXCEPT
+  {
+    return sb_.size();
+  }
+
+  /// Get the maximum size of the dynamic buffer.
+  std::size_t max_size() const ASIO_NOEXCEPT
+  {
+    return sb_.max_size();
+  }
+
+  /// Get the current capacity of the dynamic buffer.
+  std::size_t capacity() const ASIO_NOEXCEPT
+  {
+    return sb_.capacity();
+  }
+
+  /// Get a list of buffers that represents the input sequence.
+  const_buffers_type data() const ASIO_NOEXCEPT
+  {
+    return sb_.data();
+  }
+
+  /// Get a list of buffers that represents the output sequence, with the given
+  /// size.
+  mutable_buffers_type prepare(std::size_t n)
+  {
+    return sb_.prepare(n);
+  }
+
+  /// Move bytes from the output sequence to the input sequence.
+  void commit(std::size_t n)
+  {
+    return sb_.commit(n);
+  }
+
+  /// Remove characters from the input sequence.
+  void consume(std::size_t n)
+  {
+    return sb_.consume(n);
+  }
+
+private:
+  basic_streambuf<Allocator>& sb_;
+};
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // !defined(ASIO_NO_IOSTREAM)
+
+#endif // ASIO_BASIC_STREAMBUF_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/basic_streambuf_fwd.hpp b/link/modules/asio-standalone/asio/include/asio/basic_streambuf_fwd.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/basic_streambuf_fwd.hpp
@@ -0,0 +1,36 @@
+//
+// basic_streambuf_fwd.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_BASIC_STREAMBUF_FWD_HPP
+#define ASIO_BASIC_STREAMBUF_FWD_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if !defined(ASIO_NO_IOSTREAM)
+
+#include <memory>
+
+namespace asio {
+
+template <typename Allocator = std::allocator<char> >
+class basic_streambuf;
+
+template <typename Allocator = std::allocator<char> >
+class basic_streambuf_ref;
+
+} // namespace asio
+
+#endif // !defined(ASIO_NO_IOSTREAM)
+
+#endif // ASIO_BASIC_STREAMBUF_FWD_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/basic_waitable_timer.hpp b/link/modules/asio-standalone/asio/include/asio/basic_waitable_timer.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/basic_waitable_timer.hpp
@@ -0,0 +1,811 @@
+//
+// basic_waitable_timer.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_BASIC_WAITABLE_TIMER_HPP
+#define ASIO_BASIC_WAITABLE_TIMER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <cstddef>
+#include "asio/any_io_executor.hpp"
+#include "asio/detail/chrono_time_traits.hpp"
+#include "asio/detail/deadline_timer_service.hpp"
+#include "asio/detail/handler_type_requirements.hpp"
+#include "asio/detail/io_object_impl.hpp"
+#include "asio/detail/non_const_lvalue.hpp"
+#include "asio/detail/throw_error.hpp"
+#include "asio/error.hpp"
+#include "asio/wait_traits.hpp"
+
+#if defined(ASIO_HAS_MOVE)
+# include <utility>
+#endif // defined(ASIO_HAS_MOVE)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+#if !defined(ASIO_BASIC_WAITABLE_TIMER_FWD_DECL)
+#define ASIO_BASIC_WAITABLE_TIMER_FWD_DECL
+
+// Forward declaration with defaulted arguments.
+template <typename Clock,
+    typename WaitTraits = asio::wait_traits<Clock>,
+    typename Executor = any_io_executor>
+class basic_waitable_timer;
+
+#endif // !defined(ASIO_BASIC_WAITABLE_TIMER_FWD_DECL)
+
+/// Provides waitable timer functionality.
+/**
+ * The basic_waitable_timer class template provides the ability to perform a
+ * blocking or asynchronous wait for a timer to expire.
+ *
+ * A waitable timer is always in one of two states: "expired" or "not expired".
+ * If the wait() or async_wait() function is called on an expired timer, the
+ * wait operation will complete immediately.
+ *
+ * Most applications will use one of the asio::steady_timer,
+ * asio::system_timer or asio::high_resolution_timer typedefs.
+ *
+ * @note This waitable timer functionality is for use with the C++11 standard
+ * library's @c &lt;chrono&gt; facility, or with the Boost.Chrono library.
+ *
+ * @par Thread Safety
+ * @e Distinct @e objects: Safe.@n
+ * @e Shared @e objects: Unsafe.
+ *
+ * @par Examples
+ * Performing a blocking wait (C++11):
+ * @code
+ * // Construct a timer without setting an expiry time.
+ * asio::steady_timer timer(my_context);
+ *
+ * // Set an expiry time relative to now.
+ * timer.expires_after(std::chrono::seconds(5));
+ *
+ * // Wait for the timer to expire.
+ * timer.wait();
+ * @endcode
+ *
+ * @par 
+ * Performing an asynchronous wait (C++11):
+ * @code
+ * void handler(const asio::error_code& error)
+ * {
+ *   if (!error)
+ *   {
+ *     // Timer expired.
+ *   }
+ * }
+ *
+ * ...
+ *
+ * // Construct a timer with an absolute expiry time.
+ * asio::steady_timer timer(my_context,
+ *     std::chrono::steady_clock::now() + std::chrono::seconds(60));
+ *
+ * // Start an asynchronous wait.
+ * timer.async_wait(handler);
+ * @endcode
+ *
+ * @par Changing an active waitable timer's expiry time
+ *
+ * Changing the expiry time of a timer while there are pending asynchronous
+ * waits causes those wait operations to be cancelled. To ensure that the action
+ * associated with the timer is performed only once, use something like this:
+ * used:
+ *
+ * @code
+ * void on_some_event()
+ * {
+ *   if (my_timer.expires_after(seconds(5)) > 0)
+ *   {
+ *     // We managed to cancel the timer. Start new asynchronous wait.
+ *     my_timer.async_wait(on_timeout);
+ *   }
+ *   else
+ *   {
+ *     // Too late, timer has already expired!
+ *   }
+ * }
+ *
+ * void on_timeout(const asio::error_code& e)
+ * {
+ *   if (e != asio::error::operation_aborted)
+ *   {
+ *     // Timer was not cancelled, take necessary action.
+ *   }
+ * }
+ * @endcode
+ *
+ * @li The asio::basic_waitable_timer::expires_after() function
+ * cancels any pending asynchronous waits, and returns the number of
+ * asynchronous waits that were cancelled. If it returns 0 then you were too
+ * late and the wait handler has already been executed, or will soon be
+ * executed. If it returns 1 then the wait handler was successfully cancelled.
+ *
+ * @li If a wait handler is cancelled, the asio::error_code passed to
+ * it contains the value asio::error::operation_aborted.
+ */
+template <typename Clock, typename WaitTraits, typename Executor>
+class basic_waitable_timer
+{
+public:
+  /// The type of the executor associated with the object.
+  typedef Executor executor_type;
+
+  /// Rebinds the timer type to another executor.
+  template <typename Executor1>
+  struct rebind_executor
+  {
+    /// The timer type when rebound to the specified executor.
+    typedef basic_waitable_timer<Clock, WaitTraits, Executor1> other;
+  };
+
+  /// The clock type.
+  typedef Clock clock_type;
+
+  /// The duration type of the clock.
+  typedef typename clock_type::duration duration;
+
+  /// The time point type of the clock.
+  typedef typename clock_type::time_point time_point;
+
+  /// The wait traits type.
+  typedef WaitTraits traits_type;
+
+  /// Constructor.
+  /**
+   * This constructor creates a timer without setting an expiry time. The
+   * expires_at() or expires_after() functions must be called to set an expiry
+   * time before the timer can be waited on.
+   *
+   * @param ex The I/O executor that the timer will use, by default, to
+   * dispatch handlers for any asynchronous operations performed on the timer.
+   */
+  explicit basic_waitable_timer(const executor_type& ex)
+    : impl_(ex)
+  {
+  }
+
+  /// Constructor.
+  /**
+   * This constructor creates a timer without setting an expiry time. The
+   * expires_at() or expires_after() functions must be called to set an expiry
+   * time before the timer can be waited on.
+   *
+   * @param context An execution context which provides the I/O executor that
+   * the timer will use, by default, to dispatch handlers for any asynchronous
+   * operations performed on the timer.
+   */
+  template <typename ExecutionContext>
+  explicit basic_waitable_timer(ExecutionContext& context,
+      typename enable_if<
+        is_convertible<ExecutionContext&, execution_context&>::value
+      >::type* = 0)
+    : impl_(context)
+  {
+  }
+
+  /// Constructor to set a particular expiry time as an absolute time.
+  /**
+   * This constructor creates a timer and sets the expiry time.
+   *
+   * @param ex The I/O executor object that the timer will use, by default, to
+   * dispatch handlers for any asynchronous operations performed on the timer.
+   *
+   * @param expiry_time The expiry time to be used for the timer, expressed
+   * as an absolute time.
+   */
+  basic_waitable_timer(const executor_type& ex, const time_point& expiry_time)
+    : impl_(ex)
+  {
+    asio::error_code ec;
+    impl_.get_service().expires_at(impl_.get_implementation(), expiry_time, ec);
+    asio::detail::throw_error(ec, "expires_at");
+  }
+
+  /// Constructor to set a particular expiry time as an absolute time.
+  /**
+   * This constructor creates a timer and sets the expiry time.
+   *
+   * @param context An execution context which provides the I/O executor that
+   * the timer will use, by default, to dispatch handlers for any asynchronous
+   * operations performed on the timer.
+   *
+   * @param expiry_time The expiry time to be used for the timer, expressed
+   * as an absolute time.
+   */
+  template <typename ExecutionContext>
+  explicit basic_waitable_timer(ExecutionContext& context,
+      const time_point& expiry_time,
+      typename enable_if<
+        is_convertible<ExecutionContext&, execution_context&>::value
+      >::type* = 0)
+    : impl_(context)
+  {
+    asio::error_code ec;
+    impl_.get_service().expires_at(impl_.get_implementation(), expiry_time, ec);
+    asio::detail::throw_error(ec, "expires_at");
+  }
+
+  /// Constructor to set a particular expiry time relative to now.
+  /**
+   * This constructor creates a timer and sets the expiry time.
+   *
+   * @param ex The I/O executor that the timer will use, by default, to
+   * dispatch handlers for any asynchronous operations performed on the timer.
+   *
+   * @param expiry_time The expiry time to be used for the timer, relative to
+   * now.
+   */
+  basic_waitable_timer(const executor_type& ex, const duration& expiry_time)
+    : impl_(ex)
+  {
+    asio::error_code ec;
+    impl_.get_service().expires_after(
+        impl_.get_implementation(), expiry_time, ec);
+    asio::detail::throw_error(ec, "expires_after");
+  }
+
+  /// Constructor to set a particular expiry time relative to now.
+  /**
+   * This constructor creates a timer and sets the expiry time.
+   *
+   * @param context An execution context which provides the I/O executor that
+   * the timer will use, by default, to dispatch handlers for any asynchronous
+   * operations performed on the timer.
+   *
+   * @param expiry_time The expiry time to be used for the timer, relative to
+   * now.
+   */
+  template <typename ExecutionContext>
+  explicit basic_waitable_timer(ExecutionContext& context,
+      const duration& expiry_time,
+      typename enable_if<
+        is_convertible<ExecutionContext&, execution_context&>::value
+      >::type* = 0)
+    : impl_(context)
+  {
+    asio::error_code ec;
+    impl_.get_service().expires_after(
+        impl_.get_implementation(), expiry_time, ec);
+    asio::detail::throw_error(ec, "expires_after");
+  }
+
+#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+  /// Move-construct a basic_waitable_timer from another.
+  /**
+   * This constructor moves a timer from one object to another.
+   *
+   * @param other The other basic_waitable_timer object from which the move will
+   * occur.
+   *
+   * @note Following the move, the moved-from object is in the same state as if
+   * constructed using the @c basic_waitable_timer(const executor_type&)
+   * constructor.
+   */
+  basic_waitable_timer(basic_waitable_timer&& other)
+    : impl_(std::move(other.impl_))
+  {
+  }
+
+  /// Move-assign a basic_waitable_timer from another.
+  /**
+   * This assignment operator moves a timer from one object to another. Cancels
+   * any outstanding asynchronous operations associated with the target object.
+   *
+   * @param other The other basic_waitable_timer object from which the move will
+   * occur.
+   *
+   * @note Following the move, the moved-from object is in the same state as if
+   * constructed using the @c basic_waitable_timer(const executor_type&)
+   * constructor.
+   */
+  basic_waitable_timer& operator=(basic_waitable_timer&& other)
+  {
+    impl_ = std::move(other.impl_);
+    return *this;
+  }
+
+  // All timers have access to each other's implementations.
+  template <typename Clock1, typename WaitTraits1, typename Executor1>
+  friend class basic_waitable_timer;
+
+  /// Move-construct a basic_waitable_timer from another.
+  /**
+   * This constructor moves a timer from one object to another.
+   *
+   * @param other The other basic_waitable_timer object from which the move will
+   * occur.
+   *
+   * @note Following the move, the moved-from object is in the same state as if
+   * constructed using the @c basic_waitable_timer(const executor_type&)
+   * constructor.
+   */
+  template <typename Executor1>
+  basic_waitable_timer(
+      basic_waitable_timer<Clock, WaitTraits, Executor1>&& other,
+      typename enable_if<
+          is_convertible<Executor1, Executor>::value
+      >::type* = 0)
+    : impl_(std::move(other.impl_))
+  {
+  }
+
+  /// Move-assign a basic_waitable_timer from another.
+  /**
+   * This assignment operator moves a timer from one object to another. Cancels
+   * any outstanding asynchronous operations associated with the target object.
+   *
+   * @param other The other basic_waitable_timer object from which the move will
+   * occur.
+   *
+   * @note Following the move, the moved-from object is in the same state as if
+   * constructed using the @c basic_waitable_timer(const executor_type&)
+   * constructor.
+   */
+  template <typename Executor1>
+  typename enable_if<
+    is_convertible<Executor1, Executor>::value,
+    basic_waitable_timer&
+  >::type operator=(basic_waitable_timer<Clock, WaitTraits, Executor1>&& other)
+  {
+    basic_waitable_timer tmp(std::move(other));
+    impl_ = std::move(tmp.impl_);
+    return *this;
+  }
+#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+
+  /// Destroys the timer.
+  /**
+   * This function destroys the timer, cancelling any outstanding asynchronous
+   * wait operations associated with the timer as if by calling @c cancel.
+   */
+  ~basic_waitable_timer()
+  {
+  }
+
+  /// Get the executor associated with the object.
+  executor_type get_executor() ASIO_NOEXCEPT
+  {
+    return impl_.get_executor();
+  }
+
+  /// Cancel any asynchronous operations that are waiting on the timer.
+  /**
+   * This function forces the completion of any pending asynchronous wait
+   * operations against the timer. The handler for each cancelled operation will
+   * be invoked with the asio::error::operation_aborted error code.
+   *
+   * Cancelling the timer does not change the expiry time.
+   *
+   * @return The number of asynchronous operations that were cancelled.
+   *
+   * @throws asio::system_error Thrown on failure.
+   *
+   * @note If the timer has already expired when cancel() is called, then the
+   * handlers for asynchronous wait operations will:
+   *
+   * @li have already been invoked; or
+   *
+   * @li have been queued for invocation in the near future.
+   *
+   * These handlers can no longer be cancelled, and therefore are passed an
+   * error code that indicates the successful completion of the wait operation.
+   */
+  std::size_t cancel()
+  {
+    asio::error_code ec;
+    std::size_t s = impl_.get_service().cancel(impl_.get_implementation(), ec);
+    asio::detail::throw_error(ec, "cancel");
+    return s;
+  }
+
+#if !defined(ASIO_NO_DEPRECATED)
+  /// (Deprecated: Use non-error_code overload.) Cancel any asynchronous
+  /// operations that are waiting on the timer.
+  /**
+   * This function forces the completion of any pending asynchronous wait
+   * operations against the timer. The handler for each cancelled operation will
+   * be invoked with the asio::error::operation_aborted error code.
+   *
+   * Cancelling the timer does not change the expiry time.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   *
+   * @return The number of asynchronous operations that were cancelled.
+   *
+   * @note If the timer has already expired when cancel() is called, then the
+   * handlers for asynchronous wait operations will:
+   *
+   * @li have already been invoked; or
+   *
+   * @li have been queued for invocation in the near future.
+   *
+   * These handlers can no longer be cancelled, and therefore are passed an
+   * error code that indicates the successful completion of the wait operation.
+   */
+  std::size_t cancel(asio::error_code& ec)
+  {
+    return impl_.get_service().cancel(impl_.get_implementation(), ec);
+  }
+#endif // !defined(ASIO_NO_DEPRECATED)
+
+  /// Cancels one asynchronous operation that is waiting on the timer.
+  /**
+   * This function forces the completion of one pending asynchronous wait
+   * operation against the timer. Handlers are cancelled in FIFO order. The
+   * handler for the cancelled operation will be invoked with the
+   * asio::error::operation_aborted error code.
+   *
+   * Cancelling the timer does not change the expiry time.
+   *
+   * @return The number of asynchronous operations that were cancelled. That is,
+   * either 0 or 1.
+   *
+   * @throws asio::system_error Thrown on failure.
+   *
+   * @note If the timer has already expired when cancel_one() is called, then
+   * the handlers for asynchronous wait operations will:
+   *
+   * @li have already been invoked; or
+   *
+   * @li have been queued for invocation in the near future.
+   *
+   * These handlers can no longer be cancelled, and therefore are passed an
+   * error code that indicates the successful completion of the wait operation.
+   */
+  std::size_t cancel_one()
+  {
+    asio::error_code ec;
+    std::size_t s = impl_.get_service().cancel_one(
+        impl_.get_implementation(), ec);
+    asio::detail::throw_error(ec, "cancel_one");
+    return s;
+  }
+
+#if !defined(ASIO_NO_DEPRECATED)
+  /// (Deprecated: Use non-error_code overload.) Cancels one asynchronous
+  /// operation that is waiting on the timer.
+  /**
+   * This function forces the completion of one pending asynchronous wait
+   * operation against the timer. Handlers are cancelled in FIFO order. The
+   * handler for the cancelled operation will be invoked with the
+   * asio::error::operation_aborted error code.
+   *
+   * Cancelling the timer does not change the expiry time.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   *
+   * @return The number of asynchronous operations that were cancelled. That is,
+   * either 0 or 1.
+   *
+   * @note If the timer has already expired when cancel_one() is called, then
+   * the handlers for asynchronous wait operations will:
+   *
+   * @li have already been invoked; or
+   *
+   * @li have been queued for invocation in the near future.
+   *
+   * These handlers can no longer be cancelled, and therefore are passed an
+   * error code that indicates the successful completion of the wait operation.
+   */
+  std::size_t cancel_one(asio::error_code& ec)
+  {
+    return impl_.get_service().cancel_one(impl_.get_implementation(), ec);
+  }
+
+  /// (Deprecated: Use expiry().) Get the timer's expiry time as an absolute
+  /// time.
+  /**
+   * This function may be used to obtain the timer's current expiry time.
+   * Whether the timer has expired or not does not affect this value.
+   */
+  time_point expires_at() const
+  {
+    return impl_.get_service().expires_at(impl_.get_implementation());
+  }
+#endif // !defined(ASIO_NO_DEPRECATED)
+
+  /// Get the timer's expiry time as an absolute time.
+  /**
+   * This function may be used to obtain the timer's current expiry time.
+   * Whether the timer has expired or not does not affect this value.
+   */
+  time_point expiry() const
+  {
+    return impl_.get_service().expiry(impl_.get_implementation());
+  }
+
+  /// Set the timer's expiry time as an absolute time.
+  /**
+   * This function sets the expiry time. Any pending asynchronous wait
+   * operations will be cancelled. The handler for each cancelled operation will
+   * be invoked with the asio::error::operation_aborted error code.
+   *
+   * @param expiry_time The expiry time to be used for the timer.
+   *
+   * @return The number of asynchronous operations that were cancelled.
+   *
+   * @throws asio::system_error Thrown on failure.
+   *
+   * @note If the timer has already expired when expires_at() is called, then
+   * the handlers for asynchronous wait operations will:
+   *
+   * @li have already been invoked; or
+   *
+   * @li have been queued for invocation in the near future.
+   *
+   * These handlers can no longer be cancelled, and therefore are passed an
+   * error code that indicates the successful completion of the wait operation.
+   */
+  std::size_t expires_at(const time_point& expiry_time)
+  {
+    asio::error_code ec;
+    std::size_t s = impl_.get_service().expires_at(
+        impl_.get_implementation(), expiry_time, ec);
+    asio::detail::throw_error(ec, "expires_at");
+    return s;
+  }
+
+#if !defined(ASIO_NO_DEPRECATED)
+  /// (Deprecated: Use non-error_code overload.) Set the timer's expiry time as
+  /// an absolute time.
+  /**
+   * This function sets the expiry time. Any pending asynchronous wait
+   * operations will be cancelled. The handler for each cancelled operation will
+   * be invoked with the asio::error::operation_aborted error code.
+   *
+   * @param expiry_time The expiry time to be used for the timer.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   *
+   * @return The number of asynchronous operations that were cancelled.
+   *
+   * @note If the timer has already expired when expires_at() is called, then
+   * the handlers for asynchronous wait operations will:
+   *
+   * @li have already been invoked; or
+   *
+   * @li have been queued for invocation in the near future.
+   *
+   * These handlers can no longer be cancelled, and therefore are passed an
+   * error code that indicates the successful completion of the wait operation.
+   */
+  std::size_t expires_at(const time_point& expiry_time,
+      asio::error_code& ec)
+  {
+    return impl_.get_service().expires_at(
+        impl_.get_implementation(), expiry_time, ec);
+  }
+#endif // !defined(ASIO_NO_DEPRECATED)
+
+  /// Set the timer's expiry time relative to now.
+  /**
+   * This function sets the expiry time. Any pending asynchronous wait
+   * operations will be cancelled. The handler for each cancelled operation will
+   * be invoked with the asio::error::operation_aborted error code.
+   *
+   * @param expiry_time The expiry time to be used for the timer.
+   *
+   * @return The number of asynchronous operations that were cancelled.
+   *
+   * @throws asio::system_error Thrown on failure.
+   *
+   * @note If the timer has already expired when expires_after() is called,
+   * then the handlers for asynchronous wait operations will:
+   *
+   * @li have already been invoked; or
+   *
+   * @li have been queued for invocation in the near future.
+   *
+   * These handlers can no longer be cancelled, and therefore are passed an
+   * error code that indicates the successful completion of the wait operation.
+   */
+  std::size_t expires_after(const duration& expiry_time)
+  {
+    asio::error_code ec;
+    std::size_t s = impl_.get_service().expires_after(
+        impl_.get_implementation(), expiry_time, ec);
+    asio::detail::throw_error(ec, "expires_after");
+    return s;
+  }
+
+#if !defined(ASIO_NO_DEPRECATED)
+  /// (Deprecated: Use expiry().) Get the timer's expiry time relative to now.
+  /**
+   * This function may be used to obtain the timer's current expiry time.
+   * Whether the timer has expired or not does not affect this value.
+   */
+  duration expires_from_now() const
+  {
+    return impl_.get_service().expires_from_now(impl_.get_implementation());
+  }
+
+  /// (Deprecated: Use expires_after().) Set the timer's expiry time relative
+  /// to now.
+  /**
+   * This function sets the expiry time. Any pending asynchronous wait
+   * operations will be cancelled. The handler for each cancelled operation will
+   * be invoked with the asio::error::operation_aborted error code.
+   *
+   * @param expiry_time The expiry time to be used for the timer.
+   *
+   * @return The number of asynchronous operations that were cancelled.
+   *
+   * @throws asio::system_error Thrown on failure.
+   *
+   * @note If the timer has already expired when expires_from_now() is called,
+   * then the handlers for asynchronous wait operations will:
+   *
+   * @li have already been invoked; or
+   *
+   * @li have been queued for invocation in the near future.
+   *
+   * These handlers can no longer be cancelled, and therefore are passed an
+   * error code that indicates the successful completion of the wait operation.
+   */
+  std::size_t expires_from_now(const duration& expiry_time)
+  {
+    asio::error_code ec;
+    std::size_t s = impl_.get_service().expires_from_now(
+        impl_.get_implementation(), expiry_time, ec);
+    asio::detail::throw_error(ec, "expires_from_now");
+    return s;
+  }
+
+  /// (Deprecated: Use expires_after().) Set the timer's expiry time relative
+  /// to now.
+  /**
+   * This function sets the expiry time. Any pending asynchronous wait
+   * operations will be cancelled. The handler for each cancelled operation will
+   * be invoked with the asio::error::operation_aborted error code.
+   *
+   * @param expiry_time The expiry time to be used for the timer.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   *
+   * @return The number of asynchronous operations that were cancelled.
+   *
+   * @note If the timer has already expired when expires_from_now() is called,
+   * then the handlers for asynchronous wait operations will:
+   *
+   * @li have already been invoked; or
+   *
+   * @li have been queued for invocation in the near future.
+   *
+   * These handlers can no longer be cancelled, and therefore are passed an
+   * error code that indicates the successful completion of the wait operation.
+   */
+  std::size_t expires_from_now(const duration& expiry_time,
+      asio::error_code& ec)
+  {
+    return impl_.get_service().expires_from_now(
+        impl_.get_implementation(), expiry_time, ec);
+  }
+#endif // !defined(ASIO_NO_DEPRECATED)
+
+  /// Perform a blocking wait on the timer.
+  /**
+   * This function is used to wait for the timer to expire. This function
+   * blocks and does not return until the timer has expired.
+   *
+   * @throws asio::system_error Thrown on failure.
+   */
+  void wait()
+  {
+    asio::error_code ec;
+    impl_.get_service().wait(impl_.get_implementation(), ec);
+    asio::detail::throw_error(ec, "wait");
+  }
+
+  /// Perform a blocking wait on the timer.
+  /**
+   * This function is used to wait for the timer to expire. This function
+   * blocks and does not return until the timer has expired.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   */
+  void wait(asio::error_code& ec)
+  {
+    impl_.get_service().wait(impl_.get_implementation(), ec);
+  }
+
+  /// Start an asynchronous wait on the timer.
+  /**
+   * This function may be used to initiate an asynchronous wait against the
+   * timer. It always returns immediately.
+   *
+   * For each call to async_wait(), the supplied handler will be called exactly
+   * once. The handler will be called when:
+   *
+   * @li The timer has expired.
+   *
+   * @li The timer was cancelled, in which case the handler is passed the error
+   * code asio::error::operation_aborted.
+   *
+   * @param handler The handler to be called when the timer expires. Copies
+   * will be made of the handler as required. The function signature of the
+   * handler must be:
+   * @code void handler(
+   *   const asio::error_code& error // Result of operation.
+   * ); @endcode
+   * Regardless of whether the asynchronous operation completes immediately or
+   * not, the handler will not be invoked from within this function. On
+   * immediate completion, invocation of the handler will be performed in a
+   * manner equivalent to using asio::post().
+   */
+  template <
+      ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code))
+        WaitHandler ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
+  ASIO_INITFN_AUTO_RESULT_TYPE(WaitHandler,
+      void (asio::error_code))
+  async_wait(
+      ASIO_MOVE_ARG(WaitHandler) handler
+        ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
+  {
+    return async_initiate<WaitHandler, void (asio::error_code)>(
+        initiate_async_wait(this), handler);
+  }
+
+private:
+  // Disallow copying and assignment.
+  basic_waitable_timer(const basic_waitable_timer&) ASIO_DELETED;
+  basic_waitable_timer& operator=(
+      const basic_waitable_timer&) ASIO_DELETED;
+
+  class initiate_async_wait
+  {
+  public:
+    typedef Executor executor_type;
+
+    explicit initiate_async_wait(basic_waitable_timer* self)
+      : self_(self)
+    {
+    }
+
+    executor_type get_executor() const ASIO_NOEXCEPT
+    {
+      return self_->get_executor();
+    }
+
+    template <typename WaitHandler>
+    void operator()(ASIO_MOVE_ARG(WaitHandler) handler) const
+    {
+      // If you get an error on the following line it means that your handler
+      // does not meet the documented type requirements for a WaitHandler.
+      ASIO_WAIT_HANDLER_CHECK(WaitHandler, handler) type_check;
+
+      detail::non_const_lvalue<WaitHandler> handler2(handler);
+      self_->impl_.get_service().async_wait(
+          self_->impl_.get_implementation(),
+          handler2.value, self_->impl_.get_executor());
+    }
+
+  private:
+    basic_waitable_timer* self_;
+  };
+
+  detail::io_object_impl<
+    detail::deadline_timer_service<
+      detail::chrono_time_traits<Clock, WaitTraits> >,
+    executor_type > impl_;
+};
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_BASIC_WAITABLE_TIMER_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/bind_executor.hpp b/link/modules/asio-standalone/asio/include/asio/bind_executor.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/bind_executor.hpp
@@ -0,0 +1,575 @@
+//
+// bind_executor.hpp
+// ~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_BIND_EXECUTOR_HPP
+#define ASIO_BIND_EXECUTOR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/type_traits.hpp"
+#include "asio/detail/variadic_templates.hpp"
+#include "asio/associated_executor.hpp"
+#include "asio/associated_allocator.hpp"
+#include "asio/async_result.hpp"
+#include "asio/execution/executor.hpp"
+#include "asio/execution_context.hpp"
+#include "asio/is_executor.hpp"
+#include "asio/uses_executor.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+// Helper to automatically define nested typedef result_type.
+
+template <typename T, typename = void>
+struct executor_binder_result_type
+{
+protected:
+  typedef void result_type_or_void;
+};
+
+template <typename T>
+struct executor_binder_result_type<T,
+  typename void_type<typename T::result_type>::type>
+{
+  typedef typename T::result_type result_type;
+protected:
+  typedef result_type result_type_or_void;
+};
+
+template <typename R>
+struct executor_binder_result_type<R(*)()>
+{
+  typedef R result_type;
+protected:
+  typedef result_type result_type_or_void;
+};
+
+template <typename R>
+struct executor_binder_result_type<R(&)()>
+{
+  typedef R result_type;
+protected:
+  typedef result_type result_type_or_void;
+};
+
+template <typename R, typename A1>
+struct executor_binder_result_type<R(*)(A1)>
+{
+  typedef R result_type;
+protected:
+  typedef result_type result_type_or_void;
+};
+
+template <typename R, typename A1>
+struct executor_binder_result_type<R(&)(A1)>
+{
+  typedef R result_type;
+protected:
+  typedef result_type result_type_or_void;
+};
+
+template <typename R, typename A1, typename A2>
+struct executor_binder_result_type<R(*)(A1, A2)>
+{
+  typedef R result_type;
+protected:
+  typedef result_type result_type_or_void;
+};
+
+template <typename R, typename A1, typename A2>
+struct executor_binder_result_type<R(&)(A1, A2)>
+{
+  typedef R result_type;
+protected:
+  typedef result_type result_type_or_void;
+};
+
+// Helper to automatically define nested typedef argument_type.
+
+template <typename T, typename = void>
+struct executor_binder_argument_type {};
+
+template <typename T>
+struct executor_binder_argument_type<T,
+  typename void_type<typename T::argument_type>::type>
+{
+  typedef typename T::argument_type argument_type;
+};
+
+template <typename R, typename A1>
+struct executor_binder_argument_type<R(*)(A1)>
+{
+  typedef A1 argument_type;
+};
+
+template <typename R, typename A1>
+struct executor_binder_argument_type<R(&)(A1)>
+{
+  typedef A1 argument_type;
+};
+
+// Helper to automatically define nested typedefs first_argument_type and
+// second_argument_type.
+
+template <typename T, typename = void>
+struct executor_binder_argument_types {};
+
+template <typename T>
+struct executor_binder_argument_types<T,
+  typename void_type<typename T::first_argument_type>::type>
+{
+  typedef typename T::first_argument_type first_argument_type;
+  typedef typename T::second_argument_type second_argument_type;
+};
+
+template <typename R, typename A1, typename A2>
+struct executor_binder_argument_type<R(*)(A1, A2)>
+{
+  typedef A1 first_argument_type;
+  typedef A2 second_argument_type;
+};
+
+template <typename R, typename A1, typename A2>
+struct executor_binder_argument_type<R(&)(A1, A2)>
+{
+  typedef A1 first_argument_type;
+  typedef A2 second_argument_type;
+};
+
+// Helper to perform uses_executor construction of the target type, if
+// required.
+
+template <typename T, typename Executor, bool UsesExecutor>
+class executor_binder_base;
+
+template <typename T, typename Executor>
+class executor_binder_base<T, Executor, true>
+{
+protected:
+  template <typename E, typename U>
+  executor_binder_base(ASIO_MOVE_ARG(E) e, ASIO_MOVE_ARG(U) u)
+    : executor_(ASIO_MOVE_CAST(E)(e)),
+      target_(executor_arg_t(), executor_, ASIO_MOVE_CAST(U)(u))
+  {
+  }
+
+  Executor executor_;
+  T target_;
+};
+
+template <typename T, typename Executor>
+class executor_binder_base<T, Executor, false>
+{
+protected:
+  template <typename E, typename U>
+  executor_binder_base(ASIO_MOVE_ARG(E) e, ASIO_MOVE_ARG(U) u)
+    : executor_(ASIO_MOVE_CAST(E)(e)),
+      target_(ASIO_MOVE_CAST(U)(u))
+  {
+  }
+
+  Executor executor_;
+  T target_;
+};
+
+// Helper to enable SFINAE on zero-argument operator() below.
+
+template <typename T, typename = void>
+struct executor_binder_result_of0
+{
+  typedef void type;
+};
+
+template <typename T>
+struct executor_binder_result_of0<T,
+  typename void_type<typename result_of<T()>::type>::type>
+{
+  typedef typename result_of<T()>::type type;
+};
+
+} // namespace detail
+
+/// A call wrapper type to bind an executor of type @c Executor to an object of
+/// type @c T.
+template <typename T, typename Executor>
+class executor_binder
+#if !defined(GENERATING_DOCUMENTATION)
+  : public detail::executor_binder_result_type<T>,
+    public detail::executor_binder_argument_type<T>,
+    public detail::executor_binder_argument_types<T>,
+    private detail::executor_binder_base<
+      T, Executor, uses_executor<T, Executor>::value>
+#endif // !defined(GENERATING_DOCUMENTATION)
+{
+public:
+  /// The type of the target object.
+  typedef T target_type;
+
+  /// The type of the associated executor.
+  typedef Executor executor_type;
+
+#if defined(GENERATING_DOCUMENTATION)
+  /// The return type if a function.
+  /**
+   * The type of @c result_type is based on the type @c T of the wrapper's
+   * target object:
+   *
+   * @li if @c T is a pointer to function type, @c result_type is a synonym for
+   * the return type of @c T;
+   *
+   * @li if @c T is a class type with a member type @c result_type, then @c
+   * result_type is a synonym for @c T::result_type;
+   *
+   * @li otherwise @c result_type is not defined.
+   */
+  typedef see_below result_type;
+
+  /// The type of the function's argument.
+  /**
+   * The type of @c argument_type is based on the type @c T of the wrapper's
+   * target object:
+   *
+   * @li if @c T is a pointer to a function type accepting a single argument,
+   * @c argument_type is a synonym for the return type of @c T;
+   *
+   * @li if @c T is a class type with a member type @c argument_type, then @c
+   * argument_type is a synonym for @c T::argument_type;
+   *
+   * @li otherwise @c argument_type is not defined.
+   */
+  typedef see_below argument_type;
+
+  /// The type of the function's first argument.
+  /**
+   * The type of @c first_argument_type is based on the type @c T of the
+   * wrapper's target object:
+   *
+   * @li if @c T is a pointer to a function type accepting two arguments, @c
+   * first_argument_type is a synonym for the return type of @c T;
+   *
+   * @li if @c T is a class type with a member type @c first_argument_type,
+   * then @c first_argument_type is a synonym for @c T::first_argument_type;
+   *
+   * @li otherwise @c first_argument_type is not defined.
+   */
+  typedef see_below first_argument_type;
+
+  /// The type of the function's second argument.
+  /**
+   * The type of @c second_argument_type is based on the type @c T of the
+   * wrapper's target object:
+   *
+   * @li if @c T is a pointer to a function type accepting two arguments, @c
+   * second_argument_type is a synonym for the return type of @c T;
+   *
+   * @li if @c T is a class type with a member type @c first_argument_type,
+   * then @c second_argument_type is a synonym for @c T::second_argument_type;
+   *
+   * @li otherwise @c second_argument_type is not defined.
+   */
+  typedef see_below second_argument_type;
+#endif // defined(GENERATING_DOCUMENTATION)
+
+  /// Construct an executor wrapper for the specified object.
+  /**
+   * This constructor is only valid if the type @c T is constructible from type
+   * @c U.
+   */
+  template <typename U>
+  executor_binder(executor_arg_t, const executor_type& e,
+      ASIO_MOVE_ARG(U) u)
+    : base_type(e, ASIO_MOVE_CAST(U)(u))
+  {
+  }
+
+  /// Copy constructor.
+  executor_binder(const executor_binder& other)
+    : base_type(other.get_executor(), other.get())
+  {
+  }
+
+  /// Construct a copy, but specify a different executor.
+  executor_binder(executor_arg_t, const executor_type& e,
+      const executor_binder& other)
+    : base_type(e, other.get())
+  {
+  }
+
+  /// Construct a copy of a different executor wrapper type.
+  /**
+   * This constructor is only valid if the @c Executor type is constructible
+   * from type @c OtherExecutor, and the type @c T is constructible from type
+   * @c U.
+   */
+  template <typename U, typename OtherExecutor>
+  executor_binder(const executor_binder<U, OtherExecutor>& other)
+    : base_type(other.get_executor(), other.get())
+  {
+  }
+
+  /// Construct a copy of a different executor wrapper type, but specify a
+  /// different executor.
+  /**
+   * This constructor is only valid if the type @c T is constructible from type
+   * @c U.
+   */
+  template <typename U, typename OtherExecutor>
+  executor_binder(executor_arg_t, const executor_type& e,
+      const executor_binder<U, OtherExecutor>& other)
+    : base_type(e, other.get())
+  {
+  }
+
+#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+
+  /// Move constructor.
+  executor_binder(executor_binder&& other)
+    : base_type(ASIO_MOVE_CAST(executor_type)(other.get_executor()),
+        ASIO_MOVE_CAST(T)(other.get()))
+  {
+  }
+
+  /// Move construct the target object, but specify a different executor.
+  executor_binder(executor_arg_t, const executor_type& e,
+      executor_binder&& other)
+    : base_type(e, ASIO_MOVE_CAST(T)(other.get()))
+  {
+  }
+
+  /// Move construct from a different executor wrapper type.
+  template <typename U, typename OtherExecutor>
+  executor_binder(executor_binder<U, OtherExecutor>&& other)
+    : base_type(ASIO_MOVE_CAST(OtherExecutor)(other.get_executor()),
+        ASIO_MOVE_CAST(U)(other.get()))
+  {
+  }
+
+  /// Move construct from a different executor wrapper type, but specify a
+  /// different executor.
+  template <typename U, typename OtherExecutor>
+  executor_binder(executor_arg_t, const executor_type& e,
+      executor_binder<U, OtherExecutor>&& other)
+    : base_type(e, ASIO_MOVE_CAST(U)(other.get()))
+  {
+  }
+
+#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+
+  /// Destructor.
+  ~executor_binder()
+  {
+  }
+
+  /// Obtain a reference to the target object.
+  target_type& get() ASIO_NOEXCEPT
+  {
+    return this->target_;
+  }
+
+  /// Obtain a reference to the target object.
+  const target_type& get() const ASIO_NOEXCEPT
+  {
+    return this->target_;
+  }
+
+  /// Obtain the associated executor.
+  executor_type get_executor() const ASIO_NOEXCEPT
+  {
+    return this->executor_;
+  }
+
+#if defined(GENERATING_DOCUMENTATION)
+
+  template <typename... Args> auto operator()(Args&& ...);
+  template <typename... Args> auto operator()(Args&& ...) const;
+
+#elif defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+  /// Forwarding function call operator.
+  template <typename... Args>
+  typename result_of<T(Args...)>::type operator()(
+      ASIO_MOVE_ARG(Args)... args)
+  {
+    return this->target_(ASIO_MOVE_CAST(Args)(args)...);
+  }
+
+  /// Forwarding function call operator.
+  template <typename... Args>
+  typename result_of<T(Args...)>::type operator()(
+      ASIO_MOVE_ARG(Args)... args) const
+  {
+    return this->target_(ASIO_MOVE_CAST(Args)(args)...);
+  }
+
+#elif defined(ASIO_HAS_STD_TYPE_TRAITS) && !defined(_MSC_VER)
+
+  typename detail::executor_binder_result_of0<T>::type operator()()
+  {
+    return this->target_();
+  }
+
+  typename detail::executor_binder_result_of0<T>::type operator()() const
+  {
+    return this->target_();
+  }
+
+#define ASIO_PRIVATE_BIND_EXECUTOR_CALL_DEF(n) \
+  template <ASIO_VARIADIC_TPARAMS(n)> \
+  typename result_of<T(ASIO_VARIADIC_TARGS(n))>::type operator()( \
+      ASIO_VARIADIC_MOVE_PARAMS(n)) \
+  { \
+    return this->target_(ASIO_VARIADIC_MOVE_ARGS(n)); \
+  } \
+  \
+  template <ASIO_VARIADIC_TPARAMS(n)> \
+  typename result_of<T(ASIO_VARIADIC_TARGS(n))>::type operator()( \
+      ASIO_VARIADIC_MOVE_PARAMS(n)) const \
+  { \
+    return this->target_(ASIO_VARIADIC_MOVE_ARGS(n)); \
+  } \
+  /**/
+  ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_BIND_EXECUTOR_CALL_DEF)
+#undef ASIO_PRIVATE_BIND_EXECUTOR_CALL_DEF
+
+#else // defined(ASIO_HAS_STD_TYPE_TRAITS) && !defined(_MSC_VER)
+
+  typedef typename detail::executor_binder_result_type<T>::result_type_or_void
+    result_type_or_void;
+
+  result_type_or_void operator()()
+  {
+    return this->target_();
+  }
+
+  result_type_or_void operator()() const
+  {
+    return this->target_();
+  }
+
+#define ASIO_PRIVATE_BIND_EXECUTOR_CALL_DEF(n) \
+  template <ASIO_VARIADIC_TPARAMS(n)> \
+  result_type_or_void operator()( \
+      ASIO_VARIADIC_MOVE_PARAMS(n)) \
+  { \
+    return this->target_(ASIO_VARIADIC_MOVE_ARGS(n)); \
+  } \
+  \
+  template <ASIO_VARIADIC_TPARAMS(n)> \
+  result_type_or_void operator()( \
+      ASIO_VARIADIC_MOVE_PARAMS(n)) const \
+  { \
+    return this->target_(ASIO_VARIADIC_MOVE_ARGS(n)); \
+  } \
+  /**/
+  ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_BIND_EXECUTOR_CALL_DEF)
+#undef ASIO_PRIVATE_BIND_EXECUTOR_CALL_DEF
+
+#endif // defined(ASIO_HAS_STD_TYPE_TRAITS) && !defined(_MSC_VER)
+
+private:
+  typedef detail::executor_binder_base<T, Executor,
+    uses_executor<T, Executor>::value> base_type;
+};
+
+/// Associate an object of type @c T with an executor of type @c Executor.
+template <typename Executor, typename T>
+inline executor_binder<typename decay<T>::type, Executor>
+bind_executor(const Executor& ex, ASIO_MOVE_ARG(T) t,
+    typename enable_if<
+      is_executor<Executor>::value || execution::is_executor<Executor>::value
+    >::type* = 0)
+{
+  return executor_binder<typename decay<T>::type, Executor>(
+      executor_arg_t(), ex, ASIO_MOVE_CAST(T)(t));
+}
+
+/// Associate an object of type @c T with an execution context's executor.
+template <typename ExecutionContext, typename T>
+inline executor_binder<typename decay<T>::type,
+  typename ExecutionContext::executor_type>
+bind_executor(ExecutionContext& ctx, ASIO_MOVE_ARG(T) t,
+    typename enable_if<is_convertible<
+      ExecutionContext&, execution_context&>::value>::type* = 0)
+{
+  return executor_binder<typename decay<T>::type,
+    typename ExecutionContext::executor_type>(
+      executor_arg_t(), ctx.get_executor(), ASIO_MOVE_CAST(T)(t));
+}
+
+#if !defined(GENERATING_DOCUMENTATION)
+
+template <typename T, typename Executor>
+struct uses_executor<executor_binder<T, Executor>, Executor>
+  : true_type {};
+
+template <typename T, typename Executor, typename Signature>
+class async_result<executor_binder<T, Executor>, Signature>
+{
+public:
+  typedef executor_binder<
+    typename async_result<T, Signature>::completion_handler_type, Executor>
+      completion_handler_type;
+
+  typedef typename async_result<T, Signature>::return_type return_type;
+
+  explicit async_result(executor_binder<T, Executor>& b)
+    : target_(b.get())
+  {
+  }
+
+  return_type get()
+  {
+    return target_.get();
+  }
+
+private:
+  async_result(const async_result&) ASIO_DELETED;
+  async_result& operator=(const async_result&) ASIO_DELETED;
+
+  async_result<T, Signature> target_;
+};
+
+template <typename T, typename Executor, typename Allocator>
+struct associated_allocator<executor_binder<T, Executor>, Allocator>
+{
+  typedef typename associated_allocator<T, Allocator>::type type;
+
+  static type get(const executor_binder<T, Executor>& b,
+      const Allocator& a = Allocator()) ASIO_NOEXCEPT
+  {
+    return associated_allocator<T, Allocator>::get(b.get(), a);
+  }
+};
+
+template <typename T, typename Executor, typename Executor1>
+struct associated_executor<executor_binder<T, Executor>, Executor1>
+{
+  typedef Executor type;
+
+  static type get(const executor_binder<T, Executor>& b,
+      const Executor1& = Executor1()) ASIO_NOEXCEPT
+  {
+    return b.get_executor();
+  }
+};
+
+#endif // !defined(GENERATING_DOCUMENTATION)
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_BIND_EXECUTOR_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/buffer.hpp b/link/modules/asio-standalone/asio/include/asio/buffer.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/buffer.hpp
@@ -0,0 +1,2496 @@
+//
+// buffer.hpp
+// ~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_BUFFER_HPP
+#define ASIO_BUFFER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <cstddef>
+#include <cstring>
+#include <limits>
+#include <stdexcept>
+#include <string>
+#include <vector>
+#include "asio/detail/array_fwd.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/detail/string_view.hpp"
+#include "asio/detail/throw_exception.hpp"
+#include "asio/detail/type_traits.hpp"
+
+#if defined(ASIO_MSVC) && (ASIO_MSVC >= 1700)
+# if defined(_HAS_ITERATOR_DEBUGGING) && (_HAS_ITERATOR_DEBUGGING != 0)
+#  if !defined(ASIO_DISABLE_BUFFER_DEBUGGING)
+#   define ASIO_ENABLE_BUFFER_DEBUGGING
+#  endif // !defined(ASIO_DISABLE_BUFFER_DEBUGGING)
+# endif // defined(_HAS_ITERATOR_DEBUGGING)
+#endif // defined(ASIO_MSVC) && (ASIO_MSVC >= 1700)
+
+#if defined(__GNUC__)
+# if defined(_GLIBCXX_DEBUG)
+#  if !defined(ASIO_DISABLE_BUFFER_DEBUGGING)
+#   define ASIO_ENABLE_BUFFER_DEBUGGING
+#  endif // !defined(ASIO_DISABLE_BUFFER_DEBUGGING)
+# endif // defined(_GLIBCXX_DEBUG)
+#endif // defined(__GNUC__)
+
+#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
+# include "asio/detail/functional.hpp"
+#endif // ASIO_ENABLE_BUFFER_DEBUGGING
+
+#if defined(ASIO_HAS_BOOST_WORKAROUND)
+# include <boost/detail/workaround.hpp>
+# if !defined(__clang__)
+#  if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582))
+#   define ASIO_ENABLE_ARRAY_BUFFER_WORKAROUND
+#  endif // BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582))
+# elif BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x590))
+#  define ASIO_ENABLE_ARRAY_BUFFER_WORKAROUND
+# endif // BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x590))
+#endif // defined(ASIO_HAS_BOOST_WORKAROUND)
+
+#if defined(ASIO_ENABLE_ARRAY_BUFFER_WORKAROUND)
+# include "asio/detail/type_traits.hpp"
+#endif // defined(ASIO_ENABLE_ARRAY_BUFFER_WORKAROUND)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+class mutable_buffer;
+class const_buffer;
+
+/// Holds a buffer that can be modified.
+/**
+ * The mutable_buffer class provides a safe representation of a buffer that can
+ * be modified. It does not own the underlying data, and so is cheap to copy or
+ * assign.
+ *
+ * @par Accessing Buffer Contents
+ *
+ * The contents of a buffer may be accessed using the @c data() and @c size()
+ * member functions:
+ *
+ * @code asio::mutable_buffer b1 = ...;
+ * std::size_t s1 = b1.size();
+ * unsigned char* p1 = static_cast<unsigned char*>(b1.data());
+ * @endcode
+ *
+ * The @c data() member function permits violations of type safety, so uses of
+ * it in application code should be carefully considered.
+ */
+class mutable_buffer
+{
+public:
+  /// Construct an empty buffer.
+  mutable_buffer() ASIO_NOEXCEPT
+    : data_(0),
+      size_(0)
+  {
+  }
+
+  /// Construct a buffer to represent a given memory range.
+  mutable_buffer(void* data, std::size_t size) ASIO_NOEXCEPT
+    : data_(data),
+      size_(size)
+  {
+  }
+
+#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
+  mutable_buffer(void* data, std::size_t size,
+      asio::detail::function<void()> debug_check)
+    : data_(data),
+      size_(size),
+      debug_check_(debug_check)
+  {
+  }
+
+  const asio::detail::function<void()>& get_debug_check() const
+  {
+    return debug_check_;
+  }
+#endif // ASIO_ENABLE_BUFFER_DEBUGGING
+
+  /// Get a pointer to the beginning of the memory range.
+  void* data() const ASIO_NOEXCEPT
+  {
+#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
+    if (size_ && debug_check_)
+      debug_check_();
+#endif // ASIO_ENABLE_BUFFER_DEBUGGING
+    return data_;
+  }
+
+  /// Get the size of the memory range.
+  std::size_t size() const ASIO_NOEXCEPT
+  {
+    return size_;
+  }
+
+  /// Move the start of the buffer by the specified number of bytes.
+  mutable_buffer& operator+=(std::size_t n) ASIO_NOEXCEPT
+  {
+    std::size_t offset = n < size_ ? n : size_;
+    data_ = static_cast<char*>(data_) + offset;
+    size_ -= offset;
+    return *this;
+  }
+
+private:
+  void* data_;
+  std::size_t size_;
+
+#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
+  asio::detail::function<void()> debug_check_;
+#endif // ASIO_ENABLE_BUFFER_DEBUGGING
+};
+
+#if !defined(ASIO_NO_DEPRECATED)
+
+/// (Deprecated: Use mutable_buffer.) Adapts a single modifiable buffer so that
+/// it meets the requirements of the MutableBufferSequence concept.
+class mutable_buffers_1
+  : public mutable_buffer
+{
+public:
+  /// The type for each element in the list of buffers.
+  typedef mutable_buffer value_type;
+
+  /// A random-access iterator type that may be used to read elements.
+  typedef const mutable_buffer* const_iterator;
+
+  /// Construct to represent a given memory range.
+  mutable_buffers_1(void* data, std::size_t size) ASIO_NOEXCEPT
+    : mutable_buffer(data, size)
+  {
+  }
+
+#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
+  mutable_buffers_1(void* data, std::size_t size,
+      asio::detail::function<void()> debug_check)
+    : mutable_buffer(data, size, debug_check)
+  {
+  }
+#endif // ASIO_ENABLE_BUFFER_DEBUGGING
+
+  /// Construct to represent a single modifiable buffer.
+  explicit mutable_buffers_1(const mutable_buffer& b) ASIO_NOEXCEPT
+    : mutable_buffer(b)
+  {
+  }
+
+  /// Get a random-access iterator to the first element.
+  const_iterator begin() const ASIO_NOEXCEPT
+  {
+    return this;
+  }
+
+  /// Get a random-access iterator for one past the last element.
+  const_iterator end() const ASIO_NOEXCEPT
+  {
+    return begin() + 1;
+  }
+};
+
+#endif // !defined(ASIO_NO_DEPRECATED)
+
+/// Holds a buffer that cannot be modified.
+/**
+ * The const_buffer class provides a safe representation of a buffer that cannot
+ * be modified. It does not own the underlying data, and so is cheap to copy or
+ * assign.
+ *
+ * @par Accessing Buffer Contents
+ *
+ * The contents of a buffer may be accessed using the @c data() and @c size()
+ * member functions:
+ *
+ * @code asio::const_buffer b1 = ...;
+ * std::size_t s1 = b1.size();
+ * const unsigned char* p1 = static_cast<const unsigned char*>(b1.data());
+ * @endcode
+ *
+ * The @c data() member function permits violations of type safety, so uses of
+ * it in application code should be carefully considered.
+ */
+class const_buffer
+{
+public:
+  /// Construct an empty buffer.
+  const_buffer() ASIO_NOEXCEPT
+    : data_(0),
+      size_(0)
+  {
+  }
+
+  /// Construct a buffer to represent a given memory range.
+  const_buffer(const void* data, std::size_t size) ASIO_NOEXCEPT
+    : data_(data),
+      size_(size)
+  {
+  }
+
+  /// Construct a non-modifiable buffer from a modifiable one.
+  const_buffer(const mutable_buffer& b) ASIO_NOEXCEPT
+    : data_(b.data()),
+      size_(b.size())
+#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
+      , debug_check_(b.get_debug_check())
+#endif // ASIO_ENABLE_BUFFER_DEBUGGING
+  {
+  }
+
+#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
+  const_buffer(const void* data, std::size_t size,
+      asio::detail::function<void()> debug_check)
+    : data_(data),
+      size_(size),
+      debug_check_(debug_check)
+  {
+  }
+
+  const asio::detail::function<void()>& get_debug_check() const
+  {
+    return debug_check_;
+  }
+#endif // ASIO_ENABLE_BUFFER_DEBUGGING
+
+  /// Get a pointer to the beginning of the memory range.
+  const void* data() const ASIO_NOEXCEPT
+  {
+#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
+    if (size_ && debug_check_)
+      debug_check_();
+#endif // ASIO_ENABLE_BUFFER_DEBUGGING
+    return data_;
+  }
+
+  /// Get the size of the memory range.
+  std::size_t size() const ASIO_NOEXCEPT
+  {
+    return size_;
+  }
+
+  /// Move the start of the buffer by the specified number of bytes.
+  const_buffer& operator+=(std::size_t n) ASIO_NOEXCEPT
+  {
+    std::size_t offset = n < size_ ? n : size_;
+    data_ = static_cast<const char*>(data_) + offset;
+    size_ -= offset;
+    return *this;
+  }
+
+private:
+  const void* data_;
+  std::size_t size_;
+
+#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
+  asio::detail::function<void()> debug_check_;
+#endif // ASIO_ENABLE_BUFFER_DEBUGGING
+};
+
+#if !defined(ASIO_NO_DEPRECATED)
+
+/// (Deprecated: Use const_buffer.) Adapts a single non-modifiable buffer so
+/// that it meets the requirements of the ConstBufferSequence concept.
+class const_buffers_1
+  : public const_buffer
+{
+public:
+  /// The type for each element in the list of buffers.
+  typedef const_buffer value_type;
+
+  /// A random-access iterator type that may be used to read elements.
+  typedef const const_buffer* const_iterator;
+
+  /// Construct to represent a given memory range.
+  const_buffers_1(const void* data, std::size_t size) ASIO_NOEXCEPT
+    : const_buffer(data, size)
+  {
+  }
+
+#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
+  const_buffers_1(const void* data, std::size_t size,
+      asio::detail::function<void()> debug_check)
+    : const_buffer(data, size, debug_check)
+  {
+  }
+#endif // ASIO_ENABLE_BUFFER_DEBUGGING
+
+  /// Construct to represent a single non-modifiable buffer.
+  explicit const_buffers_1(const const_buffer& b) ASIO_NOEXCEPT
+    : const_buffer(b)
+  {
+  }
+
+  /// Get a random-access iterator to the first element.
+  const_iterator begin() const ASIO_NOEXCEPT
+  {
+    return this;
+  }
+
+  /// Get a random-access iterator for one past the last element.
+  const_iterator end() const ASIO_NOEXCEPT
+  {
+    return begin() + 1;
+  }
+};
+
+#endif // !defined(ASIO_NO_DEPRECATED)
+
+/// (Deprecated: Use the socket/descriptor wait() and async_wait() member
+/// functions.) An implementation of both the ConstBufferSequence and
+/// MutableBufferSequence concepts to represent a null buffer sequence.
+class null_buffers
+{
+public:
+  /// The type for each element in the list of buffers.
+  typedef mutable_buffer value_type;
+
+  /// A random-access iterator type that may be used to read elements.
+  typedef const mutable_buffer* const_iterator;
+
+  /// Get a random-access iterator to the first element.
+  const_iterator begin() const ASIO_NOEXCEPT
+  {
+    return &buf_;
+  }
+
+  /// Get a random-access iterator for one past the last element.
+  const_iterator end() const ASIO_NOEXCEPT
+  {
+    return &buf_;
+  }
+
+private:
+  mutable_buffer buf_;
+};
+
+/** @defgroup buffer_sequence_begin asio::buffer_sequence_begin
+ *
+ * @brief The asio::buffer_sequence_begin function returns an iterator
+ * pointing to the first element in a buffer sequence.
+ */
+/*@{*/
+
+/// Get an iterator to the first element in a buffer sequence.
+template <typename MutableBuffer>
+inline const mutable_buffer* buffer_sequence_begin(const MutableBuffer& b,
+    typename enable_if<
+      is_convertible<const MutableBuffer*, const mutable_buffer*>::value
+    >::type* = 0) ASIO_NOEXCEPT
+{
+  return static_cast<const mutable_buffer*>(detail::addressof(b));
+}
+
+/// Get an iterator to the first element in a buffer sequence.
+template <typename ConstBuffer>
+inline const const_buffer* buffer_sequence_begin(const ConstBuffer& b,
+    typename enable_if<
+      is_convertible<const ConstBuffer*, const const_buffer*>::value
+    >::type* = 0) ASIO_NOEXCEPT
+{
+  return static_cast<const const_buffer*>(detail::addressof(b));
+}
+
+#if defined(ASIO_HAS_DECLTYPE) || defined(GENERATING_DOCUMENTATION)
+
+/// Get an iterator to the first element in a buffer sequence.
+template <typename C>
+inline auto buffer_sequence_begin(C& c,
+    typename enable_if<
+      !is_convertible<const C*, const mutable_buffer*>::value
+        && !is_convertible<const C*, const const_buffer*>::value
+    >::type* = 0) ASIO_NOEXCEPT -> decltype(c.begin())
+{
+  return c.begin();
+}
+
+/// Get an iterator to the first element in a buffer sequence.
+template <typename C>
+inline auto buffer_sequence_begin(const C& c,
+    typename enable_if<
+      !is_convertible<const C*, const mutable_buffer*>::value
+        && !is_convertible<const C*, const const_buffer*>::value
+    >::type* = 0) ASIO_NOEXCEPT -> decltype(c.begin())
+{
+  return c.begin();
+}
+
+#else // defined(ASIO_HAS_DECLTYPE) || defined(GENERATING_DOCUMENTATION)
+
+template <typename C>
+inline typename C::iterator buffer_sequence_begin(C& c,
+    typename enable_if<
+      !is_convertible<const C*, const mutable_buffer*>::value
+        && !is_convertible<const C*, const const_buffer*>::value
+    >::type* = 0) ASIO_NOEXCEPT
+{
+  return c.begin();
+}
+
+template <typename C>
+inline typename C::const_iterator buffer_sequence_begin(const C& c,
+    typename enable_if<
+      !is_convertible<const C*, const mutable_buffer*>::value
+        && !is_convertible<const C*, const const_buffer*>::value
+    >::type* = 0) ASIO_NOEXCEPT
+{
+  return c.begin();
+}
+
+#endif // defined(ASIO_HAS_DECLTYPE) || defined(GENERATING_DOCUMENTATION)
+
+/*@}*/
+
+/** @defgroup buffer_sequence_end asio::buffer_sequence_end
+ *
+ * @brief The asio::buffer_sequence_end function returns an iterator
+ * pointing to one past the end element in a buffer sequence.
+ */
+/*@{*/
+
+/// Get an iterator to one past the end element in a buffer sequence.
+template <typename MutableBuffer>
+inline const mutable_buffer* buffer_sequence_end(const MutableBuffer& b,
+    typename enable_if<
+      is_convertible<const MutableBuffer*, const mutable_buffer*>::value
+    >::type* = 0) ASIO_NOEXCEPT
+{
+  return static_cast<const mutable_buffer*>(detail::addressof(b)) + 1;
+}
+
+/// Get an iterator to one past the end element in a buffer sequence.
+template <typename ConstBuffer>
+inline const const_buffer* buffer_sequence_end(const ConstBuffer& b,
+    typename enable_if<
+      is_convertible<const ConstBuffer*, const const_buffer*>::value
+    >::type* = 0) ASIO_NOEXCEPT
+{
+  return static_cast<const const_buffer*>(detail::addressof(b)) + 1;
+}
+
+#if defined(ASIO_HAS_DECLTYPE) || defined(GENERATING_DOCUMENTATION)
+
+/// Get an iterator to one past the end element in a buffer sequence.
+template <typename C>
+inline auto buffer_sequence_end(C& c,
+    typename enable_if<
+      !is_convertible<const C*, const mutable_buffer*>::value
+        && !is_convertible<const C*, const const_buffer*>::value
+    >::type* = 0) ASIO_NOEXCEPT -> decltype(c.end())
+{
+  return c.end();
+}
+
+/// Get an iterator to one past the end element in a buffer sequence.
+template <typename C>
+inline auto buffer_sequence_end(const C& c,
+    typename enable_if<
+      !is_convertible<const C*, const mutable_buffer*>::value
+        && !is_convertible<const C*, const const_buffer*>::value
+    >::type* = 0) ASIO_NOEXCEPT -> decltype(c.end())
+{
+  return c.end();
+}
+
+#else // defined(ASIO_HAS_DECLTYPE) || defined(GENERATING_DOCUMENTATION)
+
+template <typename C>
+inline typename C::iterator buffer_sequence_end(C& c,
+    typename enable_if<
+      !is_convertible<const C*, const mutable_buffer*>::value
+        && !is_convertible<const C*, const const_buffer*>::value
+    >::type* = 0) ASIO_NOEXCEPT
+{
+  return c.end();
+}
+
+template <typename C>
+inline typename C::const_iterator buffer_sequence_end(const C& c,
+    typename enable_if<
+      !is_convertible<const C*, const mutable_buffer*>::value
+        && !is_convertible<const C*, const const_buffer*>::value
+    >::type* = 0) ASIO_NOEXCEPT
+{
+  return c.end();
+}
+
+#endif // defined(ASIO_HAS_DECLTYPE) || defined(GENERATING_DOCUMENTATION)
+
+/*@}*/
+
+namespace detail {
+
+// Tag types used to select appropriately optimised overloads.
+struct one_buffer {};
+struct multiple_buffers {};
+
+// Helper trait to detect single buffers.
+template <typename BufferSequence>
+struct buffer_sequence_cardinality :
+  conditional<
+    is_same<BufferSequence, mutable_buffer>::value
+#if !defined(ASIO_NO_DEPRECATED)
+      || is_same<BufferSequence, mutable_buffers_1>::value
+      || is_same<BufferSequence, const_buffers_1>::value
+#endif // !defined(ASIO_NO_DEPRECATED)
+      || is_same<BufferSequence, const_buffer>::value,
+    one_buffer, multiple_buffers>::type {};
+
+template <typename Iterator>
+inline std::size_t buffer_size(one_buffer,
+    Iterator begin, Iterator) ASIO_NOEXCEPT
+{
+  return const_buffer(*begin).size();
+}
+
+template <typename Iterator>
+inline std::size_t buffer_size(multiple_buffers,
+    Iterator begin, Iterator end) ASIO_NOEXCEPT
+{
+  std::size_t total_buffer_size = 0;
+
+  Iterator iter = begin;
+  for (; iter != end; ++iter)
+  {
+    const_buffer b(*iter);
+    total_buffer_size += b.size();
+  }
+
+  return total_buffer_size;
+}
+
+} // namespace detail
+
+/// Get the total number of bytes in a buffer sequence.
+/**
+ * The @c buffer_size function determines the total size of all buffers in the
+ * buffer sequence, as if computed as follows:
+ *
+ * @code size_t total_size = 0;
+ * auto i = asio::buffer_sequence_begin(buffers);
+ * auto end = asio::buffer_sequence_end(buffers);
+ * for (; i != end; ++i)
+ * {
+ *   const_buffer b(*i);
+ *   total_size += b.size();
+ * }
+ * return total_size; @endcode
+ *
+ * The @c BufferSequence template parameter may meet either of the @c
+ * ConstBufferSequence or @c MutableBufferSequence type requirements.
+ */
+template <typename BufferSequence>
+inline std::size_t buffer_size(const BufferSequence& b) ASIO_NOEXCEPT
+{
+  return detail::buffer_size(
+      detail::buffer_sequence_cardinality<BufferSequence>(),
+      asio::buffer_sequence_begin(b),
+      asio::buffer_sequence_end(b));
+}
+
+#if !defined(ASIO_NO_DEPRECATED)
+
+/** @defgroup buffer_cast asio::buffer_cast
+ *
+ * @brief (Deprecated: Use the @c data() member function.) The
+ * asio::buffer_cast function is used to obtain a pointer to the
+ * underlying memory region associated with a buffer.
+ *
+ * @par Examples:
+ *
+ * To access the memory of a non-modifiable buffer, use:
+ * @code asio::const_buffer b1 = ...;
+ * const unsigned char* p1 = asio::buffer_cast<const unsigned char*>(b1);
+ * @endcode
+ *
+ * To access the memory of a modifiable buffer, use:
+ * @code asio::mutable_buffer b2 = ...;
+ * unsigned char* p2 = asio::buffer_cast<unsigned char*>(b2);
+ * @endcode
+ *
+ * The asio::buffer_cast function permits violations of type safety, so
+ * uses of it in application code should be carefully considered.
+ */
+/*@{*/
+
+/// Cast a non-modifiable buffer to a specified pointer to POD type.
+template <typename PointerToPodType>
+inline PointerToPodType buffer_cast(const mutable_buffer& b) ASIO_NOEXCEPT
+{
+  return static_cast<PointerToPodType>(b.data());
+}
+
+/// Cast a non-modifiable buffer to a specified pointer to POD type.
+template <typename PointerToPodType>
+inline PointerToPodType buffer_cast(const const_buffer& b) ASIO_NOEXCEPT
+{
+  return static_cast<PointerToPodType>(b.data());
+}
+
+/*@}*/
+
+#endif // !defined(ASIO_NO_DEPRECATED)
+
+/// Create a new modifiable buffer that is offset from the start of another.
+/**
+ * @relates mutable_buffer
+ */
+inline mutable_buffer operator+(const mutable_buffer& b,
+    std::size_t n) ASIO_NOEXCEPT
+{
+  std::size_t offset = n < b.size() ? n : b.size();
+  char* new_data = static_cast<char*>(b.data()) + offset;
+  std::size_t new_size = b.size() - offset;
+  return mutable_buffer(new_data, new_size
+#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
+      , b.get_debug_check()
+#endif // ASIO_ENABLE_BUFFER_DEBUGGING
+      );
+}
+
+/// Create a new modifiable buffer that is offset from the start of another.
+/**
+ * @relates mutable_buffer
+ */
+inline mutable_buffer operator+(std::size_t n,
+    const mutable_buffer& b) ASIO_NOEXCEPT
+{
+  return b + n;
+}
+
+/// Create a new non-modifiable buffer that is offset from the start of another.
+/**
+ * @relates const_buffer
+ */
+inline const_buffer operator+(const const_buffer& b,
+    std::size_t n) ASIO_NOEXCEPT
+{
+  std::size_t offset = n < b.size() ? n : b.size();
+  const char* new_data = static_cast<const char*>(b.data()) + offset;
+  std::size_t new_size = b.size() - offset;
+  return const_buffer(new_data, new_size
+#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
+      , b.get_debug_check()
+#endif // ASIO_ENABLE_BUFFER_DEBUGGING
+      );
+}
+
+/// Create a new non-modifiable buffer that is offset from the start of another.
+/**
+ * @relates const_buffer
+ */
+inline const_buffer operator+(std::size_t n,
+    const const_buffer& b) ASIO_NOEXCEPT
+{
+  return b + n;
+}
+
+#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
+namespace detail {
+
+template <typename Iterator>
+class buffer_debug_check
+{
+public:
+  buffer_debug_check(Iterator iter)
+    : iter_(iter)
+  {
+  }
+
+  ~buffer_debug_check()
+  {
+#if defined(ASIO_MSVC) && (ASIO_MSVC == 1400)
+    // MSVC 8's string iterator checking may crash in a std::string::iterator
+    // object's destructor when the iterator points to an already-destroyed
+    // std::string object, unless the iterator is cleared first.
+    iter_ = Iterator();
+#endif // defined(ASIO_MSVC) && (ASIO_MSVC == 1400)
+  }
+
+  void operator()()
+  {
+    (void)*iter_;
+  }
+
+private:
+  Iterator iter_;
+};
+
+} // namespace detail
+#endif // ASIO_ENABLE_BUFFER_DEBUGGING
+
+/** @defgroup buffer asio::buffer
+ *
+ * @brief The asio::buffer function is used to create a buffer object to
+ * represent raw memory, an array of POD elements, a vector of POD elements,
+ * or a std::string.
+ *
+ * A buffer object represents a contiguous region of memory as a 2-tuple
+ * consisting of a pointer and size in bytes. A tuple of the form <tt>{void*,
+ * size_t}</tt> specifies a mutable (modifiable) region of memory. Similarly, a
+ * tuple of the form <tt>{const void*, size_t}</tt> specifies a const
+ * (non-modifiable) region of memory. These two forms correspond to the classes
+ * mutable_buffer and const_buffer, respectively. To mirror C++'s conversion
+ * rules, a mutable_buffer is implicitly convertible to a const_buffer, and the
+ * opposite conversion is not permitted.
+ *
+ * The simplest use case involves reading or writing a single buffer of a
+ * specified size:
+ *
+ * @code sock.send(asio::buffer(data, size)); @endcode
+ *
+ * In the above example, the return value of asio::buffer meets the
+ * requirements of the ConstBufferSequence concept so that it may be directly
+ * passed to the socket's write function. A buffer created for modifiable
+ * memory also meets the requirements of the MutableBufferSequence concept.
+ *
+ * An individual buffer may be created from a builtin array, std::vector,
+ * std::array or boost::array of POD elements. This helps prevent buffer
+ * overruns by automatically determining the size of the buffer:
+ *
+ * @code char d1[128];
+ * size_t bytes_transferred = sock.receive(asio::buffer(d1));
+ *
+ * std::vector<char> d2(128);
+ * bytes_transferred = sock.receive(asio::buffer(d2));
+ *
+ * std::array<char, 128> d3;
+ * bytes_transferred = sock.receive(asio::buffer(d3));
+ *
+ * boost::array<char, 128> d4;
+ * bytes_transferred = sock.receive(asio::buffer(d4)); @endcode
+ *
+ * In all three cases above, the buffers created are exactly 128 bytes long.
+ * Note that a vector is @e never automatically resized when creating or using
+ * a buffer. The buffer size is determined using the vector's <tt>size()</tt>
+ * member function, and not its capacity.
+ *
+ * @par Accessing Buffer Contents
+ *
+ * The contents of a buffer may be accessed using the @c data() and @c size()
+ * member functions:
+ *
+ * @code asio::mutable_buffer b1 = ...;
+ * std::size_t s1 = b1.size();
+ * unsigned char* p1 = static_cast<unsigned char*>(b1.data());
+ *
+ * asio::const_buffer b2 = ...;
+ * std::size_t s2 = b2.size();
+ * const void* p2 = b2.data(); @endcode
+ *
+ * The @c data() member function permits violations of type safety, so
+ * uses of it in application code should be carefully considered.
+ *
+ * For convenience, a @ref buffer_size function is provided that works with
+ * both buffers and buffer sequences (that is, types meeting the
+ * ConstBufferSequence or MutableBufferSequence type requirements). In this
+ * case, the function returns the total size of all buffers in the sequence.
+ *
+ * @par Buffer Copying
+ *
+ * The @ref buffer_copy function may be used to copy raw bytes between
+ * individual buffers and buffer sequences.
+*
+ * In particular, when used with the @ref buffer_size function, the @ref
+ * buffer_copy function can be used to linearise a sequence of buffers. For
+ * example:
+ *
+ * @code vector<const_buffer> buffers = ...;
+ *
+ * vector<unsigned char> data(asio::buffer_size(buffers));
+ * asio::buffer_copy(asio::buffer(data), buffers); @endcode
+ *
+ * Note that @ref buffer_copy is implemented in terms of @c memcpy, and
+ * consequently it cannot be used to copy between overlapping memory regions.
+ *
+ * @par Buffer Invalidation
+ *
+ * A buffer object does not have any ownership of the memory it refers to. It
+ * is the responsibility of the application to ensure the memory region remains
+ * valid until it is no longer required for an I/O operation. When the memory
+ * is no longer available, the buffer is said to have been invalidated.
+ *
+ * For the asio::buffer overloads that accept an argument of type
+ * std::vector, the buffer objects returned are invalidated by any vector
+ * operation that also invalidates all references, pointers and iterators
+ * referring to the elements in the sequence (C++ Std, 23.2.4)
+ *
+ * For the asio::buffer overloads that accept an argument of type
+ * std::basic_string, the buffer objects returned are invalidated according to
+ * the rules defined for invalidation of references, pointers and iterators
+ * referring to elements of the sequence (C++ Std, 21.3).
+ *
+ * @par Buffer Arithmetic
+ *
+ * Buffer objects may be manipulated using simple arithmetic in a safe way
+ * which helps prevent buffer overruns. Consider an array initialised as
+ * follows:
+ *
+ * @code boost::array<char, 6> a = { 'a', 'b', 'c', 'd', 'e' }; @endcode
+ *
+ * A buffer object @c b1 created using:
+ *
+ * @code b1 = asio::buffer(a); @endcode
+ *
+ * represents the entire array, <tt>{ 'a', 'b', 'c', 'd', 'e' }</tt>. An
+ * optional second argument to the asio::buffer function may be used to
+ * limit the size, in bytes, of the buffer:
+ *
+ * @code b2 = asio::buffer(a, 3); @endcode
+ *
+ * such that @c b2 represents the data <tt>{ 'a', 'b', 'c' }</tt>. Even if the
+ * size argument exceeds the actual size of the array, the size of the buffer
+ * object created will be limited to the array size.
+ *
+ * An offset may be applied to an existing buffer to create a new one:
+ *
+ * @code b3 = b1 + 2; @endcode
+ *
+ * where @c b3 will set to represent <tt>{ 'c', 'd', 'e' }</tt>. If the offset
+ * exceeds the size of the existing buffer, the newly created buffer will be
+ * empty.
+ *
+ * Both an offset and size may be specified to create a buffer that corresponds
+ * to a specific range of bytes within an existing buffer:
+ *
+ * @code b4 = asio::buffer(b1 + 1, 3); @endcode
+ *
+ * so that @c b4 will refer to the bytes <tt>{ 'b', 'c', 'd' }</tt>.
+ *
+ * @par Buffers and Scatter-Gather I/O
+ *
+ * To read or write using multiple buffers (i.e. scatter-gather I/O), multiple
+ * buffer objects may be assigned into a container that supports the
+ * MutableBufferSequence (for read) or ConstBufferSequence (for write) concepts:
+ *
+ * @code
+ * char d1[128];
+ * std::vector<char> d2(128);
+ * boost::array<char, 128> d3;
+ *
+ * boost::array<mutable_buffer, 3> bufs1 = {
+ *   asio::buffer(d1),
+ *   asio::buffer(d2),
+ *   asio::buffer(d3) };
+ * bytes_transferred = sock.receive(bufs1);
+ *
+ * std::vector<const_buffer> bufs2;
+ * bufs2.push_back(asio::buffer(d1));
+ * bufs2.push_back(asio::buffer(d2));
+ * bufs2.push_back(asio::buffer(d3));
+ * bytes_transferred = sock.send(bufs2); @endcode
+ */
+/*@{*/
+
+#if defined(ASIO_NO_DEPRECATED) || defined(GENERATING_DOCUMENTATION)
+# define ASIO_MUTABLE_BUFFER mutable_buffer
+# define ASIO_CONST_BUFFER const_buffer
+#else // defined(ASIO_NO_DEPRECATED) || defined(GENERATING_DOCUMENTATION)
+# define ASIO_MUTABLE_BUFFER mutable_buffers_1
+# define ASIO_CONST_BUFFER const_buffers_1
+#endif // defined(ASIO_NO_DEPRECATED) || defined(GENERATING_DOCUMENTATION)
+
+/// Create a new modifiable buffer from an existing buffer.
+/**
+ * @returns <tt>mutable_buffer(b)</tt>.
+ */
+inline ASIO_MUTABLE_BUFFER buffer(
+    const mutable_buffer& b) ASIO_NOEXCEPT
+{
+  return ASIO_MUTABLE_BUFFER(b);
+}
+
+/// Create a new modifiable buffer from an existing buffer.
+/**
+ * @returns A mutable_buffer value equivalent to:
+ * @code mutable_buffer(
+ *     b.data(),
+ *     min(b.size(), max_size_in_bytes)); @endcode
+ */
+inline ASIO_MUTABLE_BUFFER buffer(const mutable_buffer& b,
+    std::size_t max_size_in_bytes) ASIO_NOEXCEPT
+{
+  return ASIO_MUTABLE_BUFFER(
+      mutable_buffer(b.data(),
+        b.size() < max_size_in_bytes
+        ? b.size() : max_size_in_bytes
+#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
+        , b.get_debug_check()
+#endif // ASIO_ENABLE_BUFFER_DEBUGGING
+        ));
+}
+
+/// Create a new non-modifiable buffer from an existing buffer.
+/**
+ * @returns <tt>const_buffer(b)</tt>.
+ */
+inline ASIO_CONST_BUFFER buffer(
+    const const_buffer& b) ASIO_NOEXCEPT
+{
+  return ASIO_CONST_BUFFER(b);
+}
+
+/// Create a new non-modifiable buffer from an existing buffer.
+/**
+ * @returns A const_buffer value equivalent to:
+ * @code const_buffer(
+ *     b.data(),
+ *     min(b.size(), max_size_in_bytes)); @endcode
+ */
+inline ASIO_CONST_BUFFER buffer(const const_buffer& b,
+    std::size_t max_size_in_bytes) ASIO_NOEXCEPT
+{
+  return ASIO_CONST_BUFFER(b.data(),
+      b.size() < max_size_in_bytes
+      ? b.size() : max_size_in_bytes
+#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
+      , b.get_debug_check()
+#endif // ASIO_ENABLE_BUFFER_DEBUGGING
+      );
+}
+
+/// Create a new modifiable buffer that represents the given memory range.
+/**
+ * @returns <tt>mutable_buffer(data, size_in_bytes)</tt>.
+ */
+inline ASIO_MUTABLE_BUFFER buffer(void* data,
+    std::size_t size_in_bytes) ASIO_NOEXCEPT
+{
+  return ASIO_MUTABLE_BUFFER(data, size_in_bytes);
+}
+
+/// Create a new non-modifiable buffer that represents the given memory range.
+/**
+ * @returns <tt>const_buffer(data, size_in_bytes)</tt>.
+ */
+inline ASIO_CONST_BUFFER buffer(const void* data,
+    std::size_t size_in_bytes) ASIO_NOEXCEPT
+{
+  return ASIO_CONST_BUFFER(data, size_in_bytes);
+}
+
+/// Create a new modifiable buffer that represents the given POD array.
+/**
+ * @returns A mutable_buffer value equivalent to:
+ * @code mutable_buffer(
+ *     static_cast<void*>(data),
+ *     N * sizeof(PodType)); @endcode
+ */
+template <typename PodType, std::size_t N>
+inline ASIO_MUTABLE_BUFFER buffer(PodType (&data)[N]) ASIO_NOEXCEPT
+{
+  return ASIO_MUTABLE_BUFFER(data, N * sizeof(PodType));
+}
+ 
+/// Create a new modifiable buffer that represents the given POD array.
+/**
+ * @returns A mutable_buffer value equivalent to:
+ * @code mutable_buffer(
+ *     static_cast<void*>(data),
+ *     min(N * sizeof(PodType), max_size_in_bytes)); @endcode
+ */
+template <typename PodType, std::size_t N>
+inline ASIO_MUTABLE_BUFFER buffer(PodType (&data)[N],
+    std::size_t max_size_in_bytes) ASIO_NOEXCEPT
+{
+  return ASIO_MUTABLE_BUFFER(data,
+      N * sizeof(PodType) < max_size_in_bytes
+      ? N * sizeof(PodType) : max_size_in_bytes);
+}
+ 
+/// Create a new non-modifiable buffer that represents the given POD array.
+/**
+ * @returns A const_buffer value equivalent to:
+ * @code const_buffer(
+ *     static_cast<const void*>(data),
+ *     N * sizeof(PodType)); @endcode
+ */
+template <typename PodType, std::size_t N>
+inline ASIO_CONST_BUFFER buffer(
+    const PodType (&data)[N]) ASIO_NOEXCEPT
+{
+  return ASIO_CONST_BUFFER(data, N * sizeof(PodType));
+}
+
+/// Create a new non-modifiable buffer that represents the given POD array.
+/**
+ * @returns A const_buffer value equivalent to:
+ * @code const_buffer(
+ *     static_cast<const void*>(data),
+ *     min(N * sizeof(PodType), max_size_in_bytes)); @endcode
+ */
+template <typename PodType, std::size_t N>
+inline ASIO_CONST_BUFFER buffer(const PodType (&data)[N],
+    std::size_t max_size_in_bytes) ASIO_NOEXCEPT
+{
+  return ASIO_CONST_BUFFER(data,
+      N * sizeof(PodType) < max_size_in_bytes
+      ? N * sizeof(PodType) : max_size_in_bytes);
+}
+
+#if defined(ASIO_ENABLE_ARRAY_BUFFER_WORKAROUND)
+
+// Borland C++ and Sun Studio think the overloads:
+//
+//   unspecified buffer(boost::array<PodType, N>& array ...);
+//
+// and
+//
+//   unspecified buffer(boost::array<const PodType, N>& array ...);
+//
+// are ambiguous. This will be worked around by using a buffer_types traits
+// class that contains typedefs for the appropriate buffer and container
+// classes, based on whether PodType is const or non-const.
+
+namespace detail {
+
+template <bool IsConst>
+struct buffer_types_base;
+
+template <>
+struct buffer_types_base<false>
+{
+  typedef mutable_buffer buffer_type;
+  typedef ASIO_MUTABLE_BUFFER container_type;
+};
+
+template <>
+struct buffer_types_base<true>
+{
+  typedef const_buffer buffer_type;
+  typedef ASIO_CONST_BUFFER container_type;
+};
+
+template <typename PodType>
+struct buffer_types
+  : public buffer_types_base<is_const<PodType>::value>
+{
+};
+
+} // namespace detail
+
+template <typename PodType, std::size_t N>
+inline typename detail::buffer_types<PodType>::container_type
+buffer(boost::array<PodType, N>& data) ASIO_NOEXCEPT
+{
+  typedef typename asio::detail::buffer_types<PodType>::buffer_type
+    buffer_type;
+  typedef typename asio::detail::buffer_types<PodType>::container_type
+    container_type;
+  return container_type(
+      buffer_type(data.c_array(), data.size() * sizeof(PodType)));
+}
+
+template <typename PodType, std::size_t N>
+inline typename detail::buffer_types<PodType>::container_type
+buffer(boost::array<PodType, N>& data,
+    std::size_t max_size_in_bytes) ASIO_NOEXCEPT
+{
+  typedef typename asio::detail::buffer_types<PodType>::buffer_type
+    buffer_type;
+  typedef typename asio::detail::buffer_types<PodType>::container_type
+    container_type;
+  return container_type(
+      buffer_type(data.c_array(),
+        data.size() * sizeof(PodType) < max_size_in_bytes
+        ? data.size() * sizeof(PodType) : max_size_in_bytes));
+}
+
+#else // defined(ASIO_ENABLE_ARRAY_BUFFER_WORKAROUND)
+
+/// Create a new modifiable buffer that represents the given POD array.
+/**
+ * @returns A mutable_buffer value equivalent to:
+ * @code mutable_buffer(
+ *     data.data(),
+ *     data.size() * sizeof(PodType)); @endcode
+ */
+template <typename PodType, std::size_t N>
+inline ASIO_MUTABLE_BUFFER buffer(
+    boost::array<PodType, N>& data) ASIO_NOEXCEPT
+{
+  return ASIO_MUTABLE_BUFFER(
+      data.c_array(), data.size() * sizeof(PodType));
+}
+
+/// Create a new modifiable buffer that represents the given POD array.
+/**
+ * @returns A mutable_buffer value equivalent to:
+ * @code mutable_buffer(
+ *     data.data(),
+ *     min(data.size() * sizeof(PodType), max_size_in_bytes)); @endcode
+ */
+template <typename PodType, std::size_t N>
+inline ASIO_MUTABLE_BUFFER buffer(boost::array<PodType, N>& data,
+    std::size_t max_size_in_bytes) ASIO_NOEXCEPT
+{
+  return ASIO_MUTABLE_BUFFER(data.c_array(),
+      data.size() * sizeof(PodType) < max_size_in_bytes
+      ? data.size() * sizeof(PodType) : max_size_in_bytes);
+}
+
+/// Create a new non-modifiable buffer that represents the given POD array.
+/**
+ * @returns A const_buffer value equivalent to:
+ * @code const_buffer(
+ *     data.data(),
+ *     data.size() * sizeof(PodType)); @endcode
+ */
+template <typename PodType, std::size_t N>
+inline ASIO_CONST_BUFFER buffer(
+    boost::array<const PodType, N>& data) ASIO_NOEXCEPT
+{
+  return ASIO_CONST_BUFFER(data.data(), data.size() * sizeof(PodType));
+}
+
+/// Create a new non-modifiable buffer that represents the given POD array.
+/**
+ * @returns A const_buffer value equivalent to:
+ * @code const_buffer(
+ *     data.data(),
+ *     min(data.size() * sizeof(PodType), max_size_in_bytes)); @endcode
+ */
+template <typename PodType, std::size_t N>
+inline ASIO_CONST_BUFFER buffer(boost::array<const PodType, N>& data,
+    std::size_t max_size_in_bytes) ASIO_NOEXCEPT
+{
+  return ASIO_CONST_BUFFER(data.data(),
+      data.size() * sizeof(PodType) < max_size_in_bytes
+      ? data.size() * sizeof(PodType) : max_size_in_bytes);
+}
+
+#endif // defined(ASIO_ENABLE_ARRAY_BUFFER_WORKAROUND)
+
+/// Create a new non-modifiable buffer that represents the given POD array.
+/**
+ * @returns A const_buffer value equivalent to:
+ * @code const_buffer(
+ *     data.data(),
+ *     data.size() * sizeof(PodType)); @endcode
+ */
+template <typename PodType, std::size_t N>
+inline ASIO_CONST_BUFFER buffer(
+    const boost::array<PodType, N>& data) ASIO_NOEXCEPT
+{
+  return ASIO_CONST_BUFFER(data.data(), data.size() * sizeof(PodType));
+}
+
+/// Create a new non-modifiable buffer that represents the given POD array.
+/**
+ * @returns A const_buffer value equivalent to:
+ * @code const_buffer(
+ *     data.data(),
+ *     min(data.size() * sizeof(PodType), max_size_in_bytes)); @endcode
+ */
+template <typename PodType, std::size_t N>
+inline ASIO_CONST_BUFFER buffer(const boost::array<PodType, N>& data,
+    std::size_t max_size_in_bytes) ASIO_NOEXCEPT
+{
+  return ASIO_CONST_BUFFER(data.data(),
+      data.size() * sizeof(PodType) < max_size_in_bytes
+      ? data.size() * sizeof(PodType) : max_size_in_bytes);
+}
+
+#if defined(ASIO_HAS_STD_ARRAY) || defined(GENERATING_DOCUMENTATION)
+
+/// Create a new modifiable buffer that represents the given POD array.
+/**
+ * @returns A mutable_buffer value equivalent to:
+ * @code mutable_buffer(
+ *     data.data(),
+ *     data.size() * sizeof(PodType)); @endcode
+ */
+template <typename PodType, std::size_t N>
+inline ASIO_MUTABLE_BUFFER buffer(
+    std::array<PodType, N>& data) ASIO_NOEXCEPT
+{
+  return ASIO_MUTABLE_BUFFER(data.data(), data.size() * sizeof(PodType));
+}
+
+/// Create a new modifiable buffer that represents the given POD array.
+/**
+ * @returns A mutable_buffer value equivalent to:
+ * @code mutable_buffer(
+ *     data.data(),
+ *     min(data.size() * sizeof(PodType), max_size_in_bytes)); @endcode
+ */
+template <typename PodType, std::size_t N>
+inline ASIO_MUTABLE_BUFFER buffer(std::array<PodType, N>& data,
+    std::size_t max_size_in_bytes) ASIO_NOEXCEPT
+{
+  return ASIO_MUTABLE_BUFFER(data.data(),
+      data.size() * sizeof(PodType) < max_size_in_bytes
+      ? data.size() * sizeof(PodType) : max_size_in_bytes);
+}
+
+/// Create a new non-modifiable buffer that represents the given POD array.
+/**
+ * @returns A const_buffer value equivalent to:
+ * @code const_buffer(
+ *     data.data(),
+ *     data.size() * sizeof(PodType)); @endcode
+ */
+template <typename PodType, std::size_t N>
+inline ASIO_CONST_BUFFER buffer(
+    std::array<const PodType, N>& data) ASIO_NOEXCEPT
+{
+  return ASIO_CONST_BUFFER(data.data(), data.size() * sizeof(PodType));
+}
+
+/// Create a new non-modifiable buffer that represents the given POD array.
+/**
+ * @returns A const_buffer value equivalent to:
+ * @code const_buffer(
+ *     data.data(),
+ *     min(data.size() * sizeof(PodType), max_size_in_bytes)); @endcode
+ */
+template <typename PodType, std::size_t N>
+inline ASIO_CONST_BUFFER buffer(std::array<const PodType, N>& data,
+    std::size_t max_size_in_bytes) ASIO_NOEXCEPT
+{
+  return ASIO_CONST_BUFFER(data.data(),
+      data.size() * sizeof(PodType) < max_size_in_bytes
+      ? data.size() * sizeof(PodType) : max_size_in_bytes);
+}
+
+/// Create a new non-modifiable buffer that represents the given POD array.
+/**
+ * @returns A const_buffer value equivalent to:
+ * @code const_buffer(
+ *     data.data(),
+ *     data.size() * sizeof(PodType)); @endcode
+ */
+template <typename PodType, std::size_t N>
+inline ASIO_CONST_BUFFER buffer(
+    const std::array<PodType, N>& data) ASIO_NOEXCEPT
+{
+  return ASIO_CONST_BUFFER(data.data(), data.size() * sizeof(PodType));
+}
+
+/// Create a new non-modifiable buffer that represents the given POD array.
+/**
+ * @returns A const_buffer value equivalent to:
+ * @code const_buffer(
+ *     data.data(),
+ *     min(data.size() * sizeof(PodType), max_size_in_bytes)); @endcode
+ */
+template <typename PodType, std::size_t N>
+inline ASIO_CONST_BUFFER buffer(const std::array<PodType, N>& data,
+    std::size_t max_size_in_bytes) ASIO_NOEXCEPT
+{
+  return ASIO_CONST_BUFFER(data.data(),
+      data.size() * sizeof(PodType) < max_size_in_bytes
+      ? data.size() * sizeof(PodType) : max_size_in_bytes);
+}
+
+#endif // defined(ASIO_HAS_STD_ARRAY) || defined(GENERATING_DOCUMENTATION)
+
+/// Create a new modifiable buffer that represents the given POD vector.
+/**
+ * @returns A mutable_buffer value equivalent to:
+ * @code mutable_buffer(
+ *     data.size() ? &data[0] : 0,
+ *     data.size() * sizeof(PodType)); @endcode
+ *
+ * @note The buffer is invalidated by any vector operation that would also
+ * invalidate iterators.
+ */
+template <typename PodType, typename Allocator>
+inline ASIO_MUTABLE_BUFFER buffer(
+    std::vector<PodType, Allocator>& data) ASIO_NOEXCEPT
+{
+  return ASIO_MUTABLE_BUFFER(
+      data.size() ? &data[0] : 0, data.size() * sizeof(PodType)
+#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
+      , detail::buffer_debug_check<
+          typename std::vector<PodType, Allocator>::iterator
+        >(data.begin())
+#endif // ASIO_ENABLE_BUFFER_DEBUGGING
+      );
+}
+
+/// Create a new modifiable buffer that represents the given POD vector.
+/**
+ * @returns A mutable_buffer value equivalent to:
+ * @code mutable_buffer(
+ *     data.size() ? &data[0] : 0,
+ *     min(data.size() * sizeof(PodType), max_size_in_bytes)); @endcode
+ *
+ * @note The buffer is invalidated by any vector operation that would also
+ * invalidate iterators.
+ */
+template <typename PodType, typename Allocator>
+inline ASIO_MUTABLE_BUFFER buffer(std::vector<PodType, Allocator>& data,
+    std::size_t max_size_in_bytes) ASIO_NOEXCEPT
+{
+  return ASIO_MUTABLE_BUFFER(data.size() ? &data[0] : 0,
+      data.size() * sizeof(PodType) < max_size_in_bytes
+      ? data.size() * sizeof(PodType) : max_size_in_bytes
+#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
+      , detail::buffer_debug_check<
+          typename std::vector<PodType, Allocator>::iterator
+        >(data.begin())
+#endif // ASIO_ENABLE_BUFFER_DEBUGGING
+      );
+}
+
+/// Create a new non-modifiable buffer that represents the given POD vector.
+/**
+ * @returns A const_buffer value equivalent to:
+ * @code const_buffer(
+ *     data.size() ? &data[0] : 0,
+ *     data.size() * sizeof(PodType)); @endcode
+ *
+ * @note The buffer is invalidated by any vector operation that would also
+ * invalidate iterators.
+ */
+template <typename PodType, typename Allocator>
+inline ASIO_CONST_BUFFER buffer(
+    const std::vector<PodType, Allocator>& data) ASIO_NOEXCEPT
+{
+  return ASIO_CONST_BUFFER(
+      data.size() ? &data[0] : 0, data.size() * sizeof(PodType)
+#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
+      , detail::buffer_debug_check<
+          typename std::vector<PodType, Allocator>::const_iterator
+        >(data.begin())
+#endif // ASIO_ENABLE_BUFFER_DEBUGGING
+      );
+}
+
+/// Create a new non-modifiable buffer that represents the given POD vector.
+/**
+ * @returns A const_buffer value equivalent to:
+ * @code const_buffer(
+ *     data.size() ? &data[0] : 0,
+ *     min(data.size() * sizeof(PodType), max_size_in_bytes)); @endcode
+ *
+ * @note The buffer is invalidated by any vector operation that would also
+ * invalidate iterators.
+ */
+template <typename PodType, typename Allocator>
+inline ASIO_CONST_BUFFER buffer(
+    const std::vector<PodType, Allocator>& data,
+    std::size_t max_size_in_bytes) ASIO_NOEXCEPT
+{
+  return ASIO_CONST_BUFFER(data.size() ? &data[0] : 0,
+      data.size() * sizeof(PodType) < max_size_in_bytes
+      ? data.size() * sizeof(PodType) : max_size_in_bytes
+#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
+      , detail::buffer_debug_check<
+          typename std::vector<PodType, Allocator>::const_iterator
+        >(data.begin())
+#endif // ASIO_ENABLE_BUFFER_DEBUGGING
+      );
+}
+
+/// Create a new modifiable buffer that represents the given string.
+/**
+ * @returns <tt>mutable_buffer(data.size() ? &data[0] : 0,
+ * data.size() * sizeof(Elem))</tt>.
+ *
+ * @note The buffer is invalidated by any non-const operation called on the
+ * given string object.
+ */
+template <typename Elem, typename Traits, typename Allocator>
+inline ASIO_MUTABLE_BUFFER buffer(
+    std::basic_string<Elem, Traits, Allocator>& data) ASIO_NOEXCEPT
+{
+  return ASIO_MUTABLE_BUFFER(data.size() ? &data[0] : 0,
+      data.size() * sizeof(Elem)
+#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
+      , detail::buffer_debug_check<
+          typename std::basic_string<Elem, Traits, Allocator>::iterator
+        >(data.begin())
+#endif // ASIO_ENABLE_BUFFER_DEBUGGING
+      );
+}
+
+/// Create a new modifiable buffer that represents the given string.
+/**
+ * @returns A mutable_buffer value equivalent to:
+ * @code mutable_buffer(
+ *     data.size() ? &data[0] : 0,
+ *     min(data.size() * sizeof(Elem), max_size_in_bytes)); @endcode
+ *
+ * @note The buffer is invalidated by any non-const operation called on the
+ * given string object.
+ */
+template <typename Elem, typename Traits, typename Allocator>
+inline ASIO_MUTABLE_BUFFER buffer(
+    std::basic_string<Elem, Traits, Allocator>& data,
+    std::size_t max_size_in_bytes) ASIO_NOEXCEPT
+{
+  return ASIO_MUTABLE_BUFFER(data.size() ? &data[0] : 0,
+      data.size() * sizeof(Elem) < max_size_in_bytes
+      ? data.size() * sizeof(Elem) : max_size_in_bytes
+#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
+      , detail::buffer_debug_check<
+          typename std::basic_string<Elem, Traits, Allocator>::iterator
+        >(data.begin())
+#endif // ASIO_ENABLE_BUFFER_DEBUGGING
+      );
+}
+
+/// Create a new non-modifiable buffer that represents the given string.
+/**
+ * @returns <tt>const_buffer(data.data(), data.size() * sizeof(Elem))</tt>.
+ *
+ * @note The buffer is invalidated by any non-const operation called on the
+ * given string object.
+ */
+template <typename Elem, typename Traits, typename Allocator>
+inline ASIO_CONST_BUFFER buffer(
+    const std::basic_string<Elem, Traits, Allocator>& data) ASIO_NOEXCEPT
+{
+  return ASIO_CONST_BUFFER(data.data(), data.size() * sizeof(Elem)
+#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
+      , detail::buffer_debug_check<
+          typename std::basic_string<Elem, Traits, Allocator>::const_iterator
+        >(data.begin())
+#endif // ASIO_ENABLE_BUFFER_DEBUGGING
+      );
+}
+
+/// Create a new non-modifiable buffer that represents the given string.
+/**
+ * @returns A const_buffer value equivalent to:
+ * @code const_buffer(
+ *     data.data(),
+ *     min(data.size() * sizeof(Elem), max_size_in_bytes)); @endcode
+ *
+ * @note The buffer is invalidated by any non-const operation called on the
+ * given string object.
+ */
+template <typename Elem, typename Traits, typename Allocator>
+inline ASIO_CONST_BUFFER buffer(
+    const std::basic_string<Elem, Traits, Allocator>& data,
+    std::size_t max_size_in_bytes) ASIO_NOEXCEPT
+{
+  return ASIO_CONST_BUFFER(data.data(),
+      data.size() * sizeof(Elem) < max_size_in_bytes
+      ? data.size() * sizeof(Elem) : max_size_in_bytes
+#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
+      , detail::buffer_debug_check<
+          typename std::basic_string<Elem, Traits, Allocator>::const_iterator
+        >(data.begin())
+#endif // ASIO_ENABLE_BUFFER_DEBUGGING
+      );
+}
+
+#if defined(ASIO_HAS_STRING_VIEW) \
+  || defined(GENERATING_DOCUMENTATION)
+
+/// Create a new modifiable buffer that represents the given string_view.
+/**
+ * @returns <tt>mutable_buffer(data.size() ? &data[0] : 0,
+ * data.size() * sizeof(Elem))</tt>.
+ */
+template <typename Elem, typename Traits>
+inline ASIO_CONST_BUFFER buffer(
+    basic_string_view<Elem, Traits> data) ASIO_NOEXCEPT
+{
+  return ASIO_CONST_BUFFER(data.size() ? &data[0] : 0,
+      data.size() * sizeof(Elem)
+#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
+      , detail::buffer_debug_check<
+          typename basic_string_view<Elem, Traits>::iterator
+        >(data.begin())
+#endif // ASIO_ENABLE_BUFFER_DEBUGGING
+      );
+}
+
+/// Create a new non-modifiable buffer that represents the given string.
+/**
+ * @returns A mutable_buffer value equivalent to:
+ * @code mutable_buffer(
+ *     data.size() ? &data[0] : 0,
+ *     min(data.size() * sizeof(Elem), max_size_in_bytes)); @endcode
+ */
+template <typename Elem, typename Traits>
+inline ASIO_CONST_BUFFER buffer(
+    basic_string_view<Elem, Traits> data,
+    std::size_t max_size_in_bytes) ASIO_NOEXCEPT
+{
+  return ASIO_CONST_BUFFER(data.size() ? &data[0] : 0,
+      data.size() * sizeof(Elem) < max_size_in_bytes
+      ? data.size() * sizeof(Elem) : max_size_in_bytes
+#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
+      , detail::buffer_debug_check<
+          typename basic_string_view<Elem, Traits>::iterator
+        >(data.begin())
+#endif // ASIO_ENABLE_BUFFER_DEBUGGING
+      );
+}
+
+#endif // defined(ASIO_HAS_STRING_VIEW)
+       //  || defined(GENERATING_DOCUMENTATION)
+
+/*@}*/
+
+/// Adapt a basic_string to the DynamicBuffer requirements.
+/**
+ * Requires that <tt>sizeof(Elem) == 1</tt>.
+ */
+template <typename Elem, typename Traits, typename Allocator>
+class dynamic_string_buffer
+{
+public:
+  /// The type used to represent a sequence of constant buffers that refers to
+  /// the underlying memory.
+  typedef ASIO_CONST_BUFFER const_buffers_type;
+
+  /// The type used to represent a sequence of mutable buffers that refers to
+  /// the underlying memory.
+  typedef ASIO_MUTABLE_BUFFER mutable_buffers_type;
+
+  /// Construct a dynamic buffer from a string.
+  /**
+   * @param s The string to be used as backing storage for the dynamic buffer.
+   * The object stores a reference to the string and the user is responsible
+   * for ensuring that the string object remains valid while the
+   * dynamic_string_buffer object, and copies of the object, are in use.
+   *
+   * @b DynamicBuffer_v1: Any existing data in the string is treated as the
+   * dynamic buffer's input sequence.
+   *
+   * @param maximum_size Specifies a maximum size for the buffer, in bytes.
+   */
+  explicit dynamic_string_buffer(std::basic_string<Elem, Traits, Allocator>& s,
+      std::size_t maximum_size =
+        (std::numeric_limits<std::size_t>::max)()) ASIO_NOEXCEPT
+    : string_(s),
+#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1)
+      size_((std::numeric_limits<std::size_t>::max)()),
+#endif // !defined(ASIO_NO_DYNAMIC_BUFFER_V1)
+      max_size_(maximum_size)
+  {
+  }
+
+  /// @b DynamicBuffer_v2: Copy construct a dynamic buffer.
+  dynamic_string_buffer(const dynamic_string_buffer& other) ASIO_NOEXCEPT
+    : string_(other.string_),
+#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1)
+      size_(other.size_),
+#endif // !defined(ASIO_NO_DYNAMIC_BUFFER_V1)
+      max_size_(other.max_size_)
+  {
+  }
+
+#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+  /// Move construct a dynamic buffer.
+  dynamic_string_buffer(dynamic_string_buffer&& other) ASIO_NOEXCEPT
+    : string_(other.string_),
+#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1)
+      size_(other.size_),
+#endif // !defined(ASIO_NO_DYNAMIC_BUFFER_V1)
+      max_size_(other.max_size_)
+  {
+  }
+#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+
+  /// @b DynamicBuffer_v1: Get the size of the input sequence.
+  /// @b DynamicBuffer_v2: Get the current size of the underlying memory.
+  /**
+   * @returns @b DynamicBuffer_v1 The current size of the input sequence.
+   * @b DynamicBuffer_v2: The current size of the underlying string if less than
+   * max_size(). Otherwise returns max_size().
+   */
+  std::size_t size() const ASIO_NOEXCEPT
+  {
+#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1)
+    if (size_ != (std::numeric_limits<std::size_t>::max)())
+      return size_;
+#endif // !defined(ASIO_NO_DYNAMIC_BUFFER_V1)
+    return (std::min)(string_.size(), max_size());
+  }
+
+  /// Get the maximum size of the dynamic buffer.
+  /**
+   * @returns The allowed maximum size of the underlying memory.
+   */
+  std::size_t max_size() const ASIO_NOEXCEPT
+  {
+    return max_size_;
+  }
+
+  /// Get the maximum size that the buffer may grow to without triggering
+  /// reallocation.
+  /**
+   * @returns The current capacity of the underlying string if less than
+   * max_size(). Otherwise returns max_size().
+   */
+  std::size_t capacity() const ASIO_NOEXCEPT
+  {
+    return (std::min)(string_.capacity(), max_size());
+  }
+
+#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1)
+  /// @b DynamicBuffer_v1: Get a list of buffers that represents the input
+  /// sequence.
+  /**
+   * @returns An object of type @c const_buffers_type that satisfies
+   * ConstBufferSequence requirements, representing the basic_string memory in
+   * the input sequence.
+   *
+   * @note The returned object is invalidated by any @c dynamic_string_buffer
+   * or @c basic_string member function that resizes or erases the string.
+   */
+  const_buffers_type data() const ASIO_NOEXCEPT
+  {
+    return const_buffers_type(asio::buffer(string_, size_));
+  }
+#endif // !defined(ASIO_NO_DYNAMIC_BUFFER_V1)
+
+  /// @b DynamicBuffer_v2: Get a sequence of buffers that represents the
+  /// underlying memory.
+  /**
+   * @param pos Position of the first byte to represent in the buffer sequence
+   *
+   * @param n The number of bytes to return in the buffer sequence. If the
+   * underlying memory is shorter, the buffer sequence represents as many bytes
+   * as are available.
+   *
+   * @returns An object of type @c mutable_buffers_type that satisfies
+   * MutableBufferSequence requirements, representing the basic_string memory.
+   *
+   * @note The returned object is invalidated by any @c dynamic_string_buffer
+   * or @c basic_string member function that resizes or erases the string.
+   */
+  mutable_buffers_type data(std::size_t pos, std::size_t n) ASIO_NOEXCEPT
+  {
+    return mutable_buffers_type(asio::buffer(
+          asio::buffer(string_, max_size_) + pos, n));
+  }
+
+  /// @b DynamicBuffer_v2: Get a sequence of buffers that represents the
+  /// underlying memory.
+  /**
+   * @param pos Position of the first byte to represent in the buffer sequence
+   *
+   * @param n The number of bytes to return in the buffer sequence. If the
+   * underlying memory is shorter, the buffer sequence represents as many bytes
+   * as are available.
+   *
+   * @note The returned object is invalidated by any @c dynamic_string_buffer
+   * or @c basic_string member function that resizes or erases the string.
+   */
+  const_buffers_type data(std::size_t pos,
+      std::size_t n) const ASIO_NOEXCEPT
+  {
+    return const_buffers_type(asio::buffer(
+          asio::buffer(string_, max_size_) + pos, n));
+  }
+
+#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1)
+  /// @b DynamicBuffer_v1: Get a list of buffers that represents the output
+  /// sequence, with the given size.
+  /**
+   * Ensures that the output sequence can accommodate @c n bytes, resizing the
+   * basic_string object as necessary.
+   *
+   * @returns An object of type @c mutable_buffers_type that satisfies
+   * MutableBufferSequence requirements, representing basic_string memory
+   * at the start of the output sequence of size @c n.
+   *
+   * @throws std::length_error If <tt>size() + n > max_size()</tt>.
+   *
+   * @note The returned object is invalidated by any @c dynamic_string_buffer
+   * or @c basic_string member function that modifies the input sequence or
+   * output sequence.
+   */
+  mutable_buffers_type prepare(std::size_t n)
+  {
+    if (size() > max_size() || max_size() - size() < n)
+    {
+      std::length_error ex("dynamic_string_buffer too long");
+      asio::detail::throw_exception(ex);
+    }
+
+    if (size_ == (std::numeric_limits<std::size_t>::max)())
+      size_ = string_.size(); // Enable v1 behaviour.
+
+    string_.resize(size_ + n);
+
+    return asio::buffer(asio::buffer(string_) + size_, n);
+  }
+
+  /// @b DynamicBuffer_v1: Move bytes from the output sequence to the input
+  /// sequence.
+  /**
+   * @param n The number of bytes to append from the start of the output
+   * sequence to the end of the input sequence. The remainder of the output
+   * sequence is discarded.
+   *
+   * Requires a preceding call <tt>prepare(x)</tt> where <tt>x >= n</tt>, and
+   * no intervening operations that modify the input or output sequence.
+   *
+   * @note If @c n is greater than the size of the output sequence, the entire
+   * output sequence is moved to the input sequence and no error is issued.
+   */
+  void commit(std::size_t n)
+  {
+    size_ += (std::min)(n, string_.size() - size_);
+    string_.resize(size_);
+  }
+#endif // !defined(ASIO_NO_DYNAMIC_BUFFER_V1)
+
+  /// @b DynamicBuffer_v2: Grow the underlying memory by the specified number of
+  /// bytes.
+  /**
+   * Resizes the string to accommodate an additional @c n bytes at the end.
+   *
+   * @throws std::length_error If <tt>size() + n > max_size()</tt>.
+   */
+  void grow(std::size_t n)
+  {
+    if (size() > max_size() || max_size() - size() < n)
+    {
+      std::length_error ex("dynamic_string_buffer too long");
+      asio::detail::throw_exception(ex);
+    }
+
+    string_.resize(size() + n);
+  }
+
+  /// @b DynamicBuffer_v2: Shrink the underlying memory by the specified number
+  /// of bytes.
+  /**
+   * Erases @c n bytes from the end of the string by resizing the basic_string
+   * object. If @c n is greater than the current size of the string, the string
+   * is emptied.
+   */
+  void shrink(std::size_t n)
+  {
+    string_.resize(n > size() ? 0 : size() - n);
+  }
+
+  /// @b DynamicBuffer_v1: Remove characters from the input sequence.
+  /// @b DynamicBuffer_v2: Consume the specified number of bytes from the
+  /// beginning of the underlying memory.
+  /**
+   * @b DynamicBuffer_v1: Removes @c n characters from the beginning of the
+   * input sequence. @note If @c n is greater than the size of the input
+   * sequence, the entire input sequence is consumed and no error is issued.
+   *
+   * @b DynamicBuffer_v2: Erases @c n bytes from the beginning of the string.
+   * If @c n is greater than the current size of the string, the string is
+   * emptied.
+   */
+  void consume(std::size_t n)
+  {
+#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1)
+    if (size_ != (std::numeric_limits<std::size_t>::max)())
+    {
+      std::size_t consume_length = (std::min)(n, size_);
+      string_.erase(0, consume_length);
+      size_ -= consume_length;
+      return;
+    }
+#endif // !defined(ASIO_NO_DYNAMIC_BUFFER_V1)
+    string_.erase(0, n);
+  }
+
+private:
+  std::basic_string<Elem, Traits, Allocator>& string_;
+#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1)
+  std::size_t size_;
+#endif // !defined(ASIO_NO_DYNAMIC_BUFFER_V1)
+  const std::size_t max_size_;
+};
+
+/// Adapt a vector to the DynamicBuffer requirements.
+/**
+ * Requires that <tt>sizeof(Elem) == 1</tt>.
+ */
+template <typename Elem, typename Allocator>
+class dynamic_vector_buffer
+{
+public:
+  /// The type used to represent a sequence of constant buffers that refers to
+  /// the underlying memory.
+  typedef ASIO_CONST_BUFFER const_buffers_type;
+
+  /// The type used to represent a sequence of mutable buffers that refers to
+  /// the underlying memory.
+  typedef ASIO_MUTABLE_BUFFER mutable_buffers_type;
+
+  /// Construct a dynamic buffer from a vector.
+  /**
+   * @param v The vector to be used as backing storage for the dynamic buffer.
+   * The object stores a reference to the vector and the user is responsible
+   * for ensuring that the vector object remains valid while the
+   * dynamic_vector_buffer object, and copies of the object, are in use.
+   *
+   * @param maximum_size Specifies a maximum size for the buffer, in bytes.
+   */
+  explicit dynamic_vector_buffer(std::vector<Elem, Allocator>& v,
+      std::size_t maximum_size =
+        (std::numeric_limits<std::size_t>::max)()) ASIO_NOEXCEPT
+    : vector_(v),
+#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1)
+      size_((std::numeric_limits<std::size_t>::max)()),
+#endif // !defined(ASIO_NO_DYNAMIC_BUFFER_V1)
+      max_size_(maximum_size)
+  {
+  }
+
+  /// @b DynamicBuffer_v2: Copy construct a dynamic buffer.
+  dynamic_vector_buffer(const dynamic_vector_buffer& other) ASIO_NOEXCEPT
+    : vector_(other.vector_),
+#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1)
+      size_(other.size_),
+#endif // !defined(ASIO_NO_DYNAMIC_BUFFER_V1)
+      max_size_(other.max_size_)
+  {
+  }
+
+#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+  /// Move construct a dynamic buffer.
+  dynamic_vector_buffer(dynamic_vector_buffer&& other) ASIO_NOEXCEPT
+    : vector_(other.vector_),
+#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1)
+      size_(other.size_),
+#endif // !defined(ASIO_NO_DYNAMIC_BUFFER_V1)
+      max_size_(other.max_size_)
+  {
+  }
+#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+
+  /// @b DynamicBuffer_v1: Get the size of the input sequence.
+  /// @b DynamicBuffer_v2: Get the current size of the underlying memory.
+  /**
+   * @returns @b DynamicBuffer_v1 The current size of the input sequence.
+   * @b DynamicBuffer_v2: The current size of the underlying vector if less than
+   * max_size(). Otherwise returns max_size().
+   */
+  std::size_t size() const ASIO_NOEXCEPT
+  {
+#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1)
+    if (size_ != (std::numeric_limits<std::size_t>::max)())
+      return size_;
+#endif // !defined(ASIO_NO_DYNAMIC_BUFFER_V1)
+    return (std::min)(vector_.size(), max_size());
+  }
+
+  /// Get the maximum size of the dynamic buffer.
+  /**
+   * @returns @b DynamicBuffer_v1: The allowed maximum of the sum of the sizes
+   * of the input sequence and output sequence. @b DynamicBuffer_v2: The allowed
+   * maximum size of the underlying memory.
+   */
+  std::size_t max_size() const ASIO_NOEXCEPT
+  {
+    return max_size_;
+  }
+
+  /// Get the maximum size that the buffer may grow to without triggering
+  /// reallocation.
+  /**
+   * @returns @b DynamicBuffer_v1: The current total capacity of the buffer,
+   * i.e. for both the input sequence and output sequence. @b DynamicBuffer_v2:
+   * The current capacity of the underlying vector if less than max_size().
+   * Otherwise returns max_size().
+   */
+  std::size_t capacity() const ASIO_NOEXCEPT
+  {
+    return (std::min)(vector_.capacity(), max_size());
+  }
+
+#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1)
+  /// @b DynamicBuffer_v1: Get a list of buffers that represents the input
+  /// sequence.
+  /**
+   * @returns An object of type @c const_buffers_type that satisfies
+   * ConstBufferSequence requirements, representing the vector memory in the
+   * input sequence.
+   *
+   * @note The returned object is invalidated by any @c dynamic_vector_buffer
+   * or @c vector member function that modifies the input sequence or output
+   * sequence.
+   */
+  const_buffers_type data() const ASIO_NOEXCEPT
+  {
+    return const_buffers_type(asio::buffer(vector_, size_));
+  }
+#endif // !defined(ASIO_NO_DYNAMIC_BUFFER_V1)
+
+  /// @b DynamicBuffer_v2: Get a sequence of buffers that represents the
+  /// underlying memory.
+  /**
+   * @param pos Position of the first byte to represent in the buffer sequence
+   *
+   * @param n The number of bytes to return in the buffer sequence. If the
+   * underlying memory is shorter, the buffer sequence represents as many bytes
+   * as are available.
+   *
+   * @returns An object of type @c mutable_buffers_type that satisfies
+   * MutableBufferSequence requirements, representing the vector memory.
+   *
+   * @note The returned object is invalidated by any @c dynamic_vector_buffer
+   * or @c vector member function that resizes or erases the vector.
+   */
+  mutable_buffers_type data(std::size_t pos, std::size_t n) ASIO_NOEXCEPT
+  {
+    return mutable_buffers_type(asio::buffer(
+          asio::buffer(vector_, max_size_) + pos, n));
+  }
+
+  /// @b DynamicBuffer_v2: Get a sequence of buffers that represents the
+  /// underlying memory.
+  /**
+   * @param pos Position of the first byte to represent in the buffer sequence
+   *
+   * @param n The number of bytes to return in the buffer sequence. If the
+   * underlying memory is shorter, the buffer sequence represents as many bytes
+   * as are available.
+   *
+   * @note The returned object is invalidated by any @c dynamic_vector_buffer
+   * or @c vector member function that resizes or erases the vector.
+   */
+  const_buffers_type data(std::size_t pos,
+      std::size_t n) const ASIO_NOEXCEPT
+  {
+    return const_buffers_type(asio::buffer(
+          asio::buffer(vector_, max_size_) + pos, n));
+  }
+
+#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1)
+  /// @b DynamicBuffer_v1: Get a list of buffers that represents the output
+  /// sequence, with the given size.
+  /**
+   * Ensures that the output sequence can accommodate @c n bytes, resizing the
+   * vector object as necessary.
+   *
+   * @returns An object of type @c mutable_buffers_type that satisfies
+   * MutableBufferSequence requirements, representing vector memory at the
+   * start of the output sequence of size @c n.
+   *
+   * @throws std::length_error If <tt>size() + n > max_size()</tt>.
+   *
+   * @note The returned object is invalidated by any @c dynamic_vector_buffer
+   * or @c vector member function that modifies the input sequence or output
+   * sequence.
+   */
+  mutable_buffers_type prepare(std::size_t n)
+  {
+    if (size () > max_size() || max_size() - size() < n)
+    {
+      std::length_error ex("dynamic_vector_buffer too long");
+      asio::detail::throw_exception(ex);
+    }
+
+    if (size_ == (std::numeric_limits<std::size_t>::max)())
+      size_ = vector_.size(); // Enable v1 behaviour.
+
+    vector_.resize(size_ + n);
+
+    return asio::buffer(asio::buffer(vector_) + size_, n);
+  }
+
+  /// @b DynamicBuffer_v1: Move bytes from the output sequence to the input
+  /// sequence.
+  /**
+   * @param n The number of bytes to append from the start of the output
+   * sequence to the end of the input sequence. The remainder of the output
+   * sequence is discarded.
+   *
+   * Requires a preceding call <tt>prepare(x)</tt> where <tt>x >= n</tt>, and
+   * no intervening operations that modify the input or output sequence.
+   *
+   * @note If @c n is greater than the size of the output sequence, the entire
+   * output sequence is moved to the input sequence and no error is issued.
+   */
+  void commit(std::size_t n)
+  {
+    size_ += (std::min)(n, vector_.size() - size_);
+    vector_.resize(size_);
+  }
+#endif // !defined(ASIO_NO_DYNAMIC_BUFFER_V1)
+
+  /// @b DynamicBuffer_v2: Grow the underlying memory by the specified number of
+  /// bytes.
+  /**
+   * Resizes the vector to accommodate an additional @c n bytes at the end.
+   *
+   * @throws std::length_error If <tt>size() + n > max_size()</tt>.
+   */
+  void grow(std::size_t n)
+  {
+    if (size() > max_size() || max_size() - size() < n)
+    {
+      std::length_error ex("dynamic_vector_buffer too long");
+      asio::detail::throw_exception(ex);
+    }
+
+    vector_.resize(size() + n);
+  }
+
+  /// @b DynamicBuffer_v2: Shrink the underlying memory by the specified number
+  /// of bytes.
+  /**
+   * Erases @c n bytes from the end of the vector by resizing the vector
+   * object. If @c n is greater than the current size of the vector, the vector
+   * is emptied.
+   */
+  void shrink(std::size_t n)
+  {
+    vector_.resize(n > size() ? 0 : size() - n);
+  }
+
+  /// @b DynamicBuffer_v1: Remove characters from the input sequence.
+  /// @b DynamicBuffer_v2: Consume the specified number of bytes from the
+  /// beginning of the underlying memory.
+  /**
+   * @b DynamicBuffer_v1: Removes @c n characters from the beginning of the
+   * input sequence. @note If @c n is greater than the size of the input
+   * sequence, the entire input sequence is consumed and no error is issued.
+   *
+   * @b DynamicBuffer_v2: Erases @c n bytes from the beginning of the vector.
+   * If @c n is greater than the current size of the vector, the vector is
+   * emptied.
+   */
+  void consume(std::size_t n)
+  {
+#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1)
+    if (size_ != (std::numeric_limits<std::size_t>::max)())
+    {
+      std::size_t consume_length = (std::min)(n, size_);
+      vector_.erase(vector_.begin(), vector_.begin() + consume_length);
+      size_ -= consume_length;
+      return;
+    }
+#endif // !defined(ASIO_NO_DYNAMIC_BUFFER_V1)
+    vector_.erase(vector_.begin(), vector_.begin() + (std::min)(size(), n));
+  }
+
+private:
+  std::vector<Elem, Allocator>& vector_;
+#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1)
+  std::size_t size_;
+#endif // !defined(ASIO_NO_DYNAMIC_BUFFER_V1)
+  const std::size_t max_size_;
+};
+
+/** @defgroup dynamic_buffer asio::dynamic_buffer
+ *
+ * @brief The asio::dynamic_buffer function is used to create a
+ * dynamically resized buffer from a @c std::basic_string or @c std::vector.
+ */
+/*@{*/
+
+/// Create a new dynamic buffer that represents the given string.
+/**
+ * @returns <tt>dynamic_string_buffer<Elem, Traits, Allocator>(data)</tt>.
+ */
+template <typename Elem, typename Traits, typename Allocator>
+inline dynamic_string_buffer<Elem, Traits, Allocator> dynamic_buffer(
+    std::basic_string<Elem, Traits, Allocator>& data) ASIO_NOEXCEPT
+{
+  return dynamic_string_buffer<Elem, Traits, Allocator>(data);
+}
+
+/// Create a new dynamic buffer that represents the given string.
+/**
+ * @returns <tt>dynamic_string_buffer<Elem, Traits, Allocator>(data,
+ * max_size)</tt>.
+ */
+template <typename Elem, typename Traits, typename Allocator>
+inline dynamic_string_buffer<Elem, Traits, Allocator> dynamic_buffer(
+    std::basic_string<Elem, Traits, Allocator>& data,
+    std::size_t max_size) ASIO_NOEXCEPT
+{
+  return dynamic_string_buffer<Elem, Traits, Allocator>(data, max_size);
+}
+
+/// Create a new dynamic buffer that represents the given vector.
+/**
+ * @returns <tt>dynamic_vector_buffer<Elem, Allocator>(data)</tt>.
+ */
+template <typename Elem, typename Allocator>
+inline dynamic_vector_buffer<Elem, Allocator> dynamic_buffer(
+    std::vector<Elem, Allocator>& data) ASIO_NOEXCEPT
+{
+  return dynamic_vector_buffer<Elem, Allocator>(data);
+}
+
+/// Create a new dynamic buffer that represents the given vector.
+/**
+ * @returns <tt>dynamic_vector_buffer<Elem, Allocator>(data, max_size)</tt>.
+ */
+template <typename Elem, typename Allocator>
+inline dynamic_vector_buffer<Elem, Allocator> dynamic_buffer(
+    std::vector<Elem, Allocator>& data,
+    std::size_t max_size) ASIO_NOEXCEPT
+{
+  return dynamic_vector_buffer<Elem, Allocator>(data, max_size);
+}
+
+/*@}*/
+
+/** @defgroup buffer_copy asio::buffer_copy
+ *
+ * @brief The asio::buffer_copy function is used to copy bytes from a
+ * source buffer (or buffer sequence) to a target buffer (or buffer sequence).
+ *
+ * The @c buffer_copy function is available in two forms:
+ *
+ * @li A 2-argument form: @c buffer_copy(target, source)
+ *
+ * @li A 3-argument form: @c buffer_copy(target, source, max_bytes_to_copy)
+ *
+ * Both forms return the number of bytes actually copied. The number of bytes
+ * copied is the lesser of:
+ *
+ * @li @c buffer_size(target)
+ *
+ * @li @c buffer_size(source)
+ *
+ * @li @c If specified, @c max_bytes_to_copy.
+ *
+ * This prevents buffer overflow, regardless of the buffer sizes used in the
+ * copy operation.
+ *
+ * Note that @ref buffer_copy is implemented in terms of @c memcpy, and
+ * consequently it cannot be used to copy between overlapping memory regions.
+ */
+/*@{*/
+
+namespace detail {
+
+inline std::size_t buffer_copy_1(const mutable_buffer& target,
+    const const_buffer& source)
+{
+  using namespace std; // For memcpy.
+  std::size_t target_size = target.size();
+  std::size_t source_size = source.size();
+  std::size_t n = target_size < source_size ? target_size : source_size;
+  if (n > 0)
+    memcpy(target.data(), source.data(), n);
+  return n;
+}
+
+template <typename TargetIterator, typename SourceIterator>
+inline std::size_t buffer_copy(one_buffer, one_buffer,
+    TargetIterator target_begin, TargetIterator,
+    SourceIterator source_begin, SourceIterator) ASIO_NOEXCEPT
+{
+  return (buffer_copy_1)(*target_begin, *source_begin);
+}
+
+template <typename TargetIterator, typename SourceIterator>
+inline std::size_t buffer_copy(one_buffer, one_buffer,
+    TargetIterator target_begin, TargetIterator,
+    SourceIterator source_begin, SourceIterator,
+    std::size_t max_bytes_to_copy) ASIO_NOEXCEPT
+{
+  return (buffer_copy_1)(*target_begin,
+      asio::buffer(*source_begin, max_bytes_to_copy));
+}
+
+template <typename TargetIterator, typename SourceIterator>
+std::size_t buffer_copy(one_buffer, multiple_buffers,
+    TargetIterator target_begin, TargetIterator,
+    SourceIterator source_begin, SourceIterator source_end,
+    std::size_t max_bytes_to_copy
+      = (std::numeric_limits<std::size_t>::max)()) ASIO_NOEXCEPT
+{
+  std::size_t total_bytes_copied = 0;
+  SourceIterator source_iter = source_begin;
+
+  for (mutable_buffer target_buffer(
+        asio::buffer(*target_begin, max_bytes_to_copy));
+      target_buffer.size() && source_iter != source_end; ++source_iter)
+  {
+    const_buffer source_buffer(*source_iter);
+    std::size_t bytes_copied = (buffer_copy_1)(target_buffer, source_buffer);
+    total_bytes_copied += bytes_copied;
+    target_buffer += bytes_copied;
+  }
+
+  return total_bytes_copied;
+}
+
+template <typename TargetIterator, typename SourceIterator>
+std::size_t buffer_copy(multiple_buffers, one_buffer,
+    TargetIterator target_begin, TargetIterator target_end,
+    SourceIterator source_begin, SourceIterator,
+    std::size_t max_bytes_to_copy
+      = (std::numeric_limits<std::size_t>::max)()) ASIO_NOEXCEPT
+{
+  std::size_t total_bytes_copied = 0;
+  TargetIterator target_iter = target_begin;
+
+  for (const_buffer source_buffer(
+        asio::buffer(*source_begin, max_bytes_to_copy));
+      source_buffer.size() && target_iter != target_end; ++target_iter)
+  {
+    mutable_buffer target_buffer(*target_iter);
+    std::size_t bytes_copied = (buffer_copy_1)(target_buffer, source_buffer);
+    total_bytes_copied += bytes_copied;
+    source_buffer += bytes_copied;
+  }
+
+  return total_bytes_copied;
+}
+
+template <typename TargetIterator, typename SourceIterator>
+std::size_t buffer_copy(multiple_buffers, multiple_buffers,
+    TargetIterator target_begin, TargetIterator target_end,
+    SourceIterator source_begin, SourceIterator source_end) ASIO_NOEXCEPT
+{
+  std::size_t total_bytes_copied = 0;
+
+  TargetIterator target_iter = target_begin;
+  std::size_t target_buffer_offset = 0;
+
+  SourceIterator source_iter = source_begin;
+  std::size_t source_buffer_offset = 0;
+
+  while (target_iter != target_end && source_iter != source_end)
+  {
+    mutable_buffer target_buffer =
+      mutable_buffer(*target_iter) + target_buffer_offset;
+
+    const_buffer source_buffer =
+      const_buffer(*source_iter) + source_buffer_offset;
+
+    std::size_t bytes_copied = (buffer_copy_1)(target_buffer, source_buffer);
+    total_bytes_copied += bytes_copied;
+
+    if (bytes_copied == target_buffer.size())
+    {
+      ++target_iter;
+      target_buffer_offset = 0;
+    }
+    else
+      target_buffer_offset += bytes_copied;
+
+    if (bytes_copied == source_buffer.size())
+    {
+      ++source_iter;
+      source_buffer_offset = 0;
+    }
+    else
+      source_buffer_offset += bytes_copied;
+  }
+
+  return total_bytes_copied;
+}
+
+template <typename TargetIterator, typename SourceIterator>
+std::size_t buffer_copy(multiple_buffers, multiple_buffers,
+    TargetIterator target_begin, TargetIterator target_end,
+    SourceIterator source_begin, SourceIterator source_end,
+    std::size_t max_bytes_to_copy) ASIO_NOEXCEPT
+{
+  std::size_t total_bytes_copied = 0;
+
+  TargetIterator target_iter = target_begin;
+  std::size_t target_buffer_offset = 0;
+
+  SourceIterator source_iter = source_begin;
+  std::size_t source_buffer_offset = 0;
+
+  while (total_bytes_copied != max_bytes_to_copy
+      && target_iter != target_end && source_iter != source_end)
+  {
+    mutable_buffer target_buffer =
+      mutable_buffer(*target_iter) + target_buffer_offset;
+
+    const_buffer source_buffer =
+      const_buffer(*source_iter) + source_buffer_offset;
+
+    std::size_t bytes_copied = (buffer_copy_1)(
+        target_buffer, asio::buffer(source_buffer,
+          max_bytes_to_copy - total_bytes_copied));
+    total_bytes_copied += bytes_copied;
+
+    if (bytes_copied == target_buffer.size())
+    {
+      ++target_iter;
+      target_buffer_offset = 0;
+    }
+    else
+      target_buffer_offset += bytes_copied;
+
+    if (bytes_copied == source_buffer.size())
+    {
+      ++source_iter;
+      source_buffer_offset = 0;
+    }
+    else
+      source_buffer_offset += bytes_copied;
+  }
+
+  return total_bytes_copied;
+}
+
+} // namespace detail
+
+/// Copies bytes from a source buffer sequence to a target buffer sequence.
+/**
+ * @param target A modifiable buffer sequence representing the memory regions to
+ * which the bytes will be copied.
+ *
+ * @param source A non-modifiable buffer sequence representing the memory
+ * regions from which the bytes will be copied.
+ *
+ * @returns The number of bytes copied.
+ *
+ * @note The number of bytes copied is the lesser of:
+ *
+ * @li @c buffer_size(target)
+ *
+ * @li @c buffer_size(source)
+ *
+ * This function is implemented in terms of @c memcpy, and consequently it
+ * cannot be used to copy between overlapping memory regions.
+ */
+template <typename MutableBufferSequence, typename ConstBufferSequence>
+inline std::size_t buffer_copy(const MutableBufferSequence& target,
+    const ConstBufferSequence& source) ASIO_NOEXCEPT
+{
+  return detail::buffer_copy(
+      detail::buffer_sequence_cardinality<MutableBufferSequence>(),
+      detail::buffer_sequence_cardinality<ConstBufferSequence>(),
+      asio::buffer_sequence_begin(target),
+      asio::buffer_sequence_end(target),
+      asio::buffer_sequence_begin(source),
+      asio::buffer_sequence_end(source));
+}
+
+/// Copies a limited number of bytes from a source buffer sequence to a target
+/// buffer sequence.
+/**
+ * @param target A modifiable buffer sequence representing the memory regions to
+ * which the bytes will be copied.
+ *
+ * @param source A non-modifiable buffer sequence representing the memory
+ * regions from which the bytes will be copied.
+ *
+ * @param max_bytes_to_copy The maximum number of bytes to be copied.
+ *
+ * @returns The number of bytes copied.
+ *
+ * @note The number of bytes copied is the lesser of:
+ *
+ * @li @c buffer_size(target)
+ *
+ * @li @c buffer_size(source)
+ *
+ * @li @c max_bytes_to_copy
+ *
+ * This function is implemented in terms of @c memcpy, and consequently it
+ * cannot be used to copy between overlapping memory regions.
+ */
+template <typename MutableBufferSequence, typename ConstBufferSequence>
+inline std::size_t buffer_copy(const MutableBufferSequence& target,
+    const ConstBufferSequence& source,
+    std::size_t max_bytes_to_copy) ASIO_NOEXCEPT
+{
+  return detail::buffer_copy(
+      detail::buffer_sequence_cardinality<MutableBufferSequence>(),
+      detail::buffer_sequence_cardinality<ConstBufferSequence>(),
+      asio::buffer_sequence_begin(target),
+      asio::buffer_sequence_end(target),
+      asio::buffer_sequence_begin(source),
+      asio::buffer_sequence_end(source), max_bytes_to_copy);
+}
+
+/*@}*/
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+#include "asio/detail/is_buffer_sequence.hpp"
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+/// Trait to determine whether a type satisfies the MutableBufferSequence
+/// requirements.
+template <typename T>
+struct is_mutable_buffer_sequence
+#if defined(GENERATING_DOCUMENTATION)
+  : integral_constant<bool, automatically_determined>
+#else // defined(GENERATING_DOCUMENTATION)
+  : asio::detail::is_buffer_sequence<T, mutable_buffer>
+#endif // defined(GENERATING_DOCUMENTATION)
+{
+};
+
+/// Trait to determine whether a type satisfies the ConstBufferSequence
+/// requirements.
+template <typename T>
+struct is_const_buffer_sequence
+#if defined(GENERATING_DOCUMENTATION)
+  : integral_constant<bool, automatically_determined>
+#else // defined(GENERATING_DOCUMENTATION)
+  : asio::detail::is_buffer_sequence<T, const_buffer>
+#endif // defined(GENERATING_DOCUMENTATION)
+{
+};
+
+#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1)
+/// Trait to determine whether a type satisfies the DynamicBuffer_v1
+/// requirements.
+template <typename T>
+struct is_dynamic_buffer_v1
+#if defined(GENERATING_DOCUMENTATION)
+  : integral_constant<bool, automatically_determined>
+#else // defined(GENERATING_DOCUMENTATION)
+  : asio::detail::is_dynamic_buffer_v1<T>
+#endif // defined(GENERATING_DOCUMENTATION)
+{
+};
+#endif // !defined(ASIO_NO_DYNAMIC_BUFFER_V1)
+
+/// Trait to determine whether a type satisfies the DynamicBuffer_v2
+/// requirements.
+template <typename T>
+struct is_dynamic_buffer_v2
+#if defined(GENERATING_DOCUMENTATION)
+  : integral_constant<bool, automatically_determined>
+#else // defined(GENERATING_DOCUMENTATION)
+  : asio::detail::is_dynamic_buffer_v2<T>
+#endif // defined(GENERATING_DOCUMENTATION)
+{
+};
+
+/// Trait to determine whether a type satisfies the DynamicBuffer requirements.
+/**
+ * If @c ASIO_NO_DYNAMIC_BUFFER_V1 is not defined, determines whether the
+ * type satisfies the DynamicBuffer_v1 requirements. Otherwise, if @c
+ * ASIO_NO_DYNAMIC_BUFFER_V1 is defined, determines whether the type
+ * satisfies the DynamicBuffer_v2 requirements.
+ */
+template <typename T>
+struct is_dynamic_buffer
+#if defined(GENERATING_DOCUMENTATION)
+  : integral_constant<bool, automatically_determined>
+#elif defined(ASIO_NO_DYNAMIC_BUFFER_V1)
+  : asio::is_dynamic_buffer_v2<T>
+#else // defined(ASIO_NO_DYNAMIC_BUFFER_V1)
+  : asio::is_dynamic_buffer_v1<T>
+#endif // defined(ASIO_NO_DYNAMIC_BUFFER_V1)
+{
+};
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_BUFFER_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/buffered_read_stream.hpp b/link/modules/asio-standalone/asio/include/asio/buffered_read_stream.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/buffered_read_stream.hpp
@@ -0,0 +1,253 @@
+//
+// buffered_read_stream.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_BUFFERED_READ_STREAM_HPP
+#define ASIO_BUFFERED_READ_STREAM_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <cstddef>
+#include "asio/async_result.hpp"
+#include "asio/buffered_read_stream_fwd.hpp"
+#include "asio/buffer.hpp"
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/buffer_resize_guard.hpp"
+#include "asio/detail/buffered_stream_storage.hpp"
+#include "asio/detail/noncopyable.hpp"
+#include "asio/detail/type_traits.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+/// Adds buffering to the read-related operations of a stream.
+/**
+ * The buffered_read_stream class template can be used to add buffering to the
+ * synchronous and asynchronous read operations of a stream.
+ *
+ * @par Thread Safety
+ * @e Distinct @e objects: Safe.@n
+ * @e Shared @e objects: Unsafe.
+ *
+ * @par Concepts:
+ * AsyncReadStream, AsyncWriteStream, Stream, SyncReadStream, SyncWriteStream.
+ */
+template <typename Stream>
+class buffered_read_stream
+  : private noncopyable
+{
+public:
+  /// The type of the next layer.
+  typedef typename remove_reference<Stream>::type next_layer_type;
+
+  /// The type of the lowest layer.
+  typedef typename next_layer_type::lowest_layer_type lowest_layer_type;
+
+  /// The type of the executor associated with the object.
+  typedef typename lowest_layer_type::executor_type executor_type;
+
+#if defined(GENERATING_DOCUMENTATION)
+  /// The default buffer size.
+  static const std::size_t default_buffer_size = implementation_defined;
+#else
+  ASIO_STATIC_CONSTANT(std::size_t, default_buffer_size = 1024);
+#endif
+
+  /// Construct, passing the specified argument to initialise the next layer.
+  template <typename Arg>
+  explicit buffered_read_stream(Arg& a)
+    : next_layer_(a),
+      storage_(default_buffer_size)
+  {
+  }
+
+  /// Construct, passing the specified argument to initialise the next layer.
+  template <typename Arg>
+  buffered_read_stream(Arg& a, std::size_t buffer_size)
+    : next_layer_(a),
+      storage_(buffer_size)
+  {
+  }
+
+  /// Get a reference to the next layer.
+  next_layer_type& next_layer()
+  {
+    return next_layer_;
+  }
+
+  /// Get a reference to the lowest layer.
+  lowest_layer_type& lowest_layer()
+  {
+    return next_layer_.lowest_layer();
+  }
+
+  /// Get a const reference to the lowest layer.
+  const lowest_layer_type& lowest_layer() const
+  {
+    return next_layer_.lowest_layer();
+  }
+
+  /// Get the executor associated with the object.
+  executor_type get_executor() ASIO_NOEXCEPT
+  {
+    return next_layer_.lowest_layer().get_executor();
+  }
+
+  /// Close the stream.
+  void close()
+  {
+    next_layer_.close();
+  }
+
+  /// Close the stream.
+  ASIO_SYNC_OP_VOID close(asio::error_code& ec)
+  {
+    next_layer_.close(ec);
+    ASIO_SYNC_OP_VOID_RETURN(ec);
+  }
+
+  /// Write the given data to the stream. Returns the number of bytes written.
+  /// Throws an exception on failure.
+  template <typename ConstBufferSequence>
+  std::size_t write_some(const ConstBufferSequence& buffers)
+  {
+    return next_layer_.write_some(buffers);
+  }
+
+  /// Write the given data to the stream. Returns the number of bytes written,
+  /// or 0 if an error occurred.
+  template <typename ConstBufferSequence>
+  std::size_t write_some(const ConstBufferSequence& buffers,
+      asio::error_code& ec)
+  {
+    return next_layer_.write_some(buffers, ec);
+  }
+
+  /// Start an asynchronous write. The data being written must be valid for the
+  /// lifetime of the asynchronous operation.
+  template <typename ConstBufferSequence,
+      ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+        std::size_t)) WriteHandler
+          ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
+  ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,
+      void (asio::error_code, std::size_t))
+  async_write_some(const ConstBufferSequence& buffers,
+      ASIO_MOVE_ARG(WriteHandler) handler
+        ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
+  {
+    return next_layer_.async_write_some(buffers,
+        ASIO_MOVE_CAST(WriteHandler)(handler));
+  }
+
+  /// Fill the buffer with some data. Returns the number of bytes placed in the
+  /// buffer as a result of the operation. Throws an exception on failure.
+  std::size_t fill();
+
+  /// Fill the buffer with some data. Returns the number of bytes placed in the
+  /// buffer as a result of the operation, or 0 if an error occurred.
+  std::size_t fill(asio::error_code& ec);
+
+  /// Start an asynchronous fill.
+  template <
+      ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+        std::size_t)) ReadHandler
+          ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
+  ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,
+      void (asio::error_code, std::size_t))
+  async_fill(
+      ASIO_MOVE_ARG(ReadHandler) handler
+        ASIO_DEFAULT_COMPLETION_TOKEN(executor_type));
+
+  /// Read some data from the stream. Returns the number of bytes read. Throws
+  /// an exception on failure.
+  template <typename MutableBufferSequence>
+  std::size_t read_some(const MutableBufferSequence& buffers);
+
+  /// Read some data from the stream. Returns the number of bytes read or 0 if
+  /// an error occurred.
+  template <typename MutableBufferSequence>
+  std::size_t read_some(const MutableBufferSequence& buffers,
+      asio::error_code& ec);
+
+  /// Start an asynchronous read. The buffer into which the data will be read
+  /// must be valid for the lifetime of the asynchronous operation.
+  template <typename MutableBufferSequence,
+      ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+        std::size_t)) ReadHandler
+          ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
+  ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,
+      void (asio::error_code, std::size_t))
+  async_read_some(const MutableBufferSequence& buffers,
+      ASIO_MOVE_ARG(ReadHandler) handler
+        ASIO_DEFAULT_COMPLETION_TOKEN(executor_type));
+
+  /// Peek at the incoming data on the stream. Returns the number of bytes read.
+  /// Throws an exception on failure.
+  template <typename MutableBufferSequence>
+  std::size_t peek(const MutableBufferSequence& buffers);
+
+  /// Peek at the incoming data on the stream. Returns the number of bytes read,
+  /// or 0 if an error occurred.
+  template <typename MutableBufferSequence>
+  std::size_t peek(const MutableBufferSequence& buffers,
+      asio::error_code& ec);
+
+  /// Determine the amount of data that may be read without blocking.
+  std::size_t in_avail()
+  {
+    return storage_.size();
+  }
+
+  /// Determine the amount of data that may be read without blocking.
+  std::size_t in_avail(asio::error_code& ec)
+  {
+    ec = asio::error_code();
+    return storage_.size();
+  }
+
+private:
+  /// Copy data out of the internal buffer to the specified target buffer.
+  /// Returns the number of bytes copied.
+  template <typename MutableBufferSequence>
+  std::size_t copy(const MutableBufferSequence& buffers)
+  {
+    std::size_t bytes_copied = asio::buffer_copy(
+        buffers, storage_.data(), storage_.size());
+    storage_.consume(bytes_copied);
+    return bytes_copied;
+  }
+
+  /// Copy data from the internal buffer to the specified target buffer, without
+  /// removing the data from the internal buffer. Returns the number of bytes
+  /// copied.
+  template <typename MutableBufferSequence>
+  std::size_t peek_copy(const MutableBufferSequence& buffers)
+  {
+    return asio::buffer_copy(buffers, storage_.data(), storage_.size());
+  }
+
+  /// The next layer.
+  Stream next_layer_;
+
+  // The data in the buffer.
+  detail::buffered_stream_storage storage_;
+};
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/impl/buffered_read_stream.hpp"
+
+#endif // ASIO_BUFFERED_READ_STREAM_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/buffered_read_stream_fwd.hpp b/link/modules/asio-standalone/asio/include/asio/buffered_read_stream_fwd.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/buffered_read_stream_fwd.hpp
@@ -0,0 +1,25 @@
+//
+// buffered_read_stream_fwd.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_BUFFERED_READ_STREAM_FWD_HPP
+#define ASIO_BUFFERED_READ_STREAM_FWD_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+namespace asio {
+
+template <typename Stream>
+class buffered_read_stream;
+
+} // namespace asio
+
+#endif // ASIO_BUFFERED_READ_STREAM_FWD_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/buffered_stream.hpp b/link/modules/asio-standalone/asio/include/asio/buffered_stream.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/buffered_stream.hpp
@@ -0,0 +1,279 @@
+//
+// buffered_stream.hpp
+// ~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_BUFFERED_STREAM_HPP
+#define ASIO_BUFFERED_STREAM_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <cstddef>
+#include "asio/async_result.hpp"
+#include "asio/buffered_read_stream.hpp"
+#include "asio/buffered_write_stream.hpp"
+#include "asio/buffered_stream_fwd.hpp"
+#include "asio/detail/noncopyable.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+/// Adds buffering to the read- and write-related operations of a stream.
+/**
+ * The buffered_stream class template can be used to add buffering to the
+ * synchronous and asynchronous read and write operations of a stream.
+ *
+ * @par Thread Safety
+ * @e Distinct @e objects: Safe.@n
+ * @e Shared @e objects: Unsafe.
+ *
+ * @par Concepts:
+ * AsyncReadStream, AsyncWriteStream, Stream, SyncReadStream, SyncWriteStream.
+ */
+template <typename Stream>
+class buffered_stream
+  : private noncopyable
+{
+public:
+  /// The type of the next layer.
+  typedef typename remove_reference<Stream>::type next_layer_type;
+
+  /// The type of the lowest layer.
+  typedef typename next_layer_type::lowest_layer_type lowest_layer_type;
+
+  /// The type of the executor associated with the object.
+  typedef typename lowest_layer_type::executor_type executor_type;
+
+  /// Construct, passing the specified argument to initialise the next layer.
+  template <typename Arg>
+  explicit buffered_stream(Arg& a)
+    : inner_stream_impl_(a),
+      stream_impl_(inner_stream_impl_)
+  {
+  }
+
+  /// Construct, passing the specified argument to initialise the next layer.
+  template <typename Arg>
+  explicit buffered_stream(Arg& a, std::size_t read_buffer_size,
+      std::size_t write_buffer_size)
+    : inner_stream_impl_(a, write_buffer_size),
+      stream_impl_(inner_stream_impl_, read_buffer_size)
+  {
+  }
+
+  /// Get a reference to the next layer.
+  next_layer_type& next_layer()
+  {
+    return stream_impl_.next_layer().next_layer();
+  }
+
+  /// Get a reference to the lowest layer.
+  lowest_layer_type& lowest_layer()
+  {
+    return stream_impl_.lowest_layer();
+  }
+
+  /// Get a const reference to the lowest layer.
+  const lowest_layer_type& lowest_layer() const
+  {
+    return stream_impl_.lowest_layer();
+  }
+
+  /// Get the executor associated with the object.
+  executor_type get_executor() ASIO_NOEXCEPT
+  {
+    return stream_impl_.lowest_layer().get_executor();
+  }
+
+  /// Close the stream.
+  void close()
+  {
+    stream_impl_.close();
+  }
+
+  /// Close the stream.
+  ASIO_SYNC_OP_VOID close(asio::error_code& ec)
+  {
+    stream_impl_.close(ec);
+    ASIO_SYNC_OP_VOID_RETURN(ec);
+  }
+
+  /// Flush all data from the buffer to the next layer. Returns the number of
+  /// bytes written to the next layer on the last write operation. Throws an
+  /// exception on failure.
+  std::size_t flush()
+  {
+    return stream_impl_.next_layer().flush();
+  }
+
+  /// Flush all data from the buffer to the next layer. Returns the number of
+  /// bytes written to the next layer on the last write operation, or 0 if an
+  /// error occurred.
+  std::size_t flush(asio::error_code& ec)
+  {
+    return stream_impl_.next_layer().flush(ec);
+  }
+
+  /// Start an asynchronous flush.
+  template <
+      ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+        std::size_t)) WriteHandler
+          ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
+  ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,
+      void (asio::error_code, std::size_t))
+  async_flush(
+      ASIO_MOVE_ARG(WriteHandler) handler
+        ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
+  {
+    return stream_impl_.next_layer().async_flush(
+        ASIO_MOVE_CAST(WriteHandler)(handler));
+  }
+
+  /// Write the given data to the stream. Returns the number of bytes written.
+  /// Throws an exception on failure.
+  template <typename ConstBufferSequence>
+  std::size_t write_some(const ConstBufferSequence& buffers)
+  {
+    return stream_impl_.write_some(buffers);
+  }
+
+  /// Write the given data to the stream. Returns the number of bytes written,
+  /// or 0 if an error occurred.
+  template <typename ConstBufferSequence>
+  std::size_t write_some(const ConstBufferSequence& buffers,
+      asio::error_code& ec)
+  {
+    return stream_impl_.write_some(buffers, ec);
+  }
+
+  /// Start an asynchronous write. The data being written must be valid for the
+  /// lifetime of the asynchronous operation.
+  template <typename ConstBufferSequence,
+      ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+        std::size_t)) WriteHandler
+          ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
+  ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,
+      void (asio::error_code, std::size_t))
+  async_write_some(const ConstBufferSequence& buffers,
+      ASIO_MOVE_ARG(WriteHandler) handler
+        ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
+  {
+    return stream_impl_.async_write_some(buffers,
+        ASIO_MOVE_CAST(WriteHandler)(handler));
+  }
+
+  /// Fill the buffer with some data. Returns the number of bytes placed in the
+  /// buffer as a result of the operation. Throws an exception on failure.
+  std::size_t fill()
+  {
+    return stream_impl_.fill();
+  }
+
+  /// Fill the buffer with some data. Returns the number of bytes placed in the
+  /// buffer as a result of the operation, or 0 if an error occurred.
+  std::size_t fill(asio::error_code& ec)
+  {
+    return stream_impl_.fill(ec);
+  }
+
+  /// Start an asynchronous fill.
+  template <
+      ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+        std::size_t)) ReadHandler
+          ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
+  ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,
+      void (asio::error_code, std::size_t))
+  async_fill(
+      ASIO_MOVE_ARG(ReadHandler) handler
+        ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
+  {
+    return stream_impl_.async_fill(ASIO_MOVE_CAST(ReadHandler)(handler));
+  }
+
+  /// Read some data from the stream. Returns the number of bytes read. Throws
+  /// an exception on failure.
+  template <typename MutableBufferSequence>
+  std::size_t read_some(const MutableBufferSequence& buffers)
+  {
+    return stream_impl_.read_some(buffers);
+  }
+
+  /// Read some data from the stream. Returns the number of bytes read or 0 if
+  /// an error occurred.
+  template <typename MutableBufferSequence>
+  std::size_t read_some(const MutableBufferSequence& buffers,
+      asio::error_code& ec)
+  {
+    return stream_impl_.read_some(buffers, ec);
+  }
+
+  /// Start an asynchronous read. The buffer into which the data will be read
+  /// must be valid for the lifetime of the asynchronous operation.
+  template <typename MutableBufferSequence,
+      ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+        std::size_t)) ReadHandler
+          ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
+  ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,
+      void (asio::error_code, std::size_t))
+  async_read_some(const MutableBufferSequence& buffers,
+      ASIO_MOVE_ARG(ReadHandler) handler
+        ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
+  {
+    return stream_impl_.async_read_some(buffers,
+        ASIO_MOVE_CAST(ReadHandler)(handler));
+  }
+
+  /// Peek at the incoming data on the stream. Returns the number of bytes read.
+  /// Throws an exception on failure.
+  template <typename MutableBufferSequence>
+  std::size_t peek(const MutableBufferSequence& buffers)
+  {
+    return stream_impl_.peek(buffers);
+  }
+
+  /// Peek at the incoming data on the stream. Returns the number of bytes read,
+  /// or 0 if an error occurred.
+  template <typename MutableBufferSequence>
+  std::size_t peek(const MutableBufferSequence& buffers,
+      asio::error_code& ec)
+  {
+    return stream_impl_.peek(buffers, ec);
+  }
+
+  /// Determine the amount of data that may be read without blocking.
+  std::size_t in_avail()
+  {
+    return stream_impl_.in_avail();
+  }
+
+  /// Determine the amount of data that may be read without blocking.
+  std::size_t in_avail(asio::error_code& ec)
+  {
+    return stream_impl_.in_avail(ec);
+  }
+
+private:
+  // The buffered write stream.
+  typedef buffered_write_stream<Stream> write_stream_type;
+  write_stream_type inner_stream_impl_;
+
+  // The buffered read stream.
+  typedef buffered_read_stream<write_stream_type&> read_stream_type;
+  read_stream_type stream_impl_;
+};
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_BUFFERED_STREAM_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/buffered_stream_fwd.hpp b/link/modules/asio-standalone/asio/include/asio/buffered_stream_fwd.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/buffered_stream_fwd.hpp
@@ -0,0 +1,25 @@
+//
+// buffered_stream_fwd.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_BUFFERED_STREAM_FWD_HPP
+#define ASIO_BUFFERED_STREAM_FWD_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+namespace asio {
+
+template <typename Stream>
+class buffered_stream;
+
+} // namespace asio
+
+#endif // ASIO_BUFFERED_STREAM_FWD_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/buffered_write_stream.hpp b/link/modules/asio-standalone/asio/include/asio/buffered_write_stream.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/buffered_write_stream.hpp
@@ -0,0 +1,245 @@
+//
+// buffered_write_stream.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_BUFFERED_WRITE_STREAM_HPP
+#define ASIO_BUFFERED_WRITE_STREAM_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <cstddef>
+#include "asio/buffered_write_stream_fwd.hpp"
+#include "asio/buffer.hpp"
+#include "asio/completion_condition.hpp"
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/buffered_stream_storage.hpp"
+#include "asio/detail/noncopyable.hpp"
+#include "asio/detail/type_traits.hpp"
+#include "asio/error.hpp"
+#include "asio/write.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+/// Adds buffering to the write-related operations of a stream.
+/**
+ * The buffered_write_stream class template can be used to add buffering to the
+ * synchronous and asynchronous write operations of a stream.
+ *
+ * @par Thread Safety
+ * @e Distinct @e objects: Safe.@n
+ * @e Shared @e objects: Unsafe.
+ *
+ * @par Concepts:
+ * AsyncReadStream, AsyncWriteStream, Stream, SyncReadStream, SyncWriteStream.
+ */
+template <typename Stream>
+class buffered_write_stream
+  : private noncopyable
+{
+public:
+  /// The type of the next layer.
+  typedef typename remove_reference<Stream>::type next_layer_type;
+
+  /// The type of the lowest layer.
+  typedef typename next_layer_type::lowest_layer_type lowest_layer_type;
+
+  /// The type of the executor associated with the object.
+  typedef typename lowest_layer_type::executor_type executor_type;
+
+#if defined(GENERATING_DOCUMENTATION)
+  /// The default buffer size.
+  static const std::size_t default_buffer_size = implementation_defined;
+#else
+  ASIO_STATIC_CONSTANT(std::size_t, default_buffer_size = 1024);
+#endif
+
+  /// Construct, passing the specified argument to initialise the next layer.
+  template <typename Arg>
+  explicit buffered_write_stream(Arg& a)
+    : next_layer_(a),
+      storage_(default_buffer_size)
+  {
+  }
+
+  /// Construct, passing the specified argument to initialise the next layer.
+  template <typename Arg>
+  buffered_write_stream(Arg& a, std::size_t buffer_size)
+    : next_layer_(a),
+      storage_(buffer_size)
+  {
+  }
+
+  /// Get a reference to the next layer.
+  next_layer_type& next_layer()
+  {
+    return next_layer_;
+  }
+
+  /// Get a reference to the lowest layer.
+  lowest_layer_type& lowest_layer()
+  {
+    return next_layer_.lowest_layer();
+  }
+
+  /// Get a const reference to the lowest layer.
+  const lowest_layer_type& lowest_layer() const
+  {
+    return next_layer_.lowest_layer();
+  }
+
+  /// Get the executor associated with the object.
+  executor_type get_executor() ASIO_NOEXCEPT
+  {
+    return next_layer_.lowest_layer().get_executor();
+  }
+
+  /// Close the stream.
+  void close()
+  {
+    next_layer_.close();
+  }
+
+  /// Close the stream.
+  ASIO_SYNC_OP_VOID close(asio::error_code& ec)
+  {
+    next_layer_.close(ec);
+    ASIO_SYNC_OP_VOID_RETURN(ec);
+  }
+
+  /// Flush all data from the buffer to the next layer. Returns the number of
+  /// bytes written to the next layer on the last write operation. Throws an
+  /// exception on failure.
+  std::size_t flush();
+
+  /// Flush all data from the buffer to the next layer. Returns the number of
+  /// bytes written to the next layer on the last write operation, or 0 if an
+  /// error occurred.
+  std::size_t flush(asio::error_code& ec);
+
+  /// Start an asynchronous flush.
+  template <
+      ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+        std::size_t)) WriteHandler
+          ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
+  ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,
+      void (asio::error_code, std::size_t))
+  async_flush(
+      ASIO_MOVE_ARG(WriteHandler) handler
+        ASIO_DEFAULT_COMPLETION_TOKEN(executor_type));
+
+  /// Write the given data to the stream. Returns the number of bytes written.
+  /// Throws an exception on failure.
+  template <typename ConstBufferSequence>
+  std::size_t write_some(const ConstBufferSequence& buffers);
+
+  /// Write the given data to the stream. Returns the number of bytes written,
+  /// or 0 if an error occurred and the error handler did not throw.
+  template <typename ConstBufferSequence>
+  std::size_t write_some(const ConstBufferSequence& buffers,
+      asio::error_code& ec);
+
+  /// Start an asynchronous write. The data being written must be valid for the
+  /// lifetime of the asynchronous operation.
+  template <typename ConstBufferSequence,
+      ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+        std::size_t)) WriteHandler
+          ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
+  ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,
+      void (asio::error_code, std::size_t))
+  async_write_some(const ConstBufferSequence& buffers,
+      ASIO_MOVE_ARG(WriteHandler) handler
+        ASIO_DEFAULT_COMPLETION_TOKEN(executor_type));
+
+  /// Read some data from the stream. Returns the number of bytes read. Throws
+  /// an exception on failure.
+  template <typename MutableBufferSequence>
+  std::size_t read_some(const MutableBufferSequence& buffers)
+  {
+    return next_layer_.read_some(buffers);
+  }
+
+  /// Read some data from the stream. Returns the number of bytes read or 0 if
+  /// an error occurred.
+  template <typename MutableBufferSequence>
+  std::size_t read_some(const MutableBufferSequence& buffers,
+      asio::error_code& ec)
+  {
+    return next_layer_.read_some(buffers, ec);
+  }
+
+  /// Start an asynchronous read. The buffer into which the data will be read
+  /// must be valid for the lifetime of the asynchronous operation.
+  template <typename MutableBufferSequence,
+      ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+        std::size_t)) ReadHandler
+          ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
+  ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,
+      void (asio::error_code, std::size_t))
+  async_read_some(const MutableBufferSequence& buffers,
+      ASIO_MOVE_ARG(ReadHandler) handler
+        ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
+  {
+    return next_layer_.async_read_some(buffers,
+        ASIO_MOVE_CAST(ReadHandler)(handler));
+  }
+
+  /// Peek at the incoming data on the stream. Returns the number of bytes read.
+  /// Throws an exception on failure.
+  template <typename MutableBufferSequence>
+  std::size_t peek(const MutableBufferSequence& buffers)
+  {
+    return next_layer_.peek(buffers);
+  }
+
+  /// Peek at the incoming data on the stream. Returns the number of bytes read,
+  /// or 0 if an error occurred.
+  template <typename MutableBufferSequence>
+  std::size_t peek(const MutableBufferSequence& buffers,
+      asio::error_code& ec)
+  {
+    return next_layer_.peek(buffers, ec);
+  }
+
+  /// Determine the amount of data that may be read without blocking.
+  std::size_t in_avail()
+  {
+    return next_layer_.in_avail();
+  }
+
+  /// Determine the amount of data that may be read without blocking.
+  std::size_t in_avail(asio::error_code& ec)
+  {
+    return next_layer_.in_avail(ec);
+  }
+
+private:
+  /// Copy data into the internal buffer from the specified source buffer.
+  /// Returns the number of bytes copied.
+  template <typename ConstBufferSequence>
+  std::size_t copy(const ConstBufferSequence& buffers);
+
+  /// The next layer.
+  Stream next_layer_;
+
+  // The data in the buffer.
+  detail::buffered_stream_storage storage_;
+};
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/impl/buffered_write_stream.hpp"
+
+#endif // ASIO_BUFFERED_WRITE_STREAM_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/buffered_write_stream_fwd.hpp b/link/modules/asio-standalone/asio/include/asio/buffered_write_stream_fwd.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/buffered_write_stream_fwd.hpp
@@ -0,0 +1,25 @@
+//
+// buffered_write_stream_fwd.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_BUFFERED_WRITE_STREAM_FWD_HPP
+#define ASIO_BUFFERED_WRITE_STREAM_FWD_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+namespace asio {
+
+template <typename Stream>
+class buffered_write_stream;
+
+} // namespace asio
+
+#endif // ASIO_BUFFERED_WRITE_STREAM_FWD_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/buffers_iterator.hpp b/link/modules/asio-standalone/asio/include/asio/buffers_iterator.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/buffers_iterator.hpp
@@ -0,0 +1,521 @@
+//
+// buffers_iterator.hpp
+// ~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_BUFFERS_ITERATOR_HPP
+#define ASIO_BUFFERS_ITERATOR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <cstddef>
+#include <iterator>
+#include "asio/buffer.hpp"
+#include "asio/detail/assert.hpp"
+#include "asio/detail/type_traits.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+namespace detail
+{
+  template <bool IsMutable>
+  struct buffers_iterator_types_helper;
+
+  template <>
+  struct buffers_iterator_types_helper<false>
+  {
+    typedef const_buffer buffer_type;
+    template <typename ByteType>
+    struct byte_type
+    {
+      typedef typename add_const<ByteType>::type type;
+    };
+  };
+
+  template <>
+  struct buffers_iterator_types_helper<true>
+  {
+    typedef mutable_buffer buffer_type;
+    template <typename ByteType>
+    struct byte_type
+    {
+      typedef ByteType type;
+    };
+  };
+
+  template <typename BufferSequence, typename ByteType>
+  struct buffers_iterator_types
+  {
+    enum
+    {
+      is_mutable = is_convertible<
+          typename BufferSequence::value_type,
+          mutable_buffer>::value
+    };
+    typedef buffers_iterator_types_helper<is_mutable> helper;
+    typedef typename helper::buffer_type buffer_type;
+    typedef typename helper::template byte_type<ByteType>::type byte_type;
+    typedef typename BufferSequence::const_iterator const_iterator;
+  };
+
+  template <typename ByteType>
+  struct buffers_iterator_types<mutable_buffer, ByteType>
+  {
+    typedef mutable_buffer buffer_type;
+    typedef ByteType byte_type;
+    typedef const mutable_buffer* const_iterator;
+  };
+
+  template <typename ByteType>
+  struct buffers_iterator_types<const_buffer, ByteType>
+  {
+    typedef const_buffer buffer_type;
+    typedef typename add_const<ByteType>::type byte_type;
+    typedef const const_buffer* const_iterator;
+  };
+
+#if !defined(ASIO_NO_DEPRECATED)
+
+  template <typename ByteType>
+  struct buffers_iterator_types<mutable_buffers_1, ByteType>
+  {
+    typedef mutable_buffer buffer_type;
+    typedef ByteType byte_type;
+    typedef const mutable_buffer* const_iterator;
+  };
+
+  template <typename ByteType>
+  struct buffers_iterator_types<const_buffers_1, ByteType>
+  {
+    typedef const_buffer buffer_type;
+    typedef typename add_const<ByteType>::type byte_type;
+    typedef const const_buffer* const_iterator;
+  };
+
+#endif // !defined(ASIO_NO_DEPRECATED)
+}
+
+/// A random access iterator over the bytes in a buffer sequence.
+template <typename BufferSequence, typename ByteType = char>
+class buffers_iterator
+{
+private:
+  typedef typename detail::buffers_iterator_types<
+      BufferSequence, ByteType>::buffer_type buffer_type;
+
+  typedef typename detail::buffers_iterator_types<BufferSequence,
+          ByteType>::const_iterator buffer_sequence_iterator_type;
+
+public:
+  /// The type used for the distance between two iterators.
+  typedef std::ptrdiff_t difference_type;
+
+  /// The type of the value pointed to by the iterator.
+  typedef ByteType value_type;
+
+#if defined(GENERATING_DOCUMENTATION)
+  /// The type of the result of applying operator->() to the iterator.
+  /**
+   * If the buffer sequence stores buffer objects that are convertible to
+   * mutable_buffer, this is a pointer to a non-const ByteType. Otherwise, a
+   * pointer to a const ByteType.
+   */
+  typedef const_or_non_const_ByteType* pointer;
+#else // defined(GENERATING_DOCUMENTATION)
+  typedef typename detail::buffers_iterator_types<
+      BufferSequence, ByteType>::byte_type* pointer;
+#endif // defined(GENERATING_DOCUMENTATION)
+
+#if defined(GENERATING_DOCUMENTATION)
+  /// The type of the result of applying operator*() to the iterator.
+  /**
+   * If the buffer sequence stores buffer objects that are convertible to
+   * mutable_buffer, this is a reference to a non-const ByteType. Otherwise, a
+   * reference to a const ByteType.
+   */
+  typedef const_or_non_const_ByteType& reference;
+#else // defined(GENERATING_DOCUMENTATION)
+  typedef typename detail::buffers_iterator_types<
+      BufferSequence, ByteType>::byte_type& reference;
+#endif // defined(GENERATING_DOCUMENTATION)
+
+  /// The iterator category.
+  typedef std::random_access_iterator_tag iterator_category;
+
+  /// Default constructor. Creates an iterator in an undefined state.
+  buffers_iterator()
+    : current_buffer_(),
+      current_buffer_position_(0),
+      begin_(),
+      current_(),
+      end_(),
+      position_(0)
+  {
+  }
+
+  /// Construct an iterator representing the beginning of the buffers' data.
+  static buffers_iterator begin(const BufferSequence& buffers)
+#if defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 3)
+    __attribute__ ((__noinline__))
+#endif // defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 3)
+  {
+    buffers_iterator new_iter;
+    new_iter.begin_ = asio::buffer_sequence_begin(buffers);
+    new_iter.current_ = asio::buffer_sequence_begin(buffers);
+    new_iter.end_ = asio::buffer_sequence_end(buffers);
+    while (new_iter.current_ != new_iter.end_)
+    {
+      new_iter.current_buffer_ = *new_iter.current_;
+      if (new_iter.current_buffer_.size() > 0)
+        break;
+      ++new_iter.current_;
+    }
+    return new_iter;
+  }
+
+  /// Construct an iterator representing the end of the buffers' data.
+  static buffers_iterator end(const BufferSequence& buffers)
+#if defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 3)
+    __attribute__ ((__noinline__))
+#endif // defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 3)
+  {
+    buffers_iterator new_iter;
+    new_iter.begin_ = asio::buffer_sequence_begin(buffers);
+    new_iter.current_ = asio::buffer_sequence_begin(buffers);
+    new_iter.end_ = asio::buffer_sequence_end(buffers);
+    while (new_iter.current_ != new_iter.end_)
+    {
+      buffer_type buffer = *new_iter.current_;
+      new_iter.position_ += buffer.size();
+      ++new_iter.current_;
+    }
+    return new_iter;
+  }
+
+  /// Dereference an iterator.
+  reference operator*() const
+  {
+    return dereference();
+  }
+
+  /// Dereference an iterator.
+  pointer operator->() const
+  {
+    return &dereference();
+  }
+
+  /// Access an individual element.
+  reference operator[](std::ptrdiff_t difference) const
+  {
+    buffers_iterator tmp(*this);
+    tmp.advance(difference);
+    return *tmp;
+  }
+
+  /// Increment operator (prefix).
+  buffers_iterator& operator++()
+  {
+    increment();
+    return *this;
+  }
+
+  /// Increment operator (postfix).
+  buffers_iterator operator++(int)
+  {
+    buffers_iterator tmp(*this);
+    ++*this;
+    return tmp;
+  }
+
+  /// Decrement operator (prefix).
+  buffers_iterator& operator--()
+  {
+    decrement();
+    return *this;
+  }
+
+  /// Decrement operator (postfix).
+  buffers_iterator operator--(int)
+  {
+    buffers_iterator tmp(*this);
+    --*this;
+    return tmp;
+  }
+
+  /// Addition operator.
+  buffers_iterator& operator+=(std::ptrdiff_t difference)
+  {
+    advance(difference);
+    return *this;
+  }
+
+  /// Subtraction operator.
+  buffers_iterator& operator-=(std::ptrdiff_t difference)
+  {
+    advance(-difference);
+    return *this;
+  }
+
+  /// Addition operator.
+  friend buffers_iterator operator+(const buffers_iterator& iter,
+      std::ptrdiff_t difference)
+  {
+    buffers_iterator tmp(iter);
+    tmp.advance(difference);
+    return tmp;
+  }
+
+  /// Addition operator.
+  friend buffers_iterator operator+(std::ptrdiff_t difference,
+      const buffers_iterator& iter)
+  {
+    buffers_iterator tmp(iter);
+    tmp.advance(difference);
+    return tmp;
+  }
+
+  /// Subtraction operator.
+  friend buffers_iterator operator-(const buffers_iterator& iter,
+      std::ptrdiff_t difference)
+  {
+    buffers_iterator tmp(iter);
+    tmp.advance(-difference);
+    return tmp;
+  }
+
+  /// Subtraction operator.
+  friend std::ptrdiff_t operator-(const buffers_iterator& a,
+      const buffers_iterator& b)
+  {
+    return b.distance_to(a);
+  }
+
+  /// Test two iterators for equality.
+  friend bool operator==(const buffers_iterator& a, const buffers_iterator& b)
+  {
+    return a.equal(b);
+  }
+
+  /// Test two iterators for inequality.
+  friend bool operator!=(const buffers_iterator& a, const buffers_iterator& b)
+  {
+    return !a.equal(b);
+  }
+
+  /// Compare two iterators.
+  friend bool operator<(const buffers_iterator& a, const buffers_iterator& b)
+  {
+    return a.distance_to(b) > 0;
+  }
+
+  /// Compare two iterators.
+  friend bool operator<=(const buffers_iterator& a, const buffers_iterator& b)
+  {
+    return !(b < a);
+  }
+
+  /// Compare two iterators.
+  friend bool operator>(const buffers_iterator& a, const buffers_iterator& b)
+  {
+    return b < a;
+  }
+
+  /// Compare two iterators.
+  friend bool operator>=(const buffers_iterator& a, const buffers_iterator& b)
+  {
+    return !(a < b);
+  }
+
+private:
+  // Dereference the iterator.
+  reference dereference() const
+  {
+    return static_cast<pointer>(
+        current_buffer_.data())[current_buffer_position_];
+  }
+
+  // Compare two iterators for equality.
+  bool equal(const buffers_iterator& other) const
+  {
+    return position_ == other.position_;
+  }
+
+  // Increment the iterator.
+  void increment()
+  {
+    ASIO_ASSERT(current_ != end_ && "iterator out of bounds");
+    ++position_;
+
+    // Check if the increment can be satisfied by the current buffer.
+    ++current_buffer_position_;
+    if (current_buffer_position_ != current_buffer_.size())
+      return;
+
+    // Find the next non-empty buffer.
+    ++current_;
+    current_buffer_position_ = 0;
+    while (current_ != end_)
+    {
+      current_buffer_ = *current_;
+      if (current_buffer_.size() > 0)
+        return;
+      ++current_;
+    }
+  }
+
+  // Decrement the iterator.
+  void decrement()
+  {
+    ASIO_ASSERT(position_ > 0 && "iterator out of bounds");
+    --position_;
+
+    // Check if the decrement can be satisfied by the current buffer.
+    if (current_buffer_position_ != 0)
+    {
+      --current_buffer_position_;
+      return;
+    }
+
+    // Find the previous non-empty buffer.
+    buffer_sequence_iterator_type iter = current_;
+    while (iter != begin_)
+    {
+      --iter;
+      buffer_type buffer = *iter;
+      std::size_t buffer_size = buffer.size();
+      if (buffer_size > 0)
+      {
+        current_ = iter;
+        current_buffer_ = buffer;
+        current_buffer_position_ = buffer_size - 1;
+        return;
+      }
+    }
+  }
+
+  // Advance the iterator by the specified distance.
+  void advance(std::ptrdiff_t n)
+  {
+    if (n > 0)
+    {
+      ASIO_ASSERT(current_ != end_ && "iterator out of bounds");
+      for (;;)
+      {
+        std::ptrdiff_t current_buffer_balance
+          = current_buffer_.size() - current_buffer_position_;
+
+        // Check if the advance can be satisfied by the current buffer.
+        if (current_buffer_balance > n)
+        {
+          position_ += n;
+          current_buffer_position_ += n;
+          return;
+        }
+
+        // Update position.
+        n -= current_buffer_balance;
+        position_ += current_buffer_balance;
+
+        // Move to next buffer. If it is empty then it will be skipped on the
+        // next iteration of this loop.
+        if (++current_ == end_)
+        {
+          ASIO_ASSERT(n == 0 && "iterator out of bounds");
+          current_buffer_ = buffer_type();
+          current_buffer_position_ = 0;
+          return;
+        }
+        current_buffer_ = *current_;
+        current_buffer_position_ = 0;
+      }
+    }
+    else if (n < 0)
+    {
+      std::size_t abs_n = -n;
+      ASIO_ASSERT(position_ >= abs_n && "iterator out of bounds");
+      for (;;)
+      {
+        // Check if the advance can be satisfied by the current buffer.
+        if (current_buffer_position_ >= abs_n)
+        {
+          position_ -= abs_n;
+          current_buffer_position_ -= abs_n;
+          return;
+        }
+
+        // Update position.
+        abs_n -= current_buffer_position_;
+        position_ -= current_buffer_position_;
+
+        // Check if we've reached the beginning of the buffers.
+        if (current_ == begin_)
+        {
+          ASIO_ASSERT(abs_n == 0 && "iterator out of bounds");
+          current_buffer_position_ = 0;
+          return;
+        }
+
+        // Find the previous non-empty buffer.
+        buffer_sequence_iterator_type iter = current_;
+        while (iter != begin_)
+        {
+          --iter;
+          buffer_type buffer = *iter;
+          std::size_t buffer_size = buffer.size();
+          if (buffer_size > 0)
+          {
+            current_ = iter;
+            current_buffer_ = buffer;
+            current_buffer_position_ = buffer_size;
+            break;
+          }
+        }
+      }
+    }
+  }
+
+  // Determine the distance between two iterators.
+  std::ptrdiff_t distance_to(const buffers_iterator& other) const
+  {
+    return other.position_ - position_;
+  }
+
+  buffer_type current_buffer_;
+  std::size_t current_buffer_position_;
+  buffer_sequence_iterator_type begin_;
+  buffer_sequence_iterator_type current_;
+  buffer_sequence_iterator_type end_;
+  std::size_t position_;
+};
+
+/// Construct an iterator representing the beginning of the buffers' data.
+template <typename BufferSequence>
+inline buffers_iterator<BufferSequence> buffers_begin(
+    const BufferSequence& buffers)
+{
+  return buffers_iterator<BufferSequence>::begin(buffers);
+}
+
+/// Construct an iterator representing the end of the buffers' data.
+template <typename BufferSequence>
+inline buffers_iterator<BufferSequence> buffers_end(
+    const BufferSequence& buffers)
+{
+  return buffers_iterator<BufferSequence>::end(buffers);
+}
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_BUFFERS_ITERATOR_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/co_spawn.hpp b/link/modules/asio-standalone/asio/include/asio/co_spawn.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/co_spawn.hpp
@@ -0,0 +1,471 @@
+//
+// co_spawn.hpp
+// ~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_CO_SPAWN_HPP
+#define ASIO_CO_SPAWN_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_CO_AWAIT) || defined(GENERATING_DOCUMENTATION)
+
+#include "asio/awaitable.hpp"
+#include "asio/execution/executor.hpp"
+#include "asio/execution_context.hpp"
+#include "asio/is_executor.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename T>
+struct awaitable_signature;
+
+template <typename T, typename Executor>
+struct awaitable_signature<awaitable<T, Executor>>
+{
+  typedef void type(std::exception_ptr, T);
+};
+
+template <typename Executor>
+struct awaitable_signature<awaitable<void, Executor>>
+{
+  typedef void type(std::exception_ptr);
+};
+
+} // namespace detail
+
+/// Spawn a new coroutined-based thread of execution.
+/**
+ * @param ex The executor that will be used to schedule the new thread of
+ * execution.
+ *
+ * @param a The asio::awaitable object that is the result of calling the
+ * coroutine's entry point function.
+ *
+ * @param token The completion token that will handle the notification that
+ * the thread of execution has completed. The function signature of the
+ * completion handler must be:
+ * @code void handler(std::exception_ptr, T); @endcode
+ *
+ * @par Example
+ * @code
+ * asio::awaitable<std::size_t> echo(tcp::socket socket)
+ * {
+ *   std::size_t bytes_transferred = 0;
+ *
+ *   try
+ *   {
+ *     char data[1024];
+ *     for (;;)
+ *     {
+ *       std::size_t n = co_await socket.async_read_some(
+ *           asio::buffer(data), asio::use_awaitable);
+ *
+ *       co_await asio::async_write(socket,
+ *           asio::buffer(data, n), asio::use_awaitable);
+ *
+ *       bytes_transferred += n;
+ *     }
+ *   }
+ *   catch (const std::exception&)
+ *   {
+ *   }
+ *
+ *   co_return bytes_transferred;
+ * }
+ *
+ * // ...
+ *
+ * asio::co_spawn(my_executor,
+ *   echo(std::move(my_tcp_socket)),
+ *   [](std::exception_ptr e, std::size_t n)
+ *   {
+ *     std::cout << "transferred " << n << "\n";
+ *   });
+ * @endcode
+ */
+template <typename Executor, typename T, typename AwaitableExecutor,
+    ASIO_COMPLETION_TOKEN_FOR(
+      void(std::exception_ptr, T)) CompletionToken
+        ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(Executor)>
+inline ASIO_INITFN_AUTO_RESULT_TYPE(
+    CompletionToken, void(std::exception_ptr, T))
+co_spawn(const Executor& ex, awaitable<T, AwaitableExecutor> a,
+    CompletionToken&& token
+      ASIO_DEFAULT_COMPLETION_TOKEN(Executor),
+    typename enable_if<
+      (is_executor<Executor>::value || execution::is_executor<Executor>::value)
+        && is_convertible<Executor, AwaitableExecutor>::value
+    >::type* = 0);
+
+/// Spawn a new coroutined-based thread of execution.
+/**
+ * @param ex The executor that will be used to schedule the new thread of
+ * execution.
+ *
+ * @param a The asio::awaitable object that is the result of calling the
+ * coroutine's entry point function.
+ *
+ * @param token The completion token that will handle the notification that
+ * the thread of execution has completed. The function signature of the
+ * completion handler must be:
+ * @code void handler(std::exception_ptr); @endcode
+ *
+ * @par Example
+ * @code
+ * asio::awaitable<void> echo(tcp::socket socket)
+ * {
+ *   try
+ *   {
+ *     char data[1024];
+ *     for (;;)
+ *     {
+ *       std::size_t n = co_await socket.async_read_some(
+ *           asio::buffer(data), asio::use_awaitable);
+ *
+ *       co_await asio::async_write(socket,
+ *           asio::buffer(data, n), asio::use_awaitable);
+ *     }
+ *   }
+ *   catch (const std::exception& e)
+ *   {
+ *     std::cerr << "Exception: " << e.what() << "\n";
+ *   }
+ * }
+ *
+ * // ...
+ *
+ * asio::co_spawn(my_executor,
+ *   echo(std::move(my_tcp_socket)),
+ *   asio::detached);
+ * @endcode
+ */
+template <typename Executor, typename AwaitableExecutor,
+    ASIO_COMPLETION_TOKEN_FOR(
+      void(std::exception_ptr)) CompletionToken
+        ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(Executor)>
+inline ASIO_INITFN_AUTO_RESULT_TYPE(
+    CompletionToken, void(std::exception_ptr))
+co_spawn(const Executor& ex, awaitable<void, AwaitableExecutor> a,
+    CompletionToken&& token
+      ASIO_DEFAULT_COMPLETION_TOKEN(Executor),
+    typename enable_if<
+      (is_executor<Executor>::value || execution::is_executor<Executor>::value)
+        && is_convertible<Executor, AwaitableExecutor>::value
+    >::type* = 0);
+
+/// Spawn a new coroutined-based thread of execution.
+/**
+ * @param ctx An execution context that will provide the executor to be used to
+ * schedule the new thread of execution.
+ *
+ * @param a The asio::awaitable object that is the result of calling the
+ * coroutine's entry point function.
+ *
+ * @param token The completion token that will handle the notification that
+ * the thread of execution has completed. The function signature of the
+ * completion handler must be:
+ * @code void handler(std::exception_ptr); @endcode
+ *
+ * @par Example
+ * @code
+ * asio::awaitable<std::size_t> echo(tcp::socket socket)
+ * {
+ *   std::size_t bytes_transferred = 0;
+ *
+ *   try
+ *   {
+ *     char data[1024];
+ *     for (;;)
+ *     {
+ *       std::size_t n = co_await socket.async_read_some(
+ *           asio::buffer(data), asio::use_awaitable);
+ *
+ *       co_await asio::async_write(socket,
+ *           asio::buffer(data, n), asio::use_awaitable);
+ *
+ *       bytes_transferred += n;
+ *     }
+ *   }
+ *   catch (const std::exception&)
+ *   {
+ *   }
+ *
+ *   co_return bytes_transferred;
+ * }
+ *
+ * // ...
+ *
+ * asio::co_spawn(my_io_context,
+ *   echo(std::move(my_tcp_socket)),
+ *   [](std::exception_ptr e, std::size_t n)
+ *   {
+ *     std::cout << "transferred " << n << "\n";
+ *   });
+ * @endcode
+ */
+template <typename ExecutionContext, typename T, typename AwaitableExecutor,
+    ASIO_COMPLETION_TOKEN_FOR(
+      void(std::exception_ptr, T)) CompletionToken
+        ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(
+          typename ExecutionContext::executor_type)>
+inline ASIO_INITFN_AUTO_RESULT_TYPE(
+    CompletionToken, void(std::exception_ptr, T))
+co_spawn(ExecutionContext& ctx, awaitable<T, AwaitableExecutor> a,
+    CompletionToken&& token
+      ASIO_DEFAULT_COMPLETION_TOKEN(
+        typename ExecutionContext::executor_type),
+    typename enable_if<
+      is_convertible<ExecutionContext&, execution_context&>::value
+        && is_convertible<typename ExecutionContext::executor_type,
+          AwaitableExecutor>::value
+    >::type* = 0);
+
+/// Spawn a new coroutined-based thread of execution.
+/**
+ * @param ctx An execution context that will provide the executor to be used to
+ * schedule the new thread of execution.
+ *
+ * @param a The asio::awaitable object that is the result of calling the
+ * coroutine's entry point function.
+ *
+ * @param token The completion token that will handle the notification that
+ * the thread of execution has completed. The function signature of the
+ * completion handler must be:
+ * @code void handler(std::exception_ptr); @endcode
+ *
+ * @par Example
+ * @code
+ * asio::awaitable<void> echo(tcp::socket socket)
+ * {
+ *   try
+ *   {
+ *     char data[1024];
+ *     for (;;)
+ *     {
+ *       std::size_t n = co_await socket.async_read_some(
+ *           asio::buffer(data), asio::use_awaitable);
+ *
+ *       co_await asio::async_write(socket,
+ *           asio::buffer(data, n), asio::use_awaitable);
+ *     }
+ *   }
+ *   catch (const std::exception& e)
+ *   {
+ *     std::cerr << "Exception: " << e.what() << "\n";
+ *   }
+ * }
+ *
+ * // ...
+ *
+ * asio::co_spawn(my_io_context,
+ *   echo(std::move(my_tcp_socket)),
+ *   asio::detached);
+ * @endcode
+ */
+template <typename ExecutionContext, typename AwaitableExecutor,
+    ASIO_COMPLETION_TOKEN_FOR(
+      void(std::exception_ptr)) CompletionToken
+        ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(
+          typename ExecutionContext::executor_type)>
+inline ASIO_INITFN_AUTO_RESULT_TYPE(
+    CompletionToken, void(std::exception_ptr))
+co_spawn(ExecutionContext& ctx, awaitable<void, AwaitableExecutor> a,
+    CompletionToken&& token
+      ASIO_DEFAULT_COMPLETION_TOKEN(
+        typename ExecutionContext::executor_type),
+    typename enable_if<
+      is_convertible<ExecutionContext&, execution_context&>::value
+        && is_convertible<typename ExecutionContext::executor_type,
+          AwaitableExecutor>::value
+    >::type* = 0);
+
+/// Spawn a new coroutined-based thread of execution.
+/**
+ * @param ex The executor that will be used to schedule the new thread of
+ * execution.
+ *
+ * @param f A nullary function object with a return type of the form
+ * @c asio::awaitable<R,E> that will be used as the coroutine's entry
+ * point.
+ *
+ * @param token The completion token that will handle the notification that the
+ * thread of execution has completed. If @c R is @c void, the function
+ * signature of the completion handler must be:
+ *
+ * @code void handler(std::exception_ptr); @endcode
+ * Otherwise, the function signature of the completion handler must be:
+ * @code void handler(std::exception_ptr, R); @endcode
+ *
+ *
+ * @par Example
+ * @code
+ * asio::awaitable<std::size_t> echo(tcp::socket socket)
+ * {
+ *   std::size_t bytes_transferred = 0;
+ *
+ *   try
+ *   {
+ *     char data[1024];
+ *     for (;;)
+ *     {
+ *       std::size_t n = co_await socket.async_read_some(
+ *           asio::buffer(data), asio::use_awaitable);
+ *
+ *       co_await asio::async_write(socket,
+ *           asio::buffer(data, n), asio::use_awaitable);
+ *
+ *       bytes_transferred += n;
+ *     }
+ *   }
+ *   catch (const std::exception&)
+ *   {
+ *   }
+ *
+ *   co_return bytes_transferred;
+ * }
+ *
+ * // ...
+ *
+ * asio::co_spawn(my_executor,
+ *   [socket = std::move(my_tcp_socket)]() mutable
+ *     -> asio::awaitable<void>
+ *   {
+ *     try
+ *     {
+ *       char data[1024];
+ *       for (;;)
+ *       {
+ *         std::size_t n = co_await socket.async_read_some(
+ *             asio::buffer(data), asio::use_awaitable);
+ *
+ *         co_await asio::async_write(socket,
+ *             asio::buffer(data, n), asio::use_awaitable);
+ *       }
+ *     }
+ *     catch (const std::exception& e)
+ *     {
+ *       std::cerr << "Exception: " << e.what() << "\n";
+ *     }
+ *   }, asio::detached);
+ * @endcode
+ */
+template <typename Executor, typename F,
+    ASIO_COMPLETION_TOKEN_FOR(typename detail::awaitable_signature<
+      typename result_of<F()>::type>::type) CompletionToken
+        ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(Executor)>
+ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken,
+    typename detail::awaitable_signature<typename result_of<F()>::type>::type)
+co_spawn(const Executor& ex, F&& f,
+    CompletionToken&& token
+      ASIO_DEFAULT_COMPLETION_TOKEN(Executor),
+    typename enable_if<
+      is_executor<Executor>::value || execution::is_executor<Executor>::value
+    >::type* = 0);
+
+/// Spawn a new coroutined-based thread of execution.
+/**
+ * @param ctx An execution context that will provide the executor to be used to
+ * schedule the new thread of execution.
+ *
+ * @param f A nullary function object with a return type of the form
+ * @c asio::awaitable<R,E> that will be used as the coroutine's entry
+ * point.
+ *
+ * @param token The completion token that will handle the notification that the
+ * thread of execution has completed. If @c R is @c void, the function
+ * signature of the completion handler must be:
+ *
+ * @code void handler(std::exception_ptr); @endcode
+ * Otherwise, the function signature of the completion handler must be:
+ * @code void handler(std::exception_ptr, R); @endcode
+ *
+ *
+ * @par Example
+ * @code
+ * asio::awaitable<std::size_t> echo(tcp::socket socket)
+ * {
+ *   std::size_t bytes_transferred = 0;
+ *
+ *   try
+ *   {
+ *     char data[1024];
+ *     for (;;)
+ *     {
+ *       std::size_t n = co_await socket.async_read_some(
+ *           asio::buffer(data), asio::use_awaitable);
+ *
+ *       co_await asio::async_write(socket,
+ *           asio::buffer(data, n), asio::use_awaitable);
+ *
+ *       bytes_transferred += n;
+ *     }
+ *   }
+ *   catch (const std::exception&)
+ *   {
+ *   }
+ *
+ *   co_return bytes_transferred;
+ * }
+ *
+ * // ...
+ *
+ * asio::co_spawn(my_io_context,
+ *   [socket = std::move(my_tcp_socket)]() mutable
+ *     -> asio::awaitable<void>
+ *   {
+ *     try
+ *     {
+ *       char data[1024];
+ *       for (;;)
+ *       {
+ *         std::size_t n = co_await socket.async_read_some(
+ *             asio::buffer(data), asio::use_awaitable);
+ *
+ *         co_await asio::async_write(socket,
+ *             asio::buffer(data, n), asio::use_awaitable);
+ *       }
+ *     }
+ *     catch (const std::exception& e)
+ *     {
+ *       std::cerr << "Exception: " << e.what() << "\n";
+ *     }
+ *   }, asio::detached);
+ * @endcode
+ */
+template <typename ExecutionContext, typename F,
+    ASIO_COMPLETION_TOKEN_FOR(typename detail::awaitable_signature<
+      typename result_of<F()>::type>::type) CompletionToken
+        ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(
+          typename ExecutionContext::executor_type)>
+ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken,
+    typename detail::awaitable_signature<typename result_of<F()>::type>::type)
+co_spawn(ExecutionContext& ctx, F&& f,
+    CompletionToken&& token
+      ASIO_DEFAULT_COMPLETION_TOKEN(
+        typename ExecutionContext::executor_type),
+    typename enable_if<
+      is_convertible<ExecutionContext&, execution_context&>::value
+    >::type* = 0);
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/impl/co_spawn.hpp"
+
+#endif // defined(ASIO_HAS_CO_AWAIT) || defined(GENERATING_DOCUMENTATION)
+
+#endif // ASIO_CO_SPAWN_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/completion_condition.hpp b/link/modules/asio-standalone/asio/include/asio/completion_condition.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/completion_condition.hpp
@@ -0,0 +1,218 @@
+//
+// completion_condition.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_COMPLETION_CONDITION_HPP
+#define ASIO_COMPLETION_CONDITION_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <cstddef>
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+namespace detail {
+
+// The default maximum number of bytes to transfer in a single operation.
+enum default_max_transfer_size_t { default_max_transfer_size = 65536 };
+
+// Adapt result of old-style completion conditions (which had a bool result
+// where true indicated that the operation was complete).
+inline std::size_t adapt_completion_condition_result(bool result)
+{
+  return result ? 0 : default_max_transfer_size;
+}
+
+// Adapt result of current completion conditions (which have a size_t result
+// where 0 means the operation is complete, and otherwise the result is the
+// maximum number of bytes to transfer on the next underlying operation).
+inline std::size_t adapt_completion_condition_result(std::size_t result)
+{
+  return result;
+}
+
+class transfer_all_t
+{
+public:
+  typedef std::size_t result_type;
+
+  template <typename Error>
+  std::size_t operator()(const Error& err, std::size_t)
+  {
+    return !!err ? 0 : default_max_transfer_size;
+  }
+};
+
+class transfer_at_least_t
+{
+public:
+  typedef std::size_t result_type;
+
+  explicit transfer_at_least_t(std::size_t minimum)
+    : minimum_(minimum)
+  {
+  }
+
+  template <typename Error>
+  std::size_t operator()(const Error& err, std::size_t bytes_transferred)
+  {
+    return (!!err || bytes_transferred >= minimum_)
+      ? 0 : default_max_transfer_size;
+  }
+
+private:
+  std::size_t minimum_;
+};
+
+class transfer_exactly_t
+{
+public:
+  typedef std::size_t result_type;
+
+  explicit transfer_exactly_t(std::size_t size)
+    : size_(size)
+  {
+  }
+
+  template <typename Error>
+  std::size_t operator()(const Error& err, std::size_t bytes_transferred)
+  {
+    return (!!err || bytes_transferred >= size_) ? 0 :
+      (size_ - bytes_transferred < default_max_transfer_size
+        ? size_ - bytes_transferred : std::size_t(default_max_transfer_size));
+  }
+
+private:
+  std::size_t size_;
+};
+
+} // namespace detail
+
+/**
+ * @defgroup completion_condition Completion Condition Function Objects
+ *
+ * Function objects used for determining when a read or write operation should
+ * complete.
+ */
+/*@{*/
+
+/// Return a completion condition function object that indicates that a read or
+/// write operation should continue until all of the data has been transferred,
+/// or until an error occurs.
+/**
+ * This function is used to create an object, of unspecified type, that meets
+ * CompletionCondition requirements.
+ *
+ * @par Example
+ * Reading until a buffer is full:
+ * @code
+ * boost::array<char, 128> buf;
+ * asio::error_code ec;
+ * std::size_t n = asio::read(
+ *     sock, asio::buffer(buf),
+ *     asio::transfer_all(), ec);
+ * if (ec)
+ * {
+ *   // An error occurred.
+ * }
+ * else
+ * {
+ *   // n == 128
+ * }
+ * @endcode
+ */
+#if defined(GENERATING_DOCUMENTATION)
+unspecified transfer_all();
+#else
+inline detail::transfer_all_t transfer_all()
+{
+  return detail::transfer_all_t();
+}
+#endif
+
+/// Return a completion condition function object that indicates that a read or
+/// write operation should continue until a minimum number of bytes has been
+/// transferred, or until an error occurs.
+/**
+ * This function is used to create an object, of unspecified type, that meets
+ * CompletionCondition requirements.
+ *
+ * @par Example
+ * Reading until a buffer is full or contains at least 64 bytes:
+ * @code
+ * boost::array<char, 128> buf;
+ * asio::error_code ec;
+ * std::size_t n = asio::read(
+ *     sock, asio::buffer(buf),
+ *     asio::transfer_at_least(64), ec);
+ * if (ec)
+ * {
+ *   // An error occurred.
+ * }
+ * else
+ * {
+ *   // n >= 64 && n <= 128
+ * }
+ * @endcode
+ */
+#if defined(GENERATING_DOCUMENTATION)
+unspecified transfer_at_least(std::size_t minimum);
+#else
+inline detail::transfer_at_least_t transfer_at_least(std::size_t minimum)
+{
+  return detail::transfer_at_least_t(minimum);
+}
+#endif
+
+/// Return a completion condition function object that indicates that a read or
+/// write operation should continue until an exact number of bytes has been
+/// transferred, or until an error occurs.
+/**
+ * This function is used to create an object, of unspecified type, that meets
+ * CompletionCondition requirements.
+ *
+ * @par Example
+ * Reading until a buffer is full or contains exactly 64 bytes:
+ * @code
+ * boost::array<char, 128> buf;
+ * asio::error_code ec;
+ * std::size_t n = asio::read(
+ *     sock, asio::buffer(buf),
+ *     asio::transfer_exactly(64), ec);
+ * if (ec)
+ * {
+ *   // An error occurred.
+ * }
+ * else
+ * {
+ *   // n == 64
+ * }
+ * @endcode
+ */
+#if defined(GENERATING_DOCUMENTATION)
+unspecified transfer_exactly(std::size_t size);
+#else
+inline detail::transfer_exactly_t transfer_exactly(std::size_t size)
+{
+  return detail::transfer_exactly_t(size);
+}
+#endif
+
+/*@}*/
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_COMPLETION_CONDITION_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/compose.hpp b/link/modules/asio-standalone/asio/include/asio/compose.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/compose.hpp
@@ -0,0 +1,136 @@
+//
+// compose.hpp
+// ~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_COMPOSE_HPP
+#define ASIO_COMPOSE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/async_result.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+#if defined(ASIO_HAS_VARIADIC_TEMPLATES) \
+  || defined(GENERATING_DOCUMENTATION)
+
+/// Launch an asynchronous operation with a stateful implementation.
+/**
+ * The async_compose function simplifies the implementation of composed
+ * asynchronous operations automatically wrapping a stateful function object
+ * with a conforming intermediate completion handler.
+ *
+ * @param implementation A function object that contains the implementation of
+ * the composed asynchronous operation. The first argument to the function
+ * object is a non-const reference to the enclosing intermediate completion
+ * handler. The remaining arguments are any arguments that originate from the
+ * completion handlers of any asynchronous operations performed by the
+ * implementation.
+
+ * @param token The completion token.
+ *
+ * @param io_objects_or_executors Zero or more I/O objects or I/O executors for
+ * which outstanding work must be maintained.
+ *
+ * @par Example:
+ *
+ * @code struct async_echo_implementation
+ * {
+ *   tcp::socket& socket_;
+ *   asio::mutable_buffer buffer_;
+ *   enum { starting, reading, writing } state_;
+ *
+ *   template <typename Self>
+ *   void operator()(Self& self,
+ *       asio::error_code error = {},
+ *       std::size_t n = 0)
+ *   {
+ *     switch (state_)
+ *     {
+ *     case starting:
+ *       state_ = reading;
+ *       socket_.async_read_some(
+ *           buffer_, std::move(self));
+ *       break;
+ *     case reading:
+ *       if (error)
+ *       {
+ *         self.complete(error, 0);
+ *       }
+ *       else
+ *       {
+ *         state_ = writing;
+ *         asio::async_write(socket_, buffer_,
+ *             asio::transfer_exactly(n),
+ *             std::move(self));
+ *       }
+ *       break;
+ *     case writing:
+ *       self.complete(error, n);
+ *       break;
+ *     }
+ *   }
+ * };
+ *
+ * template <typename CompletionToken>
+ * auto async_echo(tcp::socket& socket,
+ *     asio::mutable_buffer buffer,
+ *     CompletionToken&& token) ->
+ *   typename asio::async_result<
+ *     typename std::decay<CompletionToken>::type,
+ *       void(asio::error_code, std::size_t)>::return_type
+ * {
+ *   return asio::async_compose<CompletionToken,
+ *     void(asio::error_code, std::size_t)>(
+ *       async_echo_implementation{socket, buffer,
+ *         async_echo_implementation::starting},
+ *       token, socket);
+ * } @endcode
+ */
+template <typename CompletionToken, typename Signature,
+    typename Implementation, typename... IoObjectsOrExecutors>
+ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, Signature)
+async_compose(ASIO_MOVE_ARG(Implementation) implementation,
+    ASIO_NONDEDUCED_MOVE_ARG(CompletionToken) token,
+    ASIO_MOVE_ARG(IoObjectsOrExecutors)... io_objects_or_executors);
+
+#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+      //   || defined(GENERATING_DOCUMENTATION)
+
+template <typename CompletionToken, typename Signature, typename Implementation>
+ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, Signature)
+async_compose(ASIO_MOVE_ARG(Implementation) implementation,
+    ASIO_NONDEDUCED_MOVE_ARG(CompletionToken) token);
+
+#define ASIO_PRIVATE_ASYNC_COMPOSE_DEF(n) \
+  template <typename CompletionToken, typename Signature, \
+      typename Implementation, ASIO_VARIADIC_TPARAMS(n)> \
+  ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, Signature) \
+  async_compose(ASIO_MOVE_ARG(Implementation) implementation, \
+      ASIO_NONDEDUCED_MOVE_ARG(CompletionToken) token, \
+      ASIO_VARIADIC_MOVE_PARAMS(n));
+  /**/
+  ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_ASYNC_COMPOSE_DEF)
+#undef ASIO_PRIVATE_ASYNC_COMPOSE_DEF
+
+#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+       //   || defined(GENERATING_DOCUMENTATION)
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/impl/compose.hpp"
+
+#endif // ASIO_COMPOSE_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/connect.hpp b/link/modules/asio-standalone/asio/include/asio/connect.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/connect.hpp
@@ -0,0 +1,1076 @@
+//
+// connect.hpp
+// ~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_CONNECT_HPP
+#define ASIO_CONNECT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/async_result.hpp"
+#include "asio/basic_socket.hpp"
+#include "asio/detail/type_traits.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+namespace detail
+{
+  char (&has_iterator_helper(...))[2];
+
+  template <typename T>
+  char has_iterator_helper(T*, typename T::iterator* = 0);
+
+  template <typename T>
+  struct has_iterator_typedef
+  {
+    enum { value = (sizeof((has_iterator_helper)((T*)(0))) == 1) };
+  };
+} // namespace detail
+
+/// Type trait used to determine whether a type is an endpoint sequence that can
+/// be used with with @c connect and @c async_connect.
+template <typename T>
+struct is_endpoint_sequence
+{
+#if defined(GENERATING_DOCUMENTATION)
+  /// The value member is true if the type may be used as an endpoint sequence.
+  static const bool value;
+#else
+  enum
+  {
+    value = detail::has_iterator_typedef<T>::value
+  };
+#endif
+};
+
+/**
+ * @defgroup connect asio::connect
+ *
+ * @brief The @c connect function is a composed operation that establishes a
+ * socket connection by trying each endpoint in a sequence.
+ */
+/*@{*/
+
+/// Establishes a socket connection by trying each endpoint in a sequence.
+/**
+ * This function attempts to connect a socket to one of a sequence of
+ * endpoints. It does this by repeated calls to the socket's @c connect member
+ * function, once for each endpoint in the sequence, until a connection is
+ * successfully established.
+ *
+ * @param s The socket to be connected. If the socket is already open, it will
+ * be closed.
+ *
+ * @param endpoints A sequence of endpoints.
+ *
+ * @returns The successfully connected endpoint.
+ *
+ * @throws asio::system_error Thrown on failure. If the sequence is
+ * empty, the associated @c error_code is asio::error::not_found.
+ * Otherwise, contains the error from the last connection attempt.
+ *
+ * @par Example
+ * @code tcp::resolver r(my_context);
+ * tcp::resolver::query q("host", "service");
+ * tcp::socket s(my_context);
+ * asio::connect(s, r.resolve(q)); @endcode
+ */
+template <typename Protocol, typename Executor, typename EndpointSequence>
+typename Protocol::endpoint connect(basic_socket<Protocol, Executor>& s,
+    const EndpointSequence& endpoints,
+    typename enable_if<is_endpoint_sequence<
+        EndpointSequence>::value>::type* = 0);
+
+/// Establishes a socket connection by trying each endpoint in a sequence.
+/**
+ * This function attempts to connect a socket to one of a sequence of
+ * endpoints. It does this by repeated calls to the socket's @c connect member
+ * function, once for each endpoint in the sequence, until a connection is
+ * successfully established.
+ *
+ * @param s The socket to be connected. If the socket is already open, it will
+ * be closed.
+ *
+ * @param endpoints A sequence of endpoints.
+ *
+ * @param ec Set to indicate what error occurred, if any. If the sequence is
+ * empty, set to asio::error::not_found. Otherwise, contains the error
+ * from the last connection attempt.
+ *
+ * @returns On success, the successfully connected endpoint. Otherwise, a
+ * default-constructed endpoint.
+ *
+ * @par Example
+ * @code tcp::resolver r(my_context);
+ * tcp::resolver::query q("host", "service");
+ * tcp::socket s(my_context);
+ * asio::error_code ec;
+ * asio::connect(s, r.resolve(q), ec);
+ * if (ec)
+ * {
+ *   // An error occurred.
+ * } @endcode
+ */
+template <typename Protocol, typename Executor, typename EndpointSequence>
+typename Protocol::endpoint connect(basic_socket<Protocol, Executor>& s,
+    const EndpointSequence& endpoints, asio::error_code& ec,
+    typename enable_if<is_endpoint_sequence<
+        EndpointSequence>::value>::type* = 0);
+
+#if !defined(ASIO_NO_DEPRECATED)
+/// (Deprecated: Use range overload.) Establishes a socket connection by trying
+/// each endpoint in a sequence.
+/**
+ * This function attempts to connect a socket to one of a sequence of
+ * endpoints. It does this by repeated calls to the socket's @c connect member
+ * function, once for each endpoint in the sequence, until a connection is
+ * successfully established.
+ *
+ * @param s The socket to be connected. If the socket is already open, it will
+ * be closed.
+ *
+ * @param begin An iterator pointing to the start of a sequence of endpoints.
+ *
+ * @returns On success, an iterator denoting the successfully connected
+ * endpoint. Otherwise, the end iterator.
+ *
+ * @throws asio::system_error Thrown on failure. If the sequence is
+ * empty, the associated @c error_code is asio::error::not_found.
+ * Otherwise, contains the error from the last connection attempt.
+ *
+ * @note This overload assumes that a default constructed object of type @c
+ * Iterator represents the end of the sequence. This is a valid assumption for
+ * iterator types such as @c asio::ip::tcp::resolver::iterator.
+ */
+template <typename Protocol, typename Executor, typename Iterator>
+Iterator connect(basic_socket<Protocol, Executor>& s, Iterator begin,
+    typename enable_if<!is_endpoint_sequence<Iterator>::value>::type* = 0);
+
+/// (Deprecated: Use range overload.) Establishes a socket connection by trying
+/// each endpoint in a sequence.
+/**
+ * This function attempts to connect a socket to one of a sequence of
+ * endpoints. It does this by repeated calls to the socket's @c connect member
+ * function, once for each endpoint in the sequence, until a connection is
+ * successfully established.
+ *
+ * @param s The socket to be connected. If the socket is already open, it will
+ * be closed.
+ *
+ * @param begin An iterator pointing to the start of a sequence of endpoints.
+ *
+ * @param ec Set to indicate what error occurred, if any. If the sequence is
+ * empty, set to asio::error::not_found. Otherwise, contains the error
+ * from the last connection attempt.
+ *
+ * @returns On success, an iterator denoting the successfully connected
+ * endpoint. Otherwise, the end iterator.
+ *
+ * @note This overload assumes that a default constructed object of type @c
+ * Iterator represents the end of the sequence. This is a valid assumption for
+ * iterator types such as @c asio::ip::tcp::resolver::iterator.
+ */
+template <typename Protocol, typename Executor, typename Iterator>
+Iterator connect(basic_socket<Protocol, Executor>& s,
+    Iterator begin, asio::error_code& ec,
+    typename enable_if<!is_endpoint_sequence<Iterator>::value>::type* = 0);
+#endif // !defined(ASIO_NO_DEPRECATED)
+
+/// Establishes a socket connection by trying each endpoint in a sequence.
+/**
+ * This function attempts to connect a socket to one of a sequence of
+ * endpoints. It does this by repeated calls to the socket's @c connect member
+ * function, once for each endpoint in the sequence, until a connection is
+ * successfully established.
+ *
+ * @param s The socket to be connected. If the socket is already open, it will
+ * be closed.
+ *
+ * @param begin An iterator pointing to the start of a sequence of endpoints.
+ *
+ * @param end An iterator pointing to the end of a sequence of endpoints.
+ *
+ * @returns An iterator denoting the successfully connected endpoint.
+ *
+ * @throws asio::system_error Thrown on failure. If the sequence is
+ * empty, the associated @c error_code is asio::error::not_found.
+ * Otherwise, contains the error from the last connection attempt.
+ *
+ * @par Example
+ * @code tcp::resolver r(my_context);
+ * tcp::resolver::query q("host", "service");
+ * tcp::resolver::results_type e = r.resolve(q);
+ * tcp::socket s(my_context);
+ * asio::connect(s, e.begin(), e.end()); @endcode
+ */
+template <typename Protocol, typename Executor, typename Iterator>
+Iterator connect(basic_socket<Protocol, Executor>& s,
+    Iterator begin, Iterator end);
+
+/// Establishes a socket connection by trying each endpoint in a sequence.
+/**
+ * This function attempts to connect a socket to one of a sequence of
+ * endpoints. It does this by repeated calls to the socket's @c connect member
+ * function, once for each endpoint in the sequence, until a connection is
+ * successfully established.
+ *
+ * @param s The socket to be connected. If the socket is already open, it will
+ * be closed.
+ *
+ * @param begin An iterator pointing to the start of a sequence of endpoints.
+ *
+ * @param end An iterator pointing to the end of a sequence of endpoints.
+ *
+ * @param ec Set to indicate what error occurred, if any. If the sequence is
+ * empty, set to asio::error::not_found. Otherwise, contains the error
+ * from the last connection attempt.
+ *
+ * @returns On success, an iterator denoting the successfully connected
+ * endpoint. Otherwise, the end iterator.
+ *
+ * @par Example
+ * @code tcp::resolver r(my_context);
+ * tcp::resolver::query q("host", "service");
+ * tcp::resolver::results_type e = r.resolve(q);
+ * tcp::socket s(my_context);
+ * asio::error_code ec;
+ * asio::connect(s, e.begin(), e.end(), ec);
+ * if (ec)
+ * {
+ *   // An error occurred.
+ * } @endcode
+ */
+template <typename Protocol, typename Executor, typename Iterator>
+Iterator connect(basic_socket<Protocol, Executor>& s,
+    Iterator begin, Iterator end, asio::error_code& ec);
+
+/// Establishes a socket connection by trying each endpoint in a sequence.
+/**
+ * This function attempts to connect a socket to one of a sequence of
+ * endpoints. It does this by repeated calls to the socket's @c connect member
+ * function, once for each endpoint in the sequence, until a connection is
+ * successfully established.
+ *
+ * @param s The socket to be connected. If the socket is already open, it will
+ * be closed.
+ *
+ * @param endpoints A sequence of endpoints.
+ *
+ * @param connect_condition A function object that is called prior to each
+ * connection attempt. The signature of the function object must be:
+ * @code bool connect_condition(
+ *     const asio::error_code& ec,
+ *     const typename Protocol::endpoint& next); @endcode
+ * The @c ec parameter contains the result from the most recent connect
+ * operation. Before the first connection attempt, @c ec is always set to
+ * indicate success. The @c next parameter is the next endpoint to be tried.
+ * The function object should return true if the next endpoint should be tried,
+ * and false if it should be skipped.
+ *
+ * @returns The successfully connected endpoint.
+ *
+ * @throws asio::system_error Thrown on failure. If the sequence is
+ * empty, the associated @c error_code is asio::error::not_found.
+ * Otherwise, contains the error from the last connection attempt.
+ *
+ * @par Example
+ * The following connect condition function object can be used to output
+ * information about the individual connection attempts:
+ * @code struct my_connect_condition
+ * {
+ *   bool operator()(
+ *       const asio::error_code& ec,
+ *       const::tcp::endpoint& next)
+ *   {
+ *     if (ec) std::cout << "Error: " << ec.message() << std::endl;
+ *     std::cout << "Trying: " << next << std::endl;
+ *     return true;
+ *   }
+ * }; @endcode
+ * It would be used with the asio::connect function as follows:
+ * @code tcp::resolver r(my_context);
+ * tcp::resolver::query q("host", "service");
+ * tcp::socket s(my_context);
+ * tcp::endpoint e = asio::connect(s,
+ *     r.resolve(q), my_connect_condition());
+ * std::cout << "Connected to: " << e << std::endl; @endcode
+ */
+template <typename Protocol, typename Executor,
+    typename EndpointSequence, typename ConnectCondition>
+typename Protocol::endpoint connect(basic_socket<Protocol, Executor>& s,
+    const EndpointSequence& endpoints, ConnectCondition connect_condition,
+    typename enable_if<is_endpoint_sequence<
+        EndpointSequence>::value>::type* = 0);
+
+/// Establishes a socket connection by trying each endpoint in a sequence.
+/**
+ * This function attempts to connect a socket to one of a sequence of
+ * endpoints. It does this by repeated calls to the socket's @c connect member
+ * function, once for each endpoint in the sequence, until a connection is
+ * successfully established.
+ *
+ * @param s The socket to be connected. If the socket is already open, it will
+ * be closed.
+ *
+ * @param endpoints A sequence of endpoints.
+ *
+ * @param connect_condition A function object that is called prior to each
+ * connection attempt. The signature of the function object must be:
+ * @code bool connect_condition(
+ *     const asio::error_code& ec,
+ *     const typename Protocol::endpoint& next); @endcode
+ * The @c ec parameter contains the result from the most recent connect
+ * operation. Before the first connection attempt, @c ec is always set to
+ * indicate success. The @c next parameter is the next endpoint to be tried.
+ * The function object should return true if the next endpoint should be tried,
+ * and false if it should be skipped.
+ *
+ * @param ec Set to indicate what error occurred, if any. If the sequence is
+ * empty, set to asio::error::not_found. Otherwise, contains the error
+ * from the last connection attempt.
+ *
+ * @returns On success, the successfully connected endpoint. Otherwise, a
+ * default-constructed endpoint.
+ *
+ * @par Example
+ * The following connect condition function object can be used to output
+ * information about the individual connection attempts:
+ * @code struct my_connect_condition
+ * {
+ *   bool operator()(
+ *       const asio::error_code& ec,
+ *       const::tcp::endpoint& next)
+ *   {
+ *     if (ec) std::cout << "Error: " << ec.message() << std::endl;
+ *     std::cout << "Trying: " << next << std::endl;
+ *     return true;
+ *   }
+ * }; @endcode
+ * It would be used with the asio::connect function as follows:
+ * @code tcp::resolver r(my_context);
+ * tcp::resolver::query q("host", "service");
+ * tcp::socket s(my_context);
+ * asio::error_code ec;
+ * tcp::endpoint e = asio::connect(s,
+ *     r.resolve(q), my_connect_condition(), ec);
+ * if (ec)
+ * {
+ *   // An error occurred.
+ * }
+ * else
+ * {
+ *   std::cout << "Connected to: " << e << std::endl;
+ * } @endcode
+ */
+template <typename Protocol, typename Executor,
+    typename EndpointSequence, typename ConnectCondition>
+typename Protocol::endpoint connect(basic_socket<Protocol, Executor>& s,
+    const EndpointSequence& endpoints, ConnectCondition connect_condition,
+    asio::error_code& ec,
+    typename enable_if<is_endpoint_sequence<
+        EndpointSequence>::value>::type* = 0);
+
+#if !defined(ASIO_NO_DEPRECATED)
+/// (Deprecated: Use range overload.) Establishes a socket connection by trying
+/// each endpoint in a sequence.
+/**
+ * This function attempts to connect a socket to one of a sequence of
+ * endpoints. It does this by repeated calls to the socket's @c connect member
+ * function, once for each endpoint in the sequence, until a connection is
+ * successfully established.
+ *
+ * @param s The socket to be connected. If the socket is already open, it will
+ * be closed.
+ *
+ * @param begin An iterator pointing to the start of a sequence of endpoints.
+ *
+ * @param connect_condition A function object that is called prior to each
+ * connection attempt. The signature of the function object must be:
+ * @code bool connect_condition(
+ *     const asio::error_code& ec,
+ *     const typename Protocol::endpoint& next); @endcode
+ * The @c ec parameter contains the result from the most recent connect
+ * operation. Before the first connection attempt, @c ec is always set to
+ * indicate success. The @c next parameter is the next endpoint to be tried.
+ * The function object should return true if the next endpoint should be tried,
+ * and false if it should be skipped.
+ *
+ * @returns On success, an iterator denoting the successfully connected
+ * endpoint. Otherwise, the end iterator.
+ *
+ * @throws asio::system_error Thrown on failure. If the sequence is
+ * empty, the associated @c error_code is asio::error::not_found.
+ * Otherwise, contains the error from the last connection attempt.
+ *
+ * @note This overload assumes that a default constructed object of type @c
+ * Iterator represents the end of the sequence. This is a valid assumption for
+ * iterator types such as @c asio::ip::tcp::resolver::iterator.
+ */
+template <typename Protocol, typename Executor,
+    typename Iterator, typename ConnectCondition>
+Iterator connect(basic_socket<Protocol, Executor>& s,
+    Iterator begin, ConnectCondition connect_condition,
+    typename enable_if<!is_endpoint_sequence<Iterator>::value>::type* = 0);
+
+/// (Deprecated: Use range overload.) Establishes a socket connection by trying
+/// each endpoint in a sequence.
+/**
+ * This function attempts to connect a socket to one of a sequence of
+ * endpoints. It does this by repeated calls to the socket's @c connect member
+ * function, once for each endpoint in the sequence, until a connection is
+ * successfully established.
+ *
+ * @param s The socket to be connected. If the socket is already open, it will
+ * be closed.
+ *
+ * @param begin An iterator pointing to the start of a sequence of endpoints.
+ *
+ * @param connect_condition A function object that is called prior to each
+ * connection attempt. The signature of the function object must be:
+ * @code bool connect_condition(
+ *     const asio::error_code& ec,
+ *     const typename Protocol::endpoint& next); @endcode
+ * The @c ec parameter contains the result from the most recent connect
+ * operation. Before the first connection attempt, @c ec is always set to
+ * indicate success. The @c next parameter is the next endpoint to be tried.
+ * The function object should return true if the next endpoint should be tried,
+ * and false if it should be skipped.
+ *
+ * @param ec Set to indicate what error occurred, if any. If the sequence is
+ * empty, set to asio::error::not_found. Otherwise, contains the error
+ * from the last connection attempt.
+ *
+ * @returns On success, an iterator denoting the successfully connected
+ * endpoint. Otherwise, the end iterator.
+ *
+ * @note This overload assumes that a default constructed object of type @c
+ * Iterator represents the end of the sequence. This is a valid assumption for
+ * iterator types such as @c asio::ip::tcp::resolver::iterator.
+ */
+template <typename Protocol, typename Executor,
+    typename Iterator, typename ConnectCondition>
+Iterator connect(basic_socket<Protocol, Executor>& s, Iterator begin,
+    ConnectCondition connect_condition, asio::error_code& ec,
+    typename enable_if<!is_endpoint_sequence<Iterator>::value>::type* = 0);
+#endif // !defined(ASIO_NO_DEPRECATED)
+
+/// Establishes a socket connection by trying each endpoint in a sequence.
+/**
+ * This function attempts to connect a socket to one of a sequence of
+ * endpoints. It does this by repeated calls to the socket's @c connect member
+ * function, once for each endpoint in the sequence, until a connection is
+ * successfully established.
+ *
+ * @param s The socket to be connected. If the socket is already open, it will
+ * be closed.
+ *
+ * @param begin An iterator pointing to the start of a sequence of endpoints.
+ *
+ * @param end An iterator pointing to the end of a sequence of endpoints.
+ *
+ * @param connect_condition A function object that is called prior to each
+ * connection attempt. The signature of the function object must be:
+ * @code bool connect_condition(
+ *     const asio::error_code& ec,
+ *     const typename Protocol::endpoint& next); @endcode
+ * The @c ec parameter contains the result from the most recent connect
+ * operation. Before the first connection attempt, @c ec is always set to
+ * indicate success. The @c next parameter is the next endpoint to be tried.
+ * The function object should return true if the next endpoint should be tried,
+ * and false if it should be skipped.
+ *
+ * @returns An iterator denoting the successfully connected endpoint.
+ *
+ * @throws asio::system_error Thrown on failure. If the sequence is
+ * empty, the associated @c error_code is asio::error::not_found.
+ * Otherwise, contains the error from the last connection attempt.
+ *
+ * @par Example
+ * The following connect condition function object can be used to output
+ * information about the individual connection attempts:
+ * @code struct my_connect_condition
+ * {
+ *   bool operator()(
+ *       const asio::error_code& ec,
+ *       const::tcp::endpoint& next)
+ *   {
+ *     if (ec) std::cout << "Error: " << ec.message() << std::endl;
+ *     std::cout << "Trying: " << next << std::endl;
+ *     return true;
+ *   }
+ * }; @endcode
+ * It would be used with the asio::connect function as follows:
+ * @code tcp::resolver r(my_context);
+ * tcp::resolver::query q("host", "service");
+ * tcp::resolver::results_type e = r.resolve(q);
+ * tcp::socket s(my_context);
+ * tcp::resolver::results_type::iterator i = asio::connect(
+ *     s, e.begin(), e.end(), my_connect_condition());
+ * std::cout << "Connected to: " << i->endpoint() << std::endl; @endcode
+ */
+template <typename Protocol, typename Executor,
+    typename Iterator, typename ConnectCondition>
+Iterator connect(basic_socket<Protocol, Executor>& s, Iterator begin,
+    Iterator end, ConnectCondition connect_condition);
+
+/// Establishes a socket connection by trying each endpoint in a sequence.
+/**
+ * This function attempts to connect a socket to one of a sequence of
+ * endpoints. It does this by repeated calls to the socket's @c connect member
+ * function, once for each endpoint in the sequence, until a connection is
+ * successfully established.
+ *
+ * @param s The socket to be connected. If the socket is already open, it will
+ * be closed.
+ *
+ * @param begin An iterator pointing to the start of a sequence of endpoints.
+ *
+ * @param end An iterator pointing to the end of a sequence of endpoints.
+ *
+ * @param connect_condition A function object that is called prior to each
+ * connection attempt. The signature of the function object must be:
+ * @code bool connect_condition(
+ *     const asio::error_code& ec,
+ *     const typename Protocol::endpoint& next); @endcode
+ * The @c ec parameter contains the result from the most recent connect
+ * operation. Before the first connection attempt, @c ec is always set to
+ * indicate success. The @c next parameter is the next endpoint to be tried.
+ * The function object should return true if the next endpoint should be tried,
+ * and false if it should be skipped.
+ *
+ * @param ec Set to indicate what error occurred, if any. If the sequence is
+ * empty, set to asio::error::not_found. Otherwise, contains the error
+ * from the last connection attempt.
+ *
+ * @returns On success, an iterator denoting the successfully connected
+ * endpoint. Otherwise, the end iterator.
+ *
+ * @par Example
+ * The following connect condition function object can be used to output
+ * information about the individual connection attempts:
+ * @code struct my_connect_condition
+ * {
+ *   bool operator()(
+ *       const asio::error_code& ec,
+ *       const::tcp::endpoint& next)
+ *   {
+ *     if (ec) std::cout << "Error: " << ec.message() << std::endl;
+ *     std::cout << "Trying: " << next << std::endl;
+ *     return true;
+ *   }
+ * }; @endcode
+ * It would be used with the asio::connect function as follows:
+ * @code tcp::resolver r(my_context);
+ * tcp::resolver::query q("host", "service");
+ * tcp::resolver::results_type e = r.resolve(q);
+ * tcp::socket s(my_context);
+ * asio::error_code ec;
+ * tcp::resolver::results_type::iterator i = asio::connect(
+ *     s, e.begin(), e.end(), my_connect_condition());
+ * if (ec)
+ * {
+ *   // An error occurred.
+ * }
+ * else
+ * {
+ *   std::cout << "Connected to: " << i->endpoint() << std::endl;
+ * } @endcode
+ */
+template <typename Protocol, typename Executor,
+    typename Iterator, typename ConnectCondition>
+Iterator connect(basic_socket<Protocol, Executor>& s,
+    Iterator begin, Iterator end, ConnectCondition connect_condition,
+    asio::error_code& ec);
+
+/*@}*/
+
+/**
+ * @defgroup async_connect asio::async_connect
+ *
+ * @brief The @c async_connect function is a composed asynchronous operation
+ * that establishes a socket connection by trying each endpoint in a sequence.
+ */
+/*@{*/
+
+/// Asynchronously establishes a socket connection by trying each endpoint in a
+/// sequence.
+/**
+ * This function attempts to connect a socket to one of a sequence of
+ * endpoints. It does this by repeated calls to the socket's @c async_connect
+ * member function, once for each endpoint in the sequence, until a connection
+ * is successfully established.
+ *
+ * @param s The socket to be connected. If the socket is already open, it will
+ * be closed.
+ *
+ * @param endpoints A sequence of endpoints.
+ *
+ * @param handler The handler to be called when the connect operation
+ * completes. Copies will be made of the handler as required. The function
+ * signature of the handler must be:
+ * @code void handler(
+ *   // Result of operation. if the sequence is empty, set to
+ *   // asio::error::not_found. Otherwise, contains the
+ *   // error from the last connection attempt.
+ *   const asio::error_code& error,
+ *
+ *   // On success, the successfully connected endpoint.
+ *   // Otherwise, a default-constructed endpoint.
+ *   const typename Protocol::endpoint& endpoint
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. On
+ * immediate completion, invocation of the handler will be performed in a
+ * manner equivalent to using asio::post().
+ *
+ * @par Example
+ * @code tcp::resolver r(my_context);
+ * tcp::resolver::query q("host", "service");
+ * tcp::socket s(my_context);
+ *
+ * // ...
+ *
+ * r.async_resolve(q, resolve_handler);
+ *
+ * // ...
+ *
+ * void resolve_handler(
+ *     const asio::error_code& ec,
+ *     tcp::resolver::results_type results)
+ * {
+ *   if (!ec)
+ *   {
+ *     asio::async_connect(s, results, connect_handler);
+ *   }
+ * }
+ *
+ * // ...
+ *
+ * void connect_handler(
+ *     const asio::error_code& ec,
+ *     const tcp::endpoint& endpoint)
+ * {
+ *   // ...
+ * } @endcode
+ */
+template <typename Protocol, typename Executor, typename EndpointSequence,
+    ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+      typename Protocol::endpoint)) RangeConnectHandler
+        ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(Executor)>
+ASIO_INITFN_AUTO_RESULT_TYPE(RangeConnectHandler,
+    void (asio::error_code, typename Protocol::endpoint))
+async_connect(basic_socket<Protocol, Executor>& s,
+    const EndpointSequence& endpoints,
+    ASIO_MOVE_ARG(RangeConnectHandler) handler
+      ASIO_DEFAULT_COMPLETION_TOKEN(Executor),
+    typename enable_if<is_endpoint_sequence<
+        EndpointSequence>::value>::type* = 0);
+
+#if !defined(ASIO_NO_DEPRECATED)
+/// (Deprecated: Use range overload.) Asynchronously establishes a socket
+/// connection by trying each endpoint in a sequence.
+/**
+ * This function attempts to connect a socket to one of a sequence of
+ * endpoints. It does this by repeated calls to the socket's @c async_connect
+ * member function, once for each endpoint in the sequence, until a connection
+ * is successfully established.
+ *
+ * @param s The socket to be connected. If the socket is already open, it will
+ * be closed.
+ *
+ * @param begin An iterator pointing to the start of a sequence of endpoints.
+ *
+ * @param handler The handler to be called when the connect operation
+ * completes. Copies will be made of the handler as required. The function
+ * signature of the handler must be:
+ * @code void handler(
+ *   // Result of operation. if the sequence is empty, set to
+ *   // asio::error::not_found. Otherwise, contains the
+ *   // error from the last connection attempt.
+ *   const asio::error_code& error,
+ *
+ *   // On success, an iterator denoting the successfully
+ *   // connected endpoint. Otherwise, the end iterator.
+ *   Iterator iterator
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. On
+ * immediate completion, invocation of the handler will be performed in a
+ * manner equivalent to using asio::post().
+ *
+ * @note This overload assumes that a default constructed object of type @c
+ * Iterator represents the end of the sequence. This is a valid assumption for
+ * iterator types such as @c asio::ip::tcp::resolver::iterator.
+ */
+template <typename Protocol, typename Executor, typename Iterator,
+    ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+      Iterator)) IteratorConnectHandler
+        ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(Executor)>
+ASIO_INITFN_AUTO_RESULT_TYPE(IteratorConnectHandler,
+    void (asio::error_code, Iterator))
+async_connect(basic_socket<Protocol, Executor>& s, Iterator begin,
+    ASIO_MOVE_ARG(IteratorConnectHandler) handler
+      ASIO_DEFAULT_COMPLETION_TOKEN(Executor),
+    typename enable_if<!is_endpoint_sequence<Iterator>::value>::type* = 0);
+#endif // !defined(ASIO_NO_DEPRECATED)
+
+/// Asynchronously establishes a socket connection by trying each endpoint in a
+/// sequence.
+/**
+ * This function attempts to connect a socket to one of a sequence of
+ * endpoints. It does this by repeated calls to the socket's @c async_connect
+ * member function, once for each endpoint in the sequence, until a connection
+ * is successfully established.
+ *
+ * @param s The socket to be connected. If the socket is already open, it will
+ * be closed.
+ *
+ * @param begin An iterator pointing to the start of a sequence of endpoints.
+ *
+ * @param end An iterator pointing to the end of a sequence of endpoints.
+ *
+ * @param handler The handler to be called when the connect operation
+ * completes. Copies will be made of the handler as required. The function
+ * signature of the handler must be:
+ * @code void handler(
+ *   // Result of operation. if the sequence is empty, set to
+ *   // asio::error::not_found. Otherwise, contains the
+ *   // error from the last connection attempt.
+ *   const asio::error_code& error,
+ *
+ *   // On success, an iterator denoting the successfully
+ *   // connected endpoint. Otherwise, the end iterator.
+ *   Iterator iterator
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. On
+ * immediate completion, invocation of the handler will be performed in a
+ * manner equivalent to using asio::post().
+ *
+ * @par Example
+ * @code std::vector<tcp::endpoint> endpoints = ...;
+ * tcp::socket s(my_context);
+ * asio::async_connect(s,
+ *     endpoints.begin(), endpoints.end(),
+ *     connect_handler);
+ *
+ * // ...
+ *
+ * void connect_handler(
+ *     const asio::error_code& ec,
+ *     std::vector<tcp::endpoint>::iterator i)
+ * {
+ *   // ...
+ * } @endcode
+ */
+template <typename Protocol, typename Executor, typename Iterator,
+    ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+      Iterator)) IteratorConnectHandler
+        ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(Executor)>
+ASIO_INITFN_AUTO_RESULT_TYPE(IteratorConnectHandler,
+    void (asio::error_code, Iterator))
+async_connect(basic_socket<Protocol, Executor>& s, Iterator begin, Iterator end,
+    ASIO_MOVE_ARG(IteratorConnectHandler) handler
+      ASIO_DEFAULT_COMPLETION_TOKEN(Executor));
+
+/// Asynchronously establishes a socket connection by trying each endpoint in a
+/// sequence.
+/**
+ * This function attempts to connect a socket to one of a sequence of
+ * endpoints. It does this by repeated calls to the socket's @c async_connect
+ * member function, once for each endpoint in the sequence, until a connection
+ * is successfully established.
+ *
+ * @param s The socket to be connected. If the socket is already open, it will
+ * be closed.
+ *
+ * @param endpoints A sequence of endpoints.
+ *
+ * @param connect_condition A function object that is called prior to each
+ * connection attempt. The signature of the function object must be:
+ * @code bool connect_condition(
+ *     const asio::error_code& ec,
+ *     const typename Protocol::endpoint& next); @endcode
+ * The @c ec parameter contains the result from the most recent connect
+ * operation. Before the first connection attempt, @c ec is always set to
+ * indicate success. The @c next parameter is the next endpoint to be tried.
+ * The function object should return true if the next endpoint should be tried,
+ * and false if it should be skipped.
+ *
+ * @param handler The handler to be called when the connect operation
+ * completes. Copies will be made of the handler as required. The function
+ * signature of the handler must be:
+ * @code void handler(
+ *   // Result of operation. if the sequence is empty, set to
+ *   // asio::error::not_found. Otherwise, contains the
+ *   // error from the last connection attempt.
+ *   const asio::error_code& error,
+ *
+ *   // On success, an iterator denoting the successfully
+ *   // connected endpoint. Otherwise, the end iterator.
+ *   Iterator iterator
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. On
+ * immediate completion, invocation of the handler will be performed in a
+ * manner equivalent to using asio::post().
+ *
+ * @par Example
+ * The following connect condition function object can be used to output
+ * information about the individual connection attempts:
+ * @code struct my_connect_condition
+ * {
+ *   bool operator()(
+ *       const asio::error_code& ec,
+ *       const::tcp::endpoint& next)
+ *   {
+ *     if (ec) std::cout << "Error: " << ec.message() << std::endl;
+ *     std::cout << "Trying: " << next << std::endl;
+ *     return true;
+ *   }
+ * }; @endcode
+ * It would be used with the asio::connect function as follows:
+ * @code tcp::resolver r(my_context);
+ * tcp::resolver::query q("host", "service");
+ * tcp::socket s(my_context);
+ *
+ * // ...
+ *
+ * r.async_resolve(q, resolve_handler);
+ *
+ * // ...
+ *
+ * void resolve_handler(
+ *     const asio::error_code& ec,
+ *     tcp::resolver::results_type results)
+ * {
+ *   if (!ec)
+ *   {
+ *     asio::async_connect(s, results,
+ *         my_connect_condition(),
+ *         connect_handler);
+ *   }
+ * }
+ *
+ * // ...
+ *
+ * void connect_handler(
+ *     const asio::error_code& ec,
+ *     const tcp::endpoint& endpoint)
+ * {
+ *   if (ec)
+ *   {
+ *     // An error occurred.
+ *   }
+ *   else
+ *   {
+ *     std::cout << "Connected to: " << endpoint << std::endl;
+ *   }
+ * } @endcode
+ */
+template <typename Protocol, typename Executor,
+    typename EndpointSequence, typename ConnectCondition,
+    ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+      typename Protocol::endpoint)) RangeConnectHandler
+        ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(Executor)>
+ASIO_INITFN_AUTO_RESULT_TYPE(RangeConnectHandler,
+    void (asio::error_code, typename Protocol::endpoint))
+async_connect(basic_socket<Protocol, Executor>& s,
+    const EndpointSequence& endpoints, ConnectCondition connect_condition,
+    ASIO_MOVE_ARG(RangeConnectHandler) handler
+      ASIO_DEFAULT_COMPLETION_TOKEN(Executor),
+    typename enable_if<is_endpoint_sequence<
+        EndpointSequence>::value>::type* = 0);
+
+#if !defined(ASIO_NO_DEPRECATED)
+/// (Deprecated: Use range overload.) Asynchronously establishes a socket
+/// connection by trying each endpoint in a sequence.
+/**
+ * This function attempts to connect a socket to one of a sequence of
+ * endpoints. It does this by repeated calls to the socket's @c async_connect
+ * member function, once for each endpoint in the sequence, until a connection
+ * is successfully established.
+ *
+ * @param s The socket to be connected. If the socket is already open, it will
+ * be closed.
+ *
+ * @param begin An iterator pointing to the start of a sequence of endpoints.
+ *
+ * @param connect_condition A function object that is called prior to each
+ * connection attempt. The signature of the function object must be:
+ * @code bool connect_condition(
+ *     const asio::error_code& ec,
+ *     const typename Protocol::endpoint& next); @endcode
+ * The @c ec parameter contains the result from the most recent connect
+ * operation. Before the first connection attempt, @c ec is always set to
+ * indicate success. The @c next parameter is the next endpoint to be tried.
+ * The function object should return true if the next endpoint should be tried,
+ * and false if it should be skipped.
+ *
+ * @param handler The handler to be called when the connect operation
+ * completes. Copies will be made of the handler as required. The function
+ * signature of the handler must be:
+ * @code void handler(
+ *   // Result of operation. if the sequence is empty, set to
+ *   // asio::error::not_found. Otherwise, contains the
+ *   // error from the last connection attempt.
+ *   const asio::error_code& error,
+ *
+ *   // On success, an iterator denoting the successfully
+ *   // connected endpoint. Otherwise, the end iterator.
+ *   Iterator iterator
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. On
+ * immediate completion, invocation of the handler will be performed in a
+ * manner equivalent to using asio::post().
+ *
+ * @note This overload assumes that a default constructed object of type @c
+ * Iterator represents the end of the sequence. This is a valid assumption for
+ * iterator types such as @c asio::ip::tcp::resolver::iterator.
+ */
+template <typename Protocol, typename Executor,
+    typename Iterator, typename ConnectCondition,
+    ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+      Iterator)) IteratorConnectHandler
+        ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(Executor)>
+ASIO_INITFN_AUTO_RESULT_TYPE(IteratorConnectHandler,
+    void (asio::error_code, Iterator))
+async_connect(basic_socket<Protocol, Executor>& s, Iterator begin,
+    ConnectCondition connect_condition,
+    ASIO_MOVE_ARG(IteratorConnectHandler) handler
+      ASIO_DEFAULT_COMPLETION_TOKEN(Executor),
+    typename enable_if<!is_endpoint_sequence<Iterator>::value>::type* = 0);
+#endif // !defined(ASIO_NO_DEPRECATED)
+
+/// Asynchronously establishes a socket connection by trying each endpoint in a
+/// sequence.
+/**
+ * This function attempts to connect a socket to one of a sequence of
+ * endpoints. It does this by repeated calls to the socket's @c async_connect
+ * member function, once for each endpoint in the sequence, until a connection
+ * is successfully established.
+ *
+ * @param s The socket to be connected. If the socket is already open, it will
+ * be closed.
+ *
+ * @param begin An iterator pointing to the start of a sequence of endpoints.
+ *
+ * @param end An iterator pointing to the end of a sequence of endpoints.
+ *
+ * @param connect_condition A function object that is called prior to each
+ * connection attempt. The signature of the function object must be:
+ * @code bool connect_condition(
+ *     const asio::error_code& ec,
+ *     const typename Protocol::endpoint& next); @endcode
+ * The @c ec parameter contains the result from the most recent connect
+ * operation. Before the first connection attempt, @c ec is always set to
+ * indicate success. The @c next parameter is the next endpoint to be tried.
+ * The function object should return true if the next endpoint should be tried,
+ * and false if it should be skipped.
+ *
+ * @param handler The handler to be called when the connect operation
+ * completes. Copies will be made of the handler as required. The function
+ * signature of the handler must be:
+ * @code void handler(
+ *   // Result of operation. if the sequence is empty, set to
+ *   // asio::error::not_found. Otherwise, contains the
+ *   // error from the last connection attempt.
+ *   const asio::error_code& error,
+ *
+ *   // On success, an iterator denoting the successfully
+ *   // connected endpoint. Otherwise, the end iterator.
+ *   Iterator iterator
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. On
+ * immediate completion, invocation of the handler will be performed in a
+ * manner equivalent to using asio::post().
+ *
+ * @par Example
+ * The following connect condition function object can be used to output
+ * information about the individual connection attempts:
+ * @code struct my_connect_condition
+ * {
+ *   bool operator()(
+ *       const asio::error_code& ec,
+ *       const::tcp::endpoint& next)
+ *   {
+ *     if (ec) std::cout << "Error: " << ec.message() << std::endl;
+ *     std::cout << "Trying: " << next << std::endl;
+ *     return true;
+ *   }
+ * }; @endcode
+ * It would be used with the asio::connect function as follows:
+ * @code tcp::resolver r(my_context);
+ * tcp::resolver::query q("host", "service");
+ * tcp::socket s(my_context);
+ *
+ * // ...
+ *
+ * r.async_resolve(q, resolve_handler);
+ *
+ * // ...
+ *
+ * void resolve_handler(
+ *     const asio::error_code& ec,
+ *     tcp::resolver::iterator i)
+ * {
+ *   if (!ec)
+ *   {
+ *     tcp::resolver::iterator end;
+ *     asio::async_connect(s, i, end,
+ *         my_connect_condition(),
+ *         connect_handler);
+ *   }
+ * }
+ *
+ * // ...
+ *
+ * void connect_handler(
+ *     const asio::error_code& ec,
+ *     tcp::resolver::iterator i)
+ * {
+ *   if (ec)
+ *   {
+ *     // An error occurred.
+ *   }
+ *   else
+ *   {
+ *     std::cout << "Connected to: " << i->endpoint() << std::endl;
+ *   }
+ * } @endcode
+ */
+template <typename Protocol, typename Executor,
+    typename Iterator, typename ConnectCondition,
+    ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+      Iterator)) IteratorConnectHandler
+        ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(Executor)>
+ASIO_INITFN_AUTO_RESULT_TYPE(IteratorConnectHandler,
+    void (asio::error_code, Iterator))
+async_connect(basic_socket<Protocol, Executor>& s, Iterator begin,
+    Iterator end, ConnectCondition connect_condition,
+    ASIO_MOVE_ARG(IteratorConnectHandler) handler
+      ASIO_DEFAULT_COMPLETION_TOKEN(Executor));
+
+/*@}*/
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/impl/connect.hpp"
+
+#endif
diff --git a/link/modules/asio-standalone/asio/include/asio/coroutine.hpp b/link/modules/asio-standalone/asio/include/asio/coroutine.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/coroutine.hpp
@@ -0,0 +1,328 @@
+//
+// coroutine.hpp
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_COROUTINE_HPP
+#define ASIO_COROUTINE_HPP
+
+namespace asio {
+namespace detail {
+
+class coroutine_ref;
+
+} // namespace detail
+
+/// Provides support for implementing stackless coroutines.
+/**
+ * The @c coroutine class may be used to implement stackless coroutines. The
+ * class itself is used to store the current state of the coroutine.
+ *
+ * Coroutines are copy-constructible and assignable, and the space overhead is
+ * a single int. They can be used as a base class:
+ *
+ * @code class session : coroutine
+ * {
+ *   ...
+ * }; @endcode
+ *
+ * or as a data member:
+ *
+ * @code class session
+ * {
+ *   ...
+ *   coroutine coro_;
+ * }; @endcode
+ *
+ * or even bound in as a function argument using lambdas or @c bind(). The
+ * important thing is that as the application maintains a copy of the object
+ * for as long as the coroutine must be kept alive.
+ *
+ * @par Pseudo-keywords
+ *
+ * A coroutine is used in conjunction with certain "pseudo-keywords", which
+ * are implemented as macros. These macros are defined by a header file:
+ *
+ * @code #include <asio/yield.hpp>@endcode
+ *
+ * and may conversely be undefined as follows:
+ *
+ * @code #include <asio/unyield.hpp>@endcode
+ *
+ * <b>reenter</b>
+ *
+ * The @c reenter macro is used to define the body of a coroutine. It takes a
+ * single argument: a pointer or reference to a coroutine object. For example,
+ * if the base class is a coroutine object you may write:
+ *
+ * @code reenter (this)
+ * {
+ *   ... coroutine body ...
+ * } @endcode
+ *
+ * and if a data member or other variable you can write:
+ *
+ * @code reenter (coro_)
+ * {
+ *   ... coroutine body ...
+ * } @endcode
+ *
+ * When @c reenter is executed at runtime, control jumps to the location of the
+ * last @c yield or @c fork.
+ *
+ * The coroutine body may also be a single statement, such as:
+ *
+ * @code reenter (this) for (;;)
+ * {
+ *   ...
+ * } @endcode
+ *
+ * @b Limitation: The @c reenter macro is implemented using a switch. This
+ * means that you must take care when using local variables within the
+ * coroutine body. The local variable is not allowed in a position where
+ * reentering the coroutine could bypass the variable definition.
+ *
+ * <b>yield <em>statement</em></b>
+ *
+ * This form of the @c yield keyword is often used with asynchronous operations:
+ *
+ * @code yield socket_->async_read_some(buffer(*buffer_), *this); @endcode
+ *
+ * This divides into four logical steps:
+ *
+ * @li @c yield saves the current state of the coroutine.
+ * @li The statement initiates the asynchronous operation.
+ * @li The resume point is defined immediately following the statement.
+ * @li Control is transferred to the end of the coroutine body.
+ *
+ * When the asynchronous operation completes, the function object is invoked
+ * and @c reenter causes control to transfer to the resume point. It is
+ * important to remember to carry the coroutine state forward with the
+ * asynchronous operation. In the above snippet, the current class is a
+ * function object object with a coroutine object as base class or data member.
+ *
+ * The statement may also be a compound statement, and this permits us to
+ * define local variables with limited scope:
+ *
+ * @code yield
+ * {
+ *   mutable_buffers_1 b = buffer(*buffer_);
+ *   socket_->async_read_some(b, *this);
+ * } @endcode
+ *
+ * <b>yield return <em>expression</em> ;</b>
+ *
+ * This form of @c yield is often used in generators or coroutine-based parsers.
+ * For example, the function object:
+ *
+ * @code struct interleave : coroutine
+ * {
+ *   istream& is1;
+ *   istream& is2;
+ *   char operator()(char c)
+ *   {
+ *     reenter (this) for (;;)
+ *     {
+ *       yield return is1.get();
+ *       yield return is2.get();
+ *     }
+ *   }
+ * }; @endcode
+ *
+ * defines a trivial coroutine that interleaves the characters from two input
+ * streams.
+ *
+ * This type of @c yield divides into three logical steps:
+ *
+ * @li @c yield saves the current state of the coroutine.
+ * @li The resume point is defined immediately following the semicolon.
+ * @li The value of the expression is returned from the function.
+ *
+ * <b>yield ;</b>
+ *
+ * This form of @c yield is equivalent to the following steps:
+ *
+ * @li @c yield saves the current state of the coroutine.
+ * @li The resume point is defined immediately following the semicolon.
+ * @li Control is transferred to the end of the coroutine body.
+ *
+ * This form might be applied when coroutines are used for cooperative
+ * threading and scheduling is explicitly managed. For example:
+ *
+ * @code struct task : coroutine
+ * {
+ *   ...
+ *   void operator()()
+ *   {
+ *     reenter (this)
+ *     {
+ *       while (... not finished ...)
+ *       {
+ *         ... do something ...
+ *         yield;
+ *         ... do some more ...
+ *         yield;
+ *       }
+ *     }
+ *   }
+ *   ...
+ * };
+ * ...
+ * task t1, t2;
+ * for (;;)
+ * {
+ *   t1();
+ *   t2();
+ * } @endcode
+ *
+ * <b>yield break ;</b>
+ *
+ * The final form of @c yield is used to explicitly terminate the coroutine.
+ * This form is comprised of two steps:
+ *
+ * @li @c yield sets the coroutine state to indicate termination.
+ * @li Control is transferred to the end of the coroutine body.
+ *
+ * Once terminated, calls to is_complete() return true and the coroutine cannot
+ * be reentered.
+ *
+ * Note that a coroutine may also be implicitly terminated if the coroutine
+ * body is exited without a yield, e.g. by return, throw or by running to the
+ * end of the body.
+ *
+ * <b>fork <em>statement</em></b>
+ *
+ * The @c fork pseudo-keyword is used when "forking" a coroutine, i.e. splitting
+ * it into two (or more) copies. One use of @c fork is in a server, where a new
+ * coroutine is created to handle each client connection:
+ * 
+ * @code reenter (this)
+ * {
+ *   do
+ *   {
+ *     socket_.reset(new tcp::socket(my_context_));
+ *     yield acceptor->async_accept(*socket_, *this);
+ *     fork server(*this)();
+ *   } while (is_parent());
+ *   ... client-specific handling follows ...
+ * } @endcode
+ * 
+ * The logical steps involved in a @c fork are:
+ * 
+ * @li @c fork saves the current state of the coroutine.
+ * @li The statement creates a copy of the coroutine and either executes it
+ *     immediately or schedules it for later execution.
+ * @li The resume point is defined immediately following the semicolon.
+ * @li For the "parent", control immediately continues from the next line.
+ *
+ * The functions is_parent() and is_child() can be used to differentiate
+ * between parent and child. You would use these functions to alter subsequent
+ * control flow.
+ *
+ * Note that @c fork doesn't do the actual forking by itself. It is the
+ * application's responsibility to create a clone of the coroutine and call it.
+ * The clone can be called immediately, as above, or scheduled for delayed
+ * execution using something like asio::post().
+ *
+ * @par Alternate macro names
+ *
+ * If preferred, an application can use macro names that follow a more typical
+ * naming convention, rather than the pseudo-keywords. These are:
+ *
+ * @li @c ASIO_CORO_REENTER instead of @c reenter
+ * @li @c ASIO_CORO_YIELD instead of @c yield
+ * @li @c ASIO_CORO_FORK instead of @c fork
+ */
+class coroutine
+{
+public:
+  /// Constructs a coroutine in its initial state.
+  coroutine() : value_(0) {}
+
+  /// Returns true if the coroutine is the child of a fork.
+  bool is_child() const { return value_ < 0; }
+
+  /// Returns true if the coroutine is the parent of a fork.
+  bool is_parent() const { return !is_child(); }
+
+  /// Returns true if the coroutine has reached its terminal state.
+  bool is_complete() const { return value_ == -1; }
+
+private:
+  friend class detail::coroutine_ref;
+  int value_;
+};
+
+
+namespace detail {
+
+class coroutine_ref
+{
+public:
+  coroutine_ref(coroutine& c) : value_(c.value_), modified_(false) {}
+  coroutine_ref(coroutine* c) : value_(c->value_), modified_(false) {}
+  ~coroutine_ref() { if (!modified_) value_ = -1; }
+  operator int() const { return value_; }
+  int& operator=(int v) { modified_ = true; return value_ = v; }
+private:
+  void operator=(const coroutine_ref&);
+  int& value_;
+  bool modified_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#define ASIO_CORO_REENTER(c) \
+  switch (::asio::detail::coroutine_ref _coro_value = c) \
+    case -1: if (_coro_value) \
+    { \
+      goto terminate_coroutine; \
+      terminate_coroutine: \
+      _coro_value = -1; \
+      goto bail_out_of_coroutine; \
+      bail_out_of_coroutine: \
+      break; \
+    } \
+    else /* fall-through */ case 0:
+
+#define ASIO_CORO_YIELD_IMPL(n) \
+  for (_coro_value = (n);;) \
+    if (_coro_value == 0) \
+    { \
+      case (n): ; \
+      break; \
+    } \
+    else \
+      switch (_coro_value ? 0 : 1) \
+        for (;;) \
+          /* fall-through */ case -1: if (_coro_value) \
+            goto terminate_coroutine; \
+          else for (;;) \
+            /* fall-through */ case 1: if (_coro_value) \
+              goto bail_out_of_coroutine; \
+            else /* fall-through */ case 0:
+
+#define ASIO_CORO_FORK_IMPL(n) \
+  for (_coro_value = -(n);; _coro_value = (n)) \
+    if (_coro_value == (n)) \
+    { \
+      case -(n): ; \
+      break; \
+    } \
+    else
+
+#if defined(_MSC_VER)
+# define ASIO_CORO_YIELD ASIO_CORO_YIELD_IMPL(__COUNTER__ + 1)
+# define ASIO_CORO_FORK ASIO_CORO_FORK_IMPL(__COUNTER__ + 1)
+#else // defined(_MSC_VER)
+# define ASIO_CORO_YIELD ASIO_CORO_YIELD_IMPL(__LINE__)
+# define ASIO_CORO_FORK ASIO_CORO_FORK_IMPL(__LINE__)
+#endif // defined(_MSC_VER)
+
+#endif // ASIO_COROUTINE_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/deadline_timer.hpp b/link/modules/asio-standalone/asio/include/asio/deadline_timer.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/deadline_timer.hpp
@@ -0,0 +1,38 @@
+//
+// deadline_timer.hpp
+// ~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DEADLINE_TIMER_HPP
+#define ASIO_DEADLINE_TIMER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_BOOST_DATE_TIME) \
+  || defined(GENERATING_DOCUMENTATION)
+
+#include "asio/detail/socket_types.hpp" // Must come before posix_time.
+#include "asio/basic_deadline_timer.hpp"
+
+#include <boost/date_time/posix_time/posix_time_types.hpp>
+
+namespace asio {
+
+/// Typedef for the typical usage of timer. Uses a UTC clock.
+typedef basic_deadline_timer<boost::posix_time::ptime> deadline_timer;
+
+} // namespace asio
+
+#endif // defined(ASIO_HAS_BOOST_DATE_TIME)
+       // || defined(GENERATING_DOCUMENTATION)
+
+#endif // ASIO_DEADLINE_TIMER_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/defer.hpp b/link/modules/asio-standalone/asio/include/asio/defer.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/defer.hpp
@@ -0,0 +1,130 @@
+//
+// defer.hpp
+// ~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DEFER_HPP
+#define ASIO_DEFER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/async_result.hpp"
+#include "asio/detail/type_traits.hpp"
+#include "asio/execution_context.hpp"
+#include "asio/execution/executor.hpp"
+#include "asio/is_executor.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+/// Submits a completion token or function object for execution.
+/**
+ * This function submits an object for execution using the object's associated
+ * executor. The function object is queued for execution, and is never called
+ * from the current thread prior to returning from <tt>defer()</tt>.
+ *
+ * The use of @c defer(), rather than @ref post(), indicates the caller's
+ * preference that the executor defer the queueing of the function object. This
+ * may allow the executor to optimise queueing for cases when the function
+ * object represents a continuation of the current call context.
+ *
+ * This function has the following effects:
+ *
+ * @li Constructs a function object handler of type @c Handler, initialized
+ * with <tt>handler(forward<CompletionToken>(token))</tt>.
+ *
+ * @li Constructs an object @c result of type <tt>async_result<Handler></tt>,
+ * initializing the object as <tt>result(handler)</tt>.
+ *
+ * @li Obtains the handler's associated executor object @c ex by performing
+ * <tt>get_associated_executor(handler)</tt>.
+ *
+ * @li Obtains the handler's associated allocator object @c alloc by performing
+ * <tt>get_associated_allocator(handler)</tt>.
+ *
+ * @li Performs <tt>ex.defer(std::move(handler), alloc)</tt>.
+ *
+ * @li Returns <tt>result.get()</tt>.
+ */
+template <ASIO_COMPLETION_TOKEN_FOR(void()) CompletionToken>
+ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void()) defer(
+    ASIO_MOVE_ARG(CompletionToken) token);
+
+/// Submits a completion token or function object for execution.
+/**
+ * This function submits an object for execution using the specified executor.
+ * The function object is queued for execution, and is never called from the
+ * current thread prior to returning from <tt>defer()</tt>.
+ *
+ * The use of @c defer(), rather than @ref post(), indicates the caller's
+ * preference that the executor defer the queueing of the function object. This
+ * may allow the executor to optimise queueing for cases when the function
+ * object represents a continuation of the current call context.
+ *
+ * This function has the following effects:
+ *
+ * @li Constructs a function object handler of type @c Handler, initialized
+ * with <tt>handler(forward<CompletionToken>(token))</tt>.
+ *
+ * @li Constructs an object @c result of type <tt>async_result<Handler></tt>,
+ * initializing the object as <tt>result(handler)</tt>.
+ *
+ * @li Obtains the handler's associated executor object @c ex1 by performing
+ * <tt>get_associated_executor(handler)</tt>.
+ *
+ * @li Creates a work object @c w by performing <tt>make_work(ex1)</tt>.
+ *
+ * @li Obtains the handler's associated allocator object @c alloc by performing
+ * <tt>get_associated_allocator(handler)</tt>.
+ *
+ * @li Constructs a function object @c f with a function call operator that
+ * performs <tt>ex1.dispatch(std::move(handler), alloc)</tt> followed by
+ * <tt>w.reset()</tt>.
+ *
+ * @li Performs <tt>Executor(ex).defer(std::move(f), alloc)</tt>.
+ *
+ * @li Returns <tt>result.get()</tt>.
+ */
+template <typename Executor,
+    ASIO_COMPLETION_TOKEN_FOR(void()) CompletionToken
+      ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(Executor)>
+ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void()) defer(
+    const Executor& ex,
+    ASIO_MOVE_ARG(CompletionToken) token
+      ASIO_DEFAULT_COMPLETION_TOKEN(Executor),
+    typename enable_if<
+      execution::is_executor<Executor>::value || is_executor<Executor>::value
+    >::type* = 0);
+
+/// Submits a completion token or function object for execution.
+/**
+ * @returns <tt>defer(ctx.get_executor(), forward<CompletionToken>(token))</tt>.
+ */
+template <typename ExecutionContext,
+    ASIO_COMPLETION_TOKEN_FOR(void()) CompletionToken
+      ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(
+        typename ExecutionContext::executor_type)>
+ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void()) defer(
+    ExecutionContext& ctx,
+    ASIO_MOVE_ARG(CompletionToken) token
+      ASIO_DEFAULT_COMPLETION_TOKEN(
+        typename ExecutionContext::executor_type),
+    typename enable_if<is_convertible<
+      ExecutionContext&, execution_context&>::value>::type* = 0);
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/impl/defer.hpp"
+
+#endif // ASIO_DEFER_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detached.hpp b/link/modules/asio-standalone/asio/include/asio/detached.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detached.hpp
@@ -0,0 +1,112 @@
+//
+// detached.hpp
+// ~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETACHED_HPP
+#define ASIO_DETACHED_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <memory>
+#include "asio/detail/type_traits.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+/// Class used to specify that an asynchronous operation is detached.
+/**
+
+ * The detached_t class is used to indicate that an asynchronous operation is
+ * detached. That is, there is no completion handler waiting for the
+ * operation's result. A detached_t object may be passed as a handler to an
+ * asynchronous operation, typically using the special value
+ * @c asio::detached. For example:
+
+ * @code my_socket.async_send(my_buffer, asio::detached);
+ * @endcode
+ */
+class detached_t
+{
+public:
+  /// Constructor. 
+  ASIO_CONSTEXPR detached_t()
+  {
+  }
+
+  /// Adapts an executor to add the @c detached_t completion token as the
+  /// default.
+  template <typename InnerExecutor>
+  struct executor_with_default : InnerExecutor
+  {
+    /// Specify @c detached_t as the default completion token type.
+    typedef detached_t default_completion_token_type;
+
+    /// Construct the adapted executor from the inner executor type.
+    executor_with_default(const InnerExecutor& ex) ASIO_NOEXCEPT
+      : InnerExecutor(ex)
+    {
+    }
+
+    /// Convert the specified executor to the inner executor type, then use
+    /// that to construct the adapted executor.
+    template <typename OtherExecutor>
+    executor_with_default(const OtherExecutor& ex,
+        typename enable_if<
+          is_convertible<OtherExecutor, InnerExecutor>::value
+        >::type* = 0) ASIO_NOEXCEPT
+      : InnerExecutor(ex)
+    {
+    }
+  };
+
+  /// Type alias to adapt an I/O object to use @c detached_t as its
+  /// default completion token type.
+#if defined(ASIO_HAS_ALIAS_TEMPLATES) \
+  || defined(GENERATING_DOCUMENTATION)
+  template <typename T>
+  using as_default_on_t = typename T::template rebind_executor<
+      executor_with_default<typename T::executor_type> >::other;
+#endif // defined(ASIO_HAS_ALIAS_TEMPLATES)
+       //   || defined(GENERATING_DOCUMENTATION)
+
+  /// Function helper to adapt an I/O object to use @c detached_t as its
+  /// default completion token type.
+  template <typename T>
+  static typename decay<T>::type::template rebind_executor<
+      executor_with_default<typename decay<T>::type::executor_type>
+    >::other
+  as_default_on(ASIO_MOVE_ARG(T) object)
+  {
+    return typename decay<T>::type::template rebind_executor<
+        executor_with_default<typename decay<T>::type::executor_type>
+      >::other(ASIO_MOVE_CAST(T)(object));
+  }
+};
+
+/// A special value, similar to std::nothrow.
+/**
+ * See the documentation for asio::detached_t for a usage example.
+ */
+#if defined(ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION)
+constexpr detached_t detached;
+#elif defined(ASIO_MSVC)
+__declspec(selectany) detached_t detached;
+#endif
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/impl/detached.hpp"
+
+#endif // ASIO_DETACHED_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/array.hpp b/link/modules/asio-standalone/asio/include/asio/detail/array.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/array.hpp
@@ -0,0 +1,38 @@
+//
+// detail/array.hpp
+// ~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_ARRAY_HPP
+#define ASIO_DETAIL_ARRAY_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_STD_ARRAY)
+# include <array>
+#else // defined(ASIO_HAS_STD_ARRAY)
+# include <boost/array.hpp>
+#endif // defined(ASIO_HAS_STD_ARRAY)
+
+namespace asio {
+namespace detail {
+
+#if defined(ASIO_HAS_STD_ARRAY)
+using std::array;
+#else // defined(ASIO_HAS_STD_ARRAY)
+using boost::array;
+#endif // defined(ASIO_HAS_STD_ARRAY)
+
+} // namespace detail
+} // namespace asio
+
+#endif // ASIO_DETAIL_ARRAY_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/array_fwd.hpp b/link/modules/asio-standalone/asio/include/asio/detail/array_fwd.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/array_fwd.hpp
@@ -0,0 +1,34 @@
+//
+// detail/array_fwd.hpp
+// ~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_ARRAY_FWD_HPP
+#define ASIO_DETAIL_ARRAY_FWD_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+namespace boost {
+
+template<class T, std::size_t N>
+class array;
+
+} // namespace boost
+
+// Standard library components can't be forward declared, so we'll have to
+// include the array header. Fortunately, it's fairly lightweight and doesn't
+// add significantly to the compile time.
+#if defined(ASIO_HAS_STD_ARRAY)
+# include <array>
+#endif // defined(ASIO_HAS_STD_ARRAY)
+
+#endif // ASIO_DETAIL_ARRAY_FWD_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/assert.hpp b/link/modules/asio-standalone/asio/include/asio/detail/assert.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/assert.hpp
@@ -0,0 +1,32 @@
+//
+// detail/assert.hpp
+// ~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_ASSERT_HPP
+#define ASIO_DETAIL_ASSERT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_BOOST_ASSERT)
+# include <boost/assert.hpp>
+#else // defined(ASIO_HAS_BOOST_ASSERT)
+# include <cassert>
+#endif // defined(ASIO_HAS_BOOST_ASSERT)
+
+#if defined(ASIO_HAS_BOOST_ASSERT)
+# define ASIO_ASSERT(expr) BOOST_ASSERT(expr)
+#else // defined(ASIO_HAS_BOOST_ASSERT)
+# define ASIO_ASSERT(expr) assert(expr)
+#endif // defined(ASIO_HAS_BOOST_ASSERT)
+
+#endif // ASIO_DETAIL_ASSERT_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/atomic_count.hpp b/link/modules/asio-standalone/asio/include/asio/detail/atomic_count.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/atomic_count.hpp
@@ -0,0 +1,64 @@
+//
+// detail/atomic_count.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_ATOMIC_COUNT_HPP
+#define ASIO_DETAIL_ATOMIC_COUNT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if !defined(ASIO_HAS_THREADS)
+// Nothing to include.
+#elif defined(ASIO_HAS_STD_ATOMIC)
+# include <atomic>
+#else // defined(ASIO_HAS_STD_ATOMIC)
+# include <boost/detail/atomic_count.hpp>
+#endif // defined(ASIO_HAS_STD_ATOMIC)
+
+namespace asio {
+namespace detail {
+
+#if !defined(ASIO_HAS_THREADS)
+typedef long atomic_count;
+inline void increment(atomic_count& a, long b) { a += b; }
+inline void ref_count_up(atomic_count& a) { ++a; }
+inline bool ref_count_down(atomic_count& a) { return --a == 0; }
+#elif defined(ASIO_HAS_STD_ATOMIC)
+typedef std::atomic<long> atomic_count;
+inline void increment(atomic_count& a, long b) { a += b; }
+
+inline void ref_count_up(atomic_count& a)
+{
+  a.fetch_add(1, std::memory_order_relaxed);
+}
+
+inline bool ref_count_down(atomic_count& a)
+{
+  if (a.fetch_sub(1, std::memory_order_release) == 1)
+  {
+    std::atomic_thread_fence(std::memory_order_acquire);
+    return true;
+  }
+  return false;
+}
+#else // defined(ASIO_HAS_STD_ATOMIC)
+typedef boost::detail::atomic_count atomic_count;
+inline void increment(atomic_count& a, long b) { while (b > 0) ++a, --b; }
+inline void ref_count_up(atomic_count& a) { ++a; }
+inline bool ref_count_down(atomic_count& a) { return --a == 0; }
+#endif // defined(ASIO_HAS_STD_ATOMIC)
+
+} // namespace detail
+} // namespace asio
+
+#endif // ASIO_DETAIL_ATOMIC_COUNT_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/base_from_completion_cond.hpp b/link/modules/asio-standalone/asio/include/asio/detail/base_from_completion_cond.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/base_from_completion_cond.hpp
@@ -0,0 +1,69 @@
+//
+// detail/base_from_completion_cond.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_BASE_FROM_COMPLETION_COND_HPP
+#define ASIO_DETAIL_BASE_FROM_COMPLETION_COND_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/completion_condition.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename CompletionCondition>
+class base_from_completion_cond
+{
+protected:
+  explicit base_from_completion_cond(CompletionCondition& completion_condition)
+    : completion_condition_(
+        ASIO_MOVE_CAST(CompletionCondition)(completion_condition))
+  {
+  }
+
+  std::size_t check_for_completion(
+      const asio::error_code& ec,
+      std::size_t total_transferred)
+  {
+    return detail::adapt_completion_condition_result(
+        completion_condition_(ec, total_transferred));
+  }
+
+private:
+  CompletionCondition completion_condition_;
+};
+
+template <>
+class base_from_completion_cond<transfer_all_t>
+{
+protected:
+  explicit base_from_completion_cond(transfer_all_t)
+  {
+  }
+
+  static std::size_t check_for_completion(
+      const asio::error_code& ec,
+      std::size_t total_transferred)
+  {
+    return transfer_all_t()(ec, total_transferred);
+  }
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_BASE_FROM_COMPLETION_COND_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/bind_handler.hpp b/link/modules/asio-standalone/asio/include/asio/detail/bind_handler.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/bind_handler.hpp
@@ -0,0 +1,934 @@
+//
+// detail/bind_handler.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_BIND_HANDLER_HPP
+#define ASIO_DETAIL_BIND_HANDLER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/associated_allocator.hpp"
+#include "asio/associated_executor.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_cont_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/type_traits.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Handler, typename Arg1>
+class binder1
+{
+public:
+  template <typename T>
+  binder1(int, ASIO_MOVE_ARG(T) handler, const Arg1& arg1)
+    : handler_(ASIO_MOVE_CAST(T)(handler)),
+      arg1_(arg1)
+  {
+  }
+
+  binder1(Handler& handler, const Arg1& arg1)
+    : handler_(ASIO_MOVE_CAST(Handler)(handler)),
+      arg1_(arg1)
+  {
+  }
+
+#if defined(ASIO_HAS_MOVE)
+  binder1(const binder1& other)
+    : handler_(other.handler_),
+      arg1_(other.arg1_)
+  {
+  }
+
+  binder1(binder1&& other)
+    : handler_(ASIO_MOVE_CAST(Handler)(other.handler_)),
+      arg1_(ASIO_MOVE_CAST(Arg1)(other.arg1_))
+  {
+  }
+#endif // defined(ASIO_HAS_MOVE)
+
+  void operator()()
+  {
+    handler_(static_cast<const Arg1&>(arg1_));
+  }
+
+  void operator()() const
+  {
+    handler_(arg1_);
+  }
+
+//private:
+  Handler handler_;
+  Arg1 arg1_;
+};
+
+template <typename Handler, typename Arg1>
+inline asio_handler_allocate_is_deprecated
+asio_handler_allocate(std::size_t size,
+    binder1<Handler, Arg1>* this_handler)
+{
+#if defined(ASIO_NO_DEPRECATED)
+  asio_handler_alloc_helpers::allocate(size, this_handler->handler_);
+  return asio_handler_allocate_is_no_longer_used();
+#else // defined(ASIO_NO_DEPRECATED)
+  return asio_handler_alloc_helpers::allocate(
+      size, this_handler->handler_);
+#endif // defined(ASIO_NO_DEPRECATED)
+}
+
+template <typename Handler, typename Arg1>
+inline asio_handler_deallocate_is_deprecated
+asio_handler_deallocate(void* pointer, std::size_t size,
+    binder1<Handler, Arg1>* this_handler)
+{
+  asio_handler_alloc_helpers::deallocate(
+      pointer, size, this_handler->handler_);
+#if defined(ASIO_NO_DEPRECATED)
+  return asio_handler_deallocate_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+}
+
+template <typename Handler, typename Arg1>
+inline bool asio_handler_is_continuation(
+    binder1<Handler, Arg1>* this_handler)
+{
+  return asio_handler_cont_helpers::is_continuation(
+      this_handler->handler_);
+}
+
+template <typename Function, typename Handler, typename Arg1>
+inline asio_handler_invoke_is_deprecated
+asio_handler_invoke(Function& function,
+    binder1<Handler, Arg1>* this_handler)
+{
+  asio_handler_invoke_helpers::invoke(
+      function, this_handler->handler_);
+#if defined(ASIO_NO_DEPRECATED)
+  return asio_handler_invoke_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+}
+
+template <typename Function, typename Handler, typename Arg1>
+inline asio_handler_invoke_is_deprecated
+asio_handler_invoke(const Function& function,
+    binder1<Handler, Arg1>* this_handler)
+{
+  asio_handler_invoke_helpers::invoke(
+      function, this_handler->handler_);
+#if defined(ASIO_NO_DEPRECATED)
+  return asio_handler_invoke_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+}
+
+template <typename Handler, typename Arg1>
+inline binder1<typename decay<Handler>::type, Arg1> bind_handler(
+    ASIO_MOVE_ARG(Handler) handler, const Arg1& arg1)
+{
+  return binder1<typename decay<Handler>::type, Arg1>(0,
+      ASIO_MOVE_CAST(Handler)(handler), arg1);
+}
+
+template <typename Handler, typename Arg1, typename Arg2>
+class binder2
+{
+public:
+  template <typename T>
+  binder2(int, ASIO_MOVE_ARG(T) handler,
+      const Arg1& arg1, const Arg2& arg2)
+    : handler_(ASIO_MOVE_CAST(T)(handler)),
+      arg1_(arg1),
+      arg2_(arg2)
+  {
+  }
+
+  binder2(Handler& handler, const Arg1& arg1, const Arg2& arg2)
+    : handler_(ASIO_MOVE_CAST(Handler)(handler)),
+      arg1_(arg1),
+      arg2_(arg2)
+  {
+  }
+
+#if defined(ASIO_HAS_MOVE)
+  binder2(const binder2& other)
+    : handler_(other.handler_),
+      arg1_(other.arg1_),
+      arg2_(other.arg2_)
+  {
+  }
+
+  binder2(binder2&& other)
+    : handler_(ASIO_MOVE_CAST(Handler)(other.handler_)),
+      arg1_(ASIO_MOVE_CAST(Arg1)(other.arg1_)),
+      arg2_(ASIO_MOVE_CAST(Arg2)(other.arg2_))
+  {
+  }
+#endif // defined(ASIO_HAS_MOVE)
+
+  void operator()()
+  {
+    handler_(static_cast<const Arg1&>(arg1_),
+        static_cast<const Arg2&>(arg2_));
+  }
+
+  void operator()() const
+  {
+    handler_(arg1_, arg2_);
+  }
+
+//private:
+  Handler handler_;
+  Arg1 arg1_;
+  Arg2 arg2_;
+};
+
+template <typename Handler, typename Arg1, typename Arg2>
+inline asio_handler_allocate_is_deprecated
+asio_handler_allocate(std::size_t size,
+    binder2<Handler, Arg1, Arg2>* this_handler)
+{
+#if defined(ASIO_NO_DEPRECATED)
+  asio_handler_alloc_helpers::allocate(size, this_handler->handler_);
+  return asio_handler_allocate_is_no_longer_used();
+#else // defined(ASIO_NO_DEPRECATED)
+  return asio_handler_alloc_helpers::allocate(
+      size, this_handler->handler_);
+#endif // defined(ASIO_NO_DEPRECATED)
+}
+
+template <typename Handler, typename Arg1, typename Arg2>
+inline asio_handler_deallocate_is_deprecated
+asio_handler_deallocate(void* pointer, std::size_t size,
+    binder2<Handler, Arg1, Arg2>* this_handler)
+{
+  asio_handler_alloc_helpers::deallocate(
+      pointer, size, this_handler->handler_);
+#if defined(ASIO_NO_DEPRECATED)
+  return asio_handler_deallocate_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+}
+
+template <typename Handler, typename Arg1, typename Arg2>
+inline bool asio_handler_is_continuation(
+    binder2<Handler, Arg1, Arg2>* this_handler)
+{
+  return asio_handler_cont_helpers::is_continuation(
+      this_handler->handler_);
+}
+
+template <typename Function, typename Handler, typename Arg1, typename Arg2>
+inline asio_handler_invoke_is_deprecated
+asio_handler_invoke(Function& function,
+    binder2<Handler, Arg1, Arg2>* this_handler)
+{
+  asio_handler_invoke_helpers::invoke(
+      function, this_handler->handler_);
+#if defined(ASIO_NO_DEPRECATED)
+  return asio_handler_invoke_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+}
+
+template <typename Function, typename Handler, typename Arg1, typename Arg2>
+inline asio_handler_invoke_is_deprecated
+asio_handler_invoke(const Function& function,
+    binder2<Handler, Arg1, Arg2>* this_handler)
+{
+  asio_handler_invoke_helpers::invoke(
+      function, this_handler->handler_);
+#if defined(ASIO_NO_DEPRECATED)
+  return asio_handler_invoke_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+}
+
+template <typename Handler, typename Arg1, typename Arg2>
+inline binder2<typename decay<Handler>::type, Arg1, Arg2> bind_handler(
+    ASIO_MOVE_ARG(Handler) handler, const Arg1& arg1, const Arg2& arg2)
+{
+  return binder2<typename decay<Handler>::type, Arg1, Arg2>(0,
+      ASIO_MOVE_CAST(Handler)(handler), arg1, arg2);
+}
+
+template <typename Handler, typename Arg1, typename Arg2, typename Arg3>
+class binder3
+{
+public:
+  template <typename T>
+  binder3(int, ASIO_MOVE_ARG(T) handler, const Arg1& arg1,
+      const Arg2& arg2, const Arg3& arg3)
+    : handler_(ASIO_MOVE_CAST(T)(handler)),
+      arg1_(arg1),
+      arg2_(arg2),
+      arg3_(arg3)
+  {
+  }
+
+  binder3(Handler& handler, const Arg1& arg1,
+      const Arg2& arg2, const Arg3& arg3)
+    : handler_(ASIO_MOVE_CAST(Handler)(handler)),
+      arg1_(arg1),
+      arg2_(arg2),
+      arg3_(arg3)
+  {
+  }
+
+#if defined(ASIO_HAS_MOVE)
+  binder3(const binder3& other)
+    : handler_(other.handler_),
+      arg1_(other.arg1_),
+      arg2_(other.arg2_),
+      arg3_(other.arg3_)
+  {
+  }
+
+  binder3(binder3&& other)
+    : handler_(ASIO_MOVE_CAST(Handler)(other.handler_)),
+      arg1_(ASIO_MOVE_CAST(Arg1)(other.arg1_)),
+      arg2_(ASIO_MOVE_CAST(Arg2)(other.arg2_)),
+      arg3_(ASIO_MOVE_CAST(Arg3)(other.arg3_))
+  {
+  }
+#endif // defined(ASIO_HAS_MOVE)
+
+  void operator()()
+  {
+    handler_(static_cast<const Arg1&>(arg1_),
+        static_cast<const Arg2&>(arg2_), static_cast<const Arg3&>(arg3_));
+  }
+
+  void operator()() const
+  {
+    handler_(arg1_, arg2_, arg3_);
+  }
+
+//private:
+  Handler handler_;
+  Arg1 arg1_;
+  Arg2 arg2_;
+  Arg3 arg3_;
+};
+
+template <typename Handler, typename Arg1, typename Arg2, typename Arg3>
+inline asio_handler_allocate_is_deprecated
+asio_handler_allocate(std::size_t size,
+    binder3<Handler, Arg1, Arg2, Arg3>* this_handler)
+{
+#if defined(ASIO_NO_DEPRECATED)
+  asio_handler_alloc_helpers::allocate(size, this_handler->handler_);
+  return asio_handler_allocate_is_no_longer_used();
+#else // defined(ASIO_NO_DEPRECATED)
+  return asio_handler_alloc_helpers::allocate(
+      size, this_handler->handler_);
+#endif // defined(ASIO_NO_DEPRECATED)
+}
+
+template <typename Handler, typename Arg1, typename Arg2, typename Arg3>
+inline asio_handler_deallocate_is_deprecated
+asio_handler_deallocate(void* pointer, std::size_t size,
+    binder3<Handler, Arg1, Arg2, Arg3>* this_handler)
+{
+  asio_handler_alloc_helpers::deallocate(
+      pointer, size, this_handler->handler_);
+#if defined(ASIO_NO_DEPRECATED)
+  return asio_handler_deallocate_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+}
+
+template <typename Handler, typename Arg1, typename Arg2, typename Arg3>
+inline bool asio_handler_is_continuation(
+    binder3<Handler, Arg1, Arg2, Arg3>* this_handler)
+{
+  return asio_handler_cont_helpers::is_continuation(
+      this_handler->handler_);
+}
+
+template <typename Function, typename Handler,
+    typename Arg1, typename Arg2, typename Arg3>
+inline asio_handler_invoke_is_deprecated
+asio_handler_invoke(Function& function,
+    binder3<Handler, Arg1, Arg2, Arg3>* this_handler)
+{
+  asio_handler_invoke_helpers::invoke(
+      function, this_handler->handler_);
+#if defined(ASIO_NO_DEPRECATED)
+  return asio_handler_invoke_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+}
+
+template <typename Function, typename Handler,
+    typename Arg1, typename Arg2, typename Arg3>
+inline asio_handler_invoke_is_deprecated
+asio_handler_invoke(const Function& function,
+    binder3<Handler, Arg1, Arg2, Arg3>* this_handler)
+{
+  asio_handler_invoke_helpers::invoke(
+      function, this_handler->handler_);
+#if defined(ASIO_NO_DEPRECATED)
+  return asio_handler_invoke_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+}
+
+template <typename Handler, typename Arg1, typename Arg2, typename Arg3>
+inline binder3<typename decay<Handler>::type, Arg1, Arg2, Arg3> bind_handler(
+    ASIO_MOVE_ARG(Handler) handler, const Arg1& arg1, const Arg2& arg2,
+    const Arg3& arg3)
+{
+  return binder3<typename decay<Handler>::type, Arg1, Arg2, Arg3>(0,
+      ASIO_MOVE_CAST(Handler)(handler), arg1, arg2, arg3);
+}
+
+template <typename Handler, typename Arg1,
+    typename Arg2, typename Arg3, typename Arg4>
+class binder4
+{
+public:
+  template <typename T>
+  binder4(int, ASIO_MOVE_ARG(T) handler, const Arg1& arg1,
+      const Arg2& arg2, const Arg3& arg3, const Arg4& arg4)
+    : handler_(ASIO_MOVE_CAST(T)(handler)),
+      arg1_(arg1),
+      arg2_(arg2),
+      arg3_(arg3),
+      arg4_(arg4)
+  {
+  }
+
+  binder4(Handler& handler, const Arg1& arg1,
+      const Arg2& arg2, const Arg3& arg3, const Arg4& arg4)
+    : handler_(ASIO_MOVE_CAST(Handler)(handler)),
+      arg1_(arg1),
+      arg2_(arg2),
+      arg3_(arg3),
+      arg4_(arg4)
+  {
+  }
+
+#if defined(ASIO_HAS_MOVE)
+  binder4(const binder4& other)
+    : handler_(other.handler_),
+      arg1_(other.arg1_),
+      arg2_(other.arg2_),
+      arg3_(other.arg3_),
+      arg4_(other.arg4_)
+  {
+  }
+
+  binder4(binder4&& other)
+    : handler_(ASIO_MOVE_CAST(Handler)(other.handler_)),
+      arg1_(ASIO_MOVE_CAST(Arg1)(other.arg1_)),
+      arg2_(ASIO_MOVE_CAST(Arg2)(other.arg2_)),
+      arg3_(ASIO_MOVE_CAST(Arg3)(other.arg3_)),
+      arg4_(ASIO_MOVE_CAST(Arg4)(other.arg4_))
+  {
+  }
+#endif // defined(ASIO_HAS_MOVE)
+
+  void operator()()
+  {
+    handler_(static_cast<const Arg1&>(arg1_),
+        static_cast<const Arg2&>(arg2_), static_cast<const Arg3&>(arg3_),
+        static_cast<const Arg4&>(arg4_));
+  }
+
+  void operator()() const
+  {
+    handler_(arg1_, arg2_, arg3_, arg4_);
+  }
+
+//private:
+  Handler handler_;
+  Arg1 arg1_;
+  Arg2 arg2_;
+  Arg3 arg3_;
+  Arg4 arg4_;
+};
+
+template <typename Handler, typename Arg1,
+    typename Arg2, typename Arg3, typename Arg4>
+inline asio_handler_allocate_is_deprecated
+asio_handler_allocate(std::size_t size,
+    binder4<Handler, Arg1, Arg2, Arg3, Arg4>* this_handler)
+{
+#if defined(ASIO_NO_DEPRECATED)
+  asio_handler_alloc_helpers::allocate(size, this_handler->handler_);
+  return asio_handler_allocate_is_no_longer_used();
+#else // defined(ASIO_NO_DEPRECATED)
+  return asio_handler_alloc_helpers::allocate(
+      size, this_handler->handler_);
+#endif // defined(ASIO_NO_DEPRECATED)
+}
+
+template <typename Handler, typename Arg1,
+    typename Arg2, typename Arg3, typename Arg4>
+inline asio_handler_deallocate_is_deprecated
+asio_handler_deallocate(void* pointer, std::size_t size,
+    binder4<Handler, Arg1, Arg2, Arg3, Arg4>* this_handler)
+{
+  asio_handler_alloc_helpers::deallocate(
+      pointer, size, this_handler->handler_);
+#if defined(ASIO_NO_DEPRECATED)
+  return asio_handler_deallocate_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+}
+
+template <typename Handler, typename Arg1,
+    typename Arg2, typename Arg3, typename Arg4>
+inline bool asio_handler_is_continuation(
+    binder4<Handler, Arg1, Arg2, Arg3, Arg4>* this_handler)
+{
+  return asio_handler_cont_helpers::is_continuation(
+      this_handler->handler_);
+}
+
+template <typename Function, typename Handler, typename Arg1,
+    typename Arg2, typename Arg3, typename Arg4>
+inline asio_handler_invoke_is_deprecated
+asio_handler_invoke(Function& function,
+    binder4<Handler, Arg1, Arg2, Arg3, Arg4>* this_handler)
+{
+  asio_handler_invoke_helpers::invoke(
+      function, this_handler->handler_);
+#if defined(ASIO_NO_DEPRECATED)
+  return asio_handler_invoke_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+}
+
+template <typename Function, typename Handler, typename Arg1,
+    typename Arg2, typename Arg3, typename Arg4>
+inline asio_handler_invoke_is_deprecated
+asio_handler_invoke(const Function& function,
+    binder4<Handler, Arg1, Arg2, Arg3, Arg4>* this_handler)
+{
+  asio_handler_invoke_helpers::invoke(
+      function, this_handler->handler_);
+#if defined(ASIO_NO_DEPRECATED)
+  return asio_handler_invoke_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+}
+
+template <typename Handler, typename Arg1,
+    typename Arg2, typename Arg3, typename Arg4>
+inline binder4<typename decay<Handler>::type, Arg1, Arg2, Arg3, Arg4>
+bind_handler(ASIO_MOVE_ARG(Handler) handler, const Arg1& arg1,
+    const Arg2& arg2, const Arg3& arg3, const Arg4& arg4)
+{
+  return binder4<typename decay<Handler>::type, Arg1, Arg2, Arg3, Arg4>(0,
+      ASIO_MOVE_CAST(Handler)(handler), arg1, arg2, arg3, arg4);
+}
+
+template <typename Handler, typename Arg1, typename Arg2,
+    typename Arg3, typename Arg4, typename Arg5>
+class binder5
+{
+public:
+  template <typename T>
+  binder5(int, ASIO_MOVE_ARG(T) handler, const Arg1& arg1,
+      const Arg2& arg2, const Arg3& arg3, const Arg4& arg4, const Arg5& arg5)
+    : handler_(ASIO_MOVE_CAST(T)(handler)),
+      arg1_(arg1),
+      arg2_(arg2),
+      arg3_(arg3),
+      arg4_(arg4),
+      arg5_(arg5)
+  {
+  }
+
+  binder5(Handler& handler, const Arg1& arg1, const Arg2& arg2,
+      const Arg3& arg3, const Arg4& arg4, const Arg5& arg5)
+    : handler_(ASIO_MOVE_CAST(Handler)(handler)),
+      arg1_(arg1),
+      arg2_(arg2),
+      arg3_(arg3),
+      arg4_(arg4),
+      arg5_(arg5)
+  {
+  }
+
+#if defined(ASIO_HAS_MOVE)
+  binder5(const binder5& other)
+    : handler_(other.handler_),
+      arg1_(other.arg1_),
+      arg2_(other.arg2_),
+      arg3_(other.arg3_),
+      arg4_(other.arg4_),
+      arg5_(other.arg5_)
+  {
+  }
+
+  binder5(binder5&& other)
+    : handler_(ASIO_MOVE_CAST(Handler)(other.handler_)),
+      arg1_(ASIO_MOVE_CAST(Arg1)(other.arg1_)),
+      arg2_(ASIO_MOVE_CAST(Arg2)(other.arg2_)),
+      arg3_(ASIO_MOVE_CAST(Arg3)(other.arg3_)),
+      arg4_(ASIO_MOVE_CAST(Arg4)(other.arg4_)),
+      arg5_(ASIO_MOVE_CAST(Arg5)(other.arg5_))
+  {
+  }
+#endif // defined(ASIO_HAS_MOVE)
+
+  void operator()()
+  {
+    handler_(static_cast<const Arg1&>(arg1_),
+        static_cast<const Arg2&>(arg2_), static_cast<const Arg3&>(arg3_),
+        static_cast<const Arg4&>(arg4_), static_cast<const Arg5&>(arg5_));
+  }
+
+  void operator()() const
+  {
+    handler_(arg1_, arg2_, arg3_, arg4_, arg5_);
+  }
+
+//private:
+  Handler handler_;
+  Arg1 arg1_;
+  Arg2 arg2_;
+  Arg3 arg3_;
+  Arg4 arg4_;
+  Arg5 arg5_;
+};
+
+template <typename Handler, typename Arg1, typename Arg2,
+    typename Arg3, typename Arg4, typename Arg5>
+inline asio_handler_allocate_is_deprecated
+asio_handler_allocate(std::size_t size,
+    binder5<Handler, Arg1, Arg2, Arg3, Arg4, Arg5>* this_handler)
+{
+#if defined(ASIO_NO_DEPRECATED)
+  asio_handler_alloc_helpers::allocate(size, this_handler->handler_);
+  return asio_handler_allocate_is_no_longer_used();
+#else // defined(ASIO_NO_DEPRECATED)
+  return asio_handler_alloc_helpers::allocate(
+      size, this_handler->handler_);
+#endif // defined(ASIO_NO_DEPRECATED)
+}
+
+template <typename Handler, typename Arg1, typename Arg2,
+    typename Arg3, typename Arg4, typename Arg5>
+inline asio_handler_deallocate_is_deprecated
+asio_handler_deallocate(void* pointer, std::size_t size,
+    binder5<Handler, Arg1, Arg2, Arg3, Arg4, Arg5>* this_handler)
+{
+  asio_handler_alloc_helpers::deallocate(
+      pointer, size, this_handler->handler_);
+#if defined(ASIO_NO_DEPRECATED)
+  return asio_handler_deallocate_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+}
+
+template <typename Handler, typename Arg1, typename Arg2,
+    typename Arg3, typename Arg4, typename Arg5>
+inline bool asio_handler_is_continuation(
+    binder5<Handler, Arg1, Arg2, Arg3, Arg4, Arg5>* this_handler)
+{
+  return asio_handler_cont_helpers::is_continuation(
+      this_handler->handler_);
+}
+
+template <typename Function, typename Handler, typename Arg1,
+    typename Arg2, typename Arg3, typename Arg4, typename Arg5>
+inline asio_handler_invoke_is_deprecated
+asio_handler_invoke(Function& function,
+    binder5<Handler, Arg1, Arg2, Arg3, Arg4, Arg5>* this_handler)
+{
+  asio_handler_invoke_helpers::invoke(
+      function, this_handler->handler_);
+#if defined(ASIO_NO_DEPRECATED)
+  return asio_handler_invoke_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+}
+
+template <typename Function, typename Handler, typename Arg1,
+    typename Arg2, typename Arg3, typename Arg4, typename Arg5>
+inline asio_handler_invoke_is_deprecated
+asio_handler_invoke(const Function& function,
+    binder5<Handler, Arg1, Arg2, Arg3, Arg4, Arg5>* this_handler)
+{
+  asio_handler_invoke_helpers::invoke(
+      function, this_handler->handler_);
+#if defined(ASIO_NO_DEPRECATED)
+  return asio_handler_invoke_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+}
+
+template <typename Handler, typename Arg1, typename Arg2,
+    typename Arg3, typename Arg4, typename Arg5>
+inline binder5<typename decay<Handler>::type, Arg1, Arg2, Arg3, Arg4, Arg5>
+bind_handler(ASIO_MOVE_ARG(Handler) handler, const Arg1& arg1,
+    const Arg2& arg2, const Arg3& arg3, const Arg4& arg4, const Arg5& arg5)
+{
+  return binder5<typename decay<Handler>::type, Arg1, Arg2, Arg3, Arg4, Arg5>(0,
+      ASIO_MOVE_CAST(Handler)(handler), arg1, arg2, arg3, arg4, arg5);
+}
+
+#if defined(ASIO_HAS_MOVE)
+
+template <typename Handler, typename Arg1>
+class move_binder1
+{
+public:
+  move_binder1(int, ASIO_MOVE_ARG(Handler) handler,
+      ASIO_MOVE_ARG(Arg1) arg1)
+    : handler_(ASIO_MOVE_CAST(Handler)(handler)),
+      arg1_(ASIO_MOVE_CAST(Arg1)(arg1))
+  {
+  }
+
+  move_binder1(move_binder1&& other)
+    : handler_(ASIO_MOVE_CAST(Handler)(other.handler_)),
+      arg1_(ASIO_MOVE_CAST(Arg1)(other.arg1_))
+  {
+  }
+
+  void operator()()
+  {
+    handler_(ASIO_MOVE_CAST(Arg1)(arg1_));
+  }
+
+//private:
+  Handler handler_;
+  Arg1 arg1_;
+};
+
+template <typename Handler, typename Arg1>
+inline asio_handler_allocate_is_deprecated
+asio_handler_allocate(std::size_t size,
+    move_binder1<Handler, Arg1>* this_handler)
+{
+#if defined(ASIO_NO_DEPRECATED)
+  asio_handler_alloc_helpers::allocate(size, this_handler->handler_);
+  return asio_handler_allocate_is_no_longer_used();
+#else // defined(ASIO_NO_DEPRECATED)
+  return asio_handler_alloc_helpers::allocate(
+      size, this_handler->handler_);
+#endif // defined(ASIO_NO_DEPRECATED)
+}
+
+template <typename Handler, typename Arg1>
+inline asio_handler_deallocate_is_deprecated
+asio_handler_deallocate(void* pointer, std::size_t size,
+    move_binder1<Handler, Arg1>* this_handler)
+{
+  asio_handler_alloc_helpers::deallocate(
+      pointer, size, this_handler->handler_);
+#if defined(ASIO_NO_DEPRECATED)
+  return asio_handler_deallocate_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+}
+
+template <typename Handler, typename Arg1>
+inline bool asio_handler_is_continuation(
+    move_binder1<Handler, Arg1>* this_handler)
+{
+  return asio_handler_cont_helpers::is_continuation(
+      this_handler->handler_);
+}
+
+template <typename Function, typename Handler, typename Arg1>
+inline asio_handler_invoke_is_deprecated
+asio_handler_invoke(ASIO_MOVE_ARG(Function) function,
+    move_binder1<Handler, Arg1>* this_handler)
+{
+  asio_handler_invoke_helpers::invoke(
+      ASIO_MOVE_CAST(Function)(function), this_handler->handler_);
+#if defined(ASIO_NO_DEPRECATED)
+  return asio_handler_invoke_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+}
+
+template <typename Handler, typename Arg1, typename Arg2>
+class move_binder2
+{
+public:
+  move_binder2(int, ASIO_MOVE_ARG(Handler) handler,
+      const Arg1& arg1, ASIO_MOVE_ARG(Arg2) arg2)
+    : handler_(ASIO_MOVE_CAST(Handler)(handler)),
+      arg1_(arg1),
+      arg2_(ASIO_MOVE_CAST(Arg2)(arg2))
+  {
+  }
+
+  move_binder2(move_binder2&& other)
+    : handler_(ASIO_MOVE_CAST(Handler)(other.handler_)),
+      arg1_(ASIO_MOVE_CAST(Arg1)(other.arg1_)),
+      arg2_(ASIO_MOVE_CAST(Arg2)(other.arg2_))
+  {
+  }
+
+  void operator()()
+  {
+    handler_(static_cast<const Arg1&>(arg1_),
+        ASIO_MOVE_CAST(Arg2)(arg2_));
+  }
+
+//private:
+  Handler handler_;
+  Arg1 arg1_;
+  Arg2 arg2_;
+};
+
+template <typename Handler, typename Arg1, typename Arg2>
+inline asio_handler_allocate_is_deprecated
+asio_handler_allocate(std::size_t size,
+    move_binder2<Handler, Arg1, Arg2>* this_handler)
+{
+#if defined(ASIO_NO_DEPRECATED)
+  asio_handler_alloc_helpers::allocate(size, this_handler->handler_);
+  return asio_handler_allocate_is_no_longer_used();
+#else // defined(ASIO_NO_DEPRECATED)
+  return asio_handler_alloc_helpers::allocate(
+      size, this_handler->handler_);
+#endif // defined(ASIO_NO_DEPRECATED)
+}
+
+template <typename Handler, typename Arg1, typename Arg2>
+inline asio_handler_deallocate_is_deprecated
+asio_handler_deallocate(void* pointer, std::size_t size,
+    move_binder2<Handler, Arg1, Arg2>* this_handler)
+{
+  asio_handler_alloc_helpers::deallocate(
+      pointer, size, this_handler->handler_);
+#if defined(ASIO_NO_DEPRECATED)
+  return asio_handler_deallocate_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+}
+
+template <typename Handler, typename Arg1, typename Arg2>
+inline bool asio_handler_is_continuation(
+    move_binder2<Handler, Arg1, Arg2>* this_handler)
+{
+  return asio_handler_cont_helpers::is_continuation(
+      this_handler->handler_);
+}
+
+template <typename Function, typename Handler, typename Arg1, typename Arg2>
+inline asio_handler_invoke_is_deprecated
+asio_handler_invoke(ASIO_MOVE_ARG(Function) function,
+    move_binder2<Handler, Arg1, Arg2>* this_handler)
+{
+  asio_handler_invoke_helpers::invoke(
+      ASIO_MOVE_CAST(Function)(function), this_handler->handler_);
+#if defined(ASIO_NO_DEPRECATED)
+  return asio_handler_invoke_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+}
+
+#endif // defined(ASIO_HAS_MOVE)
+
+} // namespace detail
+
+template <typename Handler, typename Arg1, typename Allocator>
+struct associated_allocator<detail::binder1<Handler, Arg1>, Allocator>
+{
+  typedef typename associated_allocator<Handler, Allocator>::type type;
+
+  static type get(const detail::binder1<Handler, Arg1>& h,
+      const Allocator& a = Allocator()) ASIO_NOEXCEPT
+  {
+    return associated_allocator<Handler, Allocator>::get(h.handler_, a);
+  }
+};
+
+template <typename Handler, typename Arg1, typename Arg2, typename Allocator>
+struct associated_allocator<detail::binder2<Handler, Arg1, Arg2>, Allocator>
+{
+  typedef typename associated_allocator<Handler, Allocator>::type type;
+
+  static type get(const detail::binder2<Handler, Arg1, Arg2>& h,
+      const Allocator& a = Allocator()) ASIO_NOEXCEPT
+  {
+    return associated_allocator<Handler, Allocator>::get(h.handler_, a);
+  }
+};
+
+template <typename Handler, typename Arg1, typename Executor>
+struct associated_executor<detail::binder1<Handler, Arg1>, Executor>
+{
+  typedef typename associated_executor<Handler, Executor>::type type;
+
+  static type get(const detail::binder1<Handler, Arg1>& h,
+      const Executor& ex = Executor()) ASIO_NOEXCEPT
+  {
+    return associated_executor<Handler, Executor>::get(h.handler_, ex);
+  }
+};
+
+template <typename Handler, typename Arg1, typename Arg2, typename Executor>
+struct associated_executor<detail::binder2<Handler, Arg1, Arg2>, Executor>
+{
+  typedef typename associated_executor<Handler, Executor>::type type;
+
+  static type get(const detail::binder2<Handler, Arg1, Arg2>& h,
+      const Executor& ex = Executor()) ASIO_NOEXCEPT
+  {
+    return associated_executor<Handler, Executor>::get(h.handler_, ex);
+  }
+};
+
+#if defined(ASIO_HAS_MOVE)
+
+template <typename Handler, typename Arg1, typename Allocator>
+struct associated_allocator<detail::move_binder1<Handler, Arg1>, Allocator>
+{
+  typedef typename associated_allocator<Handler, Allocator>::type type;
+
+  static type get(const detail::move_binder1<Handler, Arg1>& h,
+      const Allocator& a = Allocator()) ASIO_NOEXCEPT
+  {
+    return associated_allocator<Handler, Allocator>::get(h.handler_, a);
+  }
+};
+
+template <typename Handler, typename Arg1, typename Arg2, typename Allocator>
+struct associated_allocator<
+    detail::move_binder2<Handler, Arg1, Arg2>, Allocator>
+{
+  typedef typename associated_allocator<Handler, Allocator>::type type;
+
+  static type get(const detail::move_binder2<Handler, Arg1, Arg2>& h,
+      const Allocator& a = Allocator()) ASIO_NOEXCEPT
+  {
+    return associated_allocator<Handler, Allocator>::get(h.handler_, a);
+  }
+};
+
+template <typename Handler, typename Arg1, typename Executor>
+struct associated_executor<detail::move_binder1<Handler, Arg1>, Executor>
+{
+  typedef typename associated_executor<Handler, Executor>::type type;
+
+  static type get(const detail::move_binder1<Handler, Arg1>& h,
+      const Executor& ex = Executor()) ASIO_NOEXCEPT
+  {
+    return associated_executor<Handler, Executor>::get(h.handler_, ex);
+  }
+};
+
+template <typename Handler, typename Arg1, typename Arg2, typename Executor>
+struct associated_executor<detail::move_binder2<Handler, Arg1, Arg2>, Executor>
+{
+  typedef typename associated_executor<Handler, Executor>::type type;
+
+  static type get(const detail::move_binder2<Handler, Arg1, Arg2>& h,
+      const Executor& ex = Executor()) ASIO_NOEXCEPT
+  {
+    return associated_executor<Handler, Executor>::get(h.handler_, ex);
+  }
+};
+
+#endif // defined(ASIO_HAS_MOVE)
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_BIND_HANDLER_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/blocking_executor_op.hpp b/link/modules/asio-standalone/asio/include/asio/detail/blocking_executor_op.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/blocking_executor_op.hpp
@@ -0,0 +1,107 @@
+//
+// detail/blocking_executor_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_BLOCKING_EXECUTOR_OP_HPP
+#define ASIO_DETAIL_BLOCKING_EXECUTOR_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/event.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/mutex.hpp"
+#include "asio/detail/scheduler_operation.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Operation = scheduler_operation>
+class blocking_executor_op_base : public Operation
+{
+public:
+  blocking_executor_op_base(typename Operation::func_type complete_func)
+    : Operation(complete_func),
+      is_complete_(false)
+  {
+  }
+
+  void wait()
+  {
+    asio::detail::mutex::scoped_lock lock(mutex_);
+    while (!is_complete_)
+      event_.wait(lock);
+  }
+
+protected:
+  struct do_complete_cleanup
+  {
+    ~do_complete_cleanup()
+    {
+      asio::detail::mutex::scoped_lock lock(op_->mutex_);
+      op_->is_complete_ = true;
+      op_->event_.unlock_and_signal_one_for_destruction(lock);
+    }
+
+    blocking_executor_op_base* op_;
+  };
+
+private:
+  asio::detail::mutex mutex_;
+  asio::detail::event event_;
+  bool is_complete_;
+};
+
+template <typename Handler, typename Operation = scheduler_operation>
+class blocking_executor_op : public blocking_executor_op_base<Operation>
+{
+public:
+  blocking_executor_op(Handler& h)
+    : blocking_executor_op_base<Operation>(&blocking_executor_op::do_complete),
+      handler_(h)
+  {
+  }
+
+  static void do_complete(void* owner, Operation* base,
+      const asio::error_code& /*ec*/,
+      std::size_t /*bytes_transferred*/)
+  {
+    blocking_executor_op* o(static_cast<blocking_executor_op*>(base));
+
+    typename blocking_executor_op_base<Operation>::do_complete_cleanup
+      on_exit = { o };
+    (void)on_exit;
+
+    ASIO_HANDLER_COMPLETION((*o));
+
+    // Make the upcall if required.
+    if (owner)
+    {
+      fenced_block b(fenced_block::half);
+      ASIO_HANDLER_INVOCATION_BEGIN(());
+      asio_handler_invoke_helpers::invoke(o->handler_, o->handler_);
+      ASIO_HANDLER_INVOCATION_END;
+    }
+  }
+
+private:
+  Handler& handler_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_BLOCKING_EXECUTOR_OP_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/buffer_resize_guard.hpp b/link/modules/asio-standalone/asio/include/asio/detail/buffer_resize_guard.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/buffer_resize_guard.hpp
@@ -0,0 +1,66 @@
+//
+// detail/buffer_resize_guard.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_BUFFER_RESIZE_GUARD_HPP
+#define ASIO_DETAIL_BUFFER_RESIZE_GUARD_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/limits.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+// Helper class to manage buffer resizing in an exception safe way.
+template <typename Buffer>
+class buffer_resize_guard
+{
+public:
+  // Constructor.
+  buffer_resize_guard(Buffer& buffer)
+    : buffer_(buffer),
+      old_size_(buffer.size())
+  {
+  }
+
+  // Destructor rolls back the buffer resize unless commit was called.
+  ~buffer_resize_guard()
+  {
+    if (old_size_ != (std::numeric_limits<size_t>::max)())
+    {
+      buffer_.resize(old_size_);
+    }
+  }
+
+  // Commit the resize transaction.
+  void commit()
+  {
+    old_size_ = (std::numeric_limits<size_t>::max)();
+  }
+
+private:
+  // The buffer being managed.
+  Buffer& buffer_;
+
+  // The size of the buffer at the time the guard was constructed.
+  size_t old_size_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_BUFFER_RESIZE_GUARD_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/buffer_sequence_adapter.hpp b/link/modules/asio-standalone/asio/include/asio/detail/buffer_sequence_adapter.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/buffer_sequence_adapter.hpp
@@ -0,0 +1,650 @@
+//
+// detail/buffer_sequence_adapter.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_BUFFER_SEQUENCE_ADAPTER_HPP
+#define ASIO_DETAIL_BUFFER_SEQUENCE_ADAPTER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/buffer.hpp"
+#include "asio/detail/array_fwd.hpp"
+#include "asio/detail/socket_types.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class buffer_sequence_adapter_base
+{
+#if defined(ASIO_WINDOWS_RUNTIME)
+public:
+  // The maximum number of buffers to support in a single operation.
+  enum { max_buffers = 1 };
+
+protected:
+  typedef Windows::Storage::Streams::IBuffer^ native_buffer_type;
+
+  ASIO_DECL static void init_native_buffer(
+      native_buffer_type& buf,
+      const asio::mutable_buffer& buffer);
+
+  ASIO_DECL static void init_native_buffer(
+      native_buffer_type& buf,
+      const asio::const_buffer& buffer);
+#elif defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+public:
+  // The maximum number of buffers to support in a single operation.
+  enum { max_buffers = 64 < max_iov_len ? 64 : max_iov_len };
+
+protected:
+  typedef WSABUF native_buffer_type;
+
+  static void init_native_buffer(WSABUF& buf,
+      const asio::mutable_buffer& buffer)
+  {
+    buf.buf = static_cast<char*>(buffer.data());
+    buf.len = static_cast<ULONG>(buffer.size());
+  }
+
+  static void init_native_buffer(WSABUF& buf,
+      const asio::const_buffer& buffer)
+  {
+    buf.buf = const_cast<char*>(static_cast<const char*>(buffer.data()));
+    buf.len = static_cast<ULONG>(buffer.size());
+  }
+#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+public:
+  // The maximum number of buffers to support in a single operation.
+  enum { max_buffers = 64 < max_iov_len ? 64 : max_iov_len };
+
+protected:
+  typedef iovec native_buffer_type;
+
+  static void init_iov_base(void*& base, void* addr)
+  {
+    base = addr;
+  }
+
+  template <typename T>
+  static void init_iov_base(T& base, void* addr)
+  {
+    base = static_cast<T>(addr);
+  }
+
+  static void init_native_buffer(iovec& iov,
+      const asio::mutable_buffer& buffer)
+  {
+    init_iov_base(iov.iov_base, buffer.data());
+    iov.iov_len = buffer.size();
+  }
+
+  static void init_native_buffer(iovec& iov,
+      const asio::const_buffer& buffer)
+  {
+    init_iov_base(iov.iov_base, const_cast<void*>(buffer.data()));
+    iov.iov_len = buffer.size();
+  }
+#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+};
+
+// Helper class to translate buffers into the native buffer representation.
+template <typename Buffer, typename Buffers>
+class buffer_sequence_adapter
+  : buffer_sequence_adapter_base
+{
+public:
+  enum { is_single_buffer = false };
+
+  explicit buffer_sequence_adapter(const Buffers& buffer_sequence)
+    : count_(0), total_buffer_size_(0)
+  {
+    buffer_sequence_adapter::init(
+        asio::buffer_sequence_begin(buffer_sequence),
+        asio::buffer_sequence_end(buffer_sequence));
+  }
+
+  native_buffer_type* buffers()
+  {
+    return buffers_;
+  }
+
+  std::size_t count() const
+  {
+    return count_;
+  }
+
+  std::size_t total_size() const
+  {
+    return total_buffer_size_;
+  }
+
+  bool all_empty() const
+  {
+    return total_buffer_size_ == 0;
+  }
+
+  static bool all_empty(const Buffers& buffer_sequence)
+  {
+    return buffer_sequence_adapter::all_empty(
+        asio::buffer_sequence_begin(buffer_sequence),
+        asio::buffer_sequence_end(buffer_sequence));
+  }
+
+  static void validate(const Buffers& buffer_sequence)
+  {
+    buffer_sequence_adapter::validate(
+        asio::buffer_sequence_begin(buffer_sequence),
+        asio::buffer_sequence_end(buffer_sequence));
+  }
+
+  static Buffer first(const Buffers& buffer_sequence)
+  {
+    return buffer_sequence_adapter::first(
+        asio::buffer_sequence_begin(buffer_sequence),
+        asio::buffer_sequence_end(buffer_sequence));
+  }
+
+  enum { linearisation_storage_size = 8192 };
+
+  static Buffer linearise(const Buffers& buffer_sequence,
+      const asio::mutable_buffer& storage)
+  {
+    return buffer_sequence_adapter::linearise(
+        asio::buffer_sequence_begin(buffer_sequence),
+        asio::buffer_sequence_end(buffer_sequence), storage);
+  }
+
+private:
+  template <typename Iterator>
+  void init(Iterator begin, Iterator end)
+  {
+    Iterator iter = begin;
+    for (; iter != end && count_ < max_buffers; ++iter, ++count_)
+    {
+      Buffer buffer(*iter);
+      init_native_buffer(buffers_[count_], buffer);
+      total_buffer_size_ += buffer.size();
+    }
+  }
+
+  template <typename Iterator>
+  static bool all_empty(Iterator begin, Iterator end)
+  {
+    Iterator iter = begin;
+    std::size_t i = 0;
+    for (; iter != end && i < max_buffers; ++iter, ++i)
+      if (Buffer(*iter).size() > 0)
+        return false;
+    return true;
+  }
+
+  template <typename Iterator>
+  static void validate(Iterator begin, Iterator end)
+  {
+    Iterator iter = begin;
+    for (; iter != end; ++iter)
+    {
+      Buffer buffer(*iter);
+      buffer.data();
+    }
+  }
+
+  template <typename Iterator>
+  static Buffer first(Iterator begin, Iterator end)
+  {
+    Iterator iter = begin;
+    for (; iter != end; ++iter)
+    {
+      Buffer buffer(*iter);
+      if (buffer.size() != 0)
+        return buffer;
+    }
+    return Buffer();
+  }
+
+  template <typename Iterator>
+  static Buffer linearise(Iterator begin, Iterator end,
+      const asio::mutable_buffer& storage)
+  {
+    asio::mutable_buffer unused_storage = storage;
+    Iterator iter = begin;
+    while (iter != end && unused_storage.size() != 0)
+    {
+      Buffer buffer(*iter);
+      ++iter;
+      if (buffer.size() == 0)
+        continue;
+      if (unused_storage.size() == storage.size())
+      {
+        if (iter == end)
+          return buffer;
+        if (buffer.size() >= unused_storage.size())
+          return buffer;
+      }
+      unused_storage += asio::buffer_copy(unused_storage, buffer);
+    }
+    return Buffer(storage.data(), storage.size() - unused_storage.size());
+  }
+
+  native_buffer_type buffers_[max_buffers];
+  std::size_t count_;
+  std::size_t total_buffer_size_;
+};
+
+template <typename Buffer>
+class buffer_sequence_adapter<Buffer, asio::mutable_buffer>
+  : buffer_sequence_adapter_base
+{
+public:
+  enum { is_single_buffer = true };
+
+  explicit buffer_sequence_adapter(
+      const asio::mutable_buffer& buffer_sequence)
+  {
+    init_native_buffer(buffer_, Buffer(buffer_sequence));
+    total_buffer_size_ = buffer_sequence.size();
+  }
+
+  native_buffer_type* buffers()
+  {
+    return &buffer_;
+  }
+
+  std::size_t count() const
+  {
+    return 1;
+  }
+
+  std::size_t total_size() const
+  {
+    return total_buffer_size_;
+  }
+
+  bool all_empty() const
+  {
+    return total_buffer_size_ == 0;
+  }
+
+  static bool all_empty(const asio::mutable_buffer& buffer_sequence)
+  {
+    return buffer_sequence.size() == 0;
+  }
+
+  static void validate(const asio::mutable_buffer& buffer_sequence)
+  {
+    buffer_sequence.data();
+  }
+
+  static Buffer first(const asio::mutable_buffer& buffer_sequence)
+  {
+    return Buffer(buffer_sequence);
+  }
+
+  enum { linearisation_storage_size = 1 };
+
+  static Buffer linearise(const asio::mutable_buffer& buffer_sequence,
+      const Buffer&)
+  {
+    return Buffer(buffer_sequence);
+  }
+
+private:
+  native_buffer_type buffer_;
+  std::size_t total_buffer_size_;
+};
+
+template <typename Buffer>
+class buffer_sequence_adapter<Buffer, asio::const_buffer>
+  : buffer_sequence_adapter_base
+{
+public:
+  enum { is_single_buffer = true };
+
+  explicit buffer_sequence_adapter(
+      const asio::const_buffer& buffer_sequence)
+  {
+    init_native_buffer(buffer_, Buffer(buffer_sequence));
+    total_buffer_size_ = buffer_sequence.size();
+  }
+
+  native_buffer_type* buffers()
+  {
+    return &buffer_;
+  }
+
+  std::size_t count() const
+  {
+    return 1;
+  }
+
+  std::size_t total_size() const
+  {
+    return total_buffer_size_;
+  }
+
+  bool all_empty() const
+  {
+    return total_buffer_size_ == 0;
+  }
+
+  static bool all_empty(const asio::const_buffer& buffer_sequence)
+  {
+    return buffer_sequence.size() == 0;
+  }
+
+  static void validate(const asio::const_buffer& buffer_sequence)
+  {
+    buffer_sequence.data();
+  }
+
+  static Buffer first(const asio::const_buffer& buffer_sequence)
+  {
+    return Buffer(buffer_sequence);
+  }
+
+  enum { linearisation_storage_size = 1 };
+
+  static Buffer linearise(const asio::const_buffer& buffer_sequence,
+      const Buffer&)
+  {
+    return Buffer(buffer_sequence);
+  }
+
+private:
+  native_buffer_type buffer_;
+  std::size_t total_buffer_size_;
+};
+
+#if !defined(ASIO_NO_DEPRECATED)
+
+template <typename Buffer>
+class buffer_sequence_adapter<Buffer, asio::mutable_buffers_1>
+  : buffer_sequence_adapter_base
+{
+public:
+  enum { is_single_buffer = true };
+
+  explicit buffer_sequence_adapter(
+      const asio::mutable_buffers_1& buffer_sequence)
+  {
+    init_native_buffer(buffer_, Buffer(buffer_sequence));
+    total_buffer_size_ = buffer_sequence.size();
+  }
+
+  native_buffer_type* buffers()
+  {
+    return &buffer_;
+  }
+
+  std::size_t count() const
+  {
+    return 1;
+  }
+
+  std::size_t total_size() const
+  {
+    return total_buffer_size_;
+  }
+
+  bool all_empty() const
+  {
+    return total_buffer_size_ == 0;
+  }
+
+  static bool all_empty(const asio::mutable_buffers_1& buffer_sequence)
+  {
+    return buffer_sequence.size() == 0;
+  }
+
+  static void validate(const asio::mutable_buffers_1& buffer_sequence)
+  {
+    buffer_sequence.data();
+  }
+
+  static Buffer first(const asio::mutable_buffers_1& buffer_sequence)
+  {
+    return Buffer(buffer_sequence);
+  }
+
+  enum { linearisation_storage_size = 1 };
+
+  static Buffer linearise(const asio::mutable_buffers_1& buffer_sequence,
+      const Buffer&)
+  {
+    return Buffer(buffer_sequence);
+  }
+
+private:
+  native_buffer_type buffer_;
+  std::size_t total_buffer_size_;
+};
+
+template <typename Buffer>
+class buffer_sequence_adapter<Buffer, asio::const_buffers_1>
+  : buffer_sequence_adapter_base
+{
+public:
+  enum { is_single_buffer = true };
+
+  explicit buffer_sequence_adapter(
+      const asio::const_buffers_1& buffer_sequence)
+  {
+    init_native_buffer(buffer_, Buffer(buffer_sequence));
+    total_buffer_size_ = buffer_sequence.size();
+  }
+
+  native_buffer_type* buffers()
+  {
+    return &buffer_;
+  }
+
+  std::size_t count() const
+  {
+    return 1;
+  }
+
+  std::size_t total_size() const
+  {
+    return total_buffer_size_;
+  }
+
+  bool all_empty() const
+  {
+    return total_buffer_size_ == 0;
+  }
+
+  static bool all_empty(const asio::const_buffers_1& buffer_sequence)
+  {
+    return buffer_sequence.size() == 0;
+  }
+
+  static void validate(const asio::const_buffers_1& buffer_sequence)
+  {
+    buffer_sequence.data();
+  }
+
+  static Buffer first(const asio::const_buffers_1& buffer_sequence)
+  {
+    return Buffer(buffer_sequence);
+  }
+
+  enum { linearisation_storage_size = 1 };
+
+  static Buffer linearise(const asio::const_buffers_1& buffer_sequence,
+      const Buffer&)
+  {
+    return Buffer(buffer_sequence);
+  }
+
+private:
+  native_buffer_type buffer_;
+  std::size_t total_buffer_size_;
+};
+
+#endif // !defined(ASIO_NO_DEPRECATED)
+
+template <typename Buffer, typename Elem>
+class buffer_sequence_adapter<Buffer, boost::array<Elem, 2> >
+  : buffer_sequence_adapter_base
+{
+public:
+  enum { is_single_buffer = false };
+
+  explicit buffer_sequence_adapter(
+      const boost::array<Elem, 2>& buffer_sequence)
+  {
+    init_native_buffer(buffers_[0], Buffer(buffer_sequence[0]));
+    init_native_buffer(buffers_[1], Buffer(buffer_sequence[1]));
+    total_buffer_size_ = buffer_sequence[0].size() + buffer_sequence[1].size();
+  }
+
+  native_buffer_type* buffers()
+  {
+    return buffers_;
+  }
+
+  std::size_t count() const
+  {
+    return 2;
+  }
+
+  std::size_t total_size() const
+  {
+    return total_buffer_size_;
+  }
+
+  bool all_empty() const
+  {
+    return total_buffer_size_ == 0;
+  }
+
+  static bool all_empty(const boost::array<Elem, 2>& buffer_sequence)
+  {
+    return buffer_sequence[0].size() == 0 && buffer_sequence[1].size() == 0;
+  }
+
+  static void validate(const boost::array<Elem, 2>& buffer_sequence)
+  {
+    buffer_sequence[0].data();
+    buffer_sequence[1].data();
+  }
+
+  static Buffer first(const boost::array<Elem, 2>& buffer_sequence)
+  {
+    return Buffer(buffer_sequence[0].size() != 0
+        ? buffer_sequence[0] : buffer_sequence[1]);
+  }
+
+  enum { linearisation_storage_size = 8192 };
+
+  static Buffer linearise(const boost::array<Elem, 2>& buffer_sequence,
+      const asio::mutable_buffer& storage)
+  {
+    if (buffer_sequence[0].size() == 0)
+      return Buffer(buffer_sequence[1]);
+    if (buffer_sequence[1].size() == 0)
+      return Buffer(buffer_sequence[0]);
+    return Buffer(storage.data(),
+        asio::buffer_copy(storage, buffer_sequence));
+  }
+
+private:
+  native_buffer_type buffers_[2];
+  std::size_t total_buffer_size_;
+};
+
+#if defined(ASIO_HAS_STD_ARRAY)
+
+template <typename Buffer, typename Elem>
+class buffer_sequence_adapter<Buffer, std::array<Elem, 2> >
+  : buffer_sequence_adapter_base
+{
+public:
+  enum { is_single_buffer = false };
+
+  explicit buffer_sequence_adapter(
+      const std::array<Elem, 2>& buffer_sequence)
+  {
+    init_native_buffer(buffers_[0], Buffer(buffer_sequence[0]));
+    init_native_buffer(buffers_[1], Buffer(buffer_sequence[1]));
+    total_buffer_size_ = buffer_sequence[0].size() + buffer_sequence[1].size();
+  }
+
+  native_buffer_type* buffers()
+  {
+    return buffers_;
+  }
+
+  std::size_t count() const
+  {
+    return 2;
+  }
+
+  std::size_t total_size() const
+  {
+    return total_buffer_size_;
+  }
+
+  bool all_empty() const
+  {
+    return total_buffer_size_ == 0;
+  }
+
+  static bool all_empty(const std::array<Elem, 2>& buffer_sequence)
+  {
+    return buffer_sequence[0].size() == 0 && buffer_sequence[1].size() == 0;
+  }
+
+  static void validate(const std::array<Elem, 2>& buffer_sequence)
+  {
+    buffer_sequence[0].data();
+    buffer_sequence[1].data();
+  }
+
+  static Buffer first(const std::array<Elem, 2>& buffer_sequence)
+  {
+    return Buffer(buffer_sequence[0].size() != 0
+        ? buffer_sequence[0] : buffer_sequence[1]);
+  }
+
+  enum { linearisation_storage_size = 8192 };
+
+  static Buffer linearise(const std::array<Elem, 2>& buffer_sequence,
+      const asio::mutable_buffer& storage)
+  {
+    if (buffer_sequence[0].size() == 0)
+      return Buffer(buffer_sequence[1]);
+    if (buffer_sequence[1].size() == 0)
+      return Buffer(buffer_sequence[0]);
+    return Buffer(storage.data(),
+        asio::buffer_copy(storage, buffer_sequence));
+  }
+
+private:
+  native_buffer_type buffers_[2];
+  std::size_t total_buffer_size_;
+};
+
+#endif // defined(ASIO_HAS_STD_ARRAY)
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/buffer_sequence_adapter.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // ASIO_DETAIL_BUFFER_SEQUENCE_ADAPTER_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/buffered_stream_storage.hpp b/link/modules/asio-standalone/asio/include/asio/detail/buffered_stream_storage.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/buffered_stream_storage.hpp
@@ -0,0 +1,126 @@
+//
+// detail/buffered_stream_storage.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_BUFFERED_STREAM_STORAGE_HPP
+#define ASIO_DETAIL_BUFFERED_STREAM_STORAGE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/buffer.hpp"
+#include "asio/detail/assert.hpp"
+#include <cstddef>
+#include <cstring>
+#include <vector>
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class buffered_stream_storage
+{
+public:
+  // The type of the bytes stored in the buffer.
+  typedef unsigned char byte_type;
+
+  // The type used for offsets into the buffer.
+  typedef std::size_t size_type;
+
+  // Constructor.
+  explicit buffered_stream_storage(std::size_t buffer_capacity)
+    : begin_offset_(0),
+      end_offset_(0),
+      buffer_(buffer_capacity)
+  {
+  }
+
+  /// Clear the buffer.
+  void clear()
+  {
+    begin_offset_ = 0;
+    end_offset_ = 0;
+  }
+
+  // Return a pointer to the beginning of the unread data.
+  mutable_buffer data()
+  {
+    return asio::buffer(buffer_) + begin_offset_;
+  }
+
+  // Return a pointer to the beginning of the unread data.
+  const_buffer data() const
+  {
+    return asio::buffer(buffer_) + begin_offset_;
+  }
+
+  // Is there no unread data in the buffer.
+  bool empty() const
+  {
+    return begin_offset_ == end_offset_;
+  }
+
+  // Return the amount of unread data the is in the buffer.
+  size_type size() const
+  {
+    return end_offset_ - begin_offset_;
+  }
+
+  // Resize the buffer to the specified length.
+  void resize(size_type length)
+  {
+    ASIO_ASSERT(length <= capacity());
+    if (begin_offset_ + length <= capacity())
+    {
+      end_offset_ = begin_offset_ + length;
+    }
+    else
+    {
+      using namespace std; // For memmove.
+      memmove(&buffer_[0], &buffer_[0] + begin_offset_, size());
+      end_offset_ = length;
+      begin_offset_ = 0;
+    }
+  }
+
+  // Return the maximum size for data in the buffer.
+  size_type capacity() const
+  {
+    return buffer_.size();
+  }
+
+  // Consume multiple bytes from the beginning of the buffer.
+  void consume(size_type count)
+  {
+    ASIO_ASSERT(begin_offset_ + count <= end_offset_);
+    begin_offset_ += count;
+    if (empty())
+      clear();
+  }
+
+private:
+  // The offset to the beginning of the unread data.
+  size_type begin_offset_;
+
+  // The offset to the end of the unread data.
+  size_type end_offset_;
+  
+  // The data in the buffer.
+  std::vector<byte_type> buffer_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_BUFFERED_STREAM_STORAGE_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/bulk_executor_op.hpp b/link/modules/asio-standalone/asio/include/asio/detail/bulk_executor_op.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/bulk_executor_op.hpp
@@ -0,0 +1,88 @@
+//
+// detail/bulk_executor_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_BULK_EXECUTOR_OP_HPP
+#define ASIO_DETAIL_BULK_EXECUTOR_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/scheduler_operation.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Handler, typename Alloc,
+    typename Operation = scheduler_operation>
+class bulk_executor_op : public Operation
+{
+public:
+  ASIO_DEFINE_HANDLER_ALLOCATOR_PTR(bulk_executor_op);
+
+  template <typename H>
+  bulk_executor_op(ASIO_MOVE_ARG(H) h,
+      const Alloc& allocator, std::size_t i)
+    : Operation(&bulk_executor_op::do_complete),
+      handler_(ASIO_MOVE_CAST(H)(h)),
+      allocator_(allocator),
+      index_(i)
+  {
+  }
+
+  static void do_complete(void* owner, Operation* base,
+      const asio::error_code& /*ec*/,
+      std::size_t /*bytes_transferred*/)
+  {
+    // Take ownership of the handler object.
+    bulk_executor_op* o(static_cast<bulk_executor_op*>(base));
+    Alloc allocator(o->allocator_);
+    ptr p = { detail::addressof(allocator), o, o };
+
+    ASIO_HANDLER_COMPLETION((*o));
+
+    // Make a copy of the handler so that the memory can be deallocated before
+    // the upcall is made. Even if we're not about to make an upcall, a
+    // sub-object of the handler may be the true owner of the memory associated
+    // with the handler. Consequently, a local copy of the handler is required
+    // to ensure that any owning sub-object remains valid until after we have
+    // deallocated the memory here.
+    detail::binder1<Handler, std::size_t> handler(o->handler_, o->index_);
+    p.reset();
+
+    // Make the upcall if required.
+    if (owner)
+    {
+      fenced_block b(fenced_block::half);
+      ASIO_HANDLER_INVOCATION_BEGIN(());
+      asio_handler_invoke_helpers::invoke(handler, handler.handler_);
+      ASIO_HANDLER_INVOCATION_END;
+    }
+  }
+
+private:
+  Handler handler_;
+  Alloc allocator_;
+  std::size_t index_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_BULK_EXECUTOR_OP_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/call_stack.hpp b/link/modules/asio-standalone/asio/include/asio/detail/call_stack.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/call_stack.hpp
@@ -0,0 +1,125 @@
+//
+// detail/call_stack.hpp
+// ~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_CALL_STACK_HPP
+#define ASIO_DETAIL_CALL_STACK_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/noncopyable.hpp"
+#include "asio/detail/tss_ptr.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+// Helper class to determine whether or not the current thread is inside an
+// invocation of io_context::run() for a specified io_context object.
+template <typename Key, typename Value = unsigned char>
+class call_stack
+{
+public:
+  // Context class automatically pushes the key/value pair on to the stack.
+  class context
+    : private noncopyable
+  {
+  public:
+    // Push the key on to the stack.
+    explicit context(Key* k)
+      : key_(k),
+        next_(call_stack<Key, Value>::top_)
+    {
+      value_ = reinterpret_cast<unsigned char*>(this);
+      call_stack<Key, Value>::top_ = this;
+    }
+
+    // Push the key/value pair on to the stack.
+    context(Key* k, Value& v)
+      : key_(k),
+        value_(&v),
+        next_(call_stack<Key, Value>::top_)
+    {
+      call_stack<Key, Value>::top_ = this;
+    }
+
+    // Pop the key/value pair from the stack.
+    ~context()
+    {
+      call_stack<Key, Value>::top_ = next_;
+    }
+
+    // Find the next context with the same key.
+    Value* next_by_key() const
+    {
+      context* elem = next_;
+      while (elem)
+      {
+        if (elem->key_ == key_)
+          return elem->value_;
+        elem = elem->next_;
+      }
+      return 0;
+    }
+
+  private:
+    friend class call_stack<Key, Value>;
+
+    // The key associated with the context.
+    Key* key_;
+
+    // The value associated with the context.
+    Value* value_;
+
+    // The next element in the stack.
+    context* next_;
+  };
+
+  friend class context;
+
+  // Determine whether the specified owner is on the stack. Returns address of
+  // key if present, 0 otherwise.
+  static Value* contains(Key* k)
+  {
+    context* elem = top_;
+    while (elem)
+    {
+      if (elem->key_ == k)
+        return elem->value_;
+      elem = elem->next_;
+    }
+    return 0;
+  }
+
+  // Obtain the value at the top of the stack.
+  static Value* top()
+  {
+    context* elem = top_;
+    return elem ? elem->value_ : 0;
+  }
+
+private:
+  // The top of the stack of calls for the current thread.
+  static tss_ptr<context> top_;
+};
+
+template <typename Key, typename Value>
+tss_ptr<typename call_stack<Key, Value>::context>
+call_stack<Key, Value>::top_;
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_CALL_STACK_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/chrono.hpp b/link/modules/asio-standalone/asio/include/asio/detail/chrono.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/chrono.hpp
@@ -0,0 +1,66 @@
+//
+// detail/chrono.hpp
+// ~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_CHRONO_HPP
+#define ASIO_DETAIL_CHRONO_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_STD_CHRONO)
+# include <chrono>
+#elif defined(ASIO_HAS_BOOST_CHRONO)
+# include <boost/chrono/system_clocks.hpp>
+#endif // defined(ASIO_HAS_BOOST_CHRONO)
+
+namespace asio {
+namespace chrono {
+
+#if defined(ASIO_HAS_STD_CHRONO)
+using std::chrono::duration;
+using std::chrono::time_point;
+using std::chrono::duration_cast;
+using std::chrono::nanoseconds;
+using std::chrono::microseconds;
+using std::chrono::milliseconds;
+using std::chrono::seconds;
+using std::chrono::minutes;
+using std::chrono::hours;
+using std::chrono::time_point_cast;
+#if defined(ASIO_HAS_STD_CHRONO_MONOTONIC_CLOCK)
+typedef std::chrono::monotonic_clock steady_clock;
+#else // defined(ASIO_HAS_STD_CHRONO_MONOTONIC_CLOCK)
+using std::chrono::steady_clock;
+#endif // defined(ASIO_HAS_STD_CHRONO_MONOTONIC_CLOCK)
+using std::chrono::system_clock;
+using std::chrono::high_resolution_clock;
+#elif defined(ASIO_HAS_BOOST_CHRONO)
+using boost::chrono::duration;
+using boost::chrono::time_point;
+using boost::chrono::duration_cast;
+using boost::chrono::nanoseconds;
+using boost::chrono::microseconds;
+using boost::chrono::milliseconds;
+using boost::chrono::seconds;
+using boost::chrono::minutes;
+using boost::chrono::hours;
+using boost::chrono::time_point_cast;
+using boost::chrono::system_clock;
+using boost::chrono::steady_clock;
+using boost::chrono::high_resolution_clock;
+#endif // defined(ASIO_HAS_BOOST_CHRONO)
+
+} // namespace chrono
+} // namespace asio
+
+#endif // ASIO_DETAIL_CHRONO_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/chrono_time_traits.hpp b/link/modules/asio-standalone/asio/include/asio/detail/chrono_time_traits.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/chrono_time_traits.hpp
@@ -0,0 +1,190 @@
+//
+// detail/chrono_time_traits.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_CHRONO_TIME_TRAITS_HPP
+#define ASIO_DETAIL_CHRONO_TIME_TRAITS_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/cstdint.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+// Helper template to compute the greatest common divisor.
+template <int64_t v1, int64_t v2>
+struct gcd { enum { value = gcd<v2, v1 % v2>::value }; };
+
+template <int64_t v1>
+struct gcd<v1, 0> { enum { value = v1 }; };
+
+// Adapts std::chrono clocks for use with a deadline timer.
+template <typename Clock, typename WaitTraits>
+struct chrono_time_traits
+{
+  // The clock type.
+  typedef Clock clock_type;
+
+  // The duration type of the clock.
+  typedef typename clock_type::duration duration_type;
+
+  // The time point type of the clock.
+  typedef typename clock_type::time_point time_type;
+
+  // The period of the clock.
+  typedef typename duration_type::period period_type;
+
+  // Get the current time.
+  static time_type now()
+  {
+    return clock_type::now();
+  }
+
+  // Add a duration to a time.
+  static time_type add(const time_type& t, const duration_type& d)
+  {
+    const time_type epoch;
+    if (t >= epoch)
+    {
+      if ((time_type::max)() - t < d)
+        return (time_type::max)();
+    }
+    else // t < epoch
+    {
+      if (-(t - (time_type::min)()) > d)
+        return (time_type::min)();
+    }
+
+    return t + d;
+  }
+
+  // Subtract one time from another.
+  static duration_type subtract(const time_type& t1, const time_type& t2)
+  {
+    const time_type epoch;
+    if (t1 >= epoch)
+    {
+      if (t2 >= epoch)
+      {
+        return t1 - t2;
+      }
+      else if (t2 == (time_type::min)())
+      {
+        return (duration_type::max)();
+      }
+      else if ((time_type::max)() - t1 < epoch - t2)
+      {
+        return (duration_type::max)();
+      }
+      else
+      {
+        return t1 - t2;
+      }
+    }
+    else // t1 < epoch
+    {
+      if (t2 < epoch)
+      {
+        return t1 - t2;
+      }
+      else if (t1 == (time_type::min)())
+      {
+        return (duration_type::min)();
+      }
+      else if ((time_type::max)() - t2 < epoch - t1)
+      {
+        return (duration_type::min)();
+      }
+      else
+      {
+        return -(t2 - t1);
+      }
+    }
+  }
+
+  // Test whether one time is less than another.
+  static bool less_than(const time_type& t1, const time_type& t2)
+  {
+    return t1 < t2;
+  }
+
+  // Implement just enough of the posix_time::time_duration interface to supply
+  // what the timer_queue requires.
+  class posix_time_duration
+  {
+  public:
+    explicit posix_time_duration(const duration_type& d)
+      : d_(d)
+    {
+    }
+
+    int64_t ticks() const
+    {
+      return d_.count();
+    }
+
+    int64_t total_seconds() const
+    {
+      return duration_cast<1, 1>();
+    }
+
+    int64_t total_milliseconds() const
+    {
+      return duration_cast<1, 1000>();
+    }
+
+    int64_t total_microseconds() const
+    {
+      return duration_cast<1, 1000000>();
+    }
+
+  private:
+    template <int64_t Num, int64_t Den>
+    int64_t duration_cast() const
+    {
+      const int64_t num1 = period_type::num / gcd<period_type::num, Num>::value;
+      const int64_t num2 = Num / gcd<period_type::num, Num>::value;
+
+      const int64_t den1 = period_type::den / gcd<period_type::den, Den>::value;
+      const int64_t den2 = Den / gcd<period_type::den, Den>::value;
+
+      const int64_t num = num1 * den2;
+      const int64_t den = num2 * den1;
+
+      if (num == 1 && den == 1)
+        return ticks();
+      else if (num != 1 && den == 1)
+        return ticks() * num;
+      else if (num == 1 && period_type::den != 1)
+        return ticks() / den;
+      else
+        return ticks() * num / den;
+    }
+
+    duration_type d_;
+  };
+
+  // Convert to POSIX duration type.
+  static posix_time_duration to_posix_duration(const duration_type& d)
+  {
+    return posix_time_duration(WaitTraits::to_wait_duration(d));
+  }
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_CHRONO_TIME_TRAITS_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/completion_handler.hpp b/link/modules/asio-standalone/asio/include/asio/detail/completion_handler.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/completion_handler.hpp
@@ -0,0 +1,88 @@
+//
+// detail/completion_handler.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_COMPLETION_HANDLER_HPP
+#define ASIO_DETAIL_COMPLETION_HANDLER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_work.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/detail/operation.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Handler, typename IoExecutor>
+class completion_handler : public operation
+{
+public:
+  ASIO_DEFINE_HANDLER_PTR(completion_handler);
+
+  completion_handler(Handler& h, const IoExecutor& io_ex)
+    : operation(&completion_handler::do_complete),
+      handler_(ASIO_MOVE_CAST(Handler)(h)),
+      work_(handler_, io_ex)
+  {
+  }
+
+  static void do_complete(void* owner, operation* base,
+      const asio::error_code& /*ec*/,
+      std::size_t /*bytes_transferred*/)
+  {
+    // Take ownership of the handler object.
+    completion_handler* h(static_cast<completion_handler*>(base));
+    ptr p = { asio::detail::addressof(h->handler_), h, h };
+
+    ASIO_HANDLER_COMPLETION((*h));
+
+    // Take ownership of the operation's outstanding work.
+    handler_work<Handler, IoExecutor> w(
+        ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)(
+          h->work_));
+
+    // Make a copy of the handler so that the memory can be deallocated before
+    // the upcall is made. Even if we're not about to make an upcall, a
+    // sub-object of the handler may be the true owner of the memory associated
+    // with the handler. Consequently, a local copy of the handler is required
+    // to ensure that any owning sub-object remains valid until after we have
+    // deallocated the memory here.
+    Handler handler(ASIO_MOVE_CAST(Handler)(h->handler_));
+    p.h = asio::detail::addressof(handler);
+    p.reset();
+
+    // Make the upcall if required.
+    if (owner)
+    {
+      fenced_block b(fenced_block::half);
+      ASIO_HANDLER_INVOCATION_BEGIN(());
+      w.complete(handler, handler);
+      ASIO_HANDLER_INVOCATION_END;
+    }
+  }
+
+private:
+  Handler handler_;
+  handler_work<Handler, IoExecutor> work_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_COMPLETION_HANDLER_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/concurrency_hint.hpp b/link/modules/asio-standalone/asio/include/asio/detail/concurrency_hint.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/concurrency_hint.hpp
@@ -0,0 +1,94 @@
+//
+// detail/concurrency_hint.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_CONCURRENCY_HINT_HPP
+#define ASIO_DETAIL_CONCURRENCY_HINT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/noncopyable.hpp"
+
+// The concurrency hint ID and mask are used to identify when a "well-known"
+// concurrency hint value has been passed to the io_context.
+#define ASIO_CONCURRENCY_HINT_ID 0xA5100000u
+#define ASIO_CONCURRENCY_HINT_ID_MASK 0xFFFF0000u
+
+// If set, this bit indicates that the scheduler should perform locking.
+#define ASIO_CONCURRENCY_HINT_LOCKING_SCHEDULER 0x1u
+
+// If set, this bit indicates that the reactor should perform locking when
+// managing descriptor registrations.
+#define ASIO_CONCURRENCY_HINT_LOCKING_REACTOR_REGISTRATION 0x2u
+
+// If set, this bit indicates that the reactor should perform locking for I/O.
+#define ASIO_CONCURRENCY_HINT_LOCKING_REACTOR_IO 0x4u
+
+// Helper macro to determine if we have a special concurrency hint.
+#define ASIO_CONCURRENCY_HINT_IS_SPECIAL(hint) \
+  ((static_cast<unsigned>(hint) \
+    & ASIO_CONCURRENCY_HINT_ID_MASK) \
+      == ASIO_CONCURRENCY_HINT_ID)
+
+// Helper macro to determine if locking is enabled for a given facility.
+#define ASIO_CONCURRENCY_HINT_IS_LOCKING(facility, hint) \
+  (((static_cast<unsigned>(hint) \
+    & (ASIO_CONCURRENCY_HINT_ID_MASK \
+      | ASIO_CONCURRENCY_HINT_LOCKING_ ## facility)) \
+        ^ ASIO_CONCURRENCY_HINT_ID) != 0)
+
+// This special concurrency hint disables locking in both the scheduler and
+// reactor I/O. This hint has the following restrictions:
+//
+// - Care must be taken to ensure that all operations on the io_context and any
+//   of its associated I/O objects (such as sockets and timers) occur in only
+//   one thread at a time.
+//
+// - Asynchronous resolve operations fail with operation_not_supported.
+//
+// - If a signal_set is used with the io_context, signal_set objects cannot be
+//   used with any other io_context in the program.
+#define ASIO_CONCURRENCY_HINT_UNSAFE \
+  static_cast<int>(ASIO_CONCURRENCY_HINT_ID)
+
+// This special concurrency hint disables locking in the reactor I/O. This hint
+// has the following restrictions:
+//
+// - Care must be taken to ensure that run functions on the io_context, and all
+//   operations on the io_context's associated I/O objects (such as sockets and
+//   timers), occur in only one thread at a time.
+#define ASIO_CONCURRENCY_HINT_UNSAFE_IO \
+  static_cast<int>(ASIO_CONCURRENCY_HINT_ID \
+      | ASIO_CONCURRENCY_HINT_LOCKING_SCHEDULER \
+      | ASIO_CONCURRENCY_HINT_LOCKING_REACTOR_REGISTRATION)
+
+// The special concurrency hint provides full thread safety.
+#define ASIO_CONCURRENCY_HINT_SAFE \
+  static_cast<int>(ASIO_CONCURRENCY_HINT_ID \
+      | ASIO_CONCURRENCY_HINT_LOCKING_SCHEDULER \
+      | ASIO_CONCURRENCY_HINT_LOCKING_REACTOR_REGISTRATION \
+      | ASIO_CONCURRENCY_HINT_LOCKING_REACTOR_IO)
+
+// This #define may be overridden at compile time to specify a program-wide
+// default concurrency hint, used by the zero-argument io_context constructor.
+#if !defined(ASIO_CONCURRENCY_HINT_DEFAULT)
+# define ASIO_CONCURRENCY_HINT_DEFAULT -1
+#endif // !defined(ASIO_CONCURRENCY_HINT_DEFAULT)
+
+// This #define may be overridden at compile time to specify a program-wide
+// concurrency hint, used by the one-argument io_context constructor when
+// passed a value of 1.
+#if !defined(ASIO_CONCURRENCY_HINT_1)
+# define ASIO_CONCURRENCY_HINT_1 1
+#endif // !defined(ASIO_CONCURRENCY_HINT_DEFAULT)
+
+#endif // ASIO_DETAIL_CONCURRENCY_HINT_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/conditionally_enabled_event.hpp b/link/modules/asio-standalone/asio/include/asio/detail/conditionally_enabled_event.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/conditionally_enabled_event.hpp
@@ -0,0 +1,120 @@
+//
+// detail/conditionally_enabled_event.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_CONDITIONALLY_ENABLED_EVENT_HPP
+#define ASIO_DETAIL_CONDITIONALLY_ENABLED_EVENT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/conditionally_enabled_mutex.hpp"
+#include "asio/detail/event.hpp"
+#include "asio/detail/noncopyable.hpp"
+#include "asio/detail/null_event.hpp"
+#include "asio/detail/scoped_lock.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+// Mutex adapter used to conditionally enable or disable locking.
+class conditionally_enabled_event
+  : private noncopyable
+{
+public:
+  // Constructor.
+  conditionally_enabled_event()
+  {
+  }
+
+  // Destructor.
+  ~conditionally_enabled_event()
+  {
+  }
+
+  // Signal the event. (Retained for backward compatibility.)
+  void signal(conditionally_enabled_mutex::scoped_lock& lock)
+  {
+    if (lock.mutex_.enabled_)
+      event_.signal(lock);
+  }
+
+  // Signal all waiters.
+  void signal_all(conditionally_enabled_mutex::scoped_lock& lock)
+  {
+    if (lock.mutex_.enabled_)
+      event_.signal_all(lock);
+  }
+
+  // Unlock the mutex and signal one waiter.
+  void unlock_and_signal_one(
+      conditionally_enabled_mutex::scoped_lock& lock)
+  {
+    if (lock.mutex_.enabled_)
+      event_.unlock_and_signal_one(lock);
+  }
+
+  // Unlock the mutex and signal one waiter who may destroy us.
+  void unlock_and_signal_one_for_destruction(
+      conditionally_enabled_mutex::scoped_lock& lock)
+  {
+    if (lock.mutex_.enabled_)
+      event_.unlock_and_signal_one(lock);
+  }
+
+  // If there's a waiter, unlock the mutex and signal it.
+  bool maybe_unlock_and_signal_one(
+      conditionally_enabled_mutex::scoped_lock& lock)
+  {
+    if (lock.mutex_.enabled_)
+      return event_.maybe_unlock_and_signal_one(lock);
+    else
+      return false;
+  }
+
+  // Reset the event.
+  void clear(conditionally_enabled_mutex::scoped_lock& lock)
+  {
+    if (lock.mutex_.enabled_)
+      event_.clear(lock);
+  }
+
+  // Wait for the event to become signalled.
+  void wait(conditionally_enabled_mutex::scoped_lock& lock)
+  {
+    if (lock.mutex_.enabled_)
+      event_.wait(lock);
+    else
+      null_event().wait(lock);
+  }
+
+  // Timed wait for the event to become signalled.
+  bool wait_for_usec(
+      conditionally_enabled_mutex::scoped_lock& lock, long usec)
+  {
+    if (lock.mutex_.enabled_)
+      return event_.wait_for_usec(lock, usec);
+    else
+      return null_event().wait_for_usec(lock, usec);
+  }
+
+private:
+  asio::detail::event event_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_CONDITIONALLY_ENABLED_EVENT_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/conditionally_enabled_mutex.hpp b/link/modules/asio-standalone/asio/include/asio/detail/conditionally_enabled_mutex.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/conditionally_enabled_mutex.hpp
@@ -0,0 +1,149 @@
+//
+// detail/conditionally_enabled_mutex.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_CONDITIONALLY_ENABLED_MUTEX_HPP
+#define ASIO_DETAIL_CONDITIONALLY_ENABLED_MUTEX_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/mutex.hpp"
+#include "asio/detail/noncopyable.hpp"
+#include "asio/detail/scoped_lock.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+// Mutex adapter used to conditionally enable or disable locking.
+class conditionally_enabled_mutex
+  : private noncopyable
+{
+public:
+  // Helper class to lock and unlock a mutex automatically.
+  class scoped_lock
+    : private noncopyable
+  {
+  public:
+    // Tag type used to distinguish constructors.
+    enum adopt_lock_t { adopt_lock };
+
+    // Constructor adopts a lock that is already held.
+    scoped_lock(conditionally_enabled_mutex& m, adopt_lock_t)
+      : mutex_(m),
+        locked_(m.enabled_)
+    {
+    }
+
+    // Constructor acquires the lock.
+    explicit scoped_lock(conditionally_enabled_mutex& m)
+      : mutex_(m)
+    {
+      if (m.enabled_)
+      {
+        mutex_.mutex_.lock();
+        locked_ = true;
+      }
+      else
+        locked_ = false;
+    }
+
+    // Destructor releases the lock.
+    ~scoped_lock()
+    {
+      if (locked_)
+        mutex_.mutex_.unlock();
+    }
+
+    // Explicitly acquire the lock.
+    void lock()
+    {
+      if (mutex_.enabled_ && !locked_)
+      {
+        mutex_.mutex_.lock();
+        locked_ = true;
+      }
+    }
+
+    // Explicitly release the lock.
+    void unlock()
+    {
+      if (locked_)
+      {
+        mutex_.unlock();
+        locked_ = false;
+      }
+    }
+
+    // Test whether the lock is held.
+    bool locked() const
+    {
+      return locked_;
+    }
+
+    // Get the underlying mutex.
+    asio::detail::mutex& mutex()
+    {
+      return mutex_.mutex_;
+    }
+
+  private:
+    friend class conditionally_enabled_event;
+    conditionally_enabled_mutex& mutex_;
+    bool locked_;
+  };
+
+  // Constructor.
+  explicit conditionally_enabled_mutex(bool enabled)
+    : enabled_(enabled)
+  {
+  }
+
+  // Destructor.
+  ~conditionally_enabled_mutex()
+  {
+  }
+
+  // Determine whether locking is enabled.
+  bool enabled() const
+  {
+    return enabled_;
+  }
+
+  // Lock the mutex.
+  void lock()
+  {
+    if (enabled_)
+      mutex_.lock();
+  }
+
+  // Unlock the mutex.
+  void unlock()
+  {
+    if (enabled_)
+      mutex_.unlock();
+  }
+
+private:
+  friend class scoped_lock;
+  friend class conditionally_enabled_event;
+  asio::detail::mutex mutex_;
+  const bool enabled_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_CONDITIONALLY_ENABLED_MUTEX_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/config.hpp b/link/modules/asio-standalone/asio/include/asio/detail/config.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/config.hpp
@@ -0,0 +1,1822 @@
+//
+// detail/config.hpp
+// ~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_CONFIG_HPP
+#define ASIO_DETAIL_CONFIG_HPP
+
+// boostify: non-boost code starts here
+#if !defined(ASIO_STANDALONE)
+# if !defined(ASIO_ENABLE_BOOST)
+#  if (__cplusplus >= 201103)
+#   define ASIO_STANDALONE 1
+#  elif defined(_MSC_VER) && defined(_MSVC_LANG)
+#   if (_MSC_VER >= 1900) && (_MSVC_LANG >= 201103)
+#    define ASIO_STANDALONE 1
+#   endif // (_MSC_VER >= 1900) && (_MSVC_LANG >= 201103)
+#  endif // defined(_MSC_VER) && defined(_MSVC_LANG)
+# endif // !defined(ASIO_ENABLE_BOOST)
+#endif // !defined(ASIO_STANDALONE)
+
+// boostify: non-boost code ends here
+#if defined(ASIO_STANDALONE)
+# define ASIO_DISABLE_BOOST_ARRAY 1
+# define ASIO_DISABLE_BOOST_ASSERT 1
+# define ASIO_DISABLE_BOOST_BIND 1
+# define ASIO_DISABLE_BOOST_CHRONO 1
+# define ASIO_DISABLE_BOOST_DATE_TIME 1
+# define ASIO_DISABLE_BOOST_LIMITS 1
+# define ASIO_DISABLE_BOOST_REGEX 1
+# define ASIO_DISABLE_BOOST_STATIC_CONSTANT 1
+# define ASIO_DISABLE_BOOST_THROW_EXCEPTION 1
+# define ASIO_DISABLE_BOOST_WORKAROUND 1
+#else // defined(ASIO_STANDALONE)
+# include <boost/config.hpp>
+# include <boost/version.hpp>
+# define ASIO_HAS_BOOST_CONFIG 1
+#endif // defined(ASIO_STANDALONE)
+
+// Default to a header-only implementation. The user must specifically request
+// separate compilation by defining either ASIO_SEPARATE_COMPILATION or
+// ASIO_DYN_LINK (as a DLL/shared library implies separate compilation).
+#if !defined(ASIO_HEADER_ONLY)
+# if !defined(ASIO_SEPARATE_COMPILATION)
+#  if !defined(ASIO_DYN_LINK)
+#   define ASIO_HEADER_ONLY 1
+#  endif // !defined(ASIO_DYN_LINK)
+# endif // !defined(ASIO_SEPARATE_COMPILATION)
+#endif // !defined(ASIO_HEADER_ONLY)
+
+#if defined(ASIO_HEADER_ONLY)
+# define ASIO_DECL inline
+#else // defined(ASIO_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 ASIO_DYN_LINK.
+#  if defined(ASIO_DYN_LINK)
+// Export if this is our own source, otherwise import.
+#   if defined(ASIO_SOURCE)
+#    define ASIO_DECL __declspec(dllexport)
+#   else // defined(ASIO_SOURCE)
+#    define ASIO_DECL __declspec(dllimport)
+#   endif // defined(ASIO_SOURCE)
+#  endif // defined(ASIO_DYN_LINK)
+# endif // defined(_MSC_VER) || defined(__BORLANDC__) || defined(__CODEGEARC__)
+#endif // defined(ASIO_HEADER_ONLY)
+
+// If ASIO_DECL isn't defined yet define it now.
+#if !defined(ASIO_DECL)
+# define ASIO_DECL
+#endif // !defined(ASIO_DECL)
+
+// Helper macro for documentation.
+#define ASIO_UNSPECIFIED(e) e
+
+// Microsoft Visual C++ detection.
+#if !defined(ASIO_MSVC)
+# if defined(ASIO_HAS_BOOST_CONFIG) && defined(BOOST_MSVC)
+#  define ASIO_MSVC BOOST_MSVC
+# elif defined(_MSC_VER) && (defined(__INTELLISENSE__) \
+      || (!defined(__MWERKS__) && !defined(__EDG_VERSION__)))
+#  define ASIO_MSVC _MSC_VER
+# endif // defined(ASIO_HAS_BOOST_CONFIG) && defined(BOOST_MSVC)
+#endif // !defined(ASIO_MSVC)
+
+// Clang / libc++ detection.
+#if defined(__clang__)
+# if (__cplusplus >= 201103)
+#  if __has_include(<__config>)
+#   include <__config>
+#   if defined(_LIBCPP_VERSION)
+#    define ASIO_HAS_CLANG_LIBCXX 1
+#   endif // defined(_LIBCPP_VERSION)
+#  endif // __has_include(<__config>)
+# endif // (__cplusplus >= 201103)
+#endif // defined(__clang__)
+
+// Android platform detection.
+#if defined(__ANDROID__)
+# include <android/api-level.h>
+#endif // defined(__ANDROID__)
+
+// Support move construction and assignment on compilers known to allow it.
+#if !defined(ASIO_HAS_MOVE)
+# if !defined(ASIO_DISABLE_MOVE)
+#  if defined(__clang__)
+#   if __has_feature(__cxx_rvalue_references__)
+#    define ASIO_HAS_MOVE 1
+#   endif // __has_feature(__cxx_rvalue_references__)
+#  endif // defined(__clang__)
+#  if defined(__GNUC__)
+#   if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4)
+#    if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)
+#     define ASIO_HAS_MOVE 1
+#    endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)
+#   endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4)
+#  endif // defined(__GNUC__)
+#  if defined(ASIO_MSVC)
+#   if (_MSC_VER >= 1700)
+#    define ASIO_HAS_MOVE 1
+#   endif // (_MSC_VER >= 1700)
+#  endif // defined(ASIO_MSVC)
+#  if defined(__INTEL_CXX11_MODE__)
+#    if defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 1500)
+#      define ASIO_HAS_MOVE 1
+#    endif // defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 1500)
+#    if defined(__ICL) && (__ICL >= 1500)
+#      define ASIO_HAS_MOVE 1
+#    endif // defined(__ICL) && (__ICL >= 1500)
+#  endif // defined(__INTEL_CXX11_MODE__)
+# endif // !defined(ASIO_DISABLE_MOVE)
+#endif // !defined(ASIO_HAS_MOVE)
+
+// If ASIO_MOVE_CAST isn't defined, and move support is available, define
+// * ASIO_MOVE_ARG,
+// * ASIO_NONDEDUCED_MOVE_ARG, and
+// * ASIO_MOVE_CAST
+// to take advantage of rvalue references and perfect forwarding.
+#if defined(ASIO_HAS_MOVE) && !defined(ASIO_MOVE_CAST)
+# define ASIO_MOVE_ARG(type) type&&
+# define ASIO_MOVE_ARG2(type1, type2) type1, type2&&
+# define ASIO_NONDEDUCED_MOVE_ARG(type) type&
+# define ASIO_MOVE_CAST(type) static_cast<type&&>
+# define ASIO_MOVE_CAST2(type1, type2) static_cast<type1, type2&&>
+# define ASIO_MOVE_OR_LVALUE(type) static_cast<type&&>
+# define ASIO_MOVE_OR_LVALUE_TYPE(type) type
+#endif // defined(ASIO_HAS_MOVE) && !defined(ASIO_MOVE_CAST)
+
+// If ASIO_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(ASIO_MOVE_CAST)
+# if defined(__GNUC__)
+#  if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 1)) || (__GNUC__ > 4)
+#   define ASIO_MOVE_ARG(type) const type&
+#  else // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 1)) || (__GNUC__ > 4)
+#   define ASIO_MOVE_ARG(type) type
+#  endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 1)) || (__GNUC__ > 4)
+# elif defined(ASIO_MSVC)
+#  if (_MSC_VER >= 1400)
+#   define ASIO_MOVE_ARG(type) const type&
+#  else // (_MSC_VER >= 1400)
+#   define ASIO_MOVE_ARG(type) type
+#  endif // (_MSC_VER >= 1400)
+# else
+#  define ASIO_MOVE_ARG(type) type
+# endif
+# define ASIO_NONDEDUCED_MOVE_ARG(type) const type&
+# define ASIO_MOVE_CAST(type) static_cast<const type&>
+# define ASIO_MOVE_CAST2(type1, type2) static_cast<const type1, type2&>
+# define ASIO_MOVE_OR_LVALUE(type)
+# define ASIO_MOVE_OR_LVALUE_TYPE(type) type&
+#endif // !defined(ASIO_MOVE_CAST)
+
+// Support variadic templates on compilers known to allow it.
+#if !defined(ASIO_HAS_VARIADIC_TEMPLATES)
+# if !defined(ASIO_DISABLE_VARIADIC_TEMPLATES)
+#  if defined(__clang__)
+#   if __has_feature(__cxx_variadic_templates__)
+#    define ASIO_HAS_VARIADIC_TEMPLATES 1
+#   endif // __has_feature(__cxx_variadic_templates__)
+#  endif // defined(__clang__)
+#  if defined(__GNUC__)
+#   if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4)
+#    if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)
+#     define ASIO_HAS_VARIADIC_TEMPLATES 1
+#    endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)
+#   endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4)
+#  endif // defined(__GNUC__)
+#  if defined(ASIO_MSVC)
+#   if (_MSC_VER >= 1900)
+#    define ASIO_HAS_VARIADIC_TEMPLATES 1
+#   endif // (_MSC_VER >= 1900)
+#  endif // defined(ASIO_MSVC)
+# endif // !defined(ASIO_DISABLE_VARIADIC_TEMPLATES)
+#endif // !defined(ASIO_HAS_VARIADIC_TEMPLATES)
+#if !defined(ASIO_ELLIPSIS)
+# if defined(ASIO_HAS_VARIADIC_TEMPLATES)
+#  define ASIO_ELLIPSIS ...
+# else // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+#  define ASIO_ELLIPSIS
+# endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+#endif // !defined(ASIO_ELLIPSIS)
+
+// Support deleted functions on compilers known to allow it.
+#if !defined(ASIO_DELETED)
+# if defined(__GNUC__)
+#  if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4)
+#   if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)
+#    define ASIO_DELETED = delete
+#   endif // (__cplusplus >= 201103) || 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 ASIO_DELETED = delete
+#  endif // __has_feature(__cxx_deleted_functions__)
+# endif // defined(__clang__)
+# if defined(ASIO_MSVC)
+#  if (_MSC_VER >= 1900)
+#   define ASIO_DELETED = delete
+#  endif // (_MSC_VER >= 1900)
+# endif // defined(ASIO_MSVC)
+# if !defined(ASIO_DELETED)
+#  define ASIO_DELETED
+# endif // !defined(ASIO_DELETED)
+#endif // !defined(ASIO_DELETED)
+
+// Support constexpr on compilers known to allow it.
+#if !defined(ASIO_HAS_CONSTEXPR)
+# if !defined(ASIO_DISABLE_CONSTEXPR)
+#  if defined(__clang__)
+#   if __has_feature(__cxx_constexpr__)
+#    define ASIO_HAS_CONSTEXPR 1
+#   endif // __has_feature(__cxx_constexpr__)
+#  endif // defined(__clang__)
+#  if defined(__GNUC__)
+#   if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4)
+#    if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)
+#     define ASIO_HAS_CONSTEXPR 1
+#    endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)
+#   endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4)
+#  endif // defined(__GNUC__)
+#  if defined(ASIO_MSVC)
+#   if (_MSC_VER >= 1900)
+#    define ASIO_HAS_CONSTEXPR 1
+#   endif // (_MSC_VER >= 1900)
+#  endif // defined(ASIO_MSVC)
+# endif // !defined(ASIO_DISABLE_CONSTEXPR)
+#endif // !defined(ASIO_HAS_CONSTEXPR)
+#if !defined(ASIO_CONSTEXPR)
+# if defined(ASIO_HAS_CONSTEXPR)
+#  define ASIO_CONSTEXPR constexpr
+# else // defined(ASIO_HAS_CONSTEXPR)
+#  define ASIO_CONSTEXPR
+# endif // defined(ASIO_HAS_CONSTEXPR)
+#endif // !defined(ASIO_CONSTEXPR)
+#if !defined(ASIO_STATIC_CONSTEXPR)
+# if defined(ASIO_HAS_CONSTEXPR)
+#  define ASIO_STATIC_CONSTEXPR(type, assignment) \
+    static constexpr type assignment
+# else // defined(ASIO_HAS_CONSTEXPR)
+#  define ASIO_STATIC_CONSTEXPR(type, assignment) \
+    static const type assignment
+# endif // defined(ASIO_HAS_CONSTEXPR)
+#endif // !defined(ASIO_STATIC_CONSTEXPR)
+#if !defined(ASIO_STATIC_CONSTEXPR_DEFAULT_INIT)
+# if defined(ASIO_HAS_CONSTEXPR)
+#  if defined(__GNUC__)
+#   if (__GNUC__ >= 8)
+#    define ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(type, name) \
+      static constexpr const type name{}
+#   else // (__GNUC__ >= 8)
+#    define ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(type, name) \
+      static const type name
+#   endif // (__GNUC__ >= 8)
+#  elif defined(ASIO_MSVC)
+#   define ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(type, name) \
+     static const type name
+#  else // defined(ASIO_MSVC)
+#   define ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(type, name) \
+     static constexpr const type name{}
+#  endif // defined(ASIO_MSVC)
+# else // defined(ASIO_HAS_CONSTEXPR)
+#  define ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(type, name) \
+    static const type name
+# endif // defined(ASIO_HAS_CONSTEXPR)
+#endif // !defined(ASIO_STATIC_CONSTEXPR_DEFAULT_INIT)
+
+// Support noexcept on compilers known to allow it.
+#if !defined(ASIO_HAS_NOEXCEPT)
+# if !defined(ASIO_DISABLE_NOEXCEPT)
+#  if defined(ASIO_HAS_BOOST_CONFIG) && (BOOST_VERSION >= 105300)
+#   if !defined(BOOST_NO_NOEXCEPT)
+#    define ASIO_HAS_NOEXCEPT 1
+#   endif // !defined(BOOST_NO_NOEXCEPT)
+#   define ASIO_NOEXCEPT BOOST_NOEXCEPT
+#   define ASIO_NOEXCEPT_OR_NOTHROW BOOST_NOEXCEPT_OR_NOTHROW
+#   define ASIO_NOEXCEPT_IF(c) BOOST_NOEXCEPT_IF(c)
+#  elif defined(__clang__)
+#   if __has_feature(__cxx_noexcept__)
+#    define ASIO_HAS_NOEXCEPT 1
+#   endif // __has_feature(__cxx_noexcept__)
+#  elif defined(__GNUC__)
+#   if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4)
+#    if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)
+#      define ASIO_HAS_NOEXCEPT 1
+#    endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)
+#   endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4)
+#  elif defined(ASIO_MSVC)
+#   if (_MSC_VER >= 1900)
+#    define ASIO_HAS_NOEXCEPT 1
+#   endif // (_MSC_VER >= 1900)
+#  endif // defined(ASIO_MSVC)
+# endif // !defined(ASIO_DISABLE_NOEXCEPT)
+# if !defined(ASIO_NOEXCEPT)
+# endif // !defined(ASIO_NOEXCEPT)
+# if !defined(ASIO_NOEXCEPT_OR_NOTHROW)
+# endif // !defined(ASIO_NOEXCEPT_OR_NOTHROW)
+#endif // !defined(ASIO_HAS_NOEXCEPT)
+#if !defined(ASIO_NOEXCEPT)
+# if defined(ASIO_HAS_NOEXCEPT)
+#  define ASIO_NOEXCEPT noexcept(true)
+# else // defined(ASIO_HAS_NOEXCEPT)
+#  define ASIO_NOEXCEPT
+# endif // defined(ASIO_HAS_NOEXCEPT)
+#endif // !defined(ASIO_NOEXCEPT)
+#if !defined(ASIO_NOEXCEPT_OR_NOTHROW)
+# if defined(ASIO_HAS_NOEXCEPT)
+#  define ASIO_NOEXCEPT_OR_NOTHROW noexcept(true)
+# else // defined(ASIO_HAS_NOEXCEPT)
+#  define ASIO_NOEXCEPT_OR_NOTHROW throw()
+# endif // defined(ASIO_HAS_NOEXCEPT)
+#endif // !defined(ASIO_NOEXCEPT_OR_NOTHROW)
+#if !defined(ASIO_NOEXCEPT_IF)
+# if defined(ASIO_HAS_NOEXCEPT)
+#  define ASIO_NOEXCEPT_IF(c) noexcept(c)
+# else // defined(ASIO_HAS_NOEXCEPT)
+#  define ASIO_NOEXCEPT_IF(c)
+# endif // defined(ASIO_HAS_NOEXCEPT)
+#endif // !defined(ASIO_NOEXCEPT_IF)
+
+// Support automatic type deduction on compilers known to support it.
+#if !defined(ASIO_HAS_DECLTYPE)
+# if !defined(ASIO_DISABLE_DECLTYPE)
+#  if defined(__clang__)
+#   if __has_feature(__cxx_decltype__)
+#    define ASIO_HAS_DECLTYPE 1
+#   endif // __has_feature(__cxx_decltype__)
+#  endif // defined(__clang__)
+#  if defined(__GNUC__)
+#   if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4)
+#    if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)
+#     define ASIO_HAS_DECLTYPE 1
+#    endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)
+#   endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4)
+#  endif // defined(__GNUC__)
+#  if defined(ASIO_MSVC)
+#   if (_MSC_VER >= 1800)
+#    define ASIO_HAS_DECLTYPE 1
+#   endif // (_MSC_VER >= 1800)
+#  endif // defined(ASIO_MSVC)
+# endif // !defined(ASIO_DISABLE_DECLTYPE)
+#endif // !defined(ASIO_HAS_DECLTYPE)
+
+// Support alias templates on compilers known to allow it.
+#if !defined(ASIO_HAS_ALIAS_TEMPLATES)
+# if !defined(ASIO_DISABLE_ALIAS_TEMPLATES)
+#  if defined(__clang__)
+#   if __has_feature(__cxx_alias_templates__)
+#    define ASIO_HAS_ALIAS_TEMPLATES 1
+#   endif // __has_feature(__cxx_alias_templates__)
+#  endif // defined(__clang__)
+#  if defined(__GNUC__)
+#   if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4)
+#    if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)
+#     define ASIO_HAS_ALIAS_TEMPLATES 1
+#    endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)
+#   endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4)
+#  endif // defined(__GNUC__)
+#  if defined(ASIO_MSVC)
+#   if (_MSC_VER >= 1900)
+#    define ASIO_HAS_ALIAS_TEMPLATES 1
+#   endif // (_MSC_VER >= 1900)
+#  endif // defined(ASIO_MSVC)
+# endif // !defined(ASIO_DISABLE_ALIAS_TEMPLATES)
+#endif // !defined(ASIO_HAS_ALIAS_TEMPLATES)
+
+// Support return type deduction on compilers known to allow it.
+#if !defined(ASIO_HAS_RETURN_TYPE_DEDUCTION)
+# if !defined(ASIO_DISABLE_RETURN_TYPE_DEDUCTION)
+#  if defined(__clang__)
+#   if __has_feature(__cxx_return_type_deduction__)
+#    define ASIO_HAS_RETURN_TYPE_DEDUCTION 1
+#   endif // __has_feature(__cxx_return_type_deduction__)
+#  elif (__cplusplus >= 201402)
+#   define ASIO_HAS_RETURN_TYPE_DEDUCTION 1
+#  elif defined(__cpp_return_type_deduction)
+#   if (__cpp_return_type_deduction >= 201304)
+#    define ASIO_HAS_RETURN_TYPE_DEDUCTION 1
+#   endif // (__cpp_return_type_deduction >= 201304)
+#  endif // defined(__cpp_return_type_deduction)
+# endif // !defined(ASIO_DISABLE_RETURN_TYPE_DEDUCTION)
+#endif // !defined(ASIO_HAS_RETURN_TYPE_DEDUCTION)
+
+// Support default function template arguments on compilers known to allow it.
+#if !defined(ASIO_HAS_DEFAULT_FUNCTION_TEMPLATE_ARGUMENTS)
+# if !defined(ASIO_DISABLE_DEFAULT_FUNCTION_TEMPLATE_ARGUMENTS)
+#  if (__cplusplus >= 201103)
+#   define ASIO_HAS_DEFAULT_FUNCTION_TEMPLATE_ARGUMENTS 1
+#  endif // (__cplusplus >= 201103)
+# endif // !defined(ASIO_DISABLE_DEFAULT_FUNCTION_TEMPLATE_ARGUMENTS)
+#endif // !defined(ASIO_HAS_DEFAULT_FUNCTION_TEMPLATE_ARGUMENTS)
+
+// Support concepts on compilers known to allow them.
+#if !defined(ASIO_HAS_CONCEPTS)
+# if !defined(ASIO_DISABLE_CONCEPTS)
+#  if defined(__cpp_concepts)
+#   define ASIO_HAS_CONCEPTS 1
+#   if (__cpp_concepts >= 201707)
+#    define ASIO_CONCEPT concept
+#   else // (__cpp_concepts >= 201707)
+#    define ASIO_CONCEPT concept bool
+#   endif // (__cpp_concepts >= 201707)
+#  endif // defined(__cpp_concepts)
+# endif // !defined(ASIO_DISABLE_CONCEPTS)
+#endif // !defined(ASIO_HAS_CONCEPTS)
+
+// Support template variables on compilers known to allow it.
+#if !defined(ASIO_HAS_VARIABLE_TEMPLATES)
+# if !defined(ASIO_DISABLE_VARIABLE_TEMPLATES)
+#  if defined(__clang__)
+#   if (__cplusplus >= 201402)
+#    if __has_feature(__cxx_variable_templates__)
+#     define ASIO_HAS_VARIABLE_TEMPLATES 1
+#    endif // __has_feature(__cxx_variable_templates__)
+#   endif // (__cplusplus >= 201402)
+#  endif // defined(__clang__)
+#  if defined(__GNUC__)
+#   if (__GNUC__ >= 6)
+#    if (__cplusplus >= 201402)
+#     define ASIO_HAS_VARIABLE_TEMPLATES 1
+#    endif // (__cplusplus >= 201402)
+#   endif // (__GNUC__ >= 6)
+#  endif // defined(__GNUC__)
+#  if defined(ASIO_MSVC)
+#   if (_MSC_VER >= 1901)
+#    define ASIO_HAS_VARIABLE_TEMPLATES 1
+#   endif // (_MSC_VER >= 1901)
+#  endif // defined(ASIO_MSVC)
+# endif // !defined(ASIO_DISABLE_VARIABLE_TEMPLATES)
+#endif // !defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+// Support SFINAEd template variables on compilers known to allow it.
+#if !defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+# if !defined(ASIO_DISABLE_SFINAE_VARIABLE_TEMPLATES)
+#  if defined(__clang__)
+#   if (__cplusplus >= 201703)
+#    if __has_feature(__cxx_variable_templates__)
+#     define ASIO_HAS_SFINAE_VARIABLE_TEMPLATES 1
+#    endif // __has_feature(__cxx_variable_templates__)
+#   endif // (__cplusplus >= 201703)
+#  endif // defined(__clang__)
+#  if defined(__GNUC__)
+#   if ((__GNUC__ == 8) && (__GNUC_MINOR__ >= 4)) || (__GNUC__ > 8)
+#    if (__cplusplus >= 201402)
+#     define ASIO_HAS_SFINAE_VARIABLE_TEMPLATES 1
+#    endif // (__cplusplus >= 201402)
+#   endif // ((__GNUC__ == 8) && (__GNUC_MINOR__ >= 4)) || (__GNUC__ > 8)
+#  endif // defined(__GNUC__)
+#  if defined(ASIO_MSVC)
+#   if (_MSC_VER >= 1901)
+#    define ASIO_HAS_SFINAE_VARIABLE_TEMPLATES 1
+#   endif // (_MSC_VER >= 1901)
+#  endif // defined(ASIO_MSVC)
+# endif // !defined(ASIO_DISABLE_SFINAE_VARIABLE_TEMPLATES)
+#endif // !defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+
+// Support SFINAE use of constant expressions on compilers known to allow it.
+#if !defined(ASIO_HAS_CONSTANT_EXPRESSION_SFINAE)
+# if !defined(ASIO_DISABLE_CONSTANT_EXPRESSION_SFINAE)
+#  if defined(__clang__)
+#   if (__cplusplus >= 201402)
+#    define ASIO_HAS_CONSTANT_EXPRESSION_SFINAE 1
+#   endif // (__cplusplus >= 201402)
+#  endif // defined(__clang__)
+#  if defined(__GNUC__)
+#   if (__GNUC__ >= 7)
+#    if (__cplusplus >= 201402)
+#     define ASIO_HAS_CONSTANT_EXPRESSION_SFINAE 1
+#    endif // (__cplusplus >= 201402)
+#   endif // (__GNUC__ >= 7)
+#  endif // defined(__GNUC__)
+#  if defined(ASIO_MSVC)
+#   if (_MSC_VER >= 1901)
+#    define ASIO_HAS_CONSTANT_EXPRESSION_SFINAE 1
+#   endif // (_MSC_VER >= 1901)
+#  endif // defined(ASIO_MSVC)
+# endif // !defined(ASIO_DISABLE_CONSTANT_EXPRESSION_SFINAE)
+#endif // !defined(ASIO_HAS_CONSTANT_EXPRESSION_SFINAE)
+
+// Enable workarounds for lack of working expression SFINAE.
+#if !defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)
+# if !defined(ASIO_DISABLE_WORKING_EXPRESSION_SFINAE)
+#  if !defined(ASIO_MSVC)
+#   if (__cplusplus >= 201103)
+#    define ASIO_HAS_WORKING_EXPRESSION_SFINAE 1
+#   endif // (__cplusplus >= 201103)
+#  endif // !defined(ASIO_MSVC)
+# endif // !defined(ASIO_DISABLE_WORKING_EXPRESSION_SFINAE)
+#endif // !defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)
+
+// Support ref-qualified functions on compilers known to allow it.
+#if !defined(ASIO_HAS_REF_QUALIFIED_FUNCTIONS)
+# if !defined(ASIO_DISABLE_REF_QUALIFIED_FUNCTIONS)
+#  if defined(__clang__)
+#   if __has_feature(__cxx_reference_qualified_functions__)
+#    define ASIO_HAS_REF_QUALIFIED_FUNCTIONS 1
+#   endif // __has_feature(__cxx_reference_qualified_functions__)
+#  endif // defined(__clang__)
+#  if defined(__GNUC__)
+#   if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 9)) || (__GNUC__ > 4)
+#    if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)
+#     define ASIO_HAS_REF_QUALIFIED_FUNCTIONS 1
+#    endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)
+#   endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 9)) || (__GNUC__ > 4)
+#  endif // defined(__GNUC__)
+#  if defined(ASIO_MSVC)
+#   if (_MSC_VER >= 1900)
+#    define ASIO_HAS_REF_QUALIFIED_FUNCTIONS 1
+#   endif // (_MSC_VER >= 1900)
+#  endif // defined(ASIO_MSVC)
+# endif // !defined(ASIO_DISABLE_REF_QUALIFIED_FUNCTIONS)
+#endif // !defined(ASIO_HAS_REF_QUALIFIED_FUNCTIONS)
+#if defined(ASIO_HAS_REF_QUALIFIED_FUNCTIONS)
+# if !defined(ASIO_LVALUE_REF_QUAL)
+#  define ASIO_LVALUE_REF_QUAL &
+# endif // !defined(ASIO_LVALUE_REF_QUAL)
+# if !defined(ASIO_RVALUE_REF_QUAL)
+#  define ASIO_RVALUE_REF_QUAL &&
+# endif // !defined(ASIO_RVALUE_REF_QUAL)
+#else // defined(ASIO_HAS_REF_QUALIFIED_FUNCTIONS)
+# if !defined(ASIO_LVALUE_REF_QUAL)
+#  define ASIO_LVALUE_REF_QUAL
+# endif // !defined(ASIO_LVALUE_REF_QUAL)
+# if !defined(ASIO_RVALUE_REF_QUAL)
+#  define ASIO_RVALUE_REF_QUAL
+# endif // !defined(ASIO_RVALUE_REF_QUAL)
+#endif // defined(ASIO_HAS_REF_QUALIFIED_FUNCTIONS)
+
+// Standard library support for system errors.
+#if !defined(ASIO_HAS_STD_SYSTEM_ERROR)
+# if !defined(ASIO_DISABLE_STD_SYSTEM_ERROR)
+#  if defined(__clang__)
+#   if defined(ASIO_HAS_CLANG_LIBCXX)
+#    define ASIO_HAS_STD_SYSTEM_ERROR 1
+#   elif (__cplusplus >= 201103)
+#    if __has_include(<system_error>)
+#     define ASIO_HAS_STD_SYSTEM_ERROR 1
+#    endif // __has_include(<system_error>)
+#   endif // (__cplusplus >= 201103)
+#  endif // defined(__clang__)
+#  if defined(__GNUC__)
+#   if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4)
+#    if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)
+#     define ASIO_HAS_STD_SYSTEM_ERROR 1
+#    endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)
+#   endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4)
+#  endif // defined(__GNUC__)
+#  if defined(ASIO_MSVC)
+#   if (_MSC_VER >= 1700)
+#    define ASIO_HAS_STD_SYSTEM_ERROR 1
+#   endif // (_MSC_VER >= 1700)
+#  endif // defined(ASIO_MSVC)
+# endif // !defined(ASIO_DISABLE_STD_SYSTEM_ERROR)
+#endif // !defined(ASIO_HAS_STD_SYSTEM_ERROR)
+
+// Compliant C++11 compilers put noexcept specifiers on error_category members.
+#if !defined(ASIO_ERROR_CATEGORY_NOEXCEPT)
+# if defined(ASIO_HAS_BOOST_CONFIG) && (BOOST_VERSION >= 105300)
+#  define ASIO_ERROR_CATEGORY_NOEXCEPT BOOST_NOEXCEPT
+# elif defined(__clang__)
+#  if __has_feature(__cxx_noexcept__)
+#   define ASIO_ERROR_CATEGORY_NOEXCEPT noexcept(true)
+#  endif // __has_feature(__cxx_noexcept__)
+# elif defined(__GNUC__)
+#  if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4)
+#   if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)
+#     define ASIO_ERROR_CATEGORY_NOEXCEPT noexcept(true)
+#   endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)
+#  endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4)
+# elif defined(ASIO_MSVC)
+#  if (_MSC_VER >= 1900)
+#   define ASIO_ERROR_CATEGORY_NOEXCEPT noexcept(true)
+#  endif // (_MSC_VER >= 1900)
+# endif // defined(ASIO_MSVC)
+# if !defined(ASIO_ERROR_CATEGORY_NOEXCEPT)
+#  define ASIO_ERROR_CATEGORY_NOEXCEPT
+# endif // !defined(ASIO_ERROR_CATEGORY_NOEXCEPT)
+#endif // !defined(ASIO_ERROR_CATEGORY_NOEXCEPT)
+
+// Standard library support for arrays.
+#if !defined(ASIO_HAS_STD_ARRAY)
+# if !defined(ASIO_DISABLE_STD_ARRAY)
+#  if defined(__clang__)
+#   if defined(ASIO_HAS_CLANG_LIBCXX)
+#    define ASIO_HAS_STD_ARRAY 1
+#   elif (__cplusplus >= 201103)
+#    if __has_include(<array>)
+#     define ASIO_HAS_STD_ARRAY 1
+#    endif // __has_include(<array>)
+#   endif // (__cplusplus >= 201103)
+#  endif // defined(__clang__)
+#  if defined(__GNUC__)
+#   if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 4)
+#    if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)
+#     define ASIO_HAS_STD_ARRAY 1
+#    endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)
+#   endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 4)
+#  endif // defined(__GNUC__)
+#  if defined(ASIO_MSVC)
+#   if (_MSC_VER >= 1600)
+#    define ASIO_HAS_STD_ARRAY 1
+#   endif // (_MSC_VER >= 1600)
+#  endif // defined(ASIO_MSVC)
+# endif // !defined(ASIO_DISABLE_STD_ARRAY)
+#endif // !defined(ASIO_HAS_STD_ARRAY)
+
+// Standard library support for shared_ptr and weak_ptr.
+#if !defined(ASIO_HAS_STD_SHARED_PTR)
+# if !defined(ASIO_DISABLE_STD_SHARED_PTR)
+#  if defined(__clang__)
+#   if defined(ASIO_HAS_CLANG_LIBCXX)
+#    define ASIO_HAS_STD_SHARED_PTR 1
+#   elif (__cplusplus >= 201103)
+#    define ASIO_HAS_STD_SHARED_PTR 1
+#   endif // (__cplusplus >= 201103)
+#  endif // defined(__clang__)
+#  if defined(__GNUC__)
+#   if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 4)
+#    if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)
+#     define ASIO_HAS_STD_SHARED_PTR 1
+#    endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)
+#   endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 4)
+#  endif // defined(__GNUC__)
+#  if defined(ASIO_MSVC)
+#   if (_MSC_VER >= 1600)
+#    define ASIO_HAS_STD_SHARED_PTR 1
+#   endif // (_MSC_VER >= 1600)
+#  endif // defined(ASIO_MSVC)
+# endif // !defined(ASIO_DISABLE_STD_SHARED_PTR)
+#endif // !defined(ASIO_HAS_STD_SHARED_PTR)
+
+// Standard library support for allocator_arg_t.
+#if !defined(ASIO_HAS_STD_ALLOCATOR_ARG)
+# if !defined(ASIO_DISABLE_STD_ALLOCATOR_ARG)
+#  if defined(__clang__)
+#   if defined(ASIO_HAS_CLANG_LIBCXX)
+#    define ASIO_HAS_STD_ALLOCATOR_ARG 1
+#   elif (__cplusplus >= 201103)
+#    define ASIO_HAS_STD_ALLOCATOR_ARG 1
+#   endif // (__cplusplus >= 201103)
+#  endif // defined(__clang__)
+#  if defined(__GNUC__)
+#   if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4)
+#    if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)
+#     define ASIO_HAS_STD_ALLOCATOR_ARG 1
+#    endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)
+#   endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4)
+#  endif // defined(__GNUC__)
+#  if defined(ASIO_MSVC)
+#   if (_MSC_VER >= 1600)
+#    define ASIO_HAS_STD_ALLOCATOR_ARG 1
+#   endif // (_MSC_VER >= 1600)
+#  endif // defined(ASIO_MSVC)
+# endif // !defined(ASIO_DISABLE_STD_ALLOCATOR_ARG)
+#endif // !defined(ASIO_HAS_STD_ALLOCATOR_ARG)
+
+// Standard library support for atomic operations.
+#if !defined(ASIO_HAS_STD_ATOMIC)
+# if !defined(ASIO_DISABLE_STD_ATOMIC)
+#  if defined(__clang__)
+#   if defined(ASIO_HAS_CLANG_LIBCXX)
+#    define ASIO_HAS_STD_ATOMIC 1
+#   elif (__cplusplus >= 201103)
+#    if __has_include(<atomic>)
+#     define ASIO_HAS_STD_ATOMIC 1
+#    endif // __has_include(<atomic>)
+#   elif defined(__apple_build_version__) && defined(_LIBCPP_VERSION)
+#    if (__clang_major__ >= 10)
+#     if __has_include(<atomic>)
+#      define ASIO_HAS_STD_ATOMIC 1
+#     endif // __has_include(<atomic>)
+#    endif // (__clang_major__ >= 10)
+#   endif // defined(__apple_build_version__) && defined(_LIBCPP_VERSION)
+#  endif // defined(__clang__)
+#  if defined(__GNUC__)
+#   if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4)
+#    if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)
+#     define ASIO_HAS_STD_ATOMIC 1
+#    endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)
+#   endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4)
+#  endif // defined(__GNUC__)
+#  if defined(ASIO_MSVC)
+#   if (_MSC_VER >= 1700)
+#    define ASIO_HAS_STD_ATOMIC 1
+#   endif // (_MSC_VER >= 1700)
+#  endif // defined(ASIO_MSVC)
+# endif // !defined(ASIO_DISABLE_STD_ATOMIC)
+#endif // !defined(ASIO_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(ASIO_HAS_STD_CHRONO)
+# if !defined(ASIO_DISABLE_STD_CHRONO)
+#  if defined(__clang__)
+#   if defined(ASIO_HAS_CLANG_LIBCXX)
+#    define ASIO_HAS_STD_CHRONO 1
+#   elif (__cplusplus >= 201103)
+#    if __has_include(<chrono>)
+#     define ASIO_HAS_STD_CHRONO 1
+#    endif // __has_include(<chrono>)
+#   endif // (__cplusplus >= 201103)
+#  endif // defined(__clang__)
+#  if defined(__GNUC__)
+#   if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4)
+#    if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)
+#     define ASIO_HAS_STD_CHRONO 1
+#     if ((__GNUC__ == 4) && (__GNUC_MINOR__ == 6))
+#      define ASIO_HAS_STD_CHRONO_MONOTONIC_CLOCK 1
+#     endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ == 6))
+#    endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)
+#   endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4)
+#  endif // defined(__GNUC__)
+#  if defined(ASIO_MSVC)
+#   if (_MSC_VER >= 1700)
+#    define ASIO_HAS_STD_CHRONO 1
+#   endif // (_MSC_VER >= 1700)
+#  endif // defined(ASIO_MSVC)
+# endif // !defined(ASIO_DISABLE_STD_CHRONO)
+#endif // !defined(ASIO_HAS_STD_CHRONO)
+
+// Boost support for chrono.
+#if !defined(ASIO_HAS_BOOST_CHRONO)
+# if !defined(ASIO_DISABLE_BOOST_CHRONO)
+#  if defined(ASIO_HAS_BOOST_CONFIG) && (BOOST_VERSION >= 104700)
+#   define ASIO_HAS_BOOST_CHRONO 1
+#  endif // defined(ASIO_HAS_BOOST_CONFIG) && (BOOST_VERSION >= 104700)
+# endif // !defined(ASIO_DISABLE_BOOST_CHRONO)
+#endif // !defined(ASIO_HAS_BOOST_CHRONO)
+
+// Some form of chrono library is available.
+#if !defined(ASIO_HAS_CHRONO)
+# if defined(ASIO_HAS_STD_CHRONO) \
+    || defined(ASIO_HAS_BOOST_CHRONO)
+#  define ASIO_HAS_CHRONO 1
+# endif // defined(ASIO_HAS_STD_CHRONO)
+        // || defined(ASIO_HAS_BOOST_CHRONO)
+#endif // !defined(ASIO_HAS_CHRONO)
+
+// Boost support for the DateTime library.
+#if !defined(ASIO_HAS_BOOST_DATE_TIME)
+# if !defined(ASIO_DISABLE_BOOST_DATE_TIME)
+#  define ASIO_HAS_BOOST_DATE_TIME 1
+# endif // !defined(ASIO_DISABLE_BOOST_DATE_TIME)
+#endif // !defined(ASIO_HAS_BOOST_DATE_TIME)
+
+// Standard library support for addressof.
+#if !defined(ASIO_HAS_STD_ADDRESSOF)
+# if !defined(ASIO_DISABLE_STD_ADDRESSOF)
+#  if defined(__clang__)
+#   if defined(ASIO_HAS_CLANG_LIBCXX)
+#    define ASIO_HAS_STD_ADDRESSOF 1
+#   elif (__cplusplus >= 201103)
+#    define ASIO_HAS_STD_ADDRESSOF 1
+#   endif // (__cplusplus >= 201103)
+#  endif // defined(__clang__)
+#  if defined(__GNUC__)
+#   if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4)
+#    if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)
+#     define ASIO_HAS_STD_ADDRESSOF 1
+#    endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)
+#   endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4)
+#  endif // defined(__GNUC__)
+#  if defined(ASIO_MSVC)
+#   if (_MSC_VER >= 1700)
+#    define ASIO_HAS_STD_ADDRESSOF 1
+#   endif // (_MSC_VER >= 1700)
+#  endif // defined(ASIO_MSVC)
+# endif // !defined(ASIO_DISABLE_STD_ADDRESSOF)
+#endif // !defined(ASIO_HAS_STD_ADDRESSOF)
+
+// Standard library support for the function class.
+#if !defined(ASIO_HAS_STD_FUNCTION)
+# if !defined(ASIO_DISABLE_STD_FUNCTION)
+#  if defined(__clang__)
+#   if defined(ASIO_HAS_CLANG_LIBCXX)
+#    define ASIO_HAS_STD_FUNCTION 1
+#   elif (__cplusplus >= 201103)
+#    define ASIO_HAS_STD_FUNCTION 1
+#   endif // (__cplusplus >= 201103)
+#  endif // defined(__clang__)
+#  if defined(__GNUC__)
+#   if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4)
+#    if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)
+#     define ASIO_HAS_STD_FUNCTION 1
+#    endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)
+#   endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4)
+#  endif // defined(__GNUC__)
+#  if defined(ASIO_MSVC)
+#   if (_MSC_VER >= 1700)
+#    define ASIO_HAS_STD_FUNCTION 1
+#   endif // (_MSC_VER >= 1700)
+#  endif // defined(ASIO_MSVC)
+# endif // !defined(ASIO_DISABLE_STD_FUNCTION)
+#endif // !defined(ASIO_HAS_STD_FUNCTION)
+
+// Standard library support for type traits.
+#if !defined(ASIO_HAS_STD_TYPE_TRAITS)
+# if !defined(ASIO_DISABLE_STD_TYPE_TRAITS)
+#  if defined(__clang__)
+#   if defined(ASIO_HAS_CLANG_LIBCXX)
+#    define ASIO_HAS_STD_TYPE_TRAITS 1
+#   elif (__cplusplus >= 201103)
+#    if __has_include(<type_traits>)
+#     define ASIO_HAS_STD_TYPE_TRAITS 1
+#    endif // __has_include(<type_traits>)
+#   endif // (__cplusplus >= 201103)
+#  endif // defined(__clang__)
+#  if defined(__GNUC__)
+#   if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4)
+#    if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)
+#     define ASIO_HAS_STD_TYPE_TRAITS 1
+#    endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)
+#   endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4)
+#  endif // defined(__GNUC__)
+#  if defined(ASIO_MSVC)
+#   if (_MSC_VER >= 1700)
+#    define ASIO_HAS_STD_TYPE_TRAITS 1
+#   endif // (_MSC_VER >= 1700)
+#  endif // defined(ASIO_MSVC)
+# endif // !defined(ASIO_DISABLE_STD_TYPE_TRAITS)
+#endif // !defined(ASIO_HAS_STD_TYPE_TRAITS)
+
+// Standard library support for the nullptr_t type.
+#if !defined(ASIO_HAS_NULLPTR)
+# if !defined(ASIO_DISABLE_NULLPTR)
+#  if defined(__clang__)
+#   if __has_feature(__cxx_nullptr__)
+#    define ASIO_HAS_NULLPTR 1
+#   endif // __has_feature(__cxx_nullptr__)
+#  elif defined(__GNUC__)
+#   if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4)
+#    if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)
+#     define ASIO_HAS_NULLPTR 1
+#    endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)
+#   endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4)
+#  endif // defined(__GNUC__)
+#  if defined(ASIO_MSVC)
+#   if (_MSC_VER >= 1700)
+#    define ASIO_HAS_NULLPTR 1
+#   endif // (_MSC_VER >= 1700)
+#  endif // defined(ASIO_MSVC)
+# endif // !defined(ASIO_DISABLE_NULLPTR)
+#endif // !defined(ASIO_HAS_NULLPTR)
+
+// Standard library support for the C++11 allocator additions.
+#if !defined(ASIO_HAS_CXX11_ALLOCATORS)
+# if !defined(ASIO_DISABLE_CXX11_ALLOCATORS)
+#  if defined(__clang__)
+#   if defined(ASIO_HAS_CLANG_LIBCXX)
+#    define ASIO_HAS_CXX11_ALLOCATORS 1
+#   elif (__cplusplus >= 201103)
+#    define ASIO_HAS_CXX11_ALLOCATORS 1
+#   endif // (__cplusplus >= 201103)
+#  elif defined(__GNUC__)
+#   if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4)
+#    if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)
+#     define ASIO_HAS_CXX11_ALLOCATORS 1
+#    endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)
+#   endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4)
+#  endif // defined(__GNUC__)
+#  if defined(ASIO_MSVC)
+#   if (_MSC_VER >= 1800)
+#    define ASIO_HAS_CXX11_ALLOCATORS 1
+#   endif // (_MSC_VER >= 1800)
+#  endif // defined(ASIO_MSVC)
+# endif // !defined(ASIO_DISABLE_CXX11_ALLOCATORS)
+#endif // !defined(ASIO_HAS_CXX11_ALLOCATORS)
+
+// Standard library support for the cstdint header.
+#if !defined(ASIO_HAS_CSTDINT)
+# if !defined(ASIO_DISABLE_CSTDINT)
+#  if defined(__clang__)
+#   if defined(ASIO_HAS_CLANG_LIBCXX)
+#    define ASIO_HAS_CSTDINT 1
+#   elif (__cplusplus >= 201103)
+#    define ASIO_HAS_CSTDINT 1
+#   endif // (__cplusplus >= 201103)
+#  endif // defined(__clang__)
+#  if defined(__GNUC__)
+#   if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4)
+#    if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)
+#     define ASIO_HAS_CSTDINT 1
+#    endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)
+#   endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4)
+#  endif // defined(__GNUC__)
+#  if defined(ASIO_MSVC)
+#   if (_MSC_VER >= 1700)
+#    define ASIO_HAS_CSTDINT 1
+#   endif // (_MSC_VER >= 1700)
+#  endif // defined(ASIO_MSVC)
+# endif // !defined(ASIO_DISABLE_CSTDINT)
+#endif // !defined(ASIO_HAS_CSTDINT)
+
+// Standard library support for the thread class.
+#if !defined(ASIO_HAS_STD_THREAD)
+# if !defined(ASIO_DISABLE_STD_THREAD)
+#  if defined(__clang__)
+#   if defined(ASIO_HAS_CLANG_LIBCXX)
+#    define ASIO_HAS_STD_THREAD 1
+#   elif (__cplusplus >= 201103)
+#    if __has_include(<thread>)
+#     define ASIO_HAS_STD_THREAD 1
+#    endif // __has_include(<thread>)
+#   endif // (__cplusplus >= 201103)
+#  endif // defined(__clang__)
+#  if defined(__GNUC__)
+#   if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4)
+#    if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)
+#     define ASIO_HAS_STD_THREAD 1
+#    endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)
+#   endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4)
+#  endif // defined(__GNUC__)
+#  if defined(ASIO_MSVC)
+#   if (_MSC_VER >= 1700)
+#    define ASIO_HAS_STD_THREAD 1
+#   endif // (_MSC_VER >= 1700)
+#  endif // defined(ASIO_MSVC)
+# endif // !defined(ASIO_DISABLE_STD_THREAD)
+#endif // !defined(ASIO_HAS_STD_THREAD)
+
+// Standard library support for the mutex and condition variable classes.
+#if !defined(ASIO_HAS_STD_MUTEX_AND_CONDVAR)
+# if !defined(ASIO_DISABLE_STD_MUTEX_AND_CONDVAR)
+#  if defined(__clang__)
+#   if defined(ASIO_HAS_CLANG_LIBCXX)
+#    define ASIO_HAS_STD_MUTEX_AND_CONDVAR 1
+#   elif (__cplusplus >= 201103)
+#    if __has_include(<mutex>)
+#     define ASIO_HAS_STD_MUTEX_AND_CONDVAR 1
+#    endif // __has_include(<mutex>)
+#   endif // (__cplusplus >= 201103)
+#  endif // defined(__clang__)
+#  if defined(__GNUC__)
+#   if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4)
+#    if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)
+#     define ASIO_HAS_STD_MUTEX_AND_CONDVAR 1
+#    endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)
+#   endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4)
+#  endif // defined(__GNUC__)
+#  if defined(ASIO_MSVC)
+#   if (_MSC_VER >= 1700)
+#    define ASIO_HAS_STD_MUTEX_AND_CONDVAR 1
+#   endif // (_MSC_VER >= 1700)
+#  endif // defined(ASIO_MSVC)
+# endif // !defined(ASIO_DISABLE_STD_MUTEX_AND_CONDVAR)
+#endif // !defined(ASIO_HAS_STD_MUTEX_AND_CONDVAR)
+
+// Standard library support for the call_once function.
+#if !defined(ASIO_HAS_STD_CALL_ONCE)
+# if !defined(ASIO_DISABLE_STD_CALL_ONCE)
+#  if defined(__clang__)
+#   if defined(ASIO_HAS_CLANG_LIBCXX)
+#    define ASIO_HAS_STD_CALL_ONCE 1
+#   elif (__cplusplus >= 201103)
+#    if __has_include(<mutex>)
+#     define ASIO_HAS_STD_CALL_ONCE 1
+#    endif // __has_include(<mutex>)
+#   endif // (__cplusplus >= 201103)
+#  endif // defined(__clang__)
+#  if defined(__GNUC__)
+#   if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4)
+#    if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)
+#     define ASIO_HAS_STD_CALL_ONCE 1
+#    endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)
+#   endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4)
+#  endif // defined(__GNUC__)
+#  if defined(ASIO_MSVC)
+#   if (_MSC_VER >= 1700)
+#    define ASIO_HAS_STD_CALL_ONCE 1
+#   endif // (_MSC_VER >= 1700)
+#  endif // defined(ASIO_MSVC)
+# endif // !defined(ASIO_DISABLE_STD_CALL_ONCE)
+#endif // !defined(ASIO_HAS_STD_CALL_ONCE)
+
+// Standard library support for futures.
+#if !defined(ASIO_HAS_STD_FUTURE)
+# if !defined(ASIO_DISABLE_STD_FUTURE)
+#  if defined(__clang__)
+#   if defined(ASIO_HAS_CLANG_LIBCXX)
+#    define ASIO_HAS_STD_FUTURE 1
+#   elif (__cplusplus >= 201103)
+#    if __has_include(<future>)
+#     define ASIO_HAS_STD_FUTURE 1
+#    endif // __has_include(<future>)
+#   endif // (__cplusplus >= 201103)
+#  endif // defined(__clang__)
+#  if defined(__GNUC__)
+#   if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4)
+#    if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)
+#     define ASIO_HAS_STD_FUTURE 1
+#    endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)
+#   endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4)
+#  endif // defined(__GNUC__)
+#  if defined(ASIO_MSVC)
+#   if (_MSC_VER >= 1700)
+#    define ASIO_HAS_STD_FUTURE 1
+#   endif // (_MSC_VER >= 1700)
+#  endif // defined(ASIO_MSVC)
+# endif // !defined(ASIO_DISABLE_STD_FUTURE)
+#endif // !defined(ASIO_HAS_STD_FUTURE)
+
+// Standard library support for std::string_view.
+#if !defined(ASIO_HAS_STD_STRING_VIEW)
+# if !defined(ASIO_DISABLE_STD_STRING_VIEW)
+#  if defined(__clang__)
+#   if defined(ASIO_HAS_CLANG_LIBCXX)
+#    if (__cplusplus >= 201402)
+#     if __has_include(<string_view>)
+#      define ASIO_HAS_STD_STRING_VIEW 1
+#     endif // __has_include(<string_view>)
+#    endif // (__cplusplus >= 201402)
+#   else // defined(ASIO_HAS_CLANG_LIBCXX)
+#    if (__cplusplus >= 201703)
+#     if __has_include(<string_view>)
+#      define ASIO_HAS_STD_STRING_VIEW 1
+#     endif // __has_include(<string_view>)
+#    endif // (__cplusplus >= 201703)
+#   endif // defined(ASIO_HAS_CLANG_LIBCXX)
+#  elif defined(__GNUC__)
+#   if (__GNUC__ >= 7)
+#    if (__cplusplus >= 201703)
+#     define ASIO_HAS_STD_STRING_VIEW 1
+#    endif // (__cplusplus >= 201703)
+#   endif // (__GNUC__ >= 7)
+#  elif defined(ASIO_MSVC)
+#   if (_MSC_VER >= 1910 && _MSVC_LANG >= 201703)
+#    define ASIO_HAS_STD_STRING_VIEW 1
+#   endif // (_MSC_VER >= 1910 && _MSVC_LANG >= 201703)
+#  endif // defined(ASIO_MSVC)
+# endif // !defined(ASIO_DISABLE_STD_STRING_VIEW)
+#endif // !defined(ASIO_HAS_STD_STRING_VIEW)
+
+// Standard library support for std::experimental::string_view.
+#if !defined(ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW)
+# if !defined(ASIO_DISABLE_STD_EXPERIMENTAL_STRING_VIEW)
+#  if defined(__clang__)
+#   if defined(ASIO_HAS_CLANG_LIBCXX)
+#    if (_LIBCPP_VERSION < 7000)
+#     if (__cplusplus >= 201402)
+#      if __has_include(<experimental/string_view>)
+#       define ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW 1
+#      endif // __has_include(<experimental/string_view>)
+#     endif // (__cplusplus >= 201402)
+#    endif // (_LIBCPP_VERSION < 7000)
+#   else // defined(ASIO_HAS_CLANG_LIBCXX)
+#    if (__cplusplus >= 201402)
+#     if __has_include(<experimental/string_view>)
+#      define ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW 1
+#     endif // __has_include(<experimental/string_view>)
+#    endif // (__cplusplus >= 201402)
+#   endif // // defined(ASIO_HAS_CLANG_LIBCXX)
+#  endif // defined(__clang__)
+#  if defined(__GNUC__)
+#   if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 9)) || (__GNUC__ > 4)
+#    if (__cplusplus >= 201402)
+#     define ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW 1
+#    endif // (__cplusplus >= 201402)
+#   endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 9)) || (__GNUC__ > 4)
+#  endif // defined(__GNUC__)
+# endif // !defined(ASIO_DISABLE_STD_EXPERIMENTAL_STRING_VIEW)
+#endif // !defined(ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW)
+
+// Standard library has a string_view that we can use.
+#if !defined(ASIO_HAS_STRING_VIEW)
+# if !defined(ASIO_DISABLE_STRING_VIEW)
+#  if defined(ASIO_HAS_STD_STRING_VIEW)
+#   define ASIO_HAS_STRING_VIEW 1
+#  elif defined(ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW)
+#   define ASIO_HAS_STRING_VIEW 1
+#  endif // defined(ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW)
+# endif // !defined(ASIO_DISABLE_STRING_VIEW)
+#endif // !defined(ASIO_HAS_STRING_VIEW)
+
+// Standard library support for iostream move construction and assignment.
+#if !defined(ASIO_HAS_STD_IOSTREAM_MOVE)
+# if !defined(ASIO_DISABLE_STD_IOSTREAM_MOVE)
+#  if defined(__GNUC__)
+#   if (__GNUC__ > 4)
+#    if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)
+#     define ASIO_HAS_STD_IOSTREAM_MOVE 1
+#    endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)
+#   endif // (__GNUC__ > 4)
+#  endif // defined(__GNUC__)
+#  if defined(ASIO_MSVC)
+#   if (_MSC_VER >= 1700)
+#    define ASIO_HAS_STD_IOSTREAM_MOVE 1
+#   endif // (_MSC_VER >= 1700)
+#  endif // defined(ASIO_MSVC)
+# endif // !defined(ASIO_DISABLE_STD_IOSTREAM_MOVE)
+#endif // !defined(ASIO_HAS_STD_IOSTREAM_MOVE)
+
+// Standard library has invoke_result (which supersedes result_of).
+#if !defined(ASIO_HAS_STD_INVOKE_RESULT)
+# if !defined(ASIO_DISABLE_STD_INVOKE_RESULT)
+#  if defined(ASIO_MSVC)
+#   if (_MSC_VER >= 1911 && _MSVC_LANG >= 201703)
+#    define ASIO_HAS_STD_INVOKE_RESULT 1
+#   endif // (_MSC_VER >= 1911 && _MSVC_LANG >= 201703)
+#  endif // defined(ASIO_MSVC)
+# endif // !defined(ASIO_DISABLE_STD_INVOKE_RESULT)
+#endif // !defined(ASIO_HAS_STD_INVOKE_RESULT)
+
+// Standard library support for std::exception_ptr and std::current_exception.
+#if !defined(ASIO_HAS_STD_EXCEPTION_PTR)
+# if !defined(ASIO_DISABLE_STD_EXCEPTION_PTR)
+#  if defined(__clang__)
+#   if defined(ASIO_HAS_CLANG_LIBCXX)
+#    define ASIO_HAS_STD_EXCEPTION_PTR 1
+#   elif (__cplusplus >= 201103)
+#    define ASIO_HAS_STD_EXCEPTION_PTR 1
+#   endif // (__cplusplus >= 201103)
+#  elif defined(__GNUC__)
+#   if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4)
+#    if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)
+#     define ASIO_HAS_STD_EXCEPTION_PTR 1
+#    endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)
+#   endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4)
+#  endif // defined(__GNUC__)
+#  if defined(ASIO_MSVC)
+#   if (_MSC_VER >= 1800)
+#    define ASIO_HAS_STD_EXCEPTION_PTR 1
+#   endif // (_MSC_VER >= 1800)
+#  endif // defined(ASIO_MSVC)
+# endif // !defined(ASIO_DISABLE_STD_EXCEPTION_PTR)
+#endif // !defined(ASIO_HAS_STD_EXCEPTION_PTR)
+
+// Standard library support for std::nested_exception.
+#if !defined(ASIO_HAS_STD_NESTED_EXCEPTION)
+# if !defined(ASIO_DISABLE_STD_NESTED_EXCEPTION)
+#  if defined(__clang__)
+#   if defined(ASIO_HAS_CLANG_LIBCXX)
+#    define ASIO_HAS_STD_NESTED_EXCEPTION 1
+#   elif (__cplusplus >= 201103)
+#    define ASIO_HAS_STD_NESTED_EXCEPTION 1
+#   endif // (__cplusplus >= 201103)
+#  elif defined(__GNUC__)
+#   if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4)
+#    if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)
+#     define ASIO_HAS_STD_NESTED_EXCEPTION 1
+#    endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)
+#   endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4)
+#  endif // defined(__GNUC__)
+#  if defined(ASIO_MSVC)
+#   if (_MSC_VER >= 1900)
+#    define ASIO_HAS_STD_NESTED_EXCEPTION 1
+#   endif // (_MSC_VER >= 1900)
+#  endif // defined(ASIO_MSVC)
+# endif // !defined(ASIO_DISABLE_STD_NESTED_EXCEPTION)
+#endif // !defined(ASIO_HAS_STD_NESTED_EXCEPTION)
+
+// Standard library support for std::any.
+#if !defined(ASIO_HAS_STD_ANY)
+# if !defined(ASIO_DISABLE_STD_ANY)
+#  if defined(__clang__)
+#   if (__cplusplus >= 201703)
+#    if __has_include(<any>)
+#     define ASIO_HAS_STD_ANY 1
+#    endif // __has_include(<any>)
+#   endif // (__cplusplus >= 201703)
+#  elif defined(__GNUC__)
+#   if (__GNUC__ >= 7)
+#    if (__cplusplus >= 201703)
+#     define ASIO_HAS_STD_ANY 1
+#    endif // (__cplusplus >= 201703)
+#   endif // (__GNUC__ >= 7)
+#  endif // defined(__GNUC__)
+#  if defined(ASIO_MSVC)
+#   if (_MSC_VER >= 1910) && (_MSVC_LANG >= 201703)
+#    define ASIO_HAS_STD_ANY 1
+#   endif // (_MSC_VER >= 1910) && (_MSVC_LANG >= 201703)
+#  endif // defined(ASIO_MSVC)
+# endif // !defined(ASIO_DISABLE_STD_ANY)
+#endif // !defined(ASIO_HAS_STD_ANY)
+
+// Standard library support for std::source_location.
+#if !defined(ASIO_HAS_STD_SOURCE_LOCATION)
+# if !defined(ASIO_DISABLE_STD_SOURCE_LOCATION)
+// ...
+# endif // !defined(ASIO_DISABLE_STD_SOURCE_LOCATION)
+#endif // !defined(ASIO_HAS_STD_SOURCE_LOCATION)
+
+// Standard library support for std::experimental::source_location.
+#if !defined(ASIO_HAS_STD_EXPERIMENTAL_SOURCE_LOCATION)
+# if !defined(ASIO_DISABLE_STD_EXPERIMENTAL_SOURCE_LOCATION)
+#  if defined(__GNUC__)
+#   if (__cplusplus >= 201709)
+#    if __has_include(<experimental/source_location>)
+#     define ASIO_HAS_STD_EXPERIMENTAL_SOURCE_LOCATION 1
+#    endif // __has_include(<experimental/source_location>)
+#   endif // (__cplusplus >= 201709)
+#  endif // defined(__GNUC__)
+# endif // !defined(ASIO_DISABLE_STD_EXPERIMENTAL_SOURCE_LOCATION)
+#endif // !defined(ASIO_HAS_STD_EXPERIMENTAL_SOURCE_LOCATION)
+
+// Standard library has a source_location that we can use.
+#if !defined(ASIO_HAS_SOURCE_LOCATION)
+# if !defined(ASIO_DISABLE_SOURCE_LOCATION)
+#  if defined(ASIO_HAS_STD_SOURCE_LOCATION)
+#   define ASIO_HAS_SOURCE_LOCATION 1
+#  elif defined(ASIO_HAS_STD_EXPERIMENTAL_SOURCE_LOCATION)
+#   define ASIO_HAS_SOURCE_LOCATION 1
+#  endif // defined(ASIO_HAS_STD_EXPERIMENTAL_SOURCE_LOCATION)
+# endif // !defined(ASIO_DISABLE_SOURCE_LOCATION)
+#endif // !defined(ASIO_HAS_SOURCE_LOCATION)
+
+// Windows App target. Windows but with a limited API.
+#if !defined(ASIO_WINDOWS_APP)
+# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0603)
+#  include <winapifamily.h>
+#  if (WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) \
+       || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_TV_TITLE)) \
+   && !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
+#   define ASIO_WINDOWS_APP 1
+#  endif // WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP)
+         // && !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
+# endif // defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0603)
+#endif // !defined(ASIO_WINDOWS_APP)
+
+// Legacy WinRT target. Windows App is preferred.
+#if !defined(ASIO_WINDOWS_RUNTIME)
+# if !defined(ASIO_WINDOWS_APP)
+#  if defined(__cplusplus_winrt)
+#   include <winapifamily.h>
+#   if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) \
+    && !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
+#    define ASIO_WINDOWS_RUNTIME 1
+#   endif // WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP)
+          // && !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
+#  endif // defined(__cplusplus_winrt)
+# endif // !defined(ASIO_WINDOWS_APP)
+#endif // !defined(ASIO_WINDOWS_RUNTIME)
+
+// Windows target. Excludes WinRT but includes Windows App targets.
+#if !defined(ASIO_WINDOWS)
+# if !defined(ASIO_WINDOWS_RUNTIME)
+#  if defined(ASIO_HAS_BOOST_CONFIG) && defined(BOOST_WINDOWS)
+#   define ASIO_WINDOWS 1
+#  elif defined(WIN32) || defined(_WIN32) || defined(__WIN32__)
+#   define ASIO_WINDOWS 1
+#  elif defined(ASIO_WINDOWS_APP)
+#   define ASIO_WINDOWS 1
+#  endif // defined(ASIO_HAS_BOOST_CONFIG) && defined(BOOST_WINDOWS)
+# endif // !defined(ASIO_WINDOWS_RUNTIME)
+#endif // !defined(ASIO_WINDOWS)
+
+// Windows: target OS version.
+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+# if !defined(_WIN32_WINNT) && !defined(_WIN32_WINDOWS)
+#  if defined(_MSC_VER) || (defined(__BORLANDC__) && !defined(__clang__))
+#   pragma message( \
+  "Please define _WIN32_WINNT or _WIN32_WINDOWS appropriately. For example:\n"\
+  "- add -D_WIN32_WINNT=0x0601 to the compiler command line; or\n"\
+  "- add _WIN32_WINNT=0x0601 to your project's Preprocessor Definitions.\n"\
+  "Assuming _WIN32_WINNT=0x0601 (i.e. Windows 7 target).")
+#  else // defined(_MSC_VER) || (defined(__BORLANDC__) && !defined(__clang__))
+#   warning Please define _WIN32_WINNT or _WIN32_WINDOWS appropriately.
+#   warning For example, add -D_WIN32_WINNT=0x0601 to the compiler command line.
+#   warning Assuming _WIN32_WINNT=0x0601 (i.e. Windows 7 target).
+#  endif // defined(_MSC_VER) || (defined(__BORLANDC__) && !defined(__clang__))
+#  define _WIN32_WINNT 0x0601
+# 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(ASIO_WINDOWS) || defined(__CYGWIN__)
+
+// Windows: minimise header inclusion.
+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+# if !defined(ASIO_NO_WIN32_LEAN_AND_MEAN)
+#  if !defined(WIN32_LEAN_AND_MEAN)
+#   define WIN32_LEAN_AND_MEAN
+#  endif // !defined(WIN32_LEAN_AND_MEAN)
+# endif // !defined(ASIO_NO_WIN32_LEAN_AND_MEAN)
+#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+
+// Windows: suppress definition of "min" and "max" macros.
+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+# if !defined(ASIO_NO_NOMINMAX)
+#  if !defined(NOMINMAX)
+#   define NOMINMAX 1
+#  endif // !defined(NOMINMAX)
+# endif // !defined(ASIO_NO_NOMINMAX)
+#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+
+// Windows: IO Completion Ports.
+#if !defined(ASIO_HAS_IOCP)
+# if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+#  if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0400)
+#   if !defined(UNDER_CE) && !defined(ASIO_WINDOWS_APP)
+#    if !defined(ASIO_DISABLE_IOCP)
+#     define ASIO_HAS_IOCP 1
+#    endif // !defined(ASIO_DISABLE_IOCP)
+#   endif // !defined(UNDER_CE) && !defined(ASIO_WINDOWS_APP)
+#  endif // defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0400)
+# endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+#endif // !defined(ASIO_HAS_IOCP)
+
+// 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(ASIO_HAS_UNISTD_H)
+# if !defined(ASIO_HAS_BOOST_CONFIG)
+#  if defined(unix) \
+   || defined(__unix) \
+   || defined(_XOPEN_SOURCE) \
+   || defined(_POSIX_SOURCE) \
+   || (defined(__MACH__) && defined(__APPLE__)) \
+   || defined(__FreeBSD__) \
+   || defined(__NetBSD__) \
+   || defined(__OpenBSD__) \
+   || defined(__linux__) \
+   || defined(__HAIKU__)
+#   define ASIO_HAS_UNISTD_H 1
+#  endif
+# endif // !defined(ASIO_HAS_BOOST_CONFIG)
+#endif // !defined(ASIO_HAS_UNISTD_H)
+#if defined(ASIO_HAS_UNISTD_H)
+# include <unistd.h>
+#endif // defined(ASIO_HAS_UNISTD_H)
+
+// Linux: epoll, eventfd and timerfd.
+#if defined(__linux__)
+# include <linux/version.h>
+# if !defined(ASIO_HAS_EPOLL)
+#  if !defined(ASIO_DISABLE_EPOLL)
+#   if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,45)
+#    define ASIO_HAS_EPOLL 1
+#   endif // LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,45)
+#  endif // !defined(ASIO_DISABLE_EPOLL)
+# endif // !defined(ASIO_HAS_EPOLL)
+# if !defined(ASIO_HAS_EVENTFD)
+#  if !defined(ASIO_DISABLE_EVENTFD)
+#   if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
+#    define ASIO_HAS_EVENTFD 1
+#   endif // LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
+#  endif // !defined(ASIO_DISABLE_EVENTFD)
+# endif // !defined(ASIO_HAS_EVENTFD)
+# if !defined(ASIO_HAS_TIMERFD)
+#  if defined(ASIO_HAS_EPOLL)
+#   if (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 8)
+#    define ASIO_HAS_TIMERFD 1
+#   endif // (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 8)
+#  endif // defined(ASIO_HAS_EPOLL)
+# endif // !defined(ASIO_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(ASIO_HAS_KQUEUE)
+#  if !defined(ASIO_DISABLE_KQUEUE)
+#   define ASIO_HAS_KQUEUE 1
+#  endif // !defined(ASIO_DISABLE_KQUEUE)
+# endif // !defined(ASIO_HAS_KQUEUE)
+#endif // (defined(__MACH__) && defined(__APPLE__))
+       //   || defined(__FreeBSD__)
+       //   || defined(__NetBSD__)
+       //   || defined(__OpenBSD__)
+
+// Solaris: /dev/poll.
+#if defined(__sun)
+# if !defined(ASIO_HAS_DEV_POLL)
+#  if !defined(ASIO_DISABLE_DEV_POLL)
+#   define ASIO_HAS_DEV_POLL 1
+#  endif // !defined(ASIO_DISABLE_DEV_POLL)
+# endif // !defined(ASIO_HAS_DEV_POLL)
+#endif // defined(__sun)
+
+// Serial ports.
+#if !defined(ASIO_HAS_SERIAL_PORT)
+# if defined(ASIO_HAS_IOCP) \
+  || !defined(ASIO_WINDOWS) \
+  && !defined(ASIO_WINDOWS_RUNTIME) \
+  && !defined(__CYGWIN__)
+#  if !defined(__SYMBIAN32__)
+#   if !defined(ASIO_DISABLE_SERIAL_PORT)
+#    define ASIO_HAS_SERIAL_PORT 1
+#   endif // !defined(ASIO_DISABLE_SERIAL_PORT)
+#  endif // !defined(__SYMBIAN32__)
+# endif // defined(ASIO_HAS_IOCP)
+        //   || !defined(ASIO_WINDOWS)
+        //   && !defined(ASIO_WINDOWS_RUNTIME)
+        //   && !defined(__CYGWIN__)
+#endif // !defined(ASIO_HAS_SERIAL_PORT)
+
+// Windows: stream handles.
+#if !defined(ASIO_HAS_WINDOWS_STREAM_HANDLE)
+# if !defined(ASIO_DISABLE_WINDOWS_STREAM_HANDLE)
+#  if defined(ASIO_HAS_IOCP)
+#   define ASIO_HAS_WINDOWS_STREAM_HANDLE 1
+#  endif // defined(ASIO_HAS_IOCP)
+# endif // !defined(ASIO_DISABLE_WINDOWS_STREAM_HANDLE)
+#endif // !defined(ASIO_HAS_WINDOWS_STREAM_HANDLE)
+
+// Windows: random access handles.
+#if !defined(ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE)
+# if !defined(ASIO_DISABLE_WINDOWS_RANDOM_ACCESS_HANDLE)
+#  if defined(ASIO_HAS_IOCP)
+#   define ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE 1
+#  endif // defined(ASIO_HAS_IOCP)
+# endif // !defined(ASIO_DISABLE_WINDOWS_RANDOM_ACCESS_HANDLE)
+#endif // !defined(ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE)
+
+// Windows: object handles.
+#if !defined(ASIO_HAS_WINDOWS_OBJECT_HANDLE)
+# if !defined(ASIO_DISABLE_WINDOWS_OBJECT_HANDLE)
+#  if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+#   if !defined(UNDER_CE) && !defined(ASIO_WINDOWS_APP)
+#    define ASIO_HAS_WINDOWS_OBJECT_HANDLE 1
+#   endif // !defined(UNDER_CE) && !defined(ASIO_WINDOWS_APP)
+#  endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+# endif // !defined(ASIO_DISABLE_WINDOWS_OBJECT_HANDLE)
+#endif // !defined(ASIO_HAS_WINDOWS_OBJECT_HANDLE)
+
+// Windows: OVERLAPPED wrapper.
+#if !defined(ASIO_HAS_WINDOWS_OVERLAPPED_PTR)
+# if !defined(ASIO_DISABLE_WINDOWS_OVERLAPPED_PTR)
+#  if defined(ASIO_HAS_IOCP)
+#   define ASIO_HAS_WINDOWS_OVERLAPPED_PTR 1
+#  endif // defined(ASIO_HAS_IOCP)
+# endif // !defined(ASIO_DISABLE_WINDOWS_OVERLAPPED_PTR)
+#endif // !defined(ASIO_HAS_WINDOWS_OVERLAPPED_PTR)
+
+// POSIX: stream-oriented file descriptors.
+#if !defined(ASIO_HAS_POSIX_STREAM_DESCRIPTOR)
+# if !defined(ASIO_DISABLE_POSIX_STREAM_DESCRIPTOR)
+#  if !defined(ASIO_WINDOWS) \
+  && !defined(ASIO_WINDOWS_RUNTIME) \
+  && !defined(__CYGWIN__)
+#   define ASIO_HAS_POSIX_STREAM_DESCRIPTOR 1
+#  endif // !defined(ASIO_WINDOWS)
+         //   && !defined(ASIO_WINDOWS_RUNTIME)
+         //   && !defined(__CYGWIN__)
+# endif // !defined(ASIO_DISABLE_POSIX_STREAM_DESCRIPTOR)
+#endif // !defined(ASIO_HAS_POSIX_STREAM_DESCRIPTOR)
+
+// UNIX domain sockets.
+#if !defined(ASIO_HAS_LOCAL_SOCKETS)
+# if !defined(ASIO_DISABLE_LOCAL_SOCKETS)
+#  if !defined(ASIO_WINDOWS) \
+  && !defined(ASIO_WINDOWS_RUNTIME) \
+  && !defined(__CYGWIN__)
+#   define ASIO_HAS_LOCAL_SOCKETS 1
+#  endif // !defined(ASIO_WINDOWS)
+         //   && !defined(ASIO_WINDOWS_RUNTIME)
+         //   && !defined(__CYGWIN__)
+# endif // !defined(ASIO_DISABLE_LOCAL_SOCKETS)
+#endif // !defined(ASIO_HAS_LOCAL_SOCKETS)
+
+// Can use sigaction() instead of signal().
+#if !defined(ASIO_HAS_SIGACTION)
+# if !defined(ASIO_DISABLE_SIGACTION)
+#  if !defined(ASIO_WINDOWS) \
+  && !defined(ASIO_WINDOWS_RUNTIME) \
+  && !defined(__CYGWIN__)
+#   define ASIO_HAS_SIGACTION 1
+#  endif // !defined(ASIO_WINDOWS)
+         //   && !defined(ASIO_WINDOWS_RUNTIME)
+         //   && !defined(__CYGWIN__)
+# endif // !defined(ASIO_DISABLE_SIGACTION)
+#endif // !defined(ASIO_HAS_SIGACTION)
+
+// Can use signal().
+#if !defined(ASIO_HAS_SIGNAL)
+# if !defined(ASIO_DISABLE_SIGNAL)
+#  if !defined(UNDER_CE)
+#   define ASIO_HAS_SIGNAL 1
+#  endif // !defined(UNDER_CE)
+# endif // !defined(ASIO_DISABLE_SIGNAL)
+#endif // !defined(ASIO_HAS_SIGNAL)
+
+// Can use getaddrinfo() and getnameinfo().
+#if !defined(ASIO_HAS_GETADDRINFO)
+# if !defined(ASIO_DISABLE_GETADDRINFO)
+#  if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+#   if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501)
+#    define ASIO_HAS_GETADDRINFO 1
+#   elif defined(UNDER_CE)
+#    define ASIO_HAS_GETADDRINFO 1
+#   endif // defined(UNDER_CE)
+#  elif defined(__MACH__) && defined(__APPLE__)
+#   if defined(__MAC_OS_X_VERSION_MIN_REQUIRED)
+#    if (__MAC_OS_X_VERSION_MIN_REQUIRED >= 1050)
+#     define ASIO_HAS_GETADDRINFO 1
+#    endif // (__MAC_OS_X_VERSION_MIN_REQUIRED >= 1050)
+#   else // defined(__MAC_OS_X_VERSION_MIN_REQUIRED)
+#    define ASIO_HAS_GETADDRINFO 1
+#   endif // defined(__MAC_OS_X_VERSION_MIN_REQUIRED)
+#  else // defined(__MACH__) && defined(__APPLE__)
+#   define ASIO_HAS_GETADDRINFO 1
+#  endif // defined(__MACH__) && defined(__APPLE__)
+# endif // !defined(ASIO_DISABLE_GETADDRINFO)
+#endif // !defined(ASIO_HAS_GETADDRINFO)
+
+// Whether standard iostreams are disabled.
+#if !defined(ASIO_NO_IOSTREAM)
+# if defined(ASIO_HAS_BOOST_CONFIG) && defined(BOOST_NO_IOSTREAM)
+#  define ASIO_NO_IOSTREAM 1
+# endif // !defined(BOOST_NO_IOSTREAM)
+#endif // !defined(ASIO_NO_IOSTREAM)
+
+// Whether exception handling is disabled.
+#if !defined(ASIO_NO_EXCEPTIONS)
+# if defined(ASIO_HAS_BOOST_CONFIG) && defined(BOOST_NO_EXCEPTIONS)
+#  define ASIO_NO_EXCEPTIONS 1
+# endif // !defined(BOOST_NO_EXCEPTIONS)
+#endif // !defined(ASIO_NO_EXCEPTIONS)
+
+// Whether the typeid operator is supported.
+#if !defined(ASIO_NO_TYPEID)
+# if defined(ASIO_HAS_BOOST_CONFIG) && defined(BOOST_NO_TYPEID)
+#  define ASIO_NO_TYPEID 1
+# endif // !defined(BOOST_NO_TYPEID)
+#endif // !defined(ASIO_NO_TYPEID)
+
+// Threads.
+#if !defined(ASIO_HAS_THREADS)
+# if !defined(ASIO_DISABLE_THREADS)
+#  if defined(ASIO_HAS_BOOST_CONFIG) && defined(BOOST_HAS_THREADS)
+#   define ASIO_HAS_THREADS 1
+#  elif defined(__GNUC__) && !defined(__MINGW32__) \
+     && !defined(linux) && !defined(__linux) && !defined(__linux__)
+#   define ASIO_HAS_THREADS 1
+#  elif defined(_MT) || defined(__MT__)
+#   define ASIO_HAS_THREADS 1
+#  elif defined(_REENTRANT)
+#   define ASIO_HAS_THREADS 1
+#  elif defined(__APPLE__)
+#   define ASIO_HAS_THREADS 1
+#  elif defined(__HAIKU__)
+#   define ASIO_HAS_THREADS 1
+#  elif defined(_POSIX_THREADS) && (_POSIX_THREADS + 0 >= 0)
+#   define ASIO_HAS_THREADS 1
+#  elif defined(_PTHREADS)
+#   define ASIO_HAS_THREADS 1
+#  endif // defined(ASIO_HAS_BOOST_CONFIG) && defined(BOOST_HAS_THREADS)
+# endif // !defined(ASIO_DISABLE_THREADS)
+#endif // !defined(ASIO_HAS_THREADS)
+
+// POSIX threads.
+#if !defined(ASIO_HAS_PTHREADS)
+# if defined(ASIO_HAS_THREADS)
+#  if defined(ASIO_HAS_BOOST_CONFIG) && defined(BOOST_HAS_PTHREADS)
+#   define ASIO_HAS_PTHREADS 1
+#  elif defined(_POSIX_THREADS) && (_POSIX_THREADS + 0 >= 0)
+#   define ASIO_HAS_PTHREADS 1
+#  elif defined(__HAIKU__)
+#   define ASIO_HAS_PTHREADS 1
+#  endif // defined(ASIO_HAS_BOOST_CONFIG) && defined(BOOST_HAS_PTHREADS)
+# endif // defined(ASIO_HAS_THREADS)
+#endif // !defined(ASIO_HAS_PTHREADS)
+
+// Helper to prevent macro expansion.
+#define ASIO_PREVENT_MACRO_SUBSTITUTION
+
+// Helper to define in-class constants.
+#if !defined(ASIO_STATIC_CONSTANT)
+# if !defined(ASIO_DISABLE_BOOST_STATIC_CONSTANT)
+#  define ASIO_STATIC_CONSTANT(type, assignment) \
+    BOOST_STATIC_CONSTANT(type, assignment)
+# else // !defined(ASIO_DISABLE_BOOST_STATIC_CONSTANT)
+#  define ASIO_STATIC_CONSTANT(type, assignment) \
+    static const type assignment
+# endif // !defined(ASIO_DISABLE_BOOST_STATIC_CONSTANT)
+#endif // !defined(ASIO_STATIC_CONSTANT)
+
+// Boost array library.
+#if !defined(ASIO_HAS_BOOST_ARRAY)
+# if !defined(ASIO_DISABLE_BOOST_ARRAY)
+#  define ASIO_HAS_BOOST_ARRAY 1
+# endif // !defined(ASIO_DISABLE_BOOST_ARRAY)
+#endif // !defined(ASIO_HAS_BOOST_ARRAY)
+
+// Boost assert macro.
+#if !defined(ASIO_HAS_BOOST_ASSERT)
+# if !defined(ASIO_DISABLE_BOOST_ASSERT)
+#  define ASIO_HAS_BOOST_ASSERT 1
+# endif // !defined(ASIO_DISABLE_BOOST_ASSERT)
+#endif // !defined(ASIO_HAS_BOOST_ASSERT)
+
+// Boost limits header.
+#if !defined(ASIO_HAS_BOOST_LIMITS)
+# if !defined(ASIO_DISABLE_BOOST_LIMITS)
+#  define ASIO_HAS_BOOST_LIMITS 1
+# endif // !defined(ASIO_DISABLE_BOOST_LIMITS)
+#endif // !defined(ASIO_HAS_BOOST_LIMITS)
+
+// Boost throw_exception function.
+#if !defined(ASIO_HAS_BOOST_THROW_EXCEPTION)
+# if !defined(ASIO_DISABLE_BOOST_THROW_EXCEPTION)
+#  define ASIO_HAS_BOOST_THROW_EXCEPTION 1
+# endif // !defined(ASIO_DISABLE_BOOST_THROW_EXCEPTION)
+#endif // !defined(ASIO_HAS_BOOST_THROW_EXCEPTION)
+
+// Boost regex library.
+#if !defined(ASIO_HAS_BOOST_REGEX)
+# if !defined(ASIO_DISABLE_BOOST_REGEX)
+#  define ASIO_HAS_BOOST_REGEX 1
+# endif // !defined(ASIO_DISABLE_BOOST_REGEX)
+#endif // !defined(ASIO_HAS_BOOST_REGEX)
+
+// Boost bind function.
+#if !defined(ASIO_HAS_BOOST_BIND)
+# if !defined(ASIO_DISABLE_BOOST_BIND)
+#  define ASIO_HAS_BOOST_BIND 1
+# endif // !defined(ASIO_DISABLE_BOOST_BIND)
+#endif // !defined(ASIO_HAS_BOOST_BIND)
+
+// Boost's BOOST_WORKAROUND macro.
+#if !defined(ASIO_HAS_BOOST_WORKAROUND)
+# if !defined(ASIO_DISABLE_BOOST_WORKAROUND)
+#  define ASIO_HAS_BOOST_WORKAROUND 1
+# endif // !defined(ASIO_DISABLE_BOOST_WORKAROUND)
+#endif // !defined(ASIO_HAS_BOOST_WORKAROUND)
+
+// Microsoft Visual C++'s secure C runtime library.
+#if !defined(ASIO_HAS_SECURE_RTL)
+# if !defined(ASIO_DISABLE_SECURE_RTL)
+#  if defined(ASIO_MSVC) \
+    && (ASIO_MSVC >= 1400) \
+    && !defined(UNDER_CE)
+#   define ASIO_HAS_SECURE_RTL 1
+#  endif // defined(ASIO_MSVC)
+         // && (ASIO_MSVC >= 1400)
+         // && !defined(UNDER_CE)
+# endif // !defined(ASIO_DISABLE_SECURE_RTL)
+#endif // !defined(ASIO_HAS_SECURE_RTL)
+
+// Handler hooking. Disabled for ancient Borland C++ and gcc compilers.
+#if !defined(ASIO_HAS_HANDLER_HOOKS)
+# if !defined(ASIO_DISABLE_HANDLER_HOOKS)
+#  if defined(__GNUC__)
+#   if (__GNUC__ >= 3)
+#    define ASIO_HAS_HANDLER_HOOKS 1
+#   endif // (__GNUC__ >= 3)
+#  elif !defined(__BORLANDC__) || defined(__clang__)
+#   define ASIO_HAS_HANDLER_HOOKS 1
+#  endif // !defined(__BORLANDC__) || defined(__clang__)
+# endif // !defined(ASIO_DISABLE_HANDLER_HOOKS)
+#endif // !defined(ASIO_HAS_HANDLER_HOOKS)
+
+// Support for the __thread keyword extension.
+#if !defined(ASIO_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) \
+       && !(defined(__clang__) && defined(__ANDROID__))
+#     define ASIO_HAS_THREAD_KEYWORD_EXTENSION 1
+#     define ASIO_THREAD_KEYWORD __thread
+#    elif defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 1100)
+#     define ASIO_HAS_THREAD_KEYWORD_EXTENSION 1
+#    endif // defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 1100)
+           // && !(defined(__clang__) && defined(__ANDROID__))
+#   endif // ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)
+#  endif // defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
+# endif // defined(__linux__)
+# if defined(ASIO_MSVC) && defined(ASIO_WINDOWS_RUNTIME)
+#  if (_MSC_VER >= 1700)
+#   define ASIO_HAS_THREAD_KEYWORD_EXTENSION 1
+#   define ASIO_THREAD_KEYWORD __declspec(thread)
+#  endif // (_MSC_VER >= 1700)
+# endif // defined(ASIO_MSVC) && defined(ASIO_WINDOWS_RUNTIME)
+#endif // !defined(ASIO_DISABLE_THREAD_KEYWORD_EXTENSION)
+#if !defined(ASIO_THREAD_KEYWORD)
+# define ASIO_THREAD_KEYWORD __thread
+#endif // !defined(ASIO_THREAD_KEYWORD)
+
+// Support for POSIX ssize_t typedef.
+#if !defined(ASIO_DISABLE_SSIZE_T)
+# if defined(__linux__) \
+   || (defined(__MACH__) && defined(__APPLE__))
+#  define ASIO_HAS_SSIZE_T 1
+# endif // defined(__linux__)
+        //   || (defined(__MACH__) && defined(__APPLE__))
+#endif // !defined(ASIO_DISABLE_SSIZE_T)
+
+// Helper macros to manage transition away from error_code return values.
+#if defined(ASIO_NO_DEPRECATED)
+# define ASIO_SYNC_OP_VOID void
+# define ASIO_SYNC_OP_VOID_RETURN(e) return
+#else // defined(ASIO_NO_DEPRECATED)
+# define ASIO_SYNC_OP_VOID asio::error_code
+# define ASIO_SYNC_OP_VOID_RETURN(e) return e
+#endif // defined(ASIO_NO_DEPRECATED)
+
+// Newer gcc, clang need special treatment to suppress unused typedef warnings.
+#if defined(__clang__)
+# if defined(__apple_build_version__)
+#  if (__clang_major__ >= 7)
+#   define ASIO_UNUSED_TYPEDEF __attribute__((__unused__))
+#  endif // (__clang_major__ >= 7)
+# elif ((__clang_major__ == 3) && (__clang_minor__ >= 6)) \
+    || (__clang_major__ > 3)
+#  define ASIO_UNUSED_TYPEDEF __attribute__((__unused__))
+# endif // ((__clang_major__ == 3) && (__clang_minor__ >= 6))
+        //   || (__clang_major__ > 3)
+#elif defined(__GNUC__)
+# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4)
+#  define ASIO_UNUSED_TYPEDEF __attribute__((__unused__))
+# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4)
+#endif // defined(__GNUC__)
+#if !defined(ASIO_UNUSED_TYPEDEF)
+# define ASIO_UNUSED_TYPEDEF
+#endif // !defined(ASIO_UNUSED_TYPEDEF)
+
+// Some versions of gcc generate spurious warnings about unused variables.
+#if defined(__GNUC__)
+# if (__GNUC__ >= 4)
+#  define ASIO_UNUSED_VARIABLE __attribute__((__unused__))
+# endif // (__GNUC__ >= 4)
+#endif // defined(__GNUC__)
+#if !defined(ASIO_UNUSED_VARIABLE)
+# define ASIO_UNUSED_VARIABLE
+#endif // !defined(ASIO_UNUSED_VARIABLE)
+
+// Support the co_await keyword on compilers known to allow it.
+#if !defined(ASIO_HAS_CO_AWAIT)
+# if !defined(ASIO_DISABLE_CO_AWAIT)
+#  if defined(ASIO_MSVC)
+#   if (_MSC_FULL_VER >= 190023506)
+#    if defined(_RESUMABLE_FUNCTIONS_SUPPORTED)
+#     define ASIO_HAS_CO_AWAIT 1
+#    endif // defined(_RESUMABLE_FUNCTIONS_SUPPORTED)
+#   endif // (_MSC_FULL_VER >= 190023506)
+#  endif // defined(ASIO_MSVC)
+#  if defined(__clang__)
+#   if (__cplusplus >= 201703) && (__cpp_coroutines >= 201703)
+#    if __has_include(<experimental/coroutine>)
+#     define ASIO_HAS_CO_AWAIT 1
+#    endif // __has_include(<experimental/coroutine>)
+#   endif // (__cplusplus >= 201703) && (__cpp_coroutines >= 201703)
+#  elif defined(__GNUC__)
+#   if (__cplusplus >= 201709) && (__cpp_impl_coroutine >= 201902)
+#    if __has_include(<coroutine>)
+#     define ASIO_HAS_CO_AWAIT 1
+#    endif // __has_include(<coroutine>)
+#   endif // (__cplusplus >= 201709) && (__cpp_impl_coroutine >= 201902)
+#  endif // defined(__GNUC__)
+# endif // !defined(ASIO_DISABLE_CO_AWAIT)
+#endif // !defined(ASIO_HAS_CO_AWAIT)
+
+// Standard library support for coroutines.
+#if !defined(ASIO_HAS_STD_COROUTINE)
+# if !defined(ASIO_DISABLE_STD_COROUTINE)
+#  if defined(__GNUC__)
+#   if (__cplusplus >= 201709) && (__cpp_impl_coroutine >= 201902)
+#    if __has_include(<coroutine>)
+#     define ASIO_HAS_STD_COROUTINE 1
+#    endif // __has_include(<coroutine>)
+#   endif // (__cplusplus >= 201709) && (__cpp_impl_coroutine >= 201902)
+#  endif // defined(__GNUC__)
+# endif // !defined(ASIO_DISABLE_STD_COROUTINE)
+#endif // !defined(ASIO_HAS_STD_COROUTINE)
+
+// Compiler support for the the [[nodiscard]] attribute.
+#if !defined(ASIO_NODISCARD)
+# if defined(__has_cpp_attribute)
+#  if __has_cpp_attribute(nodiscard)
+#   if (__cplusplus >= 201703)
+#    define ASIO_NODISCARD [[nodiscard]]
+#   endif // (__cplusplus >= 201703)
+#  endif // __has_cpp_attribute(nodiscard)
+# endif // defined(__has_cpp_attribute)
+#endif // !defined(ASIO_NODISCARD)
+#if !defined(ASIO_NODISCARD)
+# define ASIO_NODISCARD
+#endif // !defined(ASIO_NODISCARD)
+
+#endif // ASIO_DETAIL_CONFIG_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/consuming_buffers.hpp b/link/modules/asio-standalone/asio/include/asio/detail/consuming_buffers.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/consuming_buffers.hpp
@@ -0,0 +1,414 @@
+//
+// detail/consuming_buffers.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_CONSUMING_BUFFERS_HPP
+#define ASIO_DETAIL_CONSUMING_BUFFERS_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <cstddef>
+#include "asio/buffer.hpp"
+#include "asio/detail/buffer_sequence_adapter.hpp"
+#include "asio/detail/limits.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+// Helper template to determine the maximum number of prepared buffers.
+template <typename Buffers>
+struct prepared_buffers_max
+{
+  enum { value = buffer_sequence_adapter_base::max_buffers };
+};
+
+template <typename Elem, std::size_t N>
+struct prepared_buffers_max<boost::array<Elem, N> >
+{
+  enum { value = N };
+};
+
+#if defined(ASIO_HAS_STD_ARRAY)
+
+template <typename Elem, std::size_t N>
+struct prepared_buffers_max<std::array<Elem, N> >
+{
+  enum { value = N };
+};
+
+#endif // defined(ASIO_HAS_STD_ARRAY)
+
+// A buffer sequence used to represent a subsequence of the buffers.
+template <typename Buffer, std::size_t MaxBuffers>
+struct prepared_buffers
+{
+  typedef Buffer value_type;
+  typedef const Buffer* const_iterator;
+
+  enum { max_buffers = MaxBuffers < 16 ? MaxBuffers : 16 };
+
+  prepared_buffers() : count(0) {}
+  const_iterator begin() const { return elems; }
+  const_iterator end() const { return elems + count; }
+
+  Buffer elems[max_buffers];
+  std::size_t count;
+};
+
+// A proxy for a sub-range in a list of buffers.
+template <typename Buffer, typename Buffers, typename Buffer_Iterator>
+class consuming_buffers
+{
+public:
+  typedef prepared_buffers<Buffer, prepared_buffers_max<Buffers>::value>
+    prepared_buffers_type;
+
+  // Construct to represent the entire list of buffers.
+  explicit consuming_buffers(const Buffers& buffers)
+    : buffers_(buffers),
+      total_consumed_(0),
+      next_elem_(0),
+      next_elem_offset_(0)
+  {
+    using asio::buffer_size;
+    total_size_ = buffer_size(buffers);
+  }
+
+  // Determine if we are at the end of the buffers.
+  bool empty() const
+  {
+    return total_consumed_ >= total_size_;
+  }
+
+  // Get the buffer for a single transfer, with a size.
+  prepared_buffers_type prepare(std::size_t max_size)
+  {
+    prepared_buffers_type result;
+
+    Buffer_Iterator next = asio::buffer_sequence_begin(buffers_);
+    Buffer_Iterator end = asio::buffer_sequence_end(buffers_);
+
+    std::advance(next, next_elem_);
+    std::size_t elem_offset = next_elem_offset_;
+    while (next != end && max_size > 0 && (result.count) < result.max_buffers)
+    {
+      Buffer next_buf = Buffer(*next) + elem_offset;
+      result.elems[result.count] = asio::buffer(next_buf, max_size);
+      max_size -= result.elems[result.count].size();
+      elem_offset = 0;
+      if (result.elems[result.count].size() > 0)
+        ++result.count;
+      ++next;
+    }
+
+    return result;
+  }
+
+  // Consume the specified number of bytes from the buffers.
+  void consume(std::size_t size)
+  {
+    total_consumed_ += size;
+
+    Buffer_Iterator next = asio::buffer_sequence_begin(buffers_);
+    Buffer_Iterator end = asio::buffer_sequence_end(buffers_);
+
+    std::advance(next, next_elem_);
+    while (next != end && size > 0)
+    {
+      Buffer next_buf = Buffer(*next) + next_elem_offset_;
+      if (size < next_buf.size())
+      {
+        next_elem_offset_ += size;
+        size = 0;
+      }
+      else
+      {
+        size -= next_buf.size();
+        next_elem_offset_ = 0;
+        ++next_elem_;
+        ++next;
+      }
+    }
+  }
+
+  // Get the total number of bytes consumed from the buffers.
+  std::size_t total_consumed() const
+  {
+    return total_consumed_;
+  }
+
+private:
+  Buffers buffers_;
+  std::size_t total_size_;
+  std::size_t total_consumed_;
+  std::size_t next_elem_;
+  std::size_t next_elem_offset_;
+};
+
+// Base class of all consuming_buffers specialisations for single buffers.
+template <typename Buffer>
+class consuming_single_buffer
+{
+public:
+  // Construct to represent the entire list of buffers.
+  template <typename Buffer1>
+  explicit consuming_single_buffer(const Buffer1& buffer)
+    : buffer_(buffer),
+      total_consumed_(0)
+  {
+  }
+
+  // Determine if we are at the end of the buffers.
+  bool empty() const
+  {
+    return total_consumed_ >= buffer_.size();
+  }
+
+  // Get the buffer for a single transfer, with a size.
+  Buffer prepare(std::size_t max_size)
+  {
+    return asio::buffer(buffer_ + total_consumed_, max_size);
+  }
+
+  // Consume the specified number of bytes from the buffers.
+  void consume(std::size_t size)
+  {
+    total_consumed_ += size;
+  }
+
+  // Get the total number of bytes consumed from the buffers.
+  std::size_t total_consumed() const
+  {
+    return total_consumed_;
+  }
+
+private:
+  Buffer buffer_;
+  std::size_t total_consumed_;
+};
+
+template <>
+class consuming_buffers<mutable_buffer, mutable_buffer, const mutable_buffer*>
+  : public consuming_single_buffer<ASIO_MUTABLE_BUFFER>
+{
+public:
+  explicit consuming_buffers(const mutable_buffer& buffer)
+    : consuming_single_buffer<ASIO_MUTABLE_BUFFER>(buffer)
+  {
+  }
+};
+
+template <>
+class consuming_buffers<const_buffer, mutable_buffer, const mutable_buffer*>
+  : public consuming_single_buffer<ASIO_CONST_BUFFER>
+{
+public:
+  explicit consuming_buffers(const mutable_buffer& buffer)
+    : consuming_single_buffer<ASIO_CONST_BUFFER>(buffer)
+  {
+  }
+};
+
+template <>
+class consuming_buffers<const_buffer, const_buffer, const const_buffer*>
+  : public consuming_single_buffer<ASIO_CONST_BUFFER>
+{
+public:
+  explicit consuming_buffers(const const_buffer& buffer)
+    : consuming_single_buffer<ASIO_CONST_BUFFER>(buffer)
+  {
+  }
+};
+
+#if !defined(ASIO_NO_DEPRECATED)
+
+template <>
+class consuming_buffers<mutable_buffer,
+    mutable_buffers_1, const mutable_buffer*>
+  : public consuming_single_buffer<ASIO_MUTABLE_BUFFER>
+{
+public:
+  explicit consuming_buffers(const mutable_buffers_1& buffer)
+    : consuming_single_buffer<ASIO_MUTABLE_BUFFER>(buffer)
+  {
+  }
+};
+
+template <>
+class consuming_buffers<const_buffer, mutable_buffers_1, const mutable_buffer*>
+  : public consuming_single_buffer<ASIO_CONST_BUFFER>
+{
+public:
+  explicit consuming_buffers(const mutable_buffers_1& buffer)
+    : consuming_single_buffer<ASIO_CONST_BUFFER>(buffer)
+  {
+  }
+};
+
+template <>
+class consuming_buffers<const_buffer, const_buffers_1, const const_buffer*>
+  : public consuming_single_buffer<ASIO_CONST_BUFFER>
+{
+public:
+  explicit consuming_buffers(const const_buffers_1& buffer)
+    : consuming_single_buffer<ASIO_CONST_BUFFER>(buffer)
+  {
+  }
+};
+
+#endif // !defined(ASIO_NO_DEPRECATED)
+
+template <typename Buffer, typename Elem>
+class consuming_buffers<Buffer, boost::array<Elem, 2>,
+    typename boost::array<Elem, 2>::const_iterator>
+{
+public:
+  // Construct to represent the entire list of buffers.
+  explicit consuming_buffers(const boost::array<Elem, 2>& buffers)
+    : buffers_(buffers),
+      total_consumed_(0)
+  {
+  }
+
+  // Determine if we are at the end of the buffers.
+  bool empty() const
+  {
+    return total_consumed_ >=
+      Buffer(buffers_[0]).size() + Buffer(buffers_[1]).size();
+  }
+
+  // Get the buffer for a single transfer, with a size.
+  boost::array<Buffer, 2> prepare(std::size_t max_size)
+  {
+    boost::array<Buffer, 2> result = {{
+      Buffer(buffers_[0]), Buffer(buffers_[1]) }};
+    std::size_t buffer0_size = result[0].size();
+    result[0] = asio::buffer(result[0] + total_consumed_, max_size);
+    result[1] = asio::buffer(
+        result[1] + (total_consumed_ < buffer0_size
+          ? 0 : total_consumed_ - buffer0_size),
+        max_size - result[0].size());
+    return result;
+  }
+
+  // Consume the specified number of bytes from the buffers.
+  void consume(std::size_t size)
+  {
+    total_consumed_ += size;
+  }
+
+  // Get the total number of bytes consumed from the buffers.
+  std::size_t total_consumed() const
+  {
+    return total_consumed_;
+  }
+
+private:
+  boost::array<Elem, 2> buffers_;
+  std::size_t total_consumed_;
+};
+
+#if defined(ASIO_HAS_STD_ARRAY)
+
+template <typename Buffer, typename Elem>
+class consuming_buffers<Buffer, std::array<Elem, 2>,
+    typename std::array<Elem, 2>::const_iterator>
+{
+public:
+  // Construct to represent the entire list of buffers.
+  explicit consuming_buffers(const std::array<Elem, 2>& buffers)
+    : buffers_(buffers),
+      total_consumed_(0)
+  {
+  }
+
+  // Determine if we are at the end of the buffers.
+  bool empty() const
+  {
+    return total_consumed_ >=
+      Buffer(buffers_[0]).size() + Buffer(buffers_[1]).size();
+  }
+
+  // Get the buffer for a single transfer, with a size.
+  std::array<Buffer, 2> prepare(std::size_t max_size)
+  {
+    std::array<Buffer, 2> result = {{
+      Buffer(buffers_[0]), Buffer(buffers_[1]) }};
+    std::size_t buffer0_size = result[0].size();
+    result[0] = asio::buffer(result[0] + total_consumed_, max_size);
+    result[1] = asio::buffer(
+        result[1] + (total_consumed_ < buffer0_size
+          ? 0 : total_consumed_ - buffer0_size),
+        max_size - result[0].size());
+    return result;
+  }
+
+  // Consume the specified number of bytes from the buffers.
+  void consume(std::size_t size)
+  {
+    total_consumed_ += size;
+  }
+
+  // Get the total number of bytes consumed from the buffers.
+  std::size_t total_consumed() const
+  {
+    return total_consumed_;
+  }
+
+private:
+  std::array<Elem, 2> buffers_;
+  std::size_t total_consumed_;
+};
+
+#endif // defined(ASIO_HAS_STD_ARRAY)
+
+// Specialisation for null_buffers to ensure that the null_buffers type is
+// always passed through to the underlying read or write operation.
+template <typename Buffer>
+class consuming_buffers<Buffer, null_buffers, const mutable_buffer*>
+  : public asio::null_buffers
+{
+public:
+  consuming_buffers(const null_buffers&)
+  {
+    // No-op.
+  }
+
+  bool empty()
+  {
+    return false;
+  }
+
+  null_buffers prepare(std::size_t)
+  {
+    return null_buffers();
+  }
+
+  void consume(std::size_t)
+  {
+    // No-op.
+  }
+
+  std::size_t total_consumed() const
+  {
+    return 0;
+  }
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_CONSUMING_BUFFERS_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/cstddef.hpp b/link/modules/asio-standalone/asio/include/asio/detail/cstddef.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/cstddef.hpp
@@ -0,0 +1,31 @@
+//
+// detail/cstddef.hpp
+// ~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_CSTDDEF_HPP
+#define ASIO_DETAIL_CSTDDEF_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <cstddef>
+
+namespace asio {
+
+#if defined(ASIO_HAS_NULLPTR)
+using std::nullptr_t;
+#else // defined(ASIO_HAS_NULLPTR)
+struct nullptr_t {};
+#endif // defined(ASIO_HAS_NULLPTR)
+
+} // namespace asio
+
+#endif // ASIO_DETAIL_CSTDDEF_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/cstdint.hpp b/link/modules/asio-standalone/asio/include/asio/detail/cstdint.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/cstdint.hpp
@@ -0,0 +1,60 @@
+//
+// detail/cstdint.hpp
+// ~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_CSTDINT_HPP
+#define ASIO_DETAIL_CSTDINT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_CSTDINT)
+# include <cstdint>
+#else // defined(ASIO_HAS_CSTDINT)
+# include <boost/cstdint.hpp>
+#endif // defined(ASIO_HAS_CSTDINT)
+
+namespace asio {
+
+#if defined(ASIO_HAS_CSTDINT)
+using std::int16_t;
+using std::int_least16_t;
+using std::uint16_t;
+using std::uint_least16_t;
+using std::int32_t;
+using std::int_least32_t;
+using std::uint32_t;
+using std::uint_least32_t;
+using std::int64_t;
+using std::int_least64_t;
+using std::uint64_t;
+using std::uint_least64_t;
+using std::uintmax_t;
+#else // defined(ASIO_HAS_CSTDINT)
+using boost::int16_t;
+using boost::int_least16_t;
+using boost::uint16_t;
+using boost::uint_least16_t;
+using boost::int32_t;
+using boost::int_least32_t;
+using boost::uint32_t;
+using boost::uint_least32_t;
+using boost::int64_t;
+using boost::int_least64_t;
+using boost::uint64_t;
+using boost::uint_least64_t;
+using boost::uintmax_t;
+#endif // defined(ASIO_HAS_CSTDINT)
+
+} // namespace asio
+
+#endif // ASIO_DETAIL_CSTDINT_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/date_time_fwd.hpp b/link/modules/asio-standalone/asio/include/asio/detail/date_time_fwd.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/date_time_fwd.hpp
@@ -0,0 +1,34 @@
+//
+// detail/date_time_fwd.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_DATE_TIME_FWD_HPP
+#define ASIO_DETAIL_DATE_TIME_FWD_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+namespace boost {
+namespace date_time {
+
+template<class T, class TimeSystem>
+class base_time;
+
+} // namespace date_time
+namespace posix_time {
+
+class ptime;
+
+} // namespace posix_time
+} // namespace boost
+
+#endif // ASIO_DETAIL_DATE_TIME_FWD_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/deadline_timer_service.hpp b/link/modules/asio-standalone/asio/include/asio/detail/deadline_timer_service.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/deadline_timer_service.hpp
@@ -0,0 +1,295 @@
+//
+// detail/deadline_timer_service.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_DEADLINE_TIMER_SERVICE_HPP
+#define ASIO_DETAIL_DEADLINE_TIMER_SERVICE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <cstddef>
+#include "asio/error.hpp"
+#include "asio/execution_context.hpp"
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/detail/noncopyable.hpp"
+#include "asio/detail/socket_ops.hpp"
+#include "asio/detail/socket_types.hpp"
+#include "asio/detail/timer_queue.hpp"
+#include "asio/detail/timer_queue_ptime.hpp"
+#include "asio/detail/timer_scheduler.hpp"
+#include "asio/detail/wait_handler.hpp"
+#include "asio/detail/wait_op.hpp"
+
+#if defined(ASIO_WINDOWS_RUNTIME)
+# include <chrono>
+# include <thread>
+#endif // defined(ASIO_WINDOWS_RUNTIME)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Time_Traits>
+class deadline_timer_service
+  : public execution_context_service_base<deadline_timer_service<Time_Traits> >
+{
+public:
+  // The time type.
+  typedef typename Time_Traits::time_type time_type;
+
+  // The duration type.
+  typedef typename Time_Traits::duration_type duration_type;
+
+  // The implementation type of the timer. This type is dependent on the
+  // underlying implementation of the timer service.
+  struct implementation_type
+    : private asio::detail::noncopyable
+  {
+    time_type expiry;
+    bool might_have_pending_waits;
+    typename timer_queue<Time_Traits>::per_timer_data timer_data;
+  };
+
+  // Constructor.
+  deadline_timer_service(execution_context& context)
+    : execution_context_service_base<
+        deadline_timer_service<Time_Traits> >(context),
+      scheduler_(asio::use_service<timer_scheduler>(context))
+  {
+    scheduler_.init_task();
+    scheduler_.add_timer_queue(timer_queue_);
+  }
+
+  // Destructor.
+  ~deadline_timer_service()
+  {
+    scheduler_.remove_timer_queue(timer_queue_);
+  }
+
+  // Destroy all user-defined handler objects owned by the service.
+  void shutdown()
+  {
+  }
+
+  // Construct a new timer implementation.
+  void construct(implementation_type& impl)
+  {
+    impl.expiry = time_type();
+    impl.might_have_pending_waits = false;
+  }
+
+  // Destroy a timer implementation.
+  void destroy(implementation_type& impl)
+  {
+    asio::error_code ec;
+    cancel(impl, ec);
+  }
+
+  // Move-construct a new timer implementation.
+  void move_construct(implementation_type& impl,
+      implementation_type& other_impl)
+  {
+    scheduler_.move_timer(timer_queue_, impl.timer_data, other_impl.timer_data);
+
+    impl.expiry = other_impl.expiry;
+    other_impl.expiry = time_type();
+
+    impl.might_have_pending_waits = other_impl.might_have_pending_waits;
+    other_impl.might_have_pending_waits = false;
+  }
+
+  // Move-assign from another timer implementation.
+  void move_assign(implementation_type& impl,
+      deadline_timer_service& other_service,
+      implementation_type& other_impl)
+  {
+    if (this != &other_service)
+      if (impl.might_have_pending_waits)
+        scheduler_.cancel_timer(timer_queue_, impl.timer_data);
+
+    other_service.scheduler_.move_timer(other_service.timer_queue_,
+        impl.timer_data, other_impl.timer_data);
+
+    impl.expiry = other_impl.expiry;
+    other_impl.expiry = time_type();
+
+    impl.might_have_pending_waits = other_impl.might_have_pending_waits;
+    other_impl.might_have_pending_waits = false;
+  }
+
+  // Move-construct a new timer implementation.
+  void converting_move_construct(implementation_type& impl,
+      deadline_timer_service&, implementation_type& other_impl)
+  {
+    move_construct(impl, other_impl);
+  }
+
+  // Move-assign from another timer implementation.
+  void converting_move_assign(implementation_type& impl,
+      deadline_timer_service& other_service,
+      implementation_type& other_impl)
+  {
+    move_assign(impl, other_service, other_impl);
+  }
+
+  // Cancel any asynchronous wait operations associated with the timer.
+  std::size_t cancel(implementation_type& impl, asio::error_code& ec)
+  {
+    if (!impl.might_have_pending_waits)
+    {
+      ec = asio::error_code();
+      return 0;
+    }
+
+    ASIO_HANDLER_OPERATION((scheduler_.context(),
+          "deadline_timer", &impl, 0, "cancel"));
+
+    std::size_t count = scheduler_.cancel_timer(timer_queue_, impl.timer_data);
+    impl.might_have_pending_waits = false;
+    ec = asio::error_code();
+    return count;
+  }
+
+  // Cancels one asynchronous wait operation associated with the timer.
+  std::size_t cancel_one(implementation_type& impl,
+      asio::error_code& ec)
+  {
+    if (!impl.might_have_pending_waits)
+    {
+      ec = asio::error_code();
+      return 0;
+    }
+
+    ASIO_HANDLER_OPERATION((scheduler_.context(),
+          "deadline_timer", &impl, 0, "cancel_one"));
+
+    std::size_t count = scheduler_.cancel_timer(
+        timer_queue_, impl.timer_data, 1);
+    if (count == 0)
+      impl.might_have_pending_waits = false;
+    ec = asio::error_code();
+    return count;
+  }
+
+  // Get the expiry time for the timer as an absolute time.
+  time_type expiry(const implementation_type& impl) const
+  {
+    return impl.expiry;
+  }
+
+  // Get the expiry time for the timer as an absolute time.
+  time_type expires_at(const implementation_type& impl) const
+  {
+    return impl.expiry;
+  }
+
+  // Get the expiry time for the timer relative to now.
+  duration_type expires_from_now(const implementation_type& impl) const
+  {
+    return Time_Traits::subtract(this->expiry(impl), Time_Traits::now());
+  }
+
+  // Set the expiry time for the timer as an absolute time.
+  std::size_t expires_at(implementation_type& impl,
+      const time_type& expiry_time, asio::error_code& ec)
+  {
+    std::size_t count = cancel(impl, ec);
+    impl.expiry = expiry_time;
+    ec = asio::error_code();
+    return count;
+  }
+
+  // Set the expiry time for the timer relative to now.
+  std::size_t expires_after(implementation_type& impl,
+      const duration_type& expiry_time, asio::error_code& ec)
+  {
+    return expires_at(impl,
+        Time_Traits::add(Time_Traits::now(), expiry_time), ec);
+  }
+
+  // Set the expiry time for the timer relative to now.
+  std::size_t expires_from_now(implementation_type& impl,
+      const duration_type& expiry_time, asio::error_code& ec)
+  {
+    return expires_at(impl,
+        Time_Traits::add(Time_Traits::now(), expiry_time), ec);
+  }
+
+  // Perform a blocking wait on the timer.
+  void wait(implementation_type& impl, asio::error_code& ec)
+  {
+    time_type now = Time_Traits::now();
+    ec = asio::error_code();
+    while (Time_Traits::less_than(now, impl.expiry) && !ec)
+    {
+      this->do_wait(Time_Traits::to_posix_duration(
+            Time_Traits::subtract(impl.expiry, now)), ec);
+      now = Time_Traits::now();
+    }
+  }
+
+  // Start an asynchronous wait on the timer.
+  template <typename Handler, typename IoExecutor>
+  void async_wait(implementation_type& impl,
+      Handler& handler, const IoExecutor& io_ex)
+  {
+    // Allocate and construct an operation to wrap the handler.
+    typedef wait_handler<Handler, IoExecutor> op;
+    typename op::ptr p = { asio::detail::addressof(handler),
+      op::ptr::allocate(handler), 0 };
+    p.p = new (p.v) op(handler, io_ex);
+
+    impl.might_have_pending_waits = true;
+
+    ASIO_HANDLER_CREATION((scheduler_.context(),
+          *p.p, "deadline_timer", &impl, 0, "async_wait"));
+
+    scheduler_.schedule_timer(timer_queue_, impl.expiry, impl.timer_data, p.p);
+    p.v = p.p = 0;
+  }
+
+private:
+  // Helper function to wait given a duration type. The duration type should
+  // either be of type boost::posix_time::time_duration, or implement the
+  // required subset of its interface.
+  template <typename Duration>
+  void do_wait(const Duration& timeout, asio::error_code& ec)
+  {
+#if defined(ASIO_WINDOWS_RUNTIME)
+    std::this_thread::sleep_for(
+        std::chrono::seconds(timeout.total_seconds())
+        + std::chrono::microseconds(timeout.total_microseconds()));
+    ec = asio::error_code();
+#else // defined(ASIO_WINDOWS_RUNTIME)
+    ::timeval tv;
+    tv.tv_sec = timeout.total_seconds();
+    tv.tv_usec = timeout.total_microseconds() % 1000000;
+    socket_ops::select(0, 0, 0, 0, &tv, ec);
+#endif // defined(ASIO_WINDOWS_RUNTIME)
+  }
+
+  // The queue of timers.
+  timer_queue<Time_Traits> timer_queue_;
+
+  // The object that schedules and executes timers. Usually a reactor.
+  timer_scheduler& scheduler_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_DEADLINE_TIMER_SERVICE_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/dependent_type.hpp b/link/modules/asio-standalone/asio/include/asio/detail/dependent_type.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/dependent_type.hpp
@@ -0,0 +1,36 @@
+//
+// detail/dependent_type.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_DEPENDENT_TYPE_HPP
+#define ASIO_DETAIL_DEPENDENT_TYPE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename DependsOn, typename T>
+struct dependent_type
+{
+  typedef T type;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_DEPENDENT_TYPE_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/descriptor_ops.hpp b/link/modules/asio-standalone/asio/include/asio/detail/descriptor_ops.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/descriptor_ops.hpp
@@ -0,0 +1,139 @@
+//
+// detail/descriptor_ops.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_DESCRIPTOR_OPS_HPP
+#define ASIO_DETAIL_DESCRIPTOR_OPS_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if !defined(ASIO_WINDOWS) \
+  && !defined(ASIO_WINDOWS_RUNTIME) \
+  && !defined(__CYGWIN__)
+
+#include <cstddef>
+#include "asio/error.hpp"
+#include "asio/error_code.hpp"
+#include "asio/detail/socket_types.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+namespace descriptor_ops {
+
+// Descriptor state bits.
+enum
+{
+  // The user wants a non-blocking descriptor.
+  user_set_non_blocking = 1,
+
+  // The descriptor has been set non-blocking.
+  internal_non_blocking = 2,
+
+  // Helper "state" used to determine whether the descriptor is non-blocking.
+  non_blocking = user_set_non_blocking | internal_non_blocking,
+
+  // The descriptor may have been dup()-ed.
+  possible_dup = 4
+};
+
+typedef unsigned char state_type;
+
+inline void get_last_error(
+    asio::error_code& ec, bool is_error_condition)
+{
+  if (!is_error_condition)
+  {
+    ec.assign(0, ec.category());
+  }
+  else
+  {
+    ec = asio::error_code(errno,
+        asio::error::get_system_category());
+  }
+}
+
+ASIO_DECL int open(const char* path, int flags,
+    asio::error_code& ec);
+
+ASIO_DECL int close(int d, state_type& state,
+    asio::error_code& ec);
+
+ASIO_DECL bool set_user_non_blocking(int d,
+    state_type& state, bool value, asio::error_code& ec);
+
+ASIO_DECL bool set_internal_non_blocking(int d,
+    state_type& state, bool value, asio::error_code& ec);
+
+typedef iovec buf;
+
+ASIO_DECL std::size_t sync_read(int d, state_type state, buf* bufs,
+    std::size_t count, bool all_empty, asio::error_code& ec);
+
+ASIO_DECL std::size_t sync_read1(int d, state_type state, void* data,
+    std::size_t size, asio::error_code& ec);
+
+ASIO_DECL bool non_blocking_read(int d, buf* bufs, std::size_t count,
+    asio::error_code& ec, std::size_t& bytes_transferred);
+
+ASIO_DECL bool non_blocking_read1(int d, void* data, std::size_t size,
+    asio::error_code& ec, std::size_t& bytes_transferred);
+
+ASIO_DECL std::size_t sync_write(int d, state_type state,
+    const buf* bufs, std::size_t count, bool all_empty,
+    asio::error_code& ec);
+
+ASIO_DECL std::size_t sync_write1(int d, state_type state,
+    const void* data, std::size_t size, asio::error_code& ec);
+
+ASIO_DECL bool non_blocking_write(int d,
+    const buf* bufs, std::size_t count,
+    asio::error_code& ec, std::size_t& bytes_transferred);
+
+ASIO_DECL bool non_blocking_write1(int d,
+    const void* data, std::size_t size,
+    asio::error_code& ec, std::size_t& bytes_transferred);
+
+ASIO_DECL int ioctl(int d, state_type& state, long cmd,
+    ioctl_arg_type* arg, asio::error_code& ec);
+
+ASIO_DECL int fcntl(int d, int cmd, asio::error_code& ec);
+
+ASIO_DECL int fcntl(int d, int cmd,
+    long arg, asio::error_code& ec);
+
+ASIO_DECL int poll_read(int d,
+    state_type state, asio::error_code& ec);
+
+ASIO_DECL int poll_write(int d,
+    state_type state, asio::error_code& ec);
+
+ASIO_DECL int poll_error(int d,
+    state_type state, asio::error_code& ec);
+
+} // namespace descriptor_ops
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/descriptor_ops.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // !defined(ASIO_WINDOWS)
+       //   && !defined(ASIO_WINDOWS_RUNTIME)
+       //   && !defined(__CYGWIN__)
+
+#endif // ASIO_DETAIL_DESCRIPTOR_OPS_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/descriptor_read_op.hpp b/link/modules/asio-standalone/asio/include/asio/detail/descriptor_read_op.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/descriptor_read_op.hpp
@@ -0,0 +1,148 @@
+//
+// detail/descriptor_read_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_DESCRIPTOR_READ_OP_HPP
+#define ASIO_DETAIL_DESCRIPTOR_READ_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if !defined(ASIO_WINDOWS) && !defined(__CYGWIN__)
+
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/buffer_sequence_adapter.hpp"
+#include "asio/detail/descriptor_ops.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/handler_work.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/detail/reactor_op.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename MutableBufferSequence>
+class descriptor_read_op_base : public reactor_op
+{
+public:
+  descriptor_read_op_base(const asio::error_code& success_ec,
+      int descriptor, const MutableBufferSequence& buffers,
+      func_type complete_func)
+    : reactor_op(success_ec,
+        &descriptor_read_op_base::do_perform, complete_func),
+      descriptor_(descriptor),
+      buffers_(buffers)
+  {
+  }
+
+  static status do_perform(reactor_op* base)
+  {
+    descriptor_read_op_base* o(static_cast<descriptor_read_op_base*>(base));
+
+    typedef buffer_sequence_adapter<asio::mutable_buffer,
+        MutableBufferSequence> bufs_type;
+
+    status result;
+    if (bufs_type::is_single_buffer)
+    {
+      result = descriptor_ops::non_blocking_read1(o->descriptor_,
+          bufs_type::first(o->buffers_).data(),
+          bufs_type::first(o->buffers_).size(),
+          o->ec_, o->bytes_transferred_) ? done : not_done;
+    }
+    else
+    {
+      bufs_type bufs(o->buffers_);
+      result = descriptor_ops::non_blocking_read(o->descriptor_,
+          bufs.buffers(), bufs.count(), o->ec_, o->bytes_transferred_)
+        ? done : not_done;
+    }
+
+    ASIO_HANDLER_REACTOR_OPERATION((*o, "non_blocking_read",
+          o->ec_, o->bytes_transferred_));
+
+    return result;
+  }
+
+private:
+  int descriptor_;
+  MutableBufferSequence buffers_;
+};
+
+template <typename MutableBufferSequence, typename Handler, typename IoExecutor>
+class descriptor_read_op
+  : public descriptor_read_op_base<MutableBufferSequence>
+{
+public:
+  ASIO_DEFINE_HANDLER_PTR(descriptor_read_op);
+
+  descriptor_read_op(const asio::error_code& success_ec,
+      int descriptor, const MutableBufferSequence& buffers,
+      Handler& handler, const IoExecutor& io_ex)
+    : descriptor_read_op_base<MutableBufferSequence>(success_ec,
+        descriptor, buffers, &descriptor_read_op::do_complete),
+      handler_(ASIO_MOVE_CAST(Handler)(handler)),
+      work_(handler_, io_ex)
+  {
+  }
+
+  static void do_complete(void* owner, operation* base,
+      const asio::error_code& /*ec*/,
+      std::size_t /*bytes_transferred*/)
+  {
+    // Take ownership of the handler object.
+    descriptor_read_op* o(static_cast<descriptor_read_op*>(base));
+    ptr p = { asio::detail::addressof(o->handler_), o, o };
+
+    ASIO_HANDLER_COMPLETION((*o));
+
+    // Take ownership of the operation's outstanding work.
+    handler_work<Handler, IoExecutor> w(
+        ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)(
+          o->work_));
+
+    // Make a copy of the handler so that the memory can be deallocated before
+    // the upcall is made. Even if we're not about to make an upcall, a
+    // sub-object of the handler may be the true owner of the memory associated
+    // with the handler. Consequently, a local copy of the handler is required
+    // to ensure that any owning sub-object remains valid until after we have
+    // deallocated the memory here.
+    detail::binder2<Handler, asio::error_code, std::size_t>
+      handler(o->handler_, o->ec_, o->bytes_transferred_);
+    p.h = asio::detail::addressof(handler.handler_);
+    p.reset();
+
+    // Make the upcall if required.
+    if (owner)
+    {
+      fenced_block b(fenced_block::half);
+      ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_));
+      w.complete(handler, handler.handler_);
+      ASIO_HANDLER_INVOCATION_END;
+    }
+  }
+
+private:
+  Handler handler_;
+  handler_work<Handler, IoExecutor> work_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // !defined(ASIO_WINDOWS) && !defined(__CYGWIN__)
+
+#endif // ASIO_DETAIL_DESCRIPTOR_READ_OP_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/descriptor_write_op.hpp b/link/modules/asio-standalone/asio/include/asio/detail/descriptor_write_op.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/descriptor_write_op.hpp
@@ -0,0 +1,148 @@
+//
+// detail/descriptor_write_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_DESCRIPTOR_WRITE_OP_HPP
+#define ASIO_DETAIL_DESCRIPTOR_WRITE_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if !defined(ASIO_WINDOWS) && !defined(__CYGWIN__)
+
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/buffer_sequence_adapter.hpp"
+#include "asio/detail/descriptor_ops.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/handler_work.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/detail/reactor_op.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename ConstBufferSequence>
+class descriptor_write_op_base : public reactor_op
+{
+public:
+  descriptor_write_op_base(const asio::error_code& success_ec,
+      int descriptor, const ConstBufferSequence& buffers,
+      func_type complete_func)
+    : reactor_op(success_ec,
+        &descriptor_write_op_base::do_perform, complete_func),
+      descriptor_(descriptor),
+      buffers_(buffers)
+  {
+  }
+
+  static status do_perform(reactor_op* base)
+  {
+    descriptor_write_op_base* o(static_cast<descriptor_write_op_base*>(base));
+
+    typedef buffer_sequence_adapter<asio::const_buffer,
+        ConstBufferSequence> bufs_type;
+
+    status result;
+    if (bufs_type::is_single_buffer)
+    {
+      result = descriptor_ops::non_blocking_write1(o->descriptor_,
+          bufs_type::first(o->buffers_).data(),
+          bufs_type::first(o->buffers_).size(),
+          o->ec_, o->bytes_transferred_) ? done : not_done;
+    }
+    else
+    {
+      bufs_type bufs(o->buffers_);
+      result = descriptor_ops::non_blocking_write(o->descriptor_,
+          bufs.buffers(), bufs.count(), o->ec_, o->bytes_transferred_)
+        ? done : not_done;
+    }
+
+    ASIO_HANDLER_REACTOR_OPERATION((*o, "non_blocking_write",
+          o->ec_, o->bytes_transferred_));
+
+    return result;
+  }
+
+private:
+  int descriptor_;
+  ConstBufferSequence buffers_;
+};
+
+template <typename ConstBufferSequence, typename Handler, typename IoExecutor>
+class descriptor_write_op
+  : public descriptor_write_op_base<ConstBufferSequence>
+{
+public:
+  ASIO_DEFINE_HANDLER_PTR(descriptor_write_op);
+
+  descriptor_write_op(const asio::error_code& success_ec,
+      int descriptor, const ConstBufferSequence& buffers,
+      Handler& handler, const IoExecutor& io_ex)
+    : descriptor_write_op_base<ConstBufferSequence>(success_ec,
+        descriptor, buffers, &descriptor_write_op::do_complete),
+      handler_(ASIO_MOVE_CAST(Handler)(handler)),
+      work_(handler_, io_ex)
+  {
+  }
+
+  static void do_complete(void* owner, operation* base,
+      const asio::error_code& /*ec*/,
+      std::size_t /*bytes_transferred*/)
+  {
+    // Take ownership of the handler object.
+    descriptor_write_op* o(static_cast<descriptor_write_op*>(base));
+    ptr p = { asio::detail::addressof(o->handler_), o, o };
+
+    ASIO_HANDLER_COMPLETION((*o));
+
+    // Take ownership of the operation's outstanding work.
+    handler_work<Handler, IoExecutor> w(
+        ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)(
+          o->work_));
+
+    // Make a copy of the handler so that the memory can be deallocated before
+    // the upcall is made. Even if we're not about to make an upcall, a
+    // sub-object of the handler may be the true owner of the memory associated
+    // with the handler. Consequently, a local copy of the handler is required
+    // to ensure that any owning sub-object remains valid until after we have
+    // deallocated the memory here.
+    detail::binder2<Handler, asio::error_code, std::size_t>
+      handler(o->handler_, o->ec_, o->bytes_transferred_);
+    p.h = asio::detail::addressof(handler.handler_);
+    p.reset();
+
+    // Make the upcall if required.
+    if (owner)
+    {
+      fenced_block b(fenced_block::half);
+      ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_));
+      w.complete(handler, handler.handler_);
+      ASIO_HANDLER_INVOCATION_END;
+    }
+  }
+
+private:
+  Handler handler_;
+  handler_work<Handler, IoExecutor> work_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // !defined(ASIO_WINDOWS) && !defined(__CYGWIN__)
+
+#endif // ASIO_DETAIL_DESCRIPTOR_WRITE_OP_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/dev_poll_reactor.hpp b/link/modules/asio-standalone/asio/include/asio/detail/dev_poll_reactor.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/dev_poll_reactor.hpp
@@ -0,0 +1,218 @@
+//
+// detail/dev_poll_reactor.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_DEV_POLL_REACTOR_HPP
+#define ASIO_DETAIL_DEV_POLL_REACTOR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_DEV_POLL)
+
+#include <cstddef>
+#include <vector>
+#include <sys/devpoll.h>
+#include "asio/detail/hash_map.hpp"
+#include "asio/detail/limits.hpp"
+#include "asio/detail/mutex.hpp"
+#include "asio/detail/op_queue.hpp"
+#include "asio/detail/reactor_op.hpp"
+#include "asio/detail/reactor_op_queue.hpp"
+#include "asio/detail/select_interrupter.hpp"
+#include "asio/detail/socket_types.hpp"
+#include "asio/detail/timer_queue_base.hpp"
+#include "asio/detail/timer_queue_set.hpp"
+#include "asio/detail/wait_op.hpp"
+#include "asio/execution_context.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class dev_poll_reactor
+  : public execution_context_service_base<dev_poll_reactor>
+{
+public:
+  enum op_types { read_op = 0, write_op = 1,
+    connect_op = 1, except_op = 2, max_ops = 3 };
+
+  // Per-descriptor data.
+  struct per_descriptor_data
+  {
+  };
+
+  // Constructor.
+  ASIO_DECL dev_poll_reactor(asio::execution_context& ctx);
+
+  // Destructor.
+  ASIO_DECL ~dev_poll_reactor();
+
+  // Destroy all user-defined handler objects owned by the service.
+  ASIO_DECL void shutdown();
+
+  // Recreate internal descriptors following a fork.
+  ASIO_DECL void notify_fork(
+      asio::execution_context::fork_event fork_ev);
+
+  // Initialise the task.
+  ASIO_DECL void init_task();
+
+  // Register a socket with the reactor. Returns 0 on success, system error
+  // code on failure.
+  ASIO_DECL int register_descriptor(socket_type, per_descriptor_data&);
+
+  // Register a descriptor with an associated single operation. Returns 0 on
+  // success, system error code on failure.
+  ASIO_DECL int register_internal_descriptor(
+      int op_type, socket_type descriptor,
+      per_descriptor_data& descriptor_data, reactor_op* op);
+
+  // Move descriptor registration from one descriptor_data object to another.
+  ASIO_DECL void move_descriptor(socket_type descriptor,
+      per_descriptor_data& target_descriptor_data,
+      per_descriptor_data& source_descriptor_data);
+
+  // Post a reactor operation for immediate completion.
+  void post_immediate_completion(reactor_op* op, bool is_continuation)
+  {
+    scheduler_.post_immediate_completion(op, is_continuation);
+  }
+
+  // Start a new operation. The reactor operation will be performed when the
+  // given descriptor is flagged as ready, or an error has occurred.
+  ASIO_DECL void start_op(int op_type, socket_type descriptor,
+      per_descriptor_data&, reactor_op* op,
+      bool is_continuation, bool allow_speculative);
+
+  // Cancel all operations associated with the given descriptor. The
+  // handlers associated with the descriptor will be invoked with the
+  // operation_aborted error.
+  ASIO_DECL void cancel_ops(socket_type descriptor, per_descriptor_data&);
+
+  // Cancel any operations that are running against the descriptor and remove
+  // its registration from the reactor. The reactor resources associated with
+  // the descriptor must be released by calling cleanup_descriptor_data.
+  ASIO_DECL void deregister_descriptor(socket_type descriptor,
+      per_descriptor_data&, bool closing);
+
+  // Remove the descriptor's registration from the reactor. The reactor
+  // resources associated with the descriptor must be released by calling
+  // cleanup_descriptor_data.
+  ASIO_DECL void deregister_internal_descriptor(
+      socket_type descriptor, per_descriptor_data&);
+
+  // Perform any post-deregistration cleanup tasks associated with the
+  // descriptor data.
+  ASIO_DECL void cleanup_descriptor_data(per_descriptor_data&);
+
+  // Add a new timer queue to the reactor.
+  template <typename Time_Traits>
+  void add_timer_queue(timer_queue<Time_Traits>& queue);
+
+  // Remove a timer queue from the reactor.
+  template <typename Time_Traits>
+  void remove_timer_queue(timer_queue<Time_Traits>& queue);
+
+  // Schedule a new operation in the given timer queue to expire at the
+  // specified absolute time.
+  template <typename Time_Traits>
+  void schedule_timer(timer_queue<Time_Traits>& queue,
+      const typename Time_Traits::time_type& time,
+      typename timer_queue<Time_Traits>::per_timer_data& timer, wait_op* op);
+
+  // Cancel the timer operations associated with the given token. Returns the
+  // number of operations that have been posted or dispatched.
+  template <typename Time_Traits>
+  std::size_t cancel_timer(timer_queue<Time_Traits>& queue,
+      typename timer_queue<Time_Traits>::per_timer_data& timer,
+      std::size_t max_cancelled = (std::numeric_limits<std::size_t>::max)());
+
+  // Move the timer operations associated with the given timer.
+  template <typename Time_Traits>
+  void move_timer(timer_queue<Time_Traits>& queue,
+      typename timer_queue<Time_Traits>::per_timer_data& target,
+      typename timer_queue<Time_Traits>::per_timer_data& source);
+
+  // Run /dev/poll once until interrupted or events are ready to be dispatched.
+  ASIO_DECL void run(long usec, op_queue<operation>& ops);
+
+  // Interrupt the select loop.
+  ASIO_DECL void interrupt();
+
+private:
+  // Create the /dev/poll file descriptor. Throws an exception if the descriptor
+  // cannot be created.
+  ASIO_DECL static int do_dev_poll_create();
+
+  // Helper function to add a new timer queue.
+  ASIO_DECL void do_add_timer_queue(timer_queue_base& queue);
+
+  // Helper function to remove a timer queue.
+  ASIO_DECL void do_remove_timer_queue(timer_queue_base& queue);
+
+  // Get the timeout value for the /dev/poll DP_POLL operation. The timeout
+  // value is returned as a number of milliseconds. A return value of -1
+  // indicates that the poll should block indefinitely.
+  ASIO_DECL int get_timeout(int msec);
+
+  // Cancel all operations associated with the given descriptor. The do_cancel
+  // function of the handler objects will be invoked. This function does not
+  // acquire the dev_poll_reactor's mutex.
+  ASIO_DECL void cancel_ops_unlocked(socket_type descriptor,
+      const asio::error_code& ec);
+
+  // Add a pending event entry for the given descriptor.
+  ASIO_DECL ::pollfd& add_pending_event_change(int descriptor);
+
+  // The scheduler implementation used to post completions.
+  scheduler& scheduler_;
+
+  // Mutex to protect access to internal data.
+  asio::detail::mutex mutex_;
+
+  // The /dev/poll file descriptor.
+  int dev_poll_fd_;
+
+  // Vector of /dev/poll events waiting to be written to the descriptor.
+  std::vector< ::pollfd> pending_event_changes_;
+
+  // Hash map to associate a descriptor with a pending event change index.
+  hash_map<int, std::size_t> pending_event_change_index_;
+
+  // The interrupter is used to break a blocking DP_POLL operation.
+  select_interrupter interrupter_;
+
+  // The queues of read, write and except operations.
+  reactor_op_queue<socket_type> op_queue_[max_ops];
+
+  // The timer queues.
+  timer_queue_set timer_queues_;
+
+  // Whether the service has been shut down.
+  bool shutdown_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/detail/impl/dev_poll_reactor.hpp"
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/dev_poll_reactor.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // defined(ASIO_HAS_DEV_POLL)
+
+#endif // ASIO_DETAIL_DEV_POLL_REACTOR_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/epoll_reactor.hpp b/link/modules/asio-standalone/asio/include/asio/detail/epoll_reactor.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/epoll_reactor.hpp
@@ -0,0 +1,266 @@
+//
+// detail/epoll_reactor.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_EPOLL_REACTOR_HPP
+#define ASIO_DETAIL_EPOLL_REACTOR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_EPOLL)
+
+#include "asio/detail/atomic_count.hpp"
+#include "asio/detail/conditionally_enabled_mutex.hpp"
+#include "asio/detail/limits.hpp"
+#include "asio/detail/object_pool.hpp"
+#include "asio/detail/op_queue.hpp"
+#include "asio/detail/reactor_op.hpp"
+#include "asio/detail/select_interrupter.hpp"
+#include "asio/detail/socket_types.hpp"
+#include "asio/detail/timer_queue_base.hpp"
+#include "asio/detail/timer_queue_set.hpp"
+#include "asio/detail/wait_op.hpp"
+#include "asio/execution_context.hpp"
+
+#if defined(ASIO_HAS_TIMERFD)
+# include <sys/timerfd.h>
+#endif // defined(ASIO_HAS_TIMERFD)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class epoll_reactor
+  : public execution_context_service_base<epoll_reactor>
+{
+private:
+  // The mutex type used by this reactor.
+  typedef conditionally_enabled_mutex mutex;
+
+public:
+  enum op_types { read_op = 0, write_op = 1,
+    connect_op = 1, except_op = 2, max_ops = 3 };
+
+  // Per-descriptor queues.
+  class descriptor_state : operation
+  {
+    friend class epoll_reactor;
+    friend class object_pool_access;
+
+    descriptor_state* next_;
+    descriptor_state* prev_;
+
+    mutex mutex_;
+    epoll_reactor* reactor_;
+    int descriptor_;
+    uint32_t registered_events_;
+    op_queue<reactor_op> op_queue_[max_ops];
+    bool try_speculative_[max_ops];
+    bool shutdown_;
+
+    ASIO_DECL descriptor_state(bool locking);
+    void set_ready_events(uint32_t events) { task_result_ = events; }
+    void add_ready_events(uint32_t events) { task_result_ |= events; }
+    ASIO_DECL operation* perform_io(uint32_t events);
+    ASIO_DECL static void do_complete(
+        void* owner, operation* base,
+        const asio::error_code& ec, std::size_t bytes_transferred);
+  };
+
+  // Per-descriptor data.
+  typedef descriptor_state* per_descriptor_data;
+
+  // Constructor.
+  ASIO_DECL epoll_reactor(asio::execution_context& ctx);
+
+  // Destructor.
+  ASIO_DECL ~epoll_reactor();
+
+  // Destroy all user-defined handler objects owned by the service.
+  ASIO_DECL void shutdown();
+
+  // Recreate internal descriptors following a fork.
+  ASIO_DECL void notify_fork(
+      asio::execution_context::fork_event fork_ev);
+
+  // Initialise the task.
+  ASIO_DECL void init_task();
+
+  // Register a socket with the reactor. Returns 0 on success, system error
+  // code on failure.
+  ASIO_DECL int register_descriptor(socket_type descriptor,
+      per_descriptor_data& descriptor_data);
+
+  // Register a descriptor with an associated single operation. Returns 0 on
+  // success, system error code on failure.
+  ASIO_DECL int register_internal_descriptor(
+      int op_type, socket_type descriptor,
+      per_descriptor_data& descriptor_data, reactor_op* op);
+
+  // Move descriptor registration from one descriptor_data object to another.
+  ASIO_DECL void move_descriptor(socket_type descriptor,
+      per_descriptor_data& target_descriptor_data,
+      per_descriptor_data& source_descriptor_data);
+
+  // Post a reactor operation for immediate completion.
+  void post_immediate_completion(reactor_op* op, bool is_continuation)
+  {
+    scheduler_.post_immediate_completion(op, is_continuation);
+  }
+
+  // Start a new operation. The reactor operation will be performed when the
+  // given descriptor is flagged as ready, or an error has occurred.
+  ASIO_DECL void start_op(int op_type, socket_type descriptor,
+      per_descriptor_data& descriptor_data, reactor_op* op,
+      bool is_continuation, bool allow_speculative);
+
+  // Cancel all operations associated with the given descriptor. The
+  // handlers associated with the descriptor will be invoked with the
+  // operation_aborted error.
+  ASIO_DECL void cancel_ops(socket_type descriptor,
+      per_descriptor_data& descriptor_data);
+
+  // Cancel any operations that are running against the descriptor and remove
+  // its registration from the reactor. The reactor resources associated with
+  // the descriptor must be released by calling cleanup_descriptor_data.
+  ASIO_DECL void deregister_descriptor(socket_type descriptor,
+      per_descriptor_data& descriptor_data, bool closing);
+
+  // Remove the descriptor's registration from the reactor. The reactor
+  // resources associated with the descriptor must be released by calling
+  // cleanup_descriptor_data.
+  ASIO_DECL void deregister_internal_descriptor(
+      socket_type descriptor, per_descriptor_data& descriptor_data);
+
+  // Perform any post-deregistration cleanup tasks associated with the
+  // descriptor data.
+  ASIO_DECL void cleanup_descriptor_data(
+      per_descriptor_data& descriptor_data);
+
+  // Add a new timer queue to the reactor.
+  template <typename Time_Traits>
+  void add_timer_queue(timer_queue<Time_Traits>& timer_queue);
+
+  // Remove a timer queue from the reactor.
+  template <typename Time_Traits>
+  void remove_timer_queue(timer_queue<Time_Traits>& timer_queue);
+
+  // Schedule a new operation in the given timer queue to expire at the
+  // specified absolute time.
+  template <typename Time_Traits>
+  void schedule_timer(timer_queue<Time_Traits>& queue,
+      const typename Time_Traits::time_type& time,
+      typename timer_queue<Time_Traits>::per_timer_data& timer, wait_op* op);
+
+  // Cancel the timer operations associated with the given token. Returns the
+  // number of operations that have been posted or dispatched.
+  template <typename Time_Traits>
+  std::size_t cancel_timer(timer_queue<Time_Traits>& queue,
+      typename timer_queue<Time_Traits>::per_timer_data& timer,
+      std::size_t max_cancelled = (std::numeric_limits<std::size_t>::max)());
+
+  // Move the timer operations associated with the given timer.
+  template <typename Time_Traits>
+  void move_timer(timer_queue<Time_Traits>& queue,
+      typename timer_queue<Time_Traits>::per_timer_data& target,
+      typename timer_queue<Time_Traits>::per_timer_data& source);
+
+  // Run epoll once until interrupted or events are ready to be dispatched.
+  ASIO_DECL void run(long usec, op_queue<operation>& ops);
+
+  // Interrupt the select loop.
+  ASIO_DECL void interrupt();
+
+private:
+  // The hint to pass to epoll_create to size its data structures.
+  enum { epoll_size = 20000 };
+
+  // Create the epoll file descriptor. Throws an exception if the descriptor
+  // cannot be created.
+  ASIO_DECL static int do_epoll_create();
+
+  // Create the timerfd file descriptor. Does not throw.
+  ASIO_DECL static int do_timerfd_create();
+
+  // Allocate a new descriptor state object.
+  ASIO_DECL descriptor_state* allocate_descriptor_state();
+
+  // Free an existing descriptor state object.
+  ASIO_DECL void free_descriptor_state(descriptor_state* s);
+
+  // Helper function to add a new timer queue.
+  ASIO_DECL void do_add_timer_queue(timer_queue_base& queue);
+
+  // Helper function to remove a timer queue.
+  ASIO_DECL void do_remove_timer_queue(timer_queue_base& queue);
+
+  // Called to recalculate and update the timeout.
+  ASIO_DECL void update_timeout();
+
+  // Get the timeout value for the epoll_wait call. The timeout value is
+  // returned as a number of milliseconds. A return value of -1 indicates
+  // that epoll_wait should block indefinitely.
+  ASIO_DECL int get_timeout(int msec);
+
+#if defined(ASIO_HAS_TIMERFD)
+  // Get the timeout value for the timer descriptor. The return value is the
+  // flag argument to be used when calling timerfd_settime.
+  ASIO_DECL int get_timeout(itimerspec& ts);
+#endif // defined(ASIO_HAS_TIMERFD)
+
+  // The scheduler implementation used to post completions.
+  scheduler& scheduler_;
+
+  // Mutex to protect access to internal data.
+  mutex mutex_;
+
+  // The interrupter is used to break a blocking epoll_wait call.
+  select_interrupter interrupter_;
+
+  // The epoll file descriptor.
+  int epoll_fd_;
+
+  // The timer file descriptor.
+  int timer_fd_;
+
+  // The timer queues.
+  timer_queue_set timer_queues_;
+
+  // Whether the service has been shut down.
+  bool shutdown_;
+
+  // Mutex to protect access to the registered descriptors.
+  mutex registered_descriptors_mutex_;
+
+  // Keep track of all registered descriptors.
+  object_pool<descriptor_state> registered_descriptors_;
+
+  // Helper class to do post-perform_io cleanup.
+  struct perform_io_cleanup_on_block_exit;
+  friend struct perform_io_cleanup_on_block_exit;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/detail/impl/epoll_reactor.hpp"
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/epoll_reactor.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // defined(ASIO_HAS_EPOLL)
+
+#endif // ASIO_DETAIL_EPOLL_REACTOR_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/event.hpp b/link/modules/asio-standalone/asio/include/asio/detail/event.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/event.hpp
@@ -0,0 +1,48 @@
+//
+// detail/event.hpp
+// ~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_EVENT_HPP
+#define ASIO_DETAIL_EVENT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if !defined(ASIO_HAS_THREADS)
+# include "asio/detail/null_event.hpp"
+#elif defined(ASIO_WINDOWS)
+# include "asio/detail/win_event.hpp"
+#elif defined(ASIO_HAS_PTHREADS)
+# include "asio/detail/posix_event.hpp"
+#elif defined(ASIO_HAS_STD_MUTEX_AND_CONDVAR)
+# include "asio/detail/std_event.hpp"
+#else
+# error Only Windows, POSIX and std::condition_variable are supported!
+#endif
+
+namespace asio {
+namespace detail {
+
+#if !defined(ASIO_HAS_THREADS)
+typedef null_event event;
+#elif defined(ASIO_WINDOWS)
+typedef win_event event;
+#elif defined(ASIO_HAS_PTHREADS)
+typedef posix_event event;
+#elif defined(ASIO_HAS_STD_MUTEX_AND_CONDVAR)
+typedef std_event event;
+#endif
+
+} // namespace detail
+} // namespace asio
+
+#endif // ASIO_DETAIL_EVENT_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/eventfd_select_interrupter.hpp b/link/modules/asio-standalone/asio/include/asio/detail/eventfd_select_interrupter.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/eventfd_select_interrupter.hpp
@@ -0,0 +1,83 @@
+//
+// detail/eventfd_select_interrupter.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2008 Roelof Naude (roelof.naude at gmail 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 ASIO_DETAIL_EVENTFD_SELECT_INTERRUPTER_HPP
+#define ASIO_DETAIL_EVENTFD_SELECT_INTERRUPTER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_EVENTFD)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class eventfd_select_interrupter
+{
+public:
+  // Constructor.
+  ASIO_DECL eventfd_select_interrupter();
+
+  // Destructor.
+  ASIO_DECL ~eventfd_select_interrupter();
+
+  // Recreate the interrupter's descriptors. Used after a fork.
+  ASIO_DECL void recreate();
+
+  // Interrupt the select call.
+  ASIO_DECL void interrupt();
+
+  // Reset the select interrupter. Returns true if the reset was successful.
+  ASIO_DECL bool reset();
+
+  // Get the read descriptor to be passed to select.
+  int read_descriptor() const
+  {
+    return read_descriptor_;
+  }
+
+private:
+  // Open the descriptors. Throws on error.
+  ASIO_DECL void open_descriptors();
+
+  // Close the descriptors.
+  ASIO_DECL void close_descriptors();
+
+  // The read end of a connection used to interrupt the select call. This file
+  // descriptor is passed to select such that when it is time to stop, a single
+  // 64bit value will be written on the other end of the connection and this
+  // descriptor will become readable.
+  int read_descriptor_;
+
+  // The write end of a connection used to interrupt the select call. A single
+  // 64bit non-zero value may be written to this to wake up the select which is
+  // waiting for the other end to become readable. This descriptor will only
+  // differ from the read descriptor when a pipe is used.
+  int write_descriptor_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/eventfd_select_interrupter.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // defined(ASIO_HAS_EVENTFD)
+
+#endif // ASIO_DETAIL_EVENTFD_SELECT_INTERRUPTER_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/executor_function.hpp b/link/modules/asio-standalone/asio/include/asio/detail/executor_function.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/executor_function.hpp
@@ -0,0 +1,203 @@
+//
+// detail/executor_function.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_EXECUTOR_FUNCTION_HPP
+#define ASIO_DETAIL_EXECUTOR_FUNCTION_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/memory.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+#if defined(ASIO_HAS_MOVE)
+
+// Lightweight, move-only function object wrapper.
+class executor_function
+{
+public:
+  template <typename F, typename Alloc>
+  explicit executor_function(F f, const Alloc& a)
+  {
+    // Allocate and construct an object to wrap the function.
+    typedef impl<F, Alloc> impl_type;
+    typename impl_type::ptr p = {
+      detail::addressof(a), impl_type::ptr::allocate(a), 0 };
+    impl_ = new (p.v) impl_type(ASIO_MOVE_CAST(F)(f), a);
+    p.v = 0;
+  }
+
+  executor_function(executor_function&& other) ASIO_NOEXCEPT
+    : impl_(other.impl_)
+  {
+    other.impl_ = 0;
+  }
+
+  ~executor_function()
+  {
+    if (impl_)
+      impl_->complete_(impl_, false);
+  }
+
+  void operator()()
+  {
+    if (impl_)
+    {
+      impl_base* i = impl_;
+      impl_ = 0;
+      i->complete_(i, true);
+    }
+  }
+
+private:
+  // Base class for polymorphic function implementations.
+  struct impl_base
+  {
+    void (*complete_)(impl_base*, bool);
+  };
+
+  // Polymorphic function implementation.
+  template <typename Function, typename Alloc>
+  struct impl : impl_base
+  {
+    ASIO_DEFINE_TAGGED_HANDLER_ALLOCATOR_PTR(
+        thread_info_base::executor_function_tag, impl);
+
+    template <typename F>
+    impl(ASIO_MOVE_ARG(F) f, const Alloc& a)
+      : function_(ASIO_MOVE_CAST(F)(f)),
+        allocator_(a)
+    {
+      complete_ = &executor_function::complete<Function, Alloc>;
+    }
+
+    Function function_;
+    Alloc allocator_;
+  };
+
+  // Helper to complete function invocation.
+  template <typename Function, typename Alloc>
+  static void complete(impl_base* base, bool call)
+  {
+    // Take ownership of the function object.
+    impl<Function, Alloc>* i(static_cast<impl<Function, Alloc>*>(base));
+    Alloc allocator(i->allocator_);
+    typename impl<Function, Alloc>::ptr p = {
+      detail::addressof(allocator), i, i };
+
+    // Make a copy of the function so that the memory can be deallocated before
+    // the upcall is made. Even if we're not about to make an upcall, a
+    // sub-object of the function may be the true owner of the memory
+    // associated with the function. Consequently, a local copy of the function
+    // is required to ensure that any owning sub-object remains valid until
+    // after we have deallocated the memory here.
+    Function function(ASIO_MOVE_CAST(Function)(i->function_));
+    p.reset();
+
+    // Make the upcall if required.
+    if (call)
+    {
+      function();
+    }
+  }
+
+  impl_base* impl_;
+};
+
+#else // defined(ASIO_HAS_MOVE)
+
+// Not so lightweight, copyable function object wrapper.
+class executor_function
+{
+public:
+  template <typename F, typename Alloc>
+  explicit executor_function(const F& f, const Alloc&)
+    : impl_(new impl<typename decay<F>::type>(f))
+  {
+  }
+
+  void operator()()
+  {
+    impl_->complete_(impl_.get());
+  }
+
+private:
+  // Base class for polymorphic function implementations.
+  struct impl_base
+  {
+    void (*complete_)(impl_base*);
+  };
+
+  // Polymorphic function implementation.
+  template <typename F>
+  struct impl : impl_base
+  {
+    impl(const F& f)
+      : function_(f)
+    {
+      complete_ = &executor_function::complete<F>;
+    }
+
+    F function_;
+  };
+
+  // Helper to complete function invocation.
+  template <typename F>
+  static void complete(impl_base* i)
+  {
+    static_cast<impl<F>*>(i)->function_();
+  }
+
+  shared_ptr<impl_base> impl_;
+};
+
+#endif // defined(ASIO_HAS_MOVE)
+
+// Lightweight, non-owning, copyable function object wrapper.
+class executor_function_view
+{
+public:
+  template <typename F>
+  explicit executor_function_view(F& f) ASIO_NOEXCEPT
+    : complete_(&executor_function_view::complete<F>),
+      function_(&f)
+  {
+  }
+
+  void operator()()
+  {
+    complete_(function_);
+  }
+
+private:
+  // Helper to complete function invocation.
+  template <typename F>
+  static void complete(void* f)
+  {
+    (*static_cast<F*>(f))();
+  }
+
+  void (*complete_)(void*);
+  void* function_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_EXECUTOR_FUNCTION_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/executor_op.hpp b/link/modules/asio-standalone/asio/include/asio/detail/executor_op.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/executor_op.hpp
@@ -0,0 +1,84 @@
+//
+// detail/executor_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_EXECUTOR_OP_HPP
+#define ASIO_DETAIL_EXECUTOR_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/scheduler_operation.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Handler, typename Alloc,
+    typename Operation = scheduler_operation>
+class executor_op : public Operation
+{
+public:
+  ASIO_DEFINE_HANDLER_ALLOCATOR_PTR(executor_op);
+
+  template <typename H>
+  executor_op(ASIO_MOVE_ARG(H) h, const Alloc& allocator)
+    : Operation(&executor_op::do_complete),
+      handler_(ASIO_MOVE_CAST(H)(h)),
+      allocator_(allocator)
+  {
+  }
+
+  static void do_complete(void* owner, Operation* base,
+      const asio::error_code& /*ec*/,
+      std::size_t /*bytes_transferred*/)
+  {
+    // Take ownership of the handler object.
+    executor_op* o(static_cast<executor_op*>(base));
+    Alloc allocator(o->allocator_);
+    ptr p = { detail::addressof(allocator), o, o };
+
+    ASIO_HANDLER_COMPLETION((*o));
+
+    // Make a copy of the handler so that the memory can be deallocated before
+    // the upcall is made. Even if we're not about to make an upcall, a
+    // sub-object of the handler may be the true owner of the memory associated
+    // with the handler. Consequently, a local copy of the handler is required
+    // to ensure that any owning sub-object remains valid until after we have
+    // deallocated the memory here.
+    Handler handler(ASIO_MOVE_CAST(Handler)(o->handler_));
+    p.reset();
+
+    // Make the upcall if required.
+    if (owner)
+    {
+      fenced_block b(fenced_block::half);
+      ASIO_HANDLER_INVOCATION_BEGIN(());
+      asio_handler_invoke_helpers::invoke(handler, handler);
+      ASIO_HANDLER_INVOCATION_END;
+    }
+  }
+
+private:
+  Handler handler_;
+  Alloc allocator_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_EXECUTOR_OP_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/fd_set_adapter.hpp b/link/modules/asio-standalone/asio/include/asio/detail/fd_set_adapter.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/fd_set_adapter.hpp
@@ -0,0 +1,39 @@
+//
+// detail/fd_set_adapter.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_FD_SET_ADAPTER_HPP
+#define ASIO_DETAIL_FD_SET_ADAPTER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if !defined(ASIO_WINDOWS_RUNTIME)
+
+#include "asio/detail/posix_fd_set_adapter.hpp"
+#include "asio/detail/win_fd_set_adapter.hpp"
+
+namespace asio {
+namespace detail {
+
+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+typedef win_fd_set_adapter fd_set_adapter;
+#else
+typedef posix_fd_set_adapter fd_set_adapter;
+#endif
+
+} // namespace detail
+} // namespace asio
+
+#endif // !defined(ASIO_WINDOWS_RUNTIME)
+
+#endif // ASIO_DETAIL_FD_SET_ADAPTER_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/fenced_block.hpp b/link/modules/asio-standalone/asio/include/asio/detail/fenced_block.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/fenced_block.hpp
@@ -0,0 +1,80 @@
+//
+// detail/fenced_block.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_FENCED_BLOCK_HPP
+#define ASIO_DETAIL_FENCED_BLOCK_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if !defined(ASIO_HAS_THREADS) \
+  || defined(ASIO_DISABLE_FENCED_BLOCK)
+# include "asio/detail/null_fenced_block.hpp"
+#elif defined(ASIO_HAS_STD_ATOMIC)
+# include "asio/detail/std_fenced_block.hpp"
+#elif defined(__MACH__) && defined(__APPLE__)
+# include "asio/detail/macos_fenced_block.hpp"
+#elif defined(__sun)
+# include "asio/detail/solaris_fenced_block.hpp"
+#elif defined(__GNUC__) && defined(__arm__) \
+  && !defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4)
+# include "asio/detail/gcc_arm_fenced_block.hpp"
+#elif defined(__GNUC__) && (defined(__hppa) || defined(__hppa__))
+# include "asio/detail/gcc_hppa_fenced_block.hpp"
+#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
+# include "asio/detail/gcc_x86_fenced_block.hpp"
+#elif defined(__GNUC__) \
+  && ((__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)) \
+  && !defined(__INTEL_COMPILER) && !defined(__ICL) \
+  && !defined(__ICC) && !defined(__ECC) && !defined(__PATHSCALE__)
+# include "asio/detail/gcc_sync_fenced_block.hpp"
+#elif defined(ASIO_WINDOWS) && !defined(UNDER_CE)
+# include "asio/detail/win_fenced_block.hpp"
+#else
+# include "asio/detail/null_fenced_block.hpp"
+#endif
+
+namespace asio {
+namespace detail {
+
+#if !defined(ASIO_HAS_THREADS) \
+  || defined(ASIO_DISABLE_FENCED_BLOCK)
+typedef null_fenced_block fenced_block;
+#elif defined(ASIO_HAS_STD_ATOMIC)
+typedef std_fenced_block fenced_block;
+#elif defined(__MACH__) && defined(__APPLE__)
+typedef macos_fenced_block fenced_block;
+#elif defined(__sun)
+typedef solaris_fenced_block fenced_block;
+#elif defined(__GNUC__) && defined(__arm__) \
+  && !defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4)
+typedef gcc_arm_fenced_block fenced_block;
+#elif defined(__GNUC__) && (defined(__hppa) || defined(__hppa__))
+typedef gcc_hppa_fenced_block fenced_block;
+#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
+typedef gcc_x86_fenced_block fenced_block;
+#elif defined(__GNUC__) \
+  && ((__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)) \
+  && !defined(__INTEL_COMPILER) && !defined(__ICL) \
+  && !defined(__ICC) && !defined(__ECC) && !defined(__PATHSCALE__)
+typedef gcc_sync_fenced_block fenced_block;
+#elif defined(ASIO_WINDOWS) && !defined(UNDER_CE)
+typedef win_fenced_block fenced_block;
+#else
+typedef null_fenced_block fenced_block;
+#endif
+
+} // namespace detail
+} // namespace asio
+
+#endif // ASIO_DETAIL_FENCED_BLOCK_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/functional.hpp b/link/modules/asio-standalone/asio/include/asio/detail/functional.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/functional.hpp
@@ -0,0 +1,38 @@
+//
+// detail/functional.hpp
+// ~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_FUNCTIONAL_HPP
+#define ASIO_DETAIL_FUNCTIONAL_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#include <functional>
+
+#if !defined(ASIO_HAS_STD_FUNCTION)
+# include <boost/function.hpp>
+#endif // !defined(ASIO_HAS_STD_FUNCTION)
+
+namespace asio {
+namespace detail {
+
+#if defined(ASIO_HAS_STD_FUNCTION)
+using std::function;
+#else // defined(ASIO_HAS_STD_FUNCTION)
+using boost::function;
+#endif // defined(ASIO_HAS_STD_FUNCTION)
+
+} // namespace detail
+} // namespace asio
+
+#endif // ASIO_DETAIL_FUNCTIONAL_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/future.hpp b/link/modules/asio-standalone/asio/include/asio/detail/future.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/future.hpp
@@ -0,0 +1,33 @@
+//
+// detail/future.hpp
+// ~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_FUTURE_HPP
+#define ASIO_DETAIL_FUTURE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#if defined(ASIO_HAS_STD_FUTURE)
+# include <future>
+// Even though the future header is available, libstdc++ may not implement the
+// std::future class itself. However, we need to have already included the
+// future header to reliably test for _GLIBCXX_HAS_GTHREADS.
+# if defined(__GNUC__) && !defined(ASIO_HAS_CLANG_LIBCXX)
+#  if defined(_GLIBCXX_HAS_GTHREADS)
+#   define ASIO_HAS_STD_FUTURE_CLASS 1
+#  endif // defined(_GLIBCXX_HAS_GTHREADS)
+# else // defined(__GNUC__) && !defined(ASIO_HAS_CLANG_LIBCXX)
+#  define ASIO_HAS_STD_FUTURE_CLASS 1
+# endif // defined(__GNUC__) && !defined(ASIO_HAS_CLANG_LIBCXX)
+#endif // defined(ASIO_HAS_STD_FUTURE)
+
+#endif // ASIO_DETAIL_FUTURE_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/gcc_arm_fenced_block.hpp b/link/modules/asio-standalone/asio/include/asio/detail/gcc_arm_fenced_block.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/gcc_arm_fenced_block.hpp
@@ -0,0 +1,91 @@
+//
+// detail/gcc_arm_fenced_block.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_GCC_ARM_FENCED_BLOCK_HPP
+#define ASIO_DETAIL_GCC_ARM_FENCED_BLOCK_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(__GNUC__) && defined(__arm__)
+
+#include "asio/detail/noncopyable.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class gcc_arm_fenced_block
+  : private noncopyable
+{
+public:
+  enum half_t { half };
+  enum full_t { full };
+
+  // Constructor for a half fenced block.
+  explicit gcc_arm_fenced_block(half_t)
+  {
+  }
+
+  // Constructor for a full fenced block.
+  explicit gcc_arm_fenced_block(full_t)
+  {
+    barrier();
+  }
+
+  // Destructor.
+  ~gcc_arm_fenced_block()
+  {
+    barrier();
+  }
+
+private:
+  static void barrier()
+  {
+#if defined(__ARM_ARCH_4__) \
+    || defined(__ARM_ARCH_4T__) \
+    || defined(__ARM_ARCH_5__) \
+    || defined(__ARM_ARCH_5E__) \
+    || defined(__ARM_ARCH_5T__) \
+    || defined(__ARM_ARCH_5TE__) \
+    || defined(__ARM_ARCH_5TEJ__) \
+    || defined(__ARM_ARCH_6__) \
+    || defined(__ARM_ARCH_6J__) \
+    || defined(__ARM_ARCH_6K__) \
+    || defined(__ARM_ARCH_6Z__) \
+    || defined(__ARM_ARCH_6ZK__) \
+    || defined(__ARM_ARCH_6T2__)
+# if defined(__thumb__)
+    // This is just a placeholder and almost certainly not sufficient.
+    __asm__ __volatile__ ("" : : : "memory");
+# else // defined(__thumb__)
+    int a = 0, b = 0;
+    __asm__ __volatile__ ("swp %0, %1, [%2]"
+        : "=&r"(a) : "r"(1), "r"(&b) : "memory", "cc");
+# endif // defined(__thumb__)
+#else
+    // ARMv7 and later.
+    __asm__ __volatile__ ("dmb" : : : "memory");
+#endif
+  }
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(__GNUC__) && defined(__arm__)
+
+#endif // ASIO_DETAIL_GCC_ARM_FENCED_BLOCK_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/gcc_hppa_fenced_block.hpp b/link/modules/asio-standalone/asio/include/asio/detail/gcc_hppa_fenced_block.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/gcc_hppa_fenced_block.hpp
@@ -0,0 +1,68 @@
+//
+// detail/gcc_hppa_fenced_block.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_GCC_HPPA_FENCED_BLOCK_HPP
+#define ASIO_DETAIL_GCC_HPPA_FENCED_BLOCK_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(__GNUC__) && (defined(__hppa) || defined(__hppa__))
+
+#include "asio/detail/noncopyable.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class gcc_hppa_fenced_block
+  : private noncopyable
+{
+public:
+  enum half_t { half };
+  enum full_t { full };
+
+  // Constructor for a half fenced block.
+  explicit gcc_hppa_fenced_block(half_t)
+  {
+  }
+
+  // Constructor for a full fenced block.
+  explicit gcc_hppa_fenced_block(full_t)
+  {
+    barrier();
+  }
+
+  // Destructor.
+  ~gcc_hppa_fenced_block()
+  {
+    barrier();
+  }
+
+private:
+  static void barrier()
+  {
+    // This is just a placeholder and almost certainly not sufficient.
+    __asm__ __volatile__ ("" : : : "memory");
+  }
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(__GNUC__) && (defined(__hppa) || defined(__hppa__))
+
+#endif // ASIO_DETAIL_GCC_HPPA_FENCED_BLOCK_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/gcc_sync_fenced_block.hpp b/link/modules/asio-standalone/asio/include/asio/detail/gcc_sync_fenced_block.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/gcc_sync_fenced_block.hpp
@@ -0,0 +1,65 @@
+//
+// detail/gcc_sync_fenced_block.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_GCC_SYNC_FENCED_BLOCK_HPP
+#define ASIO_DETAIL_GCC_SYNC_FENCED_BLOCK_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(__GNUC__) \
+  && ((__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)) \
+  && !defined(__INTEL_COMPILER) && !defined(__ICL) \
+  && !defined(__ICC) && !defined(__ECC) && !defined(__PATHSCALE__)
+
+#include "asio/detail/noncopyable.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class gcc_sync_fenced_block
+  : private noncopyable
+{
+public:
+  enum half_or_full_t { half, full };
+
+  // Constructor.
+  explicit gcc_sync_fenced_block(half_or_full_t)
+    : value_(0)
+  {
+    __sync_lock_test_and_set(&value_, 1);
+  }
+
+  // Destructor.
+  ~gcc_sync_fenced_block()
+  {
+    __sync_lock_release(&value_);
+  }
+
+private:
+  int value_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(__GNUC__)
+       // && ((__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4))
+       // && !defined(__INTEL_COMPILER) && !defined(__ICL)
+       // && !defined(__ICC) && !defined(__ECC) && !defined(__PATHSCALE__)
+
+#endif // ASIO_DETAIL_GCC_SYNC_FENCED_BLOCK_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/gcc_x86_fenced_block.hpp b/link/modules/asio-standalone/asio/include/asio/detail/gcc_x86_fenced_block.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/gcc_x86_fenced_block.hpp
@@ -0,0 +1,99 @@
+//
+// detail/gcc_x86_fenced_block.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_GCC_X86_FENCED_BLOCK_HPP
+#define ASIO_DETAIL_GCC_X86_FENCED_BLOCK_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
+
+#include "asio/detail/noncopyable.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class gcc_x86_fenced_block
+  : private noncopyable
+{
+public:
+  enum half_t { half };
+  enum full_t { full };
+
+  // Constructor for a half fenced block.
+  explicit gcc_x86_fenced_block(half_t)
+  {
+  }
+
+  // Constructor for a full fenced block.
+  explicit gcc_x86_fenced_block(full_t)
+  {
+    lbarrier();
+  }
+
+  // Destructor.
+  ~gcc_x86_fenced_block()
+  {
+    sbarrier();
+  }
+
+private:
+  static int barrier()
+  {
+    int r = 0, m = 1;
+    __asm__ __volatile__ (
+        "xchgl %0, %1" :
+        "=r"(r), "=m"(m) :
+        "0"(1), "m"(m) :
+        "memory", "cc");
+    return r;
+  }
+
+  static void lbarrier()
+  {
+#if defined(__SSE2__)
+# if (__GNUC__ >= 4) && !defined(__INTEL_COMPILER) && !defined(__ICL)
+    __builtin_ia32_lfence();
+# else // (__GNUC__ >= 4) && !defined(__INTEL_COMPILER) && !defined(__ICL)
+    __asm__ __volatile__ ("lfence" ::: "memory");
+# endif // (__GNUC__ >= 4) && !defined(__INTEL_COMPILER) && !defined(__ICL)
+#else // defined(__SSE2__)
+    barrier();
+#endif // defined(__SSE2__)
+  }
+
+  static void sbarrier()
+  {
+#if defined(__SSE2__)
+# if (__GNUC__ >= 4) && !defined(__INTEL_COMPILER) && !defined(__ICL)
+    __builtin_ia32_sfence();
+# else // (__GNUC__ >= 4) && !defined(__INTEL_COMPILER) && !defined(__ICL)
+    __asm__ __volatile__ ("sfence" ::: "memory");
+# endif // (__GNUC__ >= 4) && !defined(__INTEL_COMPILER) && !defined(__ICL)
+#else // defined(__SSE2__)
+    barrier();
+#endif // defined(__SSE2__)
+  }
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
+
+#endif // ASIO_DETAIL_GCC_X86_FENCED_BLOCK_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/global.hpp b/link/modules/asio-standalone/asio/include/asio/detail/global.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/global.hpp
@@ -0,0 +1,52 @@
+//
+// detail/global.hpp
+// ~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_GLOBAL_HPP
+#define ASIO_DETAIL_GLOBAL_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if !defined(ASIO_HAS_THREADS)
+# include "asio/detail/null_global.hpp"
+#elif defined(ASIO_WINDOWS)
+# include "asio/detail/win_global.hpp"
+#elif defined(ASIO_HAS_PTHREADS)
+# include "asio/detail/posix_global.hpp"
+#elif defined(ASIO_HAS_STD_CALL_ONCE)
+# include "asio/detail/std_global.hpp"
+#else
+# error Only Windows, POSIX and std::call_once are supported!
+#endif
+
+namespace asio {
+namespace detail {
+
+template <typename T>
+inline T& global()
+{
+#if !defined(ASIO_HAS_THREADS)
+  return null_global<T>();
+#elif defined(ASIO_WINDOWS)
+  return win_global<T>();
+#elif defined(ASIO_HAS_PTHREADS)
+  return posix_global<T>();
+#elif defined(ASIO_HAS_STD_CALL_ONCE)
+  return std_global<T>();
+#endif
+}
+
+} // namespace detail
+} // namespace asio
+
+#endif // ASIO_DETAIL_GLOBAL_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/handler_alloc_helpers.hpp b/link/modules/asio-standalone/asio/include/asio/detail/handler_alloc_helpers.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/handler_alloc_helpers.hpp
@@ -0,0 +1,284 @@
+//
+// detail/handler_alloc_helpers.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_HANDLER_ALLOC_HELPERS_HPP
+#define ASIO_DETAIL_HANDLER_ALLOC_HELPERS_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/detail/noncopyable.hpp"
+#include "asio/detail/recycling_allocator.hpp"
+#include "asio/detail/thread_info_base.hpp"
+#include "asio/associated_allocator.hpp"
+#include "asio/handler_alloc_hook.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+// Calls to asio_handler_allocate and asio_handler_deallocate must be made from
+// a namespace that does not contain any overloads of these functions. The
+// asio_handler_alloc_helpers namespace is defined here for that purpose.
+namespace asio_handler_alloc_helpers {
+
+#if defined(ASIO_NO_DEPRECATED)
+template <typename Handler>
+inline void error_if_hooks_are_defined(Handler& h)
+{
+  using asio::asio_handler_allocate;
+  // If you get an error here it is because some of your handlers still
+  // overload asio_handler_allocate, but this hook is no longer used.
+  (void)static_cast<asio::asio_handler_allocate_is_no_longer_used>(
+    asio_handler_allocate(static_cast<std::size_t>(0),
+      asio::detail::addressof(h)));
+
+  using asio::asio_handler_deallocate;
+  // If you get an error here it is because some of your handlers still
+  // overload asio_handler_deallocate, but this hook is no longer used.
+  (void)static_cast<asio::asio_handler_deallocate_is_no_longer_used>(
+    asio_handler_deallocate(static_cast<void*>(0),
+      static_cast<std::size_t>(0), asio::detail::addressof(h)));
+}
+#endif // defined(ASIO_NO_DEPRECATED)
+
+template <typename Handler>
+inline void* allocate(std::size_t s, Handler& h)
+{
+#if !defined(ASIO_HAS_HANDLER_HOOKS)
+  return ::operator new(s);
+#elif defined(ASIO_NO_DEPRECATED)
+  // The asio_handler_allocate hook is no longer used to obtain memory.
+  (void)&error_if_hooks_are_defined<Handler>;
+  (void)h;
+#if !defined(ASIO_DISABLE_SMALL_BLOCK_RECYCLING)
+  return asio::detail::thread_info_base::allocate(
+      asio::detail::thread_context::thread_call_stack::top(), s);
+#else // !defined(ASIO_DISABLE_SMALL_BLOCK_RECYCLING)
+  return ::operator new(size);
+#endif // !defined(ASIO_DISABLE_SMALL_BLOCK_RECYCLING)
+#else
+  using asio::asio_handler_allocate;
+  return asio_handler_allocate(s, asio::detail::addressof(h));
+#endif
+}
+
+template <typename Handler>
+inline void deallocate(void* p, std::size_t s, Handler& h)
+{
+#if !defined(ASIO_HAS_HANDLER_HOOKS)
+  ::operator delete(p);
+#elif defined(ASIO_NO_DEPRECATED)
+  // The asio_handler_allocate hook is no longer used to obtain memory.
+  (void)&error_if_hooks_are_defined<Handler>;
+  (void)h;
+#if !defined(ASIO_DISABLE_SMALL_BLOCK_RECYCLING)
+  asio::detail::thread_info_base::deallocate(
+      asio::detail::thread_context::thread_call_stack::top(), p, s);
+#else // !defined(ASIO_DISABLE_SMALL_BLOCK_RECYCLING)
+  (void)s;
+  ::operator delete(p);
+#endif // !defined(ASIO_DISABLE_SMALL_BLOCK_RECYCLING)
+#else
+  using asio::asio_handler_deallocate;
+  asio_handler_deallocate(p, s, asio::detail::addressof(h));
+#endif
+}
+
+} // namespace asio_handler_alloc_helpers
+
+namespace asio {
+namespace detail {
+
+template <typename Handler, typename T>
+class hook_allocator
+{
+public:
+  typedef T value_type;
+
+  template <typename U>
+  struct rebind
+  {
+    typedef hook_allocator<Handler, U> other;
+  };
+
+  explicit hook_allocator(Handler& h)
+    : handler_(h)
+  {
+  }
+
+  template <typename U>
+  hook_allocator(const hook_allocator<Handler, U>& a)
+    : handler_(a.handler_)
+  {
+  }
+
+  T* allocate(std::size_t n)
+  {
+    return static_cast<T*>(
+        asio_handler_alloc_helpers::allocate(sizeof(T) * n, handler_));
+  }
+
+  void deallocate(T* p, std::size_t n)
+  {
+    asio_handler_alloc_helpers::deallocate(p, sizeof(T) * n, handler_);
+  }
+
+//private:
+  Handler& handler_;
+};
+
+template <typename Handler>
+class hook_allocator<Handler, void>
+{
+public:
+  typedef void value_type;
+
+  template <typename U>
+  struct rebind
+  {
+    typedef hook_allocator<Handler, U> other;
+  };
+
+  explicit hook_allocator(Handler& h)
+    : handler_(h)
+  {
+  }
+
+  template <typename U>
+  hook_allocator(const hook_allocator<Handler, U>& a)
+    : handler_(a.handler_)
+  {
+  }
+
+//private:
+  Handler& handler_;
+};
+
+template <typename Handler, typename Allocator>
+struct get_hook_allocator
+{
+  typedef Allocator type;
+
+  static type get(Handler&, const Allocator& a)
+  {
+    return a;
+  }
+};
+
+template <typename Handler, typename T>
+struct get_hook_allocator<Handler, std::allocator<T> >
+{
+  typedef hook_allocator<Handler, T> type;
+
+  static type get(Handler& handler, const std::allocator<T>&)
+  {
+    return type(handler);
+  }
+};
+
+} // namespace detail
+} // namespace asio
+
+#define ASIO_DEFINE_HANDLER_PTR(op) \
+  struct ptr \
+  { \
+    Handler* h; \
+    op* v; \
+    op* p; \
+    ~ptr() \
+    { \
+      reset(); \
+    } \
+    static op* allocate(Handler& handler) \
+    { \
+      typedef typename ::asio::associated_allocator< \
+        Handler>::type associated_allocator_type; \
+      typedef typename ::asio::detail::get_hook_allocator< \
+        Handler, associated_allocator_type>::type hook_allocator_type; \
+      ASIO_REBIND_ALLOC(hook_allocator_type, op) a( \
+            ::asio::detail::get_hook_allocator< \
+              Handler, associated_allocator_type>::get( \
+                handler, ::asio::get_associated_allocator(handler))); \
+      return a.allocate(1); \
+    } \
+    void reset() \
+    { \
+      if (p) \
+      { \
+        p->~op(); \
+        p = 0; \
+      } \
+      if (v) \
+      { \
+        typedef typename ::asio::associated_allocator< \
+          Handler>::type associated_allocator_type; \
+        typedef typename ::asio::detail::get_hook_allocator< \
+          Handler, associated_allocator_type>::type hook_allocator_type; \
+        ASIO_REBIND_ALLOC(hook_allocator_type, op) a( \
+              ::asio::detail::get_hook_allocator< \
+                Handler, associated_allocator_type>::get( \
+                  *h, ::asio::get_associated_allocator(*h))); \
+        a.deallocate(static_cast<op*>(v), 1); \
+        v = 0; \
+      } \
+    } \
+  } \
+  /**/
+
+#define ASIO_DEFINE_TAGGED_HANDLER_ALLOCATOR_PTR(purpose, op) \
+  struct ptr \
+  { \
+    const Alloc* a; \
+    void* v; \
+    op* p; \
+    ~ptr() \
+    { \
+      reset(); \
+    } \
+    static op* allocate(const Alloc& a) \
+    { \
+      typedef typename ::asio::detail::get_recycling_allocator< \
+        Alloc, purpose>::type recycling_allocator_type; \
+      ASIO_REBIND_ALLOC(recycling_allocator_type, op) a1( \
+            ::asio::detail::get_recycling_allocator< \
+              Alloc, purpose>::get(a)); \
+      return a1.allocate(1); \
+    } \
+    void reset() \
+    { \
+      if (p) \
+      { \
+        p->~op(); \
+        p = 0; \
+      } \
+      if (v) \
+      { \
+        typedef typename ::asio::detail::get_recycling_allocator< \
+          Alloc, purpose>::type recycling_allocator_type; \
+        ASIO_REBIND_ALLOC(recycling_allocator_type, op) a1( \
+              ::asio::detail::get_recycling_allocator< \
+                Alloc, purpose>::get(*a)); \
+        a1.deallocate(static_cast<op*>(v), 1); \
+        v = 0; \
+      } \
+    } \
+  } \
+  /**/
+
+#define ASIO_DEFINE_HANDLER_ALLOCATOR_PTR(op) \
+  ASIO_DEFINE_TAGGED_HANDLER_ALLOCATOR_PTR( \
+      ::asio::detail::thread_info_base::default_tag, op ) \
+  /**/
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_HANDLER_ALLOC_HELPERS_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/handler_cont_helpers.hpp b/link/modules/asio-standalone/asio/include/asio/detail/handler_cont_helpers.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/handler_cont_helpers.hpp
@@ -0,0 +1,45 @@
+//
+// detail/handler_cont_helpers.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_HANDLER_CONT_HELPERS_HPP
+#define ASIO_DETAIL_HANDLER_CONT_HELPERS_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/handler_continuation_hook.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+// Calls to asio_handler_is_continuation must be made from a namespace that
+// does not contain overloads of this function. This namespace is defined here
+// for that purpose.
+namespace asio_handler_cont_helpers {
+
+template <typename Context>
+inline bool is_continuation(Context& context)
+{
+#if !defined(ASIO_HAS_HANDLER_HOOKS)
+  return false;
+#else
+  using asio::asio_handler_is_continuation;
+  return asio_handler_is_continuation(
+      asio::detail::addressof(context));
+#endif
+}
+
+} // namespace asio_handler_cont_helpers
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_HANDLER_CONT_HELPERS_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/handler_invoke_helpers.hpp b/link/modules/asio-standalone/asio/include/asio/detail/handler_invoke_helpers.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/handler_invoke_helpers.hpp
@@ -0,0 +1,80 @@
+//
+// detail/handler_invoke_helpers.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_HANDLER_INVOKE_HELPERS_HPP
+#define ASIO_DETAIL_HANDLER_INVOKE_HELPERS_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/handler_invoke_hook.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+// Calls to asio_handler_invoke must be made from a namespace that does not
+// contain overloads of this function. The asio_handler_invoke_helpers
+// namespace is defined here for that purpose.
+namespace asio_handler_invoke_helpers {
+
+#if defined(ASIO_NO_DEPRECATED)
+template <typename Function, typename Context>
+inline void error_if_hook_is_defined(Function& function, Context& context)
+{
+  using asio::asio_handler_invoke;
+  // If you get an error here it is because some of your handlers still
+  // overload asio_handler_invoke, but this hook is no longer used.
+  (void)static_cast<asio::asio_handler_invoke_is_no_longer_used>(
+    asio_handler_invoke(function, asio::detail::addressof(context)));
+}
+#endif // defined(ASIO_NO_DEPRECATED)
+
+template <typename Function, typename Context>
+inline void invoke(Function& function, Context& context)
+{
+#if !defined(ASIO_HAS_HANDLER_HOOKS)
+  Function tmp(function);
+  tmp();
+#elif defined(ASIO_NO_DEPRECATED)
+  // The asio_handler_invoke hook is no longer used to invoke the function.
+  (void)&error_if_hook_is_defined<Function, Context>;
+  (void)context;
+  function();
+#else
+  using asio::asio_handler_invoke;
+  asio_handler_invoke(function, asio::detail::addressof(context));
+#endif
+}
+
+template <typename Function, typename Context>
+inline void invoke(const Function& function, Context& context)
+{
+#if !defined(ASIO_HAS_HANDLER_HOOKS)
+  Function tmp(function);
+  tmp();
+#elif defined(ASIO_NO_DEPRECATED)
+  // The asio_handler_invoke hook is no longer used to invoke the function.
+  (void)&error_if_hook_is_defined<const Function, Context>;
+  (void)context;
+  Function tmp(function);
+  tmp();
+#else
+  using asio::asio_handler_invoke;
+  asio_handler_invoke(function, asio::detail::addressof(context));
+#endif
+}
+
+} // namespace asio_handler_invoke_helpers
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_HANDLER_INVOKE_HELPERS_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/handler_tracking.hpp b/link/modules/asio-standalone/asio/include/asio/detail/handler_tracking.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/handler_tracking.hpp
@@ -0,0 +1,264 @@
+//
+// detail/handler_tracking.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_HANDLER_TRACKING_HPP
+#define ASIO_DETAIL_HANDLER_TRACKING_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+namespace asio {
+
+class execution_context;
+
+} // namespace asio
+
+#if defined(ASIO_CUSTOM_HANDLER_TRACKING)
+# include ASIO_CUSTOM_HANDLER_TRACKING
+#elif defined(ASIO_ENABLE_HANDLER_TRACKING)
+# include "asio/error_code.hpp"
+# include "asio/detail/cstdint.hpp"
+# include "asio/detail/static_mutex.hpp"
+# include "asio/detail/tss_ptr.hpp"
+#endif // defined(ASIO_ENABLE_HANDLER_TRACKING)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+#if defined(ASIO_CUSTOM_HANDLER_TRACKING)
+
+// The user-specified header must define the following macros:
+// - ASIO_INHERIT_TRACKED_HANDLER
+// - ASIO_ALSO_INHERIT_TRACKED_HANDLER
+// - ASIO_HANDLER_TRACKING_INIT
+// - ASIO_HANDLER_CREATION(args)
+// - ASIO_HANDLER_COMPLETION(args)
+// - ASIO_HANDLER_INVOCATION_BEGIN(args)
+// - ASIO_HANDLER_INVOCATION_END
+// - ASIO_HANDLER_OPERATION(args)
+// - ASIO_HANDLER_REACTOR_REGISTRATION(args)
+// - ASIO_HANDLER_REACTOR_DEREGISTRATION(args)
+// - ASIO_HANDLER_REACTOR_READ_EVENT
+// - ASIO_HANDLER_REACTOR_WRITE_EVENT
+// - ASIO_HANDLER_REACTOR_ERROR_EVENT
+// - ASIO_HANDLER_REACTOR_EVENTS(args)
+// - ASIO_HANDLER_REACTOR_OPERATION(args)
+
+# if !defined(ASIO_ENABLE_HANDLER_TRACKING)
+#  define ASIO_ENABLE_HANDLER_TRACKING 1
+# endif /// !defined(ASIO_ENABLE_HANDLER_TRACKING)
+
+#elif defined(ASIO_ENABLE_HANDLER_TRACKING)
+
+class handler_tracking
+{
+public:
+  class completion;
+
+  // Base class for objects containing tracked handlers.
+  class tracked_handler
+  {
+  private:
+    // Only the handler_tracking class will have access to the id.
+    friend class handler_tracking;
+    friend class completion;
+    uint64_t id_;
+
+  protected:
+    // Constructor initialises with no id.
+    tracked_handler() : id_(0) {}
+
+    // Prevent deletion through this type.
+    ~tracked_handler() {}
+  };
+
+  // Initialise the tracking system.
+  ASIO_DECL static void init();
+
+  class location
+  {
+  public:
+    // Constructor adds a location to the stack.
+    ASIO_DECL explicit location(const char* file,
+        int line, const char* func);
+
+    // Destructor removes a location from the stack.
+    ASIO_DECL ~location();
+
+  private:
+    // Disallow copying and assignment.
+    location(const location&) ASIO_DELETED;
+    location& operator=(const location&) ASIO_DELETED;
+
+    friend class handler_tracking;
+    const char* file_;
+    int line_;
+    const char* func_;
+    location* next_;
+  };
+
+  // Record the creation of a tracked handler.
+  ASIO_DECL static void creation(
+      execution_context& context, tracked_handler& h,
+      const char* object_type, void* object,
+      uintmax_t native_handle, const char* op_name);
+
+  class completion
+  {
+  public:
+    // Constructor records that handler is to be invoked with no arguments.
+    ASIO_DECL explicit completion(const tracked_handler& h);
+
+    // Destructor records only when an exception is thrown from the handler, or
+    // if the memory is being freed without the handler having been invoked.
+    ASIO_DECL ~completion();
+
+    // Records that handler is to be invoked with no arguments.
+    ASIO_DECL void invocation_begin();
+
+    // Records that handler is to be invoked with one arguments.
+    ASIO_DECL void invocation_begin(const asio::error_code& ec);
+
+    // Constructor records that handler is to be invoked with two arguments.
+    ASIO_DECL void invocation_begin(
+        const asio::error_code& ec, std::size_t bytes_transferred);
+
+    // Constructor records that handler is to be invoked with two arguments.
+    ASIO_DECL void invocation_begin(
+        const asio::error_code& ec, int signal_number);
+
+    // Constructor records that handler is to be invoked with two arguments.
+    ASIO_DECL void invocation_begin(
+        const asio::error_code& ec, const char* arg);
+
+    // Record that handler invocation has ended.
+    ASIO_DECL void invocation_end();
+
+  private:
+    friend class handler_tracking;
+    uint64_t id_;
+    bool invoked_;
+    completion* next_;
+  };
+
+  // Record an operation that is not directly associated with a handler.
+  ASIO_DECL static void operation(execution_context& context,
+      const char* object_type, void* object,
+      uintmax_t native_handle, const char* op_name);
+
+  // Record that a descriptor has been registered with the reactor.
+  ASIO_DECL static void reactor_registration(execution_context& context,
+      uintmax_t native_handle, uintmax_t registration);
+
+  // Record that a descriptor has been deregistered from the reactor.
+  ASIO_DECL static void reactor_deregistration(execution_context& context,
+      uintmax_t native_handle, uintmax_t registration);
+
+  // Record a reactor-based operation that is associated with a handler.
+  ASIO_DECL static void reactor_events(execution_context& context,
+      uintmax_t registration, unsigned events);
+
+  // Record a reactor-based operation that is associated with a handler.
+  ASIO_DECL static void reactor_operation(
+      const tracked_handler& h, const char* op_name,
+      const asio::error_code& ec);
+
+  // Record a reactor-based operation that is associated with a handler.
+  ASIO_DECL static void reactor_operation(
+      const tracked_handler& h, const char* op_name,
+      const asio::error_code& ec, std::size_t bytes_transferred);
+
+  // Write a line of output.
+  ASIO_DECL static void write_line(const char* format, ...);
+
+private:
+  struct tracking_state;
+  ASIO_DECL static tracking_state* get_state();
+};
+
+# define ASIO_INHERIT_TRACKED_HANDLER \
+  : public asio::detail::handler_tracking::tracked_handler
+
+# define ASIO_ALSO_INHERIT_TRACKED_HANDLER \
+  , public asio::detail::handler_tracking::tracked_handler
+
+# define ASIO_HANDLER_TRACKING_INIT \
+  asio::detail::handler_tracking::init()
+
+# define ASIO_HANDLER_LOCATION(args) \
+  asio::detail::handler_tracking::location tracked_location args
+
+# define ASIO_HANDLER_CREATION(args) \
+  asio::detail::handler_tracking::creation args
+
+# define ASIO_HANDLER_COMPLETION(args) \
+  asio::detail::handler_tracking::completion tracked_completion args
+
+# define ASIO_HANDLER_INVOCATION_BEGIN(args) \
+  tracked_completion.invocation_begin args
+
+# define ASIO_HANDLER_INVOCATION_END \
+  tracked_completion.invocation_end()
+
+# define ASIO_HANDLER_OPERATION(args) \
+  asio::detail::handler_tracking::operation args
+
+# define ASIO_HANDLER_REACTOR_REGISTRATION(args) \
+  asio::detail::handler_tracking::reactor_registration args
+
+# define ASIO_HANDLER_REACTOR_DEREGISTRATION(args) \
+  asio::detail::handler_tracking::reactor_deregistration args
+
+# define ASIO_HANDLER_REACTOR_READ_EVENT 1
+# define ASIO_HANDLER_REACTOR_WRITE_EVENT 2
+# define ASIO_HANDLER_REACTOR_ERROR_EVENT 4
+
+# define ASIO_HANDLER_REACTOR_EVENTS(args) \
+  asio::detail::handler_tracking::reactor_events args
+
+# define ASIO_HANDLER_REACTOR_OPERATION(args) \
+  asio::detail::handler_tracking::reactor_operation args
+
+#else // defined(ASIO_ENABLE_HANDLER_TRACKING)
+
+# define ASIO_INHERIT_TRACKED_HANDLER
+# define ASIO_ALSO_INHERIT_TRACKED_HANDLER
+# define ASIO_HANDLER_TRACKING_INIT (void)0
+# define ASIO_HANDLER_LOCATION(loc) (void)0
+# define ASIO_HANDLER_CREATION(args) (void)0
+# define ASIO_HANDLER_COMPLETION(args) (void)0
+# define ASIO_HANDLER_INVOCATION_BEGIN(args) (void)0
+# define ASIO_HANDLER_INVOCATION_END (void)0
+# define ASIO_HANDLER_OPERATION(args) (void)0
+# define ASIO_HANDLER_REACTOR_REGISTRATION(args) (void)0
+# define ASIO_HANDLER_REACTOR_DEREGISTRATION(args) (void)0
+# define ASIO_HANDLER_REACTOR_READ_EVENT 0
+# define ASIO_HANDLER_REACTOR_WRITE_EVENT 0
+# define ASIO_HANDLER_REACTOR_ERROR_EVENT 0
+# define ASIO_HANDLER_REACTOR_EVENTS(args) (void)0
+# define ASIO_HANDLER_REACTOR_OPERATION(args) (void)0
+
+#endif // defined(ASIO_ENABLE_HANDLER_TRACKING)
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/handler_tracking.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // ASIO_DETAIL_HANDLER_TRACKING_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/handler_type_requirements.hpp b/link/modules/asio-standalone/asio/include/asio/detail/handler_type_requirements.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/handler_type_requirements.hpp
@@ -0,0 +1,556 @@
+//
+// detail/handler_type_requirements.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_HANDLER_TYPE_REQUIREMENTS_HPP
+#define ASIO_DETAIL_HANDLER_TYPE_REQUIREMENTS_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+// Older versions of gcc have difficulty compiling the sizeof expressions where
+// we test the handler type requirements. We'll disable checking of handler type
+// requirements for those compilers, but otherwise enable it by default.
+#if !defined(ASIO_DISABLE_HANDLER_TYPE_REQUIREMENTS)
+# if !defined(__GNUC__) || (__GNUC__ >= 4)
+#  define ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS 1
+# endif // !defined(__GNUC__) || (__GNUC__ >= 4)
+#endif // !defined(ASIO_DISABLE_HANDLER_TYPE_REQUIREMENTS)
+
+// With C++0x we can use a combination of enhanced SFINAE and static_assert to
+// generate better template error messages. As this technique is not yet widely
+// portable, we'll only enable it for tested compilers.
+#if !defined(ASIO_DISABLE_HANDLER_TYPE_REQUIREMENTS_ASSERT)
+# if defined(__GNUC__)
+#  if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4)
+#   if defined(__GXX_EXPERIMENTAL_CXX0X__)
+#    define ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS_ASSERT 1
+#   endif // defined(__GXX_EXPERIMENTAL_CXX0X__)
+#  endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4)
+# endif // defined(__GNUC__)
+# if defined(ASIO_MSVC)
+#  if (_MSC_VER >= 1600)
+#   define ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS_ASSERT 1
+#  endif // (_MSC_VER >= 1600)
+# endif // defined(ASIO_MSVC)
+# if defined(__clang__)
+#  if __has_feature(__cxx_static_assert__)
+#   define ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS_ASSERT 1
+#  endif // __has_feature(cxx_static_assert)
+# endif // defined(__clang__)
+#endif // !defined(ASIO_DISABLE_HANDLER_TYPE_REQUIREMENTS)
+
+#if defined(ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS)
+# include "asio/async_result.hpp"
+#endif // defined(ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS)
+
+namespace asio {
+namespace detail {
+
+#if defined(ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS)
+
+# if defined(ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS_ASSERT)
+
+template <typename Handler>
+auto zero_arg_copyable_handler_test(Handler h, void*)
+  -> decltype(
+    sizeof(Handler(static_cast<const Handler&>(h))),
+    ((h)()),
+    char(0));
+
+template <typename Handler>
+char (&zero_arg_copyable_handler_test(Handler, ...))[2];
+
+template <typename Handler, typename Arg1>
+auto one_arg_handler_test(Handler h, Arg1* a1)
+  -> decltype(
+    sizeof(Handler(ASIO_MOVE_CAST(Handler)(h))),
+    ((h)(*a1)),
+    char(0));
+
+template <typename Handler>
+char (&one_arg_handler_test(Handler h, ...))[2];
+
+template <typename Handler, typename Arg1, typename Arg2>
+auto two_arg_handler_test(Handler h, Arg1* a1, Arg2* a2)
+  -> decltype(
+    sizeof(Handler(ASIO_MOVE_CAST(Handler)(h))),
+    ((h)(*a1, *a2)),
+    char(0));
+
+template <typename Handler>
+char (&two_arg_handler_test(Handler, ...))[2];
+
+template <typename Handler, typename Arg1, typename Arg2>
+auto two_arg_move_handler_test(Handler h, Arg1* a1, Arg2* a2)
+  -> decltype(
+    sizeof(Handler(ASIO_MOVE_CAST(Handler)(h))),
+    ((h)(*a1, ASIO_MOVE_CAST(Arg2)(*a2))),
+    char(0));
+
+template <typename Handler>
+char (&two_arg_move_handler_test(Handler, ...))[2];
+
+#  define ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT(expr, msg) \
+     static_assert(expr, msg);
+
+# else // defined(ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS_ASSERT)
+
+#  define ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT(expr, msg)
+
+# endif // defined(ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS_ASSERT)
+
+template <typename T> T& lvref();
+template <typename T> T& lvref(T);
+template <typename T> const T& clvref();
+template <typename T> const T& clvref(T);
+#if defined(ASIO_HAS_MOVE)
+template <typename T> T rvref();
+template <typename T> T rvref(T);
+#else // defined(ASIO_HAS_MOVE)
+template <typename T> const T& rvref();
+template <typename T> const T& rvref(T);
+#endif // defined(ASIO_HAS_MOVE)
+template <typename T> char argbyv(T);
+
+template <int>
+struct handler_type_requirements
+{
+};
+
+#define ASIO_LEGACY_COMPLETION_HANDLER_CHECK( \
+    handler_type, handler) \
+  \
+  typedef ASIO_HANDLER_TYPE(handler_type, \
+      void()) asio_true_handler_type; \
+  \
+  ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \
+      sizeof(asio::detail::zero_arg_copyable_handler_test( \
+          asio::detail::clvref< \
+            asio_true_handler_type>(), 0)) == 1, \
+      "CompletionHandler type requirements not met") \
+  \
+  typedef asio::detail::handler_type_requirements< \
+      sizeof( \
+        asio::detail::argbyv( \
+          asio::detail::clvref< \
+            asio_true_handler_type>())) + \
+      sizeof( \
+        asio::detail::lvref< \
+          asio_true_handler_type>()(), \
+        char(0))> ASIO_UNUSED_TYPEDEF
+
+#define ASIO_READ_HANDLER_CHECK( \
+    handler_type, handler) \
+  \
+  typedef ASIO_HANDLER_TYPE(handler_type, \
+      void(asio::error_code, std::size_t)) \
+    asio_true_handler_type; \
+  \
+  ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \
+      sizeof(asio::detail::two_arg_handler_test( \
+          asio::detail::rvref< \
+            asio_true_handler_type>(), \
+          static_cast<const asio::error_code*>(0), \
+          static_cast<const std::size_t*>(0))) == 1, \
+      "ReadHandler type requirements not met") \
+  \
+  typedef asio::detail::handler_type_requirements< \
+      sizeof( \
+        asio::detail::argbyv( \
+          asio::detail::rvref< \
+            asio_true_handler_type>())) + \
+      sizeof( \
+        asio::detail::lvref< \
+          asio_true_handler_type>()( \
+            asio::detail::lvref<const asio::error_code>(), \
+            asio::detail::lvref<const std::size_t>()), \
+        char(0))> ASIO_UNUSED_TYPEDEF
+
+#define ASIO_WRITE_HANDLER_CHECK( \
+    handler_type, handler) \
+  \
+  typedef ASIO_HANDLER_TYPE(handler_type, \
+      void(asio::error_code, std::size_t)) \
+    asio_true_handler_type; \
+  \
+  ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \
+      sizeof(asio::detail::two_arg_handler_test( \
+          asio::detail::rvref< \
+            asio_true_handler_type>(), \
+          static_cast<const asio::error_code*>(0), \
+          static_cast<const std::size_t*>(0))) == 1, \
+      "WriteHandler type requirements not met") \
+  \
+  typedef asio::detail::handler_type_requirements< \
+      sizeof( \
+        asio::detail::argbyv( \
+          asio::detail::rvref< \
+            asio_true_handler_type>())) + \
+      sizeof( \
+        asio::detail::lvref< \
+          asio_true_handler_type>()( \
+            asio::detail::lvref<const asio::error_code>(), \
+            asio::detail::lvref<const std::size_t>()), \
+        char(0))> ASIO_UNUSED_TYPEDEF
+
+#define ASIO_ACCEPT_HANDLER_CHECK( \
+    handler_type, handler) \
+  \
+  typedef ASIO_HANDLER_TYPE(handler_type, \
+      void(asio::error_code)) \
+    asio_true_handler_type; \
+  \
+  ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \
+      sizeof(asio::detail::one_arg_handler_test( \
+          asio::detail::rvref< \
+            asio_true_handler_type>(), \
+          static_cast<const asio::error_code*>(0))) == 1, \
+      "AcceptHandler type requirements not met") \
+  \
+  typedef asio::detail::handler_type_requirements< \
+      sizeof( \
+        asio::detail::argbyv( \
+          asio::detail::rvref< \
+            asio_true_handler_type>())) + \
+      sizeof( \
+        asio::detail::lvref< \
+          asio_true_handler_type>()( \
+            asio::detail::lvref<const asio::error_code>()), \
+        char(0))> ASIO_UNUSED_TYPEDEF
+
+#define ASIO_MOVE_ACCEPT_HANDLER_CHECK( \
+    handler_type, handler, socket_type) \
+  \
+  typedef ASIO_HANDLER_TYPE(handler_type, \
+      void(asio::error_code, socket_type)) \
+    asio_true_handler_type; \
+  \
+  ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \
+      sizeof(asio::detail::two_arg_move_handler_test( \
+          asio::detail::rvref< \
+            asio_true_handler_type>(), \
+          static_cast<const asio::error_code*>(0), \
+          static_cast<socket_type*>(0))) == 1, \
+      "MoveAcceptHandler type requirements not met") \
+  \
+  typedef asio::detail::handler_type_requirements< \
+      sizeof( \
+        asio::detail::argbyv( \
+          asio::detail::rvref< \
+            asio_true_handler_type>())) + \
+      sizeof( \
+        asio::detail::lvref< \
+          asio_true_handler_type>()( \
+            asio::detail::lvref<const asio::error_code>(), \
+            asio::detail::rvref<socket_type>()), \
+        char(0))> ASIO_UNUSED_TYPEDEF
+
+#define ASIO_CONNECT_HANDLER_CHECK( \
+    handler_type, handler) \
+  \
+  typedef ASIO_HANDLER_TYPE(handler_type, \
+      void(asio::error_code)) \
+    asio_true_handler_type; \
+  \
+  ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \
+      sizeof(asio::detail::one_arg_handler_test( \
+          asio::detail::rvref< \
+            asio_true_handler_type>(), \
+          static_cast<const asio::error_code*>(0))) == 1, \
+      "ConnectHandler type requirements not met") \
+  \
+  typedef asio::detail::handler_type_requirements< \
+      sizeof( \
+        asio::detail::argbyv( \
+          asio::detail::rvref< \
+            asio_true_handler_type>())) + \
+      sizeof( \
+        asio::detail::lvref< \
+          asio_true_handler_type>()( \
+            asio::detail::lvref<const asio::error_code>()), \
+        char(0))> ASIO_UNUSED_TYPEDEF
+
+#define ASIO_RANGE_CONNECT_HANDLER_CHECK( \
+    handler_type, handler, endpoint_type) \
+  \
+  typedef ASIO_HANDLER_TYPE(handler_type, \
+      void(asio::error_code, endpoint_type)) \
+    asio_true_handler_type; \
+  \
+  ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \
+      sizeof(asio::detail::two_arg_handler_test( \
+          asio::detail::rvref< \
+            asio_true_handler_type>(), \
+          static_cast<const asio::error_code*>(0), \
+          static_cast<const endpoint_type*>(0))) == 1, \
+      "RangeConnectHandler type requirements not met") \
+  \
+  typedef asio::detail::handler_type_requirements< \
+      sizeof( \
+        asio::detail::argbyv( \
+          asio::detail::rvref< \
+            asio_true_handler_type>())) + \
+      sizeof( \
+        asio::detail::lvref< \
+          asio_true_handler_type>()( \
+            asio::detail::lvref<const asio::error_code>(), \
+            asio::detail::lvref<const endpoint_type>()), \
+        char(0))> ASIO_UNUSED_TYPEDEF
+
+#define ASIO_ITERATOR_CONNECT_HANDLER_CHECK( \
+    handler_type, handler, iter_type) \
+  \
+  typedef ASIO_HANDLER_TYPE(handler_type, \
+      void(asio::error_code, iter_type)) \
+    asio_true_handler_type; \
+  \
+  ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \
+      sizeof(asio::detail::two_arg_handler_test( \
+          asio::detail::rvref< \
+            asio_true_handler_type>(), \
+          static_cast<const asio::error_code*>(0), \
+          static_cast<const iter_type*>(0))) == 1, \
+      "IteratorConnectHandler type requirements not met") \
+  \
+  typedef asio::detail::handler_type_requirements< \
+      sizeof( \
+        asio::detail::argbyv( \
+          asio::detail::rvref< \
+            asio_true_handler_type>())) + \
+      sizeof( \
+        asio::detail::lvref< \
+          asio_true_handler_type>()( \
+            asio::detail::lvref<const asio::error_code>(), \
+            asio::detail::lvref<const iter_type>()), \
+        char(0))> ASIO_UNUSED_TYPEDEF
+
+#define ASIO_RESOLVE_HANDLER_CHECK( \
+    handler_type, handler, range_type) \
+  \
+  typedef ASIO_HANDLER_TYPE(handler_type, \
+      void(asio::error_code, range_type)) \
+    asio_true_handler_type; \
+  \
+  ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \
+      sizeof(asio::detail::two_arg_handler_test( \
+          asio::detail::rvref< \
+            asio_true_handler_type>(), \
+          static_cast<const asio::error_code*>(0), \
+          static_cast<const range_type*>(0))) == 1, \
+      "ResolveHandler type requirements not met") \
+  \
+  typedef asio::detail::handler_type_requirements< \
+      sizeof( \
+        asio::detail::argbyv( \
+          asio::detail::rvref< \
+            asio_true_handler_type>())) + \
+      sizeof( \
+        asio::detail::lvref< \
+          asio_true_handler_type>()( \
+            asio::detail::lvref<const asio::error_code>(), \
+            asio::detail::lvref<const range_type>()), \
+        char(0))> ASIO_UNUSED_TYPEDEF
+
+#define ASIO_WAIT_HANDLER_CHECK( \
+    handler_type, handler) \
+  \
+  typedef ASIO_HANDLER_TYPE(handler_type, \
+      void(asio::error_code)) \
+    asio_true_handler_type; \
+  \
+  ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \
+      sizeof(asio::detail::one_arg_handler_test( \
+          asio::detail::rvref< \
+            asio_true_handler_type>(), \
+          static_cast<const asio::error_code*>(0))) == 1, \
+      "WaitHandler type requirements not met") \
+  \
+  typedef asio::detail::handler_type_requirements< \
+      sizeof( \
+        asio::detail::argbyv( \
+          asio::detail::rvref< \
+            asio_true_handler_type>())) + \
+      sizeof( \
+        asio::detail::lvref< \
+          asio_true_handler_type>()( \
+            asio::detail::lvref<const asio::error_code>()), \
+        char(0))> ASIO_UNUSED_TYPEDEF
+
+#define ASIO_SIGNAL_HANDLER_CHECK( \
+    handler_type, handler) \
+  \
+  typedef ASIO_HANDLER_TYPE(handler_type, \
+      void(asio::error_code, int)) \
+    asio_true_handler_type; \
+  \
+  ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \
+      sizeof(asio::detail::two_arg_handler_test( \
+          asio::detail::rvref< \
+            asio_true_handler_type>(), \
+          static_cast<const asio::error_code*>(0), \
+          static_cast<const int*>(0))) == 1, \
+      "SignalHandler type requirements not met") \
+  \
+  typedef asio::detail::handler_type_requirements< \
+      sizeof( \
+        asio::detail::argbyv( \
+          asio::detail::rvref< \
+            asio_true_handler_type>())) + \
+      sizeof( \
+        asio::detail::lvref< \
+          asio_true_handler_type>()( \
+            asio::detail::lvref<const asio::error_code>(), \
+            asio::detail::lvref<const int>()), \
+        char(0))> ASIO_UNUSED_TYPEDEF
+
+#define ASIO_HANDSHAKE_HANDLER_CHECK( \
+    handler_type, handler) \
+  \
+  typedef ASIO_HANDLER_TYPE(handler_type, \
+      void(asio::error_code)) \
+    asio_true_handler_type; \
+  \
+  ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \
+      sizeof(asio::detail::one_arg_handler_test( \
+          asio::detail::rvref< \
+            asio_true_handler_type>(), \
+          static_cast<const asio::error_code*>(0))) == 1, \
+      "HandshakeHandler type requirements not met") \
+  \
+  typedef asio::detail::handler_type_requirements< \
+      sizeof( \
+        asio::detail::argbyv( \
+          asio::detail::rvref< \
+            asio_true_handler_type>())) + \
+      sizeof( \
+        asio::detail::lvref< \
+          asio_true_handler_type>()( \
+            asio::detail::lvref<const asio::error_code>()), \
+        char(0))> ASIO_UNUSED_TYPEDEF
+
+#define ASIO_BUFFERED_HANDSHAKE_HANDLER_CHECK( \
+    handler_type, handler) \
+  \
+  typedef ASIO_HANDLER_TYPE(handler_type, \
+      void(asio::error_code, std::size_t)) \
+    asio_true_handler_type; \
+  \
+  ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \
+      sizeof(asio::detail::two_arg_handler_test( \
+          asio::detail::rvref< \
+            asio_true_handler_type>(), \
+          static_cast<const asio::error_code*>(0), \
+          static_cast<const std::size_t*>(0))) == 1, \
+      "BufferedHandshakeHandler type requirements not met") \
+  \
+  typedef asio::detail::handler_type_requirements< \
+      sizeof( \
+        asio::detail::argbyv( \
+          asio::detail::rvref< \
+            asio_true_handler_type>())) + \
+      sizeof( \
+        asio::detail::lvref< \
+          asio_true_handler_type>()( \
+          asio::detail::lvref<const asio::error_code>(), \
+          asio::detail::lvref<const std::size_t>()), \
+        char(0))> ASIO_UNUSED_TYPEDEF
+
+#define ASIO_SHUTDOWN_HANDLER_CHECK( \
+    handler_type, handler) \
+  \
+  typedef ASIO_HANDLER_TYPE(handler_type, \
+      void(asio::error_code)) \
+    asio_true_handler_type; \
+  \
+  ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \
+      sizeof(asio::detail::one_arg_handler_test( \
+          asio::detail::rvref< \
+            asio_true_handler_type>(), \
+          static_cast<const asio::error_code*>(0))) == 1, \
+      "ShutdownHandler type requirements not met") \
+  \
+  typedef asio::detail::handler_type_requirements< \
+      sizeof( \
+        asio::detail::argbyv( \
+          asio::detail::rvref< \
+            asio_true_handler_type>())) + \
+      sizeof( \
+        asio::detail::lvref< \
+          asio_true_handler_type>()( \
+            asio::detail::lvref<const asio::error_code>()), \
+        char(0))> ASIO_UNUSED_TYPEDEF
+
+#else // !defined(ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS)
+
+#define ASIO_LEGACY_COMPLETION_HANDLER_CHECK( \
+    handler_type, handler) \
+  typedef int ASIO_UNUSED_TYPEDEF
+
+#define ASIO_READ_HANDLER_CHECK( \
+    handler_type, handler) \
+  typedef int ASIO_UNUSED_TYPEDEF
+
+#define ASIO_WRITE_HANDLER_CHECK( \
+    handler_type, handler) \
+  typedef int ASIO_UNUSED_TYPEDEF
+
+#define ASIO_ACCEPT_HANDLER_CHECK( \
+    handler_type, handler) \
+  typedef int ASIO_UNUSED_TYPEDEF
+
+#define ASIO_MOVE_ACCEPT_HANDLER_CHECK( \
+    handler_type, handler, socket_type) \
+  typedef int ASIO_UNUSED_TYPEDEF
+
+#define ASIO_CONNECT_HANDLER_CHECK( \
+    handler_type, handler) \
+  typedef int ASIO_UNUSED_TYPEDEF
+
+#define ASIO_RANGE_CONNECT_HANDLER_CHECK( \
+    handler_type, handler, iter_type) \
+  typedef int ASIO_UNUSED_TYPEDEF
+
+#define ASIO_ITERATOR_CONNECT_HANDLER_CHECK( \
+    handler_type, handler, iter_type) \
+  typedef int ASIO_UNUSED_TYPEDEF
+
+#define ASIO_RESOLVE_HANDLER_CHECK( \
+    handler_type, handler, iter_type) \
+  typedef int ASIO_UNUSED_TYPEDEF
+
+#define ASIO_WAIT_HANDLER_CHECK( \
+    handler_type, handler) \
+  typedef int ASIO_UNUSED_TYPEDEF
+
+#define ASIO_SIGNAL_HANDLER_CHECK( \
+    handler_type, handler) \
+  typedef int ASIO_UNUSED_TYPEDEF
+
+#define ASIO_HANDSHAKE_HANDLER_CHECK( \
+    handler_type, handler) \
+  typedef int ASIO_UNUSED_TYPEDEF
+
+#define ASIO_BUFFERED_HANDSHAKE_HANDLER_CHECK( \
+    handler_type, handler) \
+  typedef int ASIO_UNUSED_TYPEDEF
+
+#define ASIO_SHUTDOWN_HANDLER_CHECK( \
+    handler_type, handler) \
+  typedef int ASIO_UNUSED_TYPEDEF
+
+#endif // !defined(ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS)
+
+} // namespace detail
+} // namespace asio
+
+#endif // ASIO_DETAIL_HANDLER_TYPE_REQUIREMENTS_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/handler_work.hpp b/link/modules/asio-standalone/asio/include/asio/detail/handler_work.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/handler_work.hpp
@@ -0,0 +1,438 @@
+//
+// detail/handler_work.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_HANDLER_WORK_HPP
+#define ASIO_DETAIL_HANDLER_WORK_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/associated_executor.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/type_traits.hpp"
+#include "asio/execution/allocator.hpp"
+#include "asio/execution/blocking.hpp"
+#include "asio/execution/execute.hpp"
+#include "asio/execution/executor.hpp"
+#include "asio/execution/outstanding_work.hpp"
+#include "asio/executor_work_guard.hpp"
+#include "asio/prefer.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+class executor;
+class io_context;
+
+namespace execution {
+
+#if defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+template <typename...> class any_executor;
+
+#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+template <typename, typename, typename, typename, typename,
+    typename, typename, typename, typename> class any_executor;
+
+#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+} // namespace execution
+namespace detail {
+
+template <typename Executor, typename CandidateExecutor = void,
+    typename IoContext = io_context,
+    typename PolymorphicExecutor = executor, typename = void>
+class handler_work_base
+{
+public:
+  explicit handler_work_base(const Executor& ex) ASIO_NOEXCEPT
+    : executor_(asio::prefer(ex, execution::outstanding_work.tracked))
+  {
+  }
+
+  template <typename OtherExecutor>
+  handler_work_base(const Executor& ex,
+      const OtherExecutor&) ASIO_NOEXCEPT
+    : executor_(asio::prefer(ex, execution::outstanding_work.tracked))
+  {
+  }
+
+  handler_work_base(const handler_work_base& other) ASIO_NOEXCEPT
+    : executor_(other.executor_)
+  {
+  }
+
+#if defined(ASIO_HAS_MOVE)
+  handler_work_base(handler_work_base&& other) ASIO_NOEXCEPT
+    : executor_(ASIO_MOVE_CAST(executor_type)(other.executor_))
+  {
+  }
+#endif // defined(ASIO_HAS_MOVE)
+
+  bool owns_work() const ASIO_NOEXCEPT
+  {
+    return true;
+  }
+
+  template <typename Function, typename Handler>
+  void dispatch(Function& function, Handler& handler)
+  {
+    execution::execute(
+        asio::prefer(executor_,
+          execution::blocking.possibly,
+          execution::allocator((get_associated_allocator)(handler))),
+        ASIO_MOVE_CAST(Function)(function));
+  }
+
+private:
+  typedef typename decay<
+      typename prefer_result<Executor,
+        execution::outstanding_work_t::tracked_t
+      >::type
+    >::type executor_type;
+
+  executor_type executor_;
+};
+
+template <typename Executor, typename CandidateExecutor,
+    typename IoContext, typename PolymorphicExecutor>
+class handler_work_base<Executor, CandidateExecutor,
+    IoContext, PolymorphicExecutor,
+    typename enable_if<
+      !execution::is_executor<Executor>::value
+        && (!is_same<Executor, PolymorphicExecutor>::value
+          || !is_same<CandidateExecutor, void>::value)
+    >::type>
+{
+public:
+  explicit handler_work_base(const Executor& ex) ASIO_NOEXCEPT
+    : executor_(ex),
+      owns_work_(true)
+  {
+    executor_.on_work_started();
+  }
+
+  handler_work_base(const Executor& ex,
+      const Executor& candidate) ASIO_NOEXCEPT
+    : executor_(ex),
+      owns_work_(ex != candidate)
+  {
+    if (owns_work_)
+      executor_.on_work_started();
+  }
+
+  template <typename OtherExecutor>
+  handler_work_base(const Executor& ex,
+      const OtherExecutor&) ASIO_NOEXCEPT
+    : executor_(ex),
+      owns_work_(true)
+  {
+    executor_.on_work_started();
+  }
+
+  handler_work_base(const handler_work_base& other) ASIO_NOEXCEPT
+    : executor_(other.executor_),
+      owns_work_(other.owns_work_)
+  {
+    if (owns_work_)
+      executor_.on_work_started();
+  }
+
+#if defined(ASIO_HAS_MOVE)
+  handler_work_base(handler_work_base&& other) ASIO_NOEXCEPT
+    : executor_(ASIO_MOVE_CAST(Executor)(other.executor_)),
+      owns_work_(other.owns_work_)
+  {
+    other.owns_work_ = false;
+  }
+#endif // defined(ASIO_HAS_MOVE)
+
+  ~handler_work_base()
+  {
+    if (owns_work_)
+      executor_.on_work_finished();
+  }
+
+  bool owns_work() const ASIO_NOEXCEPT
+  {
+    return owns_work_;
+  }
+
+  template <typename Function, typename Handler>
+  void dispatch(Function& function, Handler& handler)
+  {
+    executor_.dispatch(ASIO_MOVE_CAST(Function)(function),
+        asio::get_associated_allocator(handler));
+  }
+
+private:
+  Executor executor_;
+  bool owns_work_;
+};
+
+template <typename Executor, typename IoContext, typename PolymorphicExecutor>
+class handler_work_base<Executor, void, IoContext, PolymorphicExecutor,
+    typename enable_if<
+      is_same<
+        Executor,
+        typename IoContext::executor_type
+      >::value
+    >::type>
+{
+public:
+  explicit handler_work_base(const Executor&)
+  {
+  }
+
+  bool owns_work() const ASIO_NOEXCEPT
+  {
+    return false;
+  }
+
+  template <typename Function, typename Handler>
+  void dispatch(Function& function, Handler& handler)
+  {
+    // When using a native implementation, I/O completion handlers are
+    // already dispatched according to the execution context's executor's
+    // rules. We can call the function directly.
+    asio_handler_invoke_helpers::invoke(function, handler);
+  }
+};
+
+template <typename Executor, typename IoContext>
+class handler_work_base<Executor, void, IoContext, Executor>
+{
+public:
+  explicit handler_work_base(const Executor& ex) ASIO_NOEXCEPT
+#if !defined(ASIO_NO_TYPEID)
+    : executor_(
+        ex.target_type() == typeid(typename IoContext::executor_type)
+          ? Executor() : ex)
+#else // !defined(ASIO_NO_TYPEID)
+    : executor_(ex)
+#endif // !defined(ASIO_NO_TYPEID)
+  {
+    if (executor_)
+      executor_.on_work_started();
+  }
+
+  handler_work_base(const Executor& ex,
+      const Executor& candidate) ASIO_NOEXCEPT
+    : executor_(ex != candidate ? ex : Executor())
+  {
+    if (executor_)
+      executor_.on_work_started();
+  }
+
+  template <typename OtherExecutor>
+  handler_work_base(const Executor& ex,
+      const OtherExecutor&) ASIO_NOEXCEPT
+    : executor_(ex)
+  {
+    executor_.on_work_started();
+  }
+
+  handler_work_base(const handler_work_base& other) ASIO_NOEXCEPT
+    : executor_(other.executor_)
+  {
+    if (executor_)
+      executor_.on_work_started();
+  }
+
+#if defined(ASIO_HAS_MOVE)
+  handler_work_base(handler_work_base&& other) ASIO_NOEXCEPT
+    : executor_(ASIO_MOVE_CAST(Executor)(other.executor_))
+  {
+  }
+#endif // defined(ASIO_HAS_MOVE)
+
+  ~handler_work_base()
+  {
+    if (executor_)
+      executor_.on_work_finished();
+  }
+
+  bool owns_work() const ASIO_NOEXCEPT
+  {
+    return !!executor_;
+  }
+
+  template <typename Function, typename Handler>
+  void dispatch(Function& function, Handler& handler)
+  {
+    executor_.dispatch(ASIO_MOVE_CAST(Function)(function),
+        asio::get_associated_allocator(handler));
+  }
+
+private:
+  Executor executor_;
+};
+
+template <
+#if defined(ASIO_HAS_VARIADIC_TEMPLATES)
+    typename... SupportableProperties,
+#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+    typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9,
+#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+    typename IoContext, typename PolymorphicExecutor>
+class handler_work_base<
+#if defined(ASIO_HAS_VARIADIC_TEMPLATES)
+    execution::any_executor<SupportableProperties...>,
+#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+    execution::any_executor<T1, T2, T3, T4, T5, T6, T7, T8, T9>,
+#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+    void, IoContext, PolymorphicExecutor>
+{
+public:
+  typedef
+#if defined(ASIO_HAS_VARIADIC_TEMPLATES)
+    execution::any_executor<SupportableProperties...>
+#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+    execution::any_executor<T1, T2, T3, T4, T5, T6, T7, T8, T9>
+#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+    executor_type;
+
+  explicit handler_work_base(const executor_type& ex) ASIO_NOEXCEPT
+#if !defined(ASIO_NO_TYPEID)
+    : executor_(
+        ex.target_type() == typeid(typename IoContext::executor_type)
+          ? executor_type()
+          : asio::prefer(ex, execution::outstanding_work.tracked))
+#else // !defined(ASIO_NO_TYPEID)
+    : executor_(asio::prefer(ex, execution::outstanding_work.tracked))
+#endif // !defined(ASIO_NO_TYPEID)
+  {
+  }
+
+  handler_work_base(const executor_type& ex,
+      const executor_type& candidate) ASIO_NOEXCEPT
+    : executor_(ex != candidate ? ex : executor_type())
+  {
+  }
+
+  template <typename OtherExecutor>
+  handler_work_base(const executor_type& ex,
+      const OtherExecutor&) ASIO_NOEXCEPT
+    : executor_(asio::prefer(ex, execution::outstanding_work.tracked))
+  {
+  }
+
+  handler_work_base(const handler_work_base& other) ASIO_NOEXCEPT
+    : executor_(other.executor_)
+  {
+  }
+
+#if defined(ASIO_HAS_MOVE)
+  handler_work_base(handler_work_base&& other) ASIO_NOEXCEPT
+    : executor_(ASIO_MOVE_CAST(executor_type)(other.executor_))
+  {
+  }
+#endif // defined(ASIO_HAS_MOVE)
+
+  bool owns_work() const ASIO_NOEXCEPT
+  {
+    return !!executor_;
+  }
+
+  template <typename Function, typename Handler>
+  void dispatch(Function& function, Handler& handler)
+  {
+    execution::execute(
+        asio::prefer(executor_,
+          execution::blocking.possibly,
+          execution::allocator((get_associated_allocator)(handler))),
+        ASIO_MOVE_CAST(Function)(function));
+  }
+
+private:
+  executor_type executor_;
+};
+
+template <typename Handler, typename IoExecutor, typename = void>
+class handler_work :
+  handler_work_base<IoExecutor>,
+  handler_work_base<typename associated_executor<
+      Handler, IoExecutor>::type, IoExecutor>
+{
+public:
+  typedef handler_work_base<IoExecutor> base1_type;
+  typedef handler_work_base<typename associated_executor<
+    Handler, IoExecutor>::type, IoExecutor> base2_type;
+
+  handler_work(Handler& handler, const IoExecutor& io_ex) ASIO_NOEXCEPT
+    : base1_type(io_ex),
+      base2_type(asio::get_associated_executor(handler, io_ex), io_ex)
+  {
+  }
+
+  template <typename Function>
+  void complete(Function& function, Handler& handler)
+  {
+    if (!base1_type::owns_work() && !base2_type::owns_work())
+    {
+      // When using a native implementation, I/O completion handlers are
+      // already dispatched according to the execution context's executor's
+      // rules. We can call the function directly.
+      asio_handler_invoke_helpers::invoke(function, handler);
+    }
+    else
+    {
+      base2_type::dispatch(function, handler);
+    }
+  }
+};
+
+template <typename Handler, typename IoExecutor>
+class handler_work<
+    Handler, IoExecutor,
+    typename enable_if<
+      is_same<
+        typename associated_executor<Handler,
+          IoExecutor>::asio_associated_executor_is_unspecialised,
+        void
+      >::value
+    >::type> : handler_work_base<IoExecutor>
+{
+public:
+  typedef handler_work_base<IoExecutor> base1_type;
+
+  handler_work(Handler&, const IoExecutor& io_ex) ASIO_NOEXCEPT
+    : base1_type(io_ex)
+  {
+  }
+
+  template <typename Function>
+  void complete(Function& function, Handler& handler)
+  {
+    if (!base1_type::owns_work())
+    {
+      // When using a native implementation, I/O completion handlers are
+      // already dispatched according to the execution context's executor's
+      // rules. We can call the function directly.
+      asio_handler_invoke_helpers::invoke(function, handler);
+    }
+    else
+    {
+      base1_type::dispatch(function, handler);
+    }
+  }
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_HANDLER_WORK_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/hash_map.hpp b/link/modules/asio-standalone/asio/include/asio/detail/hash_map.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/hash_map.hpp
@@ -0,0 +1,331 @@
+//
+// detail/hash_map.hpp
+// ~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_HASH_MAP_HPP
+#define ASIO_DETAIL_HASH_MAP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <list>
+#include <utility>
+#include "asio/detail/assert.hpp"
+#include "asio/detail/noncopyable.hpp"
+
+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+# include "asio/detail/socket_types.hpp"
+#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+inline std::size_t calculate_hash_value(int i)
+{
+  return static_cast<std::size_t>(i);
+}
+
+inline std::size_t calculate_hash_value(void* p)
+{
+  return reinterpret_cast<std::size_t>(p)
+    + (reinterpret_cast<std::size_t>(p) >> 3);
+}
+
+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+inline std::size_t calculate_hash_value(SOCKET s)
+{
+  return static_cast<std::size_t>(s);
+}
+#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+
+// Note: assumes K and V are POD types.
+template <typename K, typename V>
+class hash_map
+  : private noncopyable
+{
+public:
+  // The type of a value in the map.
+  typedef std::pair<K, V> value_type;
+
+  // The type of a non-const iterator over the hash map.
+  typedef typename std::list<value_type>::iterator iterator;
+
+  // The type of a const iterator over the hash map.
+  typedef typename std::list<value_type>::const_iterator const_iterator;
+
+  // Constructor.
+  hash_map()
+    : size_(0),
+      buckets_(0),
+      num_buckets_(0)
+  {
+  }
+
+  // Destructor.
+  ~hash_map()
+  {
+    delete[] buckets_;
+  }
+
+  // Get an iterator for the beginning of the map.
+  iterator begin()
+  {
+    return values_.begin();
+  }
+
+  // Get an iterator for the beginning of the map.
+  const_iterator begin() const
+  {
+    return values_.begin();
+  }
+
+  // Get an iterator for the end of the map.
+  iterator end()
+  {
+    return values_.end();
+  }
+
+  // Get an iterator for the end of the map.
+  const_iterator end() const
+  {
+    return values_.end();
+  }
+
+  // Check whether the map is empty.
+  bool empty() const
+  {
+    return values_.empty();
+  }
+
+  // Find an entry in the map.
+  iterator find(const K& k)
+  {
+    if (num_buckets_)
+    {
+      size_t bucket = calculate_hash_value(k) % num_buckets_;
+      iterator it = buckets_[bucket].first;
+      if (it == values_.end())
+        return values_.end();
+      iterator end_it = buckets_[bucket].last;
+      ++end_it;
+      while (it != end_it)
+      {
+        if (it->first == k)
+          return it;
+        ++it;
+      }
+    }
+    return values_.end();
+  }
+
+  // Find an entry in the map.
+  const_iterator find(const K& k) const
+  {
+    if (num_buckets_)
+    {
+      size_t bucket = calculate_hash_value(k) % num_buckets_;
+      const_iterator it = buckets_[bucket].first;
+      if (it == values_.end())
+        return it;
+      const_iterator end_it = buckets_[bucket].last;
+      ++end_it;
+      while (it != end_it)
+      {
+        if (it->first == k)
+          return it;
+        ++it;
+      }
+    }
+    return values_.end();
+  }
+
+  // Insert a new entry into the map.
+  std::pair<iterator, bool> insert(const value_type& v)
+  {
+    if (size_ + 1 >= num_buckets_)
+      rehash(hash_size(size_ + 1));
+    size_t bucket = calculate_hash_value(v.first) % num_buckets_;
+    iterator it = buckets_[bucket].first;
+    if (it == values_.end())
+    {
+      buckets_[bucket].first = buckets_[bucket].last =
+        values_insert(values_.end(), v);
+      ++size_;
+      return std::pair<iterator, bool>(buckets_[bucket].last, true);
+    }
+    iterator end_it = buckets_[bucket].last;
+    ++end_it;
+    while (it != end_it)
+    {
+      if (it->first == v.first)
+        return std::pair<iterator, bool>(it, false);
+      ++it;
+    }
+    buckets_[bucket].last = values_insert(end_it, v);
+    ++size_;
+    return std::pair<iterator, bool>(buckets_[bucket].last, true);
+  }
+
+  // Erase an entry from the map.
+  void erase(iterator it)
+  {
+    ASIO_ASSERT(it != values_.end());
+    ASIO_ASSERT(num_buckets_ != 0);
+
+    size_t bucket = calculate_hash_value(it->first) % num_buckets_;
+    bool is_first = (it == buckets_[bucket].first);
+    bool is_last = (it == buckets_[bucket].last);
+    if (is_first && is_last)
+      buckets_[bucket].first = buckets_[bucket].last = values_.end();
+    else if (is_first)
+      ++buckets_[bucket].first;
+    else if (is_last)
+      --buckets_[bucket].last;
+
+    values_erase(it);
+    --size_;
+  }
+
+  // Erase a key from the map.
+  void erase(const K& k)
+  {
+    iterator it = find(k);
+    if (it != values_.end())
+      erase(it);
+  }
+
+  // Remove all entries from the map.
+  void clear()
+  {
+    // Clear the values.
+    values_.clear();
+    size_ = 0;
+
+    // Initialise all buckets to empty.
+    iterator end_it = values_.end();
+    for (size_t i = 0; i < num_buckets_; ++i)
+      buckets_[i].first = buckets_[i].last = end_it;
+  }
+
+private:
+  // Calculate the hash size for the specified number of elements.
+  static std::size_t hash_size(std::size_t num_elems)
+  {
+    static std::size_t sizes[] =
+    {
+#if defined(ASIO_HASH_MAP_BUCKETS)
+      ASIO_HASH_MAP_BUCKETS
+#else // ASIO_HASH_MAP_BUCKETS
+      3, 13, 23, 53, 97, 193, 389, 769, 1543, 3079, 6151, 12289, 24593,
+      49157, 98317, 196613, 393241, 786433, 1572869, 3145739, 6291469,
+      12582917, 25165843
+#endif // ASIO_HASH_MAP_BUCKETS
+    };
+    const std::size_t nth_size = sizeof(sizes) / sizeof(std::size_t) - 1;
+    for (std::size_t i = 0; i < nth_size; ++i)
+      if (num_elems < sizes[i])
+        return sizes[i];
+    return sizes[nth_size];
+  }
+
+  // Re-initialise the hash from the values already contained in the list.
+  void rehash(std::size_t num_buckets)
+  {
+    if (num_buckets == num_buckets_)
+      return;
+    ASIO_ASSERT(num_buckets != 0);
+
+    iterator end_iter = values_.end();
+
+    // Update number of buckets and initialise all buckets to empty.
+    bucket_type* tmp = new bucket_type[num_buckets];
+    delete[] buckets_;
+    buckets_ = tmp;
+    num_buckets_ = num_buckets;
+    for (std::size_t i = 0; i < num_buckets_; ++i)
+      buckets_[i].first = buckets_[i].last = end_iter;
+
+    // Put all values back into the hash.
+    iterator iter = values_.begin();
+    while (iter != end_iter)
+    {
+      std::size_t bucket = calculate_hash_value(iter->first) % num_buckets_;
+      if (buckets_[bucket].last == end_iter)
+      {
+        buckets_[bucket].first = buckets_[bucket].last = iter++;
+      }
+      else if (++buckets_[bucket].last == iter)
+      {
+        ++iter;
+      }
+      else
+      {
+        values_.splice(buckets_[bucket].last, values_, iter++);
+        --buckets_[bucket].last;
+      }
+    }
+  }
+
+  // Insert an element into the values list by splicing from the spares list,
+  // if a spare is available, and otherwise by inserting a new element.
+  iterator values_insert(iterator it, const value_type& v)
+  {
+    if (spares_.empty())
+    {
+      return values_.insert(it, v);
+    }
+    else
+    {
+      spares_.front() = v;
+      values_.splice(it, spares_, spares_.begin());
+      return --it;
+    }
+  }
+
+  // Erase an element from the values list by splicing it to the spares list.
+  void values_erase(iterator it)
+  {
+    *it = value_type();
+    spares_.splice(spares_.begin(), values_, it);
+  }
+
+  // The number of elements in the hash.
+  std::size_t size_;
+
+  // The list of all values in the hash map.
+  std::list<value_type> values_;
+
+  // The list of spare nodes waiting to be recycled. Assumes that POD types only
+  // are stored in the hash map.
+  std::list<value_type> spares_;
+
+  // The type for a bucket in the hash table.
+  struct bucket_type
+  {
+    iterator first;
+    iterator last;
+  };
+
+  // The buckets in the hash.
+  bucket_type* buckets_;
+
+  // The number of buckets in the hash.
+  std::size_t num_buckets_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_HASH_MAP_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/impl/buffer_sequence_adapter.ipp b/link/modules/asio-standalone/asio/include/asio/detail/impl/buffer_sequence_adapter.ipp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/impl/buffer_sequence_adapter.ipp
@@ -0,0 +1,118 @@
+//
+// detail/impl/buffer_sequence_adapter.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_IMPL_BUFFER_SEQUENCE_ADAPTER_IPP
+#define ASIO_DETAIL_IMPL_BUFFER_SEQUENCE_ADAPTER_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_WINDOWS_RUNTIME)
+
+#include <robuffer.h>
+#include <windows.storage.streams.h>
+#include <wrl/implements.h>
+#include "asio/detail/buffer_sequence_adapter.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class winrt_buffer_impl :
+  public Microsoft::WRL::RuntimeClass<
+    Microsoft::WRL::RuntimeClassFlags<
+      Microsoft::WRL::RuntimeClassType::WinRtClassicComMix>,
+    ABI::Windows::Storage::Streams::IBuffer,
+    Windows::Storage::Streams::IBufferByteAccess>
+{
+public:
+  explicit winrt_buffer_impl(const asio::const_buffer& b)
+  {
+    bytes_ = const_cast<byte*>(static_cast<const byte*>(b.data()));
+    length_ = b.size();
+    capacity_ = b.size();
+  }
+
+  explicit winrt_buffer_impl(const asio::mutable_buffer& b)
+  {
+    bytes_ = static_cast<byte*>(b.data());
+    length_ = 0;
+    capacity_ = b.size();
+  }
+
+  ~winrt_buffer_impl()
+  {
+  }
+
+  STDMETHODIMP Buffer(byte** value)
+  {
+    *value = bytes_;
+    return S_OK;
+  }
+
+  STDMETHODIMP get_Capacity(UINT32* value)
+  {
+    *value = capacity_;
+    return S_OK;
+  }
+
+  STDMETHODIMP get_Length(UINT32 *value)
+  {
+    *value = length_;
+    return S_OK;
+  }
+
+  STDMETHODIMP put_Length(UINT32 value)
+  {
+    if (value > capacity_)
+      return E_INVALIDARG;
+    length_ = value;
+    return S_OK;
+  }
+
+private:
+  byte* bytes_;
+  UINT32 length_;
+  UINT32 capacity_;
+};
+
+void buffer_sequence_adapter_base::init_native_buffer(
+    buffer_sequence_adapter_base::native_buffer_type& buf,
+    const asio::mutable_buffer& buffer)
+{
+  std::memset(&buf, 0, sizeof(native_buffer_type));
+  Microsoft::WRL::ComPtr<IInspectable> insp
+    = Microsoft::WRL::Make<winrt_buffer_impl>(buffer);
+  buf = reinterpret_cast<Windows::Storage::Streams::IBuffer^>(insp.Get());
+}
+
+void buffer_sequence_adapter_base::init_native_buffer(
+    buffer_sequence_adapter_base::native_buffer_type& buf,
+    const asio::const_buffer& buffer)
+{
+  std::memset(&buf, 0, sizeof(native_buffer_type));
+  Microsoft::WRL::ComPtr<IInspectable> insp
+    = Microsoft::WRL::Make<winrt_buffer_impl>(buffer);
+  Platform::Object^ buf_obj = reinterpret_cast<Platform::Object^>(insp.Get());
+  buf = reinterpret_cast<Windows::Storage::Streams::IBuffer^>(insp.Get());
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_WINDOWS_RUNTIME)
+
+#endif // ASIO_DETAIL_IMPL_BUFFER_SEQUENCE_ADAPTER_IPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/impl/descriptor_ops.ipp b/link/modules/asio-standalone/asio/include/asio/detail/impl/descriptor_ops.ipp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/impl/descriptor_ops.ipp
@@ -0,0 +1,608 @@
+//
+// detail/impl/descriptor_ops.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_IMPL_DESCRIPTOR_OPS_IPP
+#define ASIO_DETAIL_IMPL_DESCRIPTOR_OPS_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <cerrno>
+#include "asio/detail/descriptor_ops.hpp"
+#include "asio/error.hpp"
+
+#if !defined(ASIO_WINDOWS) \
+  && !defined(ASIO_WINDOWS_RUNTIME) \
+  && !defined(__CYGWIN__)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+namespace descriptor_ops {
+
+int open(const char* path, int flags, asio::error_code& ec)
+{
+  int result = ::open(path, flags);
+  get_last_error(ec, result < 0);
+  return result;
+}
+
+int close(int d, state_type& state, asio::error_code& ec)
+{
+  int result = 0;
+  if (d != -1)
+  {
+    result = ::close(d);
+    get_last_error(ec, result < 0);
+
+    if (result != 0
+        && (ec == asio::error::would_block
+          || ec == asio::error::try_again))
+    {
+      // According to UNIX Network Programming Vol. 1, it is possible for
+      // close() to fail with EWOULDBLOCK under certain circumstances. What
+      // isn't clear is the state of the descriptor after this error. The one
+      // current OS where this behaviour is seen, Windows, says that the socket
+      // remains open. Therefore we'll put the descriptor back into blocking
+      // mode and have another attempt at closing it.
+#if defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__)
+      int flags = ::fcntl(d, F_GETFL, 0);
+      if (flags >= 0)
+        ::fcntl(d, F_SETFL, flags & ~O_NONBLOCK);
+#else // defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__)
+      ioctl_arg_type arg = 0;
+      ::ioctl(d, FIONBIO, &arg);
+#endif // defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__)
+      state &= ~non_blocking;
+
+      result = ::close(d);
+      get_last_error(ec, result < 0);
+    }
+  }
+
+  return result;
+}
+
+bool set_user_non_blocking(int d, state_type& state,
+    bool value, asio::error_code& ec)
+{
+  if (d == -1)
+  {
+    ec = asio::error::bad_descriptor;
+    return false;
+  }
+
+#if defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__)
+  int result = ::fcntl(d, F_GETFL, 0);
+  get_last_error(ec, result < 0);
+  if (result >= 0)
+  {
+    int flag = (value ? (result | O_NONBLOCK) : (result & ~O_NONBLOCK));
+    result = ::fcntl(d, F_SETFL, flag);
+    get_last_error(ec, result < 0);
+  }
+#else // defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__)
+  ioctl_arg_type arg = (value ? 1 : 0);
+  int result = ::ioctl(d, FIONBIO, &arg);
+  get_last_error(ec, result < 0);
+#endif // defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__)
+
+  if (result >= 0)
+  {
+    if (value)
+      state |= user_set_non_blocking;
+    else
+    {
+      // Clearing the user-set non-blocking mode always overrides any
+      // internally-set non-blocking flag. Any subsequent asynchronous
+      // operations will need to re-enable non-blocking I/O.
+      state &= ~(user_set_non_blocking | internal_non_blocking);
+    }
+    return true;
+  }
+
+  return false;
+}
+
+bool set_internal_non_blocking(int d, state_type& state,
+    bool value, asio::error_code& ec)
+{
+  if (d == -1)
+  {
+    ec = asio::error::bad_descriptor;
+    return false;
+  }
+
+  if (!value && (state & user_set_non_blocking))
+  {
+    // It does not make sense to clear the internal non-blocking flag if the
+    // user still wants non-blocking behaviour. Return an error and let the
+    // caller figure out whether to update the user-set non-blocking flag.
+    ec = asio::error::invalid_argument;
+    return false;
+  }
+
+#if defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__)
+  int result = ::fcntl(d, F_GETFL, 0);
+  get_last_error(ec, result < 0);
+  if (result >= 0)
+  {
+    int flag = (value ? (result | O_NONBLOCK) : (result & ~O_NONBLOCK));
+    result = ::fcntl(d, F_SETFL, flag);
+    get_last_error(ec, result < 0);
+  }
+#else // defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__)
+  ioctl_arg_type arg = (value ? 1 : 0);
+  int result = ::ioctl(d, FIONBIO, &arg);
+  get_last_error(ec, result < 0);
+#endif // defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__)
+
+  if (result >= 0)
+  {
+    if (value)
+      state |= internal_non_blocking;
+    else
+      state &= ~internal_non_blocking;
+    return true;
+  }
+
+  return false;
+}
+
+std::size_t sync_read(int d, state_type state, buf* bufs,
+    std::size_t count, bool all_empty, asio::error_code& ec)
+{
+  if (d == -1)
+  {
+    ec = asio::error::bad_descriptor;
+    return 0;
+  }
+
+  // A request to read 0 bytes on a stream is a no-op.
+  if (all_empty)
+  {
+    ec.assign(0, ec.category());
+    return 0;
+  }
+
+  // Read some data.
+  for (;;)
+  {
+    // Try to complete the operation without blocking.
+    signed_size_type bytes = ::readv(d, bufs, static_cast<int>(count));
+    get_last_error(ec, bytes < 0);
+
+    // Check if operation succeeded.
+    if (bytes > 0)
+      return bytes;
+
+    // Check for EOF.
+    if (bytes == 0)
+    {
+      ec = asio::error::eof;
+      return 0;
+    }
+
+    // Operation failed.
+    if ((state & user_set_non_blocking)
+        || (ec != asio::error::would_block
+          && ec != asio::error::try_again))
+      return 0;
+
+    // Wait for descriptor to become ready.
+    if (descriptor_ops::poll_read(d, 0, ec) < 0)
+      return 0;
+  }
+}
+
+std::size_t sync_read1(int d, state_type state, void* data,
+    std::size_t size, asio::error_code& ec)
+{
+  if (d == -1)
+  {
+    ec = asio::error::bad_descriptor;
+    return 0;
+  }
+
+  // A request to read 0 bytes on a stream is a no-op.
+  if (size == 0)
+  {
+    ec.assign(0, ec.category());
+    return 0;
+  }
+
+  // Read some data.
+  for (;;)
+  {
+    // Try to complete the operation without blocking.
+    signed_size_type bytes = ::read(d, data, size);
+    get_last_error(ec, bytes < 0);
+
+    // Check if operation succeeded.
+    if (bytes > 0)
+      return bytes;
+
+    // Check for EOF.
+    if (bytes == 0)
+    {
+      ec = asio::error::eof;
+      return 0;
+    }
+
+    // Operation failed.
+    if ((state & user_set_non_blocking)
+        || (ec != asio::error::would_block
+          && ec != asio::error::try_again))
+      return 0;
+
+    // Wait for descriptor to become ready.
+    if (descriptor_ops::poll_read(d, 0, ec) < 0)
+      return 0;
+  }
+}
+
+bool non_blocking_read(int d, buf* bufs, std::size_t count,
+    asio::error_code& ec, std::size_t& bytes_transferred)
+{
+  for (;;)
+  {
+    // Read some data.
+    signed_size_type bytes = ::readv(d, bufs, static_cast<int>(count));
+    get_last_error(ec, bytes < 0);
+
+    // Check for end of stream.
+    if (bytes == 0)
+    {
+      ec = asio::error::eof;
+      return true;
+    }
+
+    // Check if operation succeeded.
+    if (bytes > 0)
+    {
+      bytes_transferred = bytes;
+      return true;
+    }
+
+    // Retry operation if interrupted by signal.
+    if (ec == asio::error::interrupted)
+      continue;
+
+    // Check if we need to run the operation again.
+    if (ec == asio::error::would_block
+        || ec == asio::error::try_again)
+      return false;
+
+    // Operation failed.
+    bytes_transferred = 0;
+    return true;
+  }
+}
+
+bool non_blocking_read1(int d, void* data, std::size_t size,
+    asio::error_code& ec, std::size_t& bytes_transferred)
+{
+  for (;;)
+  {
+    // Read some data.
+    signed_size_type bytes = ::read(d, data, size);
+    get_last_error(ec, bytes < 0);
+
+    // Check for end of stream.
+    if (bytes == 0)
+    {
+      ec = asio::error::eof;
+      return true;
+    }
+
+    // Check if operation succeeded.
+    if (bytes > 0)
+    {
+      bytes_transferred = bytes;
+      return true;
+    }
+
+    // Retry operation if interrupted by signal.
+    if (ec == asio::error::interrupted)
+      continue;
+
+    // Check if we need to run the operation again.
+    if (ec == asio::error::would_block
+        || ec == asio::error::try_again)
+      return false;
+
+    // Operation failed.
+    bytes_transferred = 0;
+    return true;
+  }
+}
+
+std::size_t sync_write(int d, state_type state, const buf* bufs,
+    std::size_t count, bool all_empty, asio::error_code& ec)
+{
+  if (d == -1)
+  {
+    ec = asio::error::bad_descriptor;
+    return 0;
+  }
+
+  // A request to write 0 bytes on a stream is a no-op.
+  if (all_empty)
+  {
+    ec.assign(0, ec.category());
+    return 0;
+  }
+
+  // Write some data.
+  for (;;)
+  {
+    // Try to complete the operation without blocking.
+    signed_size_type bytes = ::writev(d, bufs, static_cast<int>(count));
+    get_last_error(ec, bytes < 0);
+
+    // Check if operation succeeded.
+    if (bytes > 0)
+      return bytes;
+
+    // Operation failed.
+    if ((state & user_set_non_blocking)
+        || (ec != asio::error::would_block
+          && ec != asio::error::try_again))
+      return 0;
+
+    // Wait for descriptor to become ready.
+    if (descriptor_ops::poll_write(d, 0, ec) < 0)
+      return 0;
+  }
+}
+
+std::size_t sync_write1(int d, state_type state, const void* data,
+    std::size_t size, asio::error_code& ec)
+{
+  if (d == -1)
+  {
+    ec = asio::error::bad_descriptor;
+    return 0;
+  }
+
+  // A request to write 0 bytes on a stream is a no-op.
+  if (size == 0)
+  {
+    ec.assign(0, ec.category());
+    return 0;
+  }
+
+  // Write some data.
+  for (;;)
+  {
+    // Try to complete the operation without blocking.
+    signed_size_type bytes = ::write(d, data, size);
+    get_last_error(ec, bytes < 0);
+
+    // Check if operation succeeded.
+    if (bytes > 0)
+      return bytes;
+
+    // Operation failed.
+    if ((state & user_set_non_blocking)
+        || (ec != asio::error::would_block
+          && ec != asio::error::try_again))
+      return 0;
+
+    // Wait for descriptor to become ready.
+    if (descriptor_ops::poll_write(d, 0, ec) < 0)
+      return 0;
+  }
+}
+
+bool non_blocking_write(int d, const buf* bufs, std::size_t count,
+    asio::error_code& ec, std::size_t& bytes_transferred)
+{
+  for (;;)
+  {
+    // Write some data.
+    signed_size_type bytes = ::writev(d, bufs, static_cast<int>(count));
+    get_last_error(ec, bytes < 0);
+
+    // Check if operation succeeded.
+    if (bytes >= 0)
+    {
+      bytes_transferred = bytes;
+      return true;
+    }
+
+    // Retry operation if interrupted by signal.
+    if (ec == asio::error::interrupted)
+      continue;
+
+    // Check if we need to run the operation again.
+    if (ec == asio::error::would_block
+        || ec == asio::error::try_again)
+      return false;
+
+    // Operation failed.
+    bytes_transferred = 0;
+    return true;
+  }
+}
+
+bool non_blocking_write1(int d, const void* data, std::size_t size,
+    asio::error_code& ec, std::size_t& bytes_transferred)
+{
+  for (;;)
+  {
+    // Write some data.
+    signed_size_type bytes = ::write(d, data, size);
+    get_last_error(ec, bytes < 0);
+
+    // Check if operation succeeded.
+    if (bytes >= 0)
+    {
+      bytes_transferred = bytes;
+      return true;
+    }
+
+    // Retry operation if interrupted by signal.
+    if (ec == asio::error::interrupted)
+      continue;
+
+    // Check if we need to run the operation again.
+    if (ec == asio::error::would_block
+        || ec == asio::error::try_again)
+      return false;
+
+    // Operation failed.
+    bytes_transferred = 0;
+    return true;
+  }
+}
+
+int ioctl(int d, state_type& state, long cmd,
+    ioctl_arg_type* arg, asio::error_code& ec)
+{
+  if (d == -1)
+  {
+    ec = asio::error::bad_descriptor;
+    return -1;
+  }
+
+  int result = ::ioctl(d, cmd, arg);
+  get_last_error(ec, result < 0);
+
+  if (result >= 0)
+  {
+    // When updating the non-blocking mode we always perform the ioctl syscall,
+    // even if the flags would otherwise indicate that the descriptor is
+    // already in the correct state. This ensures that the underlying
+    // descriptor is put into the state that has been requested by the user. If
+    // the ioctl syscall was successful then we need to update the flags to
+    // match.
+    if (cmd == static_cast<long>(FIONBIO))
+    {
+      if (*arg)
+      {
+        state |= user_set_non_blocking;
+      }
+      else
+      {
+        // Clearing the non-blocking mode always overrides any internally-set
+        // non-blocking flag. Any subsequent asynchronous operations will need
+        // to re-enable non-blocking I/O.
+        state &= ~(user_set_non_blocking | internal_non_blocking);
+      }
+    }
+  }
+
+  return result;
+}
+
+int fcntl(int d, int cmd, asio::error_code& ec)
+{
+  if (d == -1)
+  {
+    ec = asio::error::bad_descriptor;
+    return -1;
+  }
+
+  int result = ::fcntl(d, cmd);
+  get_last_error(ec, result < 0);
+  return result;
+}
+
+int fcntl(int d, int cmd, long arg, asio::error_code& ec)
+{
+  if (d == -1)
+  {
+    ec = asio::error::bad_descriptor;
+    return -1;
+  }
+
+  int result = ::fcntl(d, cmd, arg);
+  get_last_error(ec, result < 0);
+  return result;
+}
+
+int poll_read(int d, state_type state, asio::error_code& ec)
+{
+  if (d == -1)
+  {
+    ec = asio::error::bad_descriptor;
+    return -1;
+  }
+
+  pollfd fds;
+  fds.fd = d;
+  fds.events = POLLIN;
+  fds.revents = 0;
+  int timeout = (state & user_set_non_blocking) ? 0 : -1;
+  int result = ::poll(&fds, 1, timeout);
+  get_last_error(ec, result < 0);
+  if (result == 0)
+    if (state & user_set_non_blocking)
+      ec = asio::error::would_block;
+  return result;
+}
+
+int poll_write(int d, state_type state, asio::error_code& ec)
+{
+  if (d == -1)
+  {
+    ec = asio::error::bad_descriptor;
+    return -1;
+  }
+
+  pollfd fds;
+  fds.fd = d;
+  fds.events = POLLOUT;
+  fds.revents = 0;
+  int timeout = (state & user_set_non_blocking) ? 0 : -1;
+  int result = ::poll(&fds, 1, timeout);
+  get_last_error(ec, result < 0);
+  if (result == 0)
+    if (state & user_set_non_blocking)
+      ec = asio::error::would_block;
+  return result;
+}
+
+int poll_error(int d, state_type state, asio::error_code& ec)
+{
+  if (d == -1)
+  {
+    ec = asio::error::bad_descriptor;
+    return -1;
+  }
+
+  pollfd fds;
+  fds.fd = d;
+  fds.events = POLLPRI | POLLERR | POLLHUP;
+  fds.revents = 0;
+  int timeout = (state & user_set_non_blocking) ? 0 : -1;
+  int result = ::poll(&fds, 1, timeout);
+  get_last_error(ec, result < 0);
+  if (result == 0)
+    if (state & user_set_non_blocking)
+      ec = asio::error::would_block;
+  return result;
+}
+
+} // namespace descriptor_ops
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // !defined(ASIO_WINDOWS)
+       //   && !defined(ASIO_WINDOWS_RUNTIME)
+       //   && !defined(__CYGWIN__)
+
+#endif // ASIO_DETAIL_IMPL_DESCRIPTOR_OPS_IPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/impl/dev_poll_reactor.hpp b/link/modules/asio-standalone/asio/include/asio/detail/impl/dev_poll_reactor.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/impl/dev_poll_reactor.hpp
@@ -0,0 +1,91 @@
+//
+// detail/impl/dev_poll_reactor.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_IMPL_DEV_POLL_REACTOR_HPP
+#define ASIO_DETAIL_IMPL_DEV_POLL_REACTOR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_DEV_POLL)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Time_Traits>
+void dev_poll_reactor::add_timer_queue(timer_queue<Time_Traits>& queue)
+{
+  do_add_timer_queue(queue);
+}
+
+template <typename Time_Traits>
+void dev_poll_reactor::remove_timer_queue(timer_queue<Time_Traits>& queue)
+{
+  do_remove_timer_queue(queue);
+}
+
+template <typename Time_Traits>
+void dev_poll_reactor::schedule_timer(timer_queue<Time_Traits>& queue,
+    const typename Time_Traits::time_type& time,
+    typename timer_queue<Time_Traits>::per_timer_data& timer, wait_op* op)
+{
+  asio::detail::mutex::scoped_lock lock(mutex_);
+
+  if (shutdown_)
+  {
+    scheduler_.post_immediate_completion(op, false);
+    return;
+  }
+
+  bool earliest = queue.enqueue_timer(time, timer, op);
+  scheduler_.work_started();
+  if (earliest)
+    interrupter_.interrupt();
+}
+
+template <typename Time_Traits>
+std::size_t dev_poll_reactor::cancel_timer(timer_queue<Time_Traits>& queue,
+    typename timer_queue<Time_Traits>::per_timer_data& timer,
+    std::size_t max_cancelled)
+{
+  asio::detail::mutex::scoped_lock lock(mutex_);
+  op_queue<operation> ops;
+  std::size_t n = queue.cancel_timer(timer, ops, max_cancelled);
+  lock.unlock();
+  scheduler_.post_deferred_completions(ops);
+  return n;
+}
+
+template <typename Time_Traits>
+void dev_poll_reactor::move_timer(timer_queue<Time_Traits>& queue,
+    typename timer_queue<Time_Traits>::per_timer_data& target,
+    typename timer_queue<Time_Traits>::per_timer_data& source)
+{
+  asio::detail::mutex::scoped_lock lock(mutex_);
+  op_queue<operation> ops;
+  queue.cancel_timer(target, ops);
+  queue.move_timer(target, source);
+  lock.unlock();
+  scheduler_.post_deferred_completions(ops);
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_DEV_POLL)
+
+#endif // ASIO_DETAIL_IMPL_DEV_POLL_REACTOR_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/impl/dev_poll_reactor.ipp b/link/modules/asio-standalone/asio/include/asio/detail/impl/dev_poll_reactor.ipp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/impl/dev_poll_reactor.ipp
@@ -0,0 +1,446 @@
+//
+// detail/impl/dev_poll_reactor.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_IMPL_DEV_POLL_REACTOR_IPP
+#define ASIO_DETAIL_IMPL_DEV_POLL_REACTOR_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_DEV_POLL)
+
+#include "asio/detail/dev_poll_reactor.hpp"
+#include "asio/detail/assert.hpp"
+#include "asio/detail/throw_error.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+dev_poll_reactor::dev_poll_reactor(asio::execution_context& ctx)
+  : asio::detail::execution_context_service_base<dev_poll_reactor>(ctx),
+    scheduler_(use_service<scheduler>(ctx)),
+    mutex_(),
+    dev_poll_fd_(do_dev_poll_create()),
+    interrupter_(),
+    shutdown_(false)
+{
+  // Add the interrupter's descriptor to /dev/poll.
+  ::pollfd ev = { 0, 0, 0 };
+  ev.fd = interrupter_.read_descriptor();
+  ev.events = POLLIN | POLLERR;
+  ev.revents = 0;
+  ::write(dev_poll_fd_, &ev, sizeof(ev));
+}
+
+dev_poll_reactor::~dev_poll_reactor()
+{
+  shutdown();
+  ::close(dev_poll_fd_);
+}
+
+void dev_poll_reactor::shutdown()
+{
+  asio::detail::mutex::scoped_lock lock(mutex_);
+  shutdown_ = true;
+  lock.unlock();
+
+  op_queue<operation> ops;
+
+  for (int i = 0; i < max_ops; ++i)
+    op_queue_[i].get_all_operations(ops);
+
+  timer_queues_.get_all_timers(ops);
+
+  scheduler_.abandon_operations(ops);
+} 
+
+void dev_poll_reactor::notify_fork(
+    asio::execution_context::fork_event fork_ev)
+{
+  if (fork_ev == asio::execution_context::fork_child)
+  {
+    detail::mutex::scoped_lock lock(mutex_);
+
+    if (dev_poll_fd_ != -1)
+      ::close(dev_poll_fd_);
+    dev_poll_fd_ = -1;
+    dev_poll_fd_ = do_dev_poll_create();
+
+    interrupter_.recreate();
+
+    // Add the interrupter's descriptor to /dev/poll.
+    ::pollfd ev = { 0, 0, 0 };
+    ev.fd = interrupter_.read_descriptor();
+    ev.events = POLLIN | POLLERR;
+    ev.revents = 0;
+    ::write(dev_poll_fd_, &ev, sizeof(ev));
+
+    // Re-register all descriptors with /dev/poll. The changes will be written
+    // to the /dev/poll descriptor the next time the reactor is run.
+    for (int i = 0; i < max_ops; ++i)
+    {
+      reactor_op_queue<socket_type>::iterator iter = op_queue_[i].begin();
+      reactor_op_queue<socket_type>::iterator end = op_queue_[i].end();
+      for (; iter != end; ++iter)
+      {
+        ::pollfd& pending_ev = add_pending_event_change(iter->first);
+        pending_ev.events |= POLLERR | POLLHUP;
+        switch (i)
+        {
+        case read_op: pending_ev.events |= POLLIN; break;
+        case write_op: pending_ev.events |= POLLOUT; break;
+        case except_op: pending_ev.events |= POLLPRI; break;
+        default: break;
+        }
+      }
+    }
+    interrupter_.interrupt();
+  }
+}
+
+void dev_poll_reactor::init_task()
+{
+  scheduler_.init_task();
+}
+
+int dev_poll_reactor::register_descriptor(socket_type, per_descriptor_data&)
+{
+  return 0;
+}
+
+int dev_poll_reactor::register_internal_descriptor(int op_type,
+    socket_type descriptor, per_descriptor_data&, reactor_op* op)
+{
+  asio::detail::mutex::scoped_lock lock(mutex_);
+
+  op_queue_[op_type].enqueue_operation(descriptor, op);
+  ::pollfd& ev = add_pending_event_change(descriptor);
+  ev.events = POLLERR | POLLHUP;
+  switch (op_type)
+  {
+  case read_op: ev.events |= POLLIN; break;
+  case write_op: ev.events |= POLLOUT; break;
+  case except_op: ev.events |= POLLPRI; break;
+  default: break;
+  }
+  interrupter_.interrupt();
+
+  return 0;
+}
+
+void dev_poll_reactor::move_descriptor(socket_type,
+    dev_poll_reactor::per_descriptor_data&,
+    dev_poll_reactor::per_descriptor_data&)
+{
+}
+
+void dev_poll_reactor::start_op(int op_type, socket_type descriptor,
+    dev_poll_reactor::per_descriptor_data&, reactor_op* op,
+    bool is_continuation, bool allow_speculative)
+{
+  asio::detail::mutex::scoped_lock lock(mutex_);
+
+  if (shutdown_)
+  {
+    post_immediate_completion(op, is_continuation);
+    return;
+  }
+
+  if (allow_speculative)
+  {
+    if (op_type != read_op || !op_queue_[except_op].has_operation(descriptor))
+    {
+      if (!op_queue_[op_type].has_operation(descriptor))
+      {
+        if (op->perform())
+        {
+          lock.unlock();
+          scheduler_.post_immediate_completion(op, is_continuation);
+          return;
+        }
+      }
+    }
+  }
+
+  bool first = op_queue_[op_type].enqueue_operation(descriptor, op);
+  scheduler_.work_started();
+  if (first)
+  {
+    ::pollfd& ev = add_pending_event_change(descriptor);
+    ev.events = POLLERR | POLLHUP;
+    if (op_type == read_op
+        || op_queue_[read_op].has_operation(descriptor))
+      ev.events |= POLLIN;
+    if (op_type == write_op
+        || op_queue_[write_op].has_operation(descriptor))
+      ev.events |= POLLOUT;
+    if (op_type == except_op
+        || op_queue_[except_op].has_operation(descriptor))
+      ev.events |= POLLPRI;
+    interrupter_.interrupt();
+  }
+}
+
+void dev_poll_reactor::cancel_ops(socket_type descriptor,
+    dev_poll_reactor::per_descriptor_data&)
+{
+  asio::detail::mutex::scoped_lock lock(mutex_);
+  cancel_ops_unlocked(descriptor, asio::error::operation_aborted);
+}
+
+void dev_poll_reactor::deregister_descriptor(socket_type descriptor,
+    dev_poll_reactor::per_descriptor_data&, bool)
+{
+  asio::detail::mutex::scoped_lock lock(mutex_);
+
+  // Remove the descriptor from /dev/poll.
+  ::pollfd& ev = add_pending_event_change(descriptor);
+  ev.events = POLLREMOVE;
+  interrupter_.interrupt();
+
+  // Cancel any outstanding operations associated with the descriptor.
+  cancel_ops_unlocked(descriptor, asio::error::operation_aborted);
+}
+
+void dev_poll_reactor::deregister_internal_descriptor(
+    socket_type descriptor, dev_poll_reactor::per_descriptor_data&)
+{
+  asio::detail::mutex::scoped_lock lock(mutex_);
+
+  // Remove the descriptor from /dev/poll. Since this function is only called
+  // during a fork, we can apply the change immediately.
+  ::pollfd ev = { 0, 0, 0 };
+  ev.fd = descriptor;
+  ev.events = POLLREMOVE;
+  ev.revents = 0;
+  ::write(dev_poll_fd_, &ev, sizeof(ev));
+
+  // Destroy all operations associated with the descriptor.
+  op_queue<operation> ops;
+  asio::error_code ec;
+  for (int i = 0; i < max_ops; ++i)
+    op_queue_[i].cancel_operations(descriptor, ops, ec);
+}
+
+void dev_poll_reactor::cleanup_descriptor_data(
+    dev_poll_reactor::per_descriptor_data&)
+{
+}
+
+void dev_poll_reactor::run(long usec, op_queue<operation>& ops)
+{
+  asio::detail::mutex::scoped_lock lock(mutex_);
+
+  // We can return immediately if there's no work to do and the reactor is
+  // not supposed to block.
+  if (usec == 0 && op_queue_[read_op].empty() && op_queue_[write_op].empty()
+      && op_queue_[except_op].empty() && timer_queues_.all_empty())
+    return;
+
+  // Write the pending event registration changes to the /dev/poll descriptor.
+  std::size_t events_size = sizeof(::pollfd) * pending_event_changes_.size();
+  if (events_size > 0)
+  {
+    errno = 0;
+    int result = ::write(dev_poll_fd_,
+        &pending_event_changes_[0], events_size);
+    if (result != static_cast<int>(events_size))
+    {
+      asio::error_code ec = asio::error_code(
+          errno, asio::error::get_system_category());
+      for (std::size_t i = 0; i < pending_event_changes_.size(); ++i)
+      {
+        int descriptor = pending_event_changes_[i].fd;
+        for (int j = 0; j < max_ops; ++j)
+          op_queue_[j].cancel_operations(descriptor, ops, ec);
+      }
+    }
+    pending_event_changes_.clear();
+    pending_event_change_index_.clear();
+  }
+
+  // Calculate timeout.
+  int timeout;
+  if (usec == 0)
+    timeout = 0;
+  else
+  {
+    timeout = (usec < 0) ? -1 : ((usec - 1) / 1000 + 1);
+    timeout = get_timeout(timeout);
+  }
+  lock.unlock();
+
+  // Block on the /dev/poll descriptor.
+  ::pollfd events[128] = { { 0, 0, 0 } };
+  ::dvpoll dp = { 0, 0, 0 };
+  dp.dp_fds = events;
+  dp.dp_nfds = 128;
+  dp.dp_timeout = timeout;
+  int num_events = ::ioctl(dev_poll_fd_, DP_POLL, &dp);
+
+  lock.lock();
+
+  // Dispatch the waiting events.
+  for (int i = 0; i < num_events; ++i)
+  {
+    int descriptor = events[i].fd;
+    if (descriptor == interrupter_.read_descriptor())
+    {
+      interrupter_.reset();
+    }
+    else
+    {
+      bool more_reads = false;
+      bool more_writes = false;
+      bool more_except = false;
+
+      // Exception operations must be processed first to ensure that any
+      // out-of-band data is read before normal data.
+      if (events[i].events & (POLLPRI | POLLERR | POLLHUP))
+        more_except =
+          op_queue_[except_op].perform_operations(descriptor, ops);
+      else
+        more_except = op_queue_[except_op].has_operation(descriptor);
+
+      if (events[i].events & (POLLIN | POLLERR | POLLHUP))
+        more_reads = op_queue_[read_op].perform_operations(descriptor, ops);
+      else
+        more_reads = op_queue_[read_op].has_operation(descriptor);
+
+      if (events[i].events & (POLLOUT | POLLERR | POLLHUP))
+        more_writes = op_queue_[write_op].perform_operations(descriptor, ops);
+      else
+        more_writes = op_queue_[write_op].has_operation(descriptor);
+
+      if ((events[i].events & (POLLERR | POLLHUP)) != 0
+            && !more_except && !more_reads && !more_writes)
+      {
+        // If we have an event and no operations associated with the
+        // descriptor then we need to delete the descriptor from /dev/poll.
+        // The poll operation can produce POLLHUP or POLLERR events when there
+        // is no operation pending, so if we do not remove the descriptor we
+        // can end up in a tight polling loop.
+        ::pollfd ev = { 0, 0, 0 };
+        ev.fd = descriptor;
+        ev.events = POLLREMOVE;
+        ev.revents = 0;
+        ::write(dev_poll_fd_, &ev, sizeof(ev));
+      }
+      else
+      {
+        ::pollfd ev = { 0, 0, 0 };
+        ev.fd = descriptor;
+        ev.events = POLLERR | POLLHUP;
+        if (more_reads)
+          ev.events |= POLLIN;
+        if (more_writes)
+          ev.events |= POLLOUT;
+        if (more_except)
+          ev.events |= POLLPRI;
+        ev.revents = 0;
+        int result = ::write(dev_poll_fd_, &ev, sizeof(ev));
+        if (result != sizeof(ev))
+        {
+          asio::error_code ec(errno,
+              asio::error::get_system_category());
+          for (int j = 0; j < max_ops; ++j)
+            op_queue_[j].cancel_operations(descriptor, ops, ec);
+        }
+      }
+    }
+  }
+  timer_queues_.get_ready_timers(ops);
+}
+
+void dev_poll_reactor::interrupt()
+{
+  interrupter_.interrupt();
+}
+
+int dev_poll_reactor::do_dev_poll_create()
+{
+  int fd = ::open("/dev/poll", O_RDWR);
+  if (fd == -1)
+  {
+    asio::error_code ec(errno,
+        asio::error::get_system_category());
+    asio::detail::throw_error(ec, "/dev/poll");
+  }
+  return fd;
+}
+
+void dev_poll_reactor::do_add_timer_queue(timer_queue_base& queue)
+{
+  mutex::scoped_lock lock(mutex_);
+  timer_queues_.insert(&queue);
+}
+
+void dev_poll_reactor::do_remove_timer_queue(timer_queue_base& queue)
+{
+  mutex::scoped_lock lock(mutex_);
+  timer_queues_.erase(&queue);
+}
+
+int dev_poll_reactor::get_timeout(int msec)
+{
+  // By default we will wait no longer than 5 minutes. This will ensure that
+  // any changes to the system clock are detected after no longer than this.
+  const int max_msec = 5 * 60 * 1000;
+  return timer_queues_.wait_duration_msec(
+      (msec < 0 || max_msec < msec) ? max_msec : msec);
+}
+
+void dev_poll_reactor::cancel_ops_unlocked(socket_type descriptor,
+    const asio::error_code& ec)
+{
+  bool need_interrupt = false;
+  op_queue<operation> ops;
+  for (int i = 0; i < max_ops; ++i)
+    need_interrupt = op_queue_[i].cancel_operations(
+        descriptor, ops, ec) || need_interrupt;
+  scheduler_.post_deferred_completions(ops);
+  if (need_interrupt)
+    interrupter_.interrupt();
+}
+
+::pollfd& dev_poll_reactor::add_pending_event_change(int descriptor)
+{
+  hash_map<int, std::size_t>::iterator iter
+    = pending_event_change_index_.find(descriptor);
+  if (iter == pending_event_change_index_.end())
+  {
+    std::size_t index = pending_event_changes_.size();
+    pending_event_changes_.reserve(pending_event_changes_.size() + 1);
+    pending_event_change_index_.insert(std::make_pair(descriptor, index));
+    pending_event_changes_.push_back(::pollfd());
+    pending_event_changes_[index].fd = descriptor;
+    pending_event_changes_[index].revents = 0;
+    return pending_event_changes_[index];
+  }
+  else
+  {
+    return pending_event_changes_[iter->second];
+  }
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_DEV_POLL)
+
+#endif // ASIO_DETAIL_IMPL_DEV_POLL_REACTOR_IPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/impl/epoll_reactor.hpp b/link/modules/asio-standalone/asio/include/asio/detail/impl/epoll_reactor.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/impl/epoll_reactor.hpp
@@ -0,0 +1,89 @@
+//
+// detail/impl/epoll_reactor.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_IMPL_EPOLL_REACTOR_HPP
+#define ASIO_DETAIL_IMPL_EPOLL_REACTOR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#if defined(ASIO_HAS_EPOLL)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Time_Traits>
+void epoll_reactor::add_timer_queue(timer_queue<Time_Traits>& queue)
+{
+  do_add_timer_queue(queue);
+}
+
+template <typename Time_Traits>
+void epoll_reactor::remove_timer_queue(timer_queue<Time_Traits>& queue)
+{
+  do_remove_timer_queue(queue);
+}
+
+template <typename Time_Traits>
+void epoll_reactor::schedule_timer(timer_queue<Time_Traits>& queue,
+    const typename Time_Traits::time_type& time,
+    typename timer_queue<Time_Traits>::per_timer_data& timer, wait_op* op)
+{
+  mutex::scoped_lock lock(mutex_);
+
+  if (shutdown_)
+  {
+    scheduler_.post_immediate_completion(op, false);
+    return;
+  }
+
+  bool earliest = queue.enqueue_timer(time, timer, op);
+  scheduler_.work_started();
+  if (earliest)
+    update_timeout();
+}
+
+template <typename Time_Traits>
+std::size_t epoll_reactor::cancel_timer(timer_queue<Time_Traits>& queue,
+    typename timer_queue<Time_Traits>::per_timer_data& timer,
+    std::size_t max_cancelled)
+{
+  mutex::scoped_lock lock(mutex_);
+  op_queue<operation> ops;
+  std::size_t n = queue.cancel_timer(timer, ops, max_cancelled);
+  lock.unlock();
+  scheduler_.post_deferred_completions(ops);
+  return n;
+}
+
+template <typename Time_Traits>
+void epoll_reactor::move_timer(timer_queue<Time_Traits>& queue,
+    typename timer_queue<Time_Traits>::per_timer_data& target,
+    typename timer_queue<Time_Traits>::per_timer_data& source)
+{
+  mutex::scoped_lock lock(mutex_);
+  op_queue<operation> ops;
+  queue.cancel_timer(target, ops);
+  queue.move_timer(target, source);
+  lock.unlock();
+  scheduler_.post_deferred_completions(ops);
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_EPOLL)
+
+#endif // ASIO_DETAIL_IMPL_EPOLL_REACTOR_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/impl/epoll_reactor.ipp b/link/modules/asio-standalone/asio/include/asio/detail/impl/epoll_reactor.ipp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/impl/epoll_reactor.ipp
@@ -0,0 +1,787 @@
+//
+// detail/impl/epoll_reactor.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_IMPL_EPOLL_REACTOR_IPP
+#define ASIO_DETAIL_IMPL_EPOLL_REACTOR_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_EPOLL)
+
+#include <cstddef>
+#include <sys/epoll.h>
+#include "asio/detail/epoll_reactor.hpp"
+#include "asio/detail/throw_error.hpp"
+#include "asio/error.hpp"
+
+#if defined(ASIO_HAS_TIMERFD)
+# include <sys/timerfd.h>
+#endif // defined(ASIO_HAS_TIMERFD)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+epoll_reactor::epoll_reactor(asio::execution_context& ctx)
+  : execution_context_service_base<epoll_reactor>(ctx),
+    scheduler_(use_service<scheduler>(ctx)),
+    mutex_(ASIO_CONCURRENCY_HINT_IS_LOCKING(
+          REACTOR_REGISTRATION, scheduler_.concurrency_hint())),
+    interrupter_(),
+    epoll_fd_(do_epoll_create()),
+    timer_fd_(do_timerfd_create()),
+    shutdown_(false),
+    registered_descriptors_mutex_(mutex_.enabled())
+{
+  // Add the interrupter's descriptor to epoll.
+  epoll_event ev = { 0, { 0 } };
+  ev.events = EPOLLIN | EPOLLERR | EPOLLET;
+  ev.data.ptr = &interrupter_;
+  epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, interrupter_.read_descriptor(), &ev);
+  interrupter_.interrupt();
+
+  // Add the timer descriptor to epoll.
+  if (timer_fd_ != -1)
+  {
+    ev.events = EPOLLIN | EPOLLERR;
+    ev.data.ptr = &timer_fd_;
+    epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, timer_fd_, &ev);
+  }
+}
+
+epoll_reactor::~epoll_reactor()
+{
+  if (epoll_fd_ != -1)
+    close(epoll_fd_);
+  if (timer_fd_ != -1)
+    close(timer_fd_);
+}
+
+void epoll_reactor::shutdown()
+{
+  mutex::scoped_lock lock(mutex_);
+  shutdown_ = true;
+  lock.unlock();
+
+  op_queue<operation> ops;
+
+  while (descriptor_state* state = registered_descriptors_.first())
+  {
+    for (int i = 0; i < max_ops; ++i)
+      ops.push(state->op_queue_[i]);
+    state->shutdown_ = true;
+    registered_descriptors_.free(state);
+  }
+
+  timer_queues_.get_all_timers(ops);
+
+  scheduler_.abandon_operations(ops);
+}
+
+void epoll_reactor::notify_fork(
+    asio::execution_context::fork_event fork_ev)
+{
+  if (fork_ev == asio::execution_context::fork_child)
+  {
+    if (epoll_fd_ != -1)
+      ::close(epoll_fd_);
+    epoll_fd_ = -1;
+    epoll_fd_ = do_epoll_create();
+
+    if (timer_fd_ != -1)
+      ::close(timer_fd_);
+    timer_fd_ = -1;
+    timer_fd_ = do_timerfd_create();
+
+    interrupter_.recreate();
+
+    // Add the interrupter's descriptor to epoll.
+    epoll_event ev = { 0, { 0 } };
+    ev.events = EPOLLIN | EPOLLERR | EPOLLET;
+    ev.data.ptr = &interrupter_;
+    epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, interrupter_.read_descriptor(), &ev);
+    interrupter_.interrupt();
+
+    // Add the timer descriptor to epoll.
+    if (timer_fd_ != -1)
+    {
+      ev.events = EPOLLIN | EPOLLERR;
+      ev.data.ptr = &timer_fd_;
+      epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, timer_fd_, &ev);
+    }
+
+    update_timeout();
+
+    // Re-register all descriptors with epoll.
+    mutex::scoped_lock descriptors_lock(registered_descriptors_mutex_);
+    for (descriptor_state* state = registered_descriptors_.first();
+        state != 0; state = state->next_)
+    {
+      ev.events = state->registered_events_;
+      ev.data.ptr = state;
+      int result = epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, state->descriptor_, &ev);
+      if (result != 0)
+      {
+        asio::error_code ec(errno,
+            asio::error::get_system_category());
+        asio::detail::throw_error(ec, "epoll re-registration");
+      }
+    }
+  }
+}
+
+void epoll_reactor::init_task()
+{
+  scheduler_.init_task();
+}
+
+int epoll_reactor::register_descriptor(socket_type descriptor,
+    epoll_reactor::per_descriptor_data& descriptor_data)
+{
+  descriptor_data = allocate_descriptor_state();
+
+  ASIO_HANDLER_REACTOR_REGISTRATION((
+        context(), static_cast<uintmax_t>(descriptor),
+        reinterpret_cast<uintmax_t>(descriptor_data)));
+
+  {
+    mutex::scoped_lock descriptor_lock(descriptor_data->mutex_);
+
+    descriptor_data->reactor_ = this;
+    descriptor_data->descriptor_ = descriptor;
+    descriptor_data->shutdown_ = false;
+    for (int i = 0; i < max_ops; ++i)
+      descriptor_data->try_speculative_[i] = true;
+  }
+
+  epoll_event ev = { 0, { 0 } };
+  ev.events = EPOLLIN | EPOLLERR | EPOLLHUP | EPOLLPRI | EPOLLET;
+  descriptor_data->registered_events_ = ev.events;
+  ev.data.ptr = descriptor_data;
+  int result = epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, descriptor, &ev);
+  if (result != 0)
+  {
+    if (errno == EPERM)
+    {
+      // This file descriptor type is not supported by epoll. However, if it is
+      // a regular file then operations on it will not block. We will allow
+      // this descriptor to be used and fail later if an operation on it would
+      // otherwise require a trip through the reactor.
+      descriptor_data->registered_events_ = 0;
+      return 0;
+    }
+    return errno;
+  }
+
+  return 0;
+}
+
+int epoll_reactor::register_internal_descriptor(
+    int op_type, socket_type descriptor,
+    epoll_reactor::per_descriptor_data& descriptor_data, reactor_op* op)
+{
+  descriptor_data = allocate_descriptor_state();
+
+  ASIO_HANDLER_REACTOR_REGISTRATION((
+        context(), static_cast<uintmax_t>(descriptor),
+        reinterpret_cast<uintmax_t>(descriptor_data)));
+
+  {
+    mutex::scoped_lock descriptor_lock(descriptor_data->mutex_);
+
+    descriptor_data->reactor_ = this;
+    descriptor_data->descriptor_ = descriptor;
+    descriptor_data->shutdown_ = false;
+    descriptor_data->op_queue_[op_type].push(op);
+    for (int i = 0; i < max_ops; ++i)
+      descriptor_data->try_speculative_[i] = true;
+  }
+
+  epoll_event ev = { 0, { 0 } };
+  ev.events = EPOLLIN | EPOLLERR | EPOLLHUP | EPOLLPRI | EPOLLET;
+  descriptor_data->registered_events_ = ev.events;
+  ev.data.ptr = descriptor_data;
+  int result = epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, descriptor, &ev);
+  if (result != 0)
+    return errno;
+
+  return 0;
+}
+
+void epoll_reactor::move_descriptor(socket_type,
+    epoll_reactor::per_descriptor_data& target_descriptor_data,
+    epoll_reactor::per_descriptor_data& source_descriptor_data)
+{
+  target_descriptor_data = source_descriptor_data;
+  source_descriptor_data = 0;
+}
+
+void epoll_reactor::start_op(int op_type, socket_type descriptor,
+    epoll_reactor::per_descriptor_data& descriptor_data, reactor_op* op,
+    bool is_continuation, bool allow_speculative)
+{
+  if (!descriptor_data)
+  {
+    op->ec_ = asio::error::bad_descriptor;
+    post_immediate_completion(op, is_continuation);
+    return;
+  }
+
+  mutex::scoped_lock descriptor_lock(descriptor_data->mutex_);
+
+  if (descriptor_data->shutdown_)
+  {
+    post_immediate_completion(op, is_continuation);
+    return;
+  }
+
+  if (descriptor_data->op_queue_[op_type].empty())
+  {
+    if (allow_speculative
+        && (op_type != read_op
+          || descriptor_data->op_queue_[except_op].empty()))
+    {
+      if (descriptor_data->try_speculative_[op_type])
+      {
+        if (reactor_op::status status = op->perform())
+        {
+          if (status == reactor_op::done_and_exhausted)
+            if (descriptor_data->registered_events_ != 0)
+              descriptor_data->try_speculative_[op_type] = false;
+          descriptor_lock.unlock();
+          scheduler_.post_immediate_completion(op, is_continuation);
+          return;
+        }
+      }
+
+      if (descriptor_data->registered_events_ == 0)
+      {
+        op->ec_ = asio::error::operation_not_supported;
+        scheduler_.post_immediate_completion(op, is_continuation);
+        return;
+      }
+
+      if (op_type == write_op)
+      {
+        if ((descriptor_data->registered_events_ & EPOLLOUT) == 0)
+        {
+          epoll_event ev = { 0, { 0 } };
+          ev.events = descriptor_data->registered_events_ | EPOLLOUT;
+          ev.data.ptr = descriptor_data;
+          if (epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, descriptor, &ev) == 0)
+          {
+            descriptor_data->registered_events_ |= ev.events;
+          }
+          else
+          {
+            op->ec_ = asio::error_code(errno,
+                asio::error::get_system_category());
+            scheduler_.post_immediate_completion(op, is_continuation);
+            return;
+          }
+        }
+      }
+    }
+    else if (descriptor_data->registered_events_ == 0)
+    {
+      op->ec_ = asio::error::operation_not_supported;
+      scheduler_.post_immediate_completion(op, is_continuation);
+      return;
+    }
+    else
+    {
+      if (op_type == write_op)
+      {
+        descriptor_data->registered_events_ |= EPOLLOUT;
+      }
+
+      epoll_event ev = { 0, { 0 } };
+      ev.events = descriptor_data->registered_events_;
+      ev.data.ptr = descriptor_data;
+      epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, descriptor, &ev);
+    }
+  }
+
+  descriptor_data->op_queue_[op_type].push(op);
+  scheduler_.work_started();
+}
+
+void epoll_reactor::cancel_ops(socket_type,
+    epoll_reactor::per_descriptor_data& descriptor_data)
+{
+  if (!descriptor_data)
+    return;
+
+  mutex::scoped_lock descriptor_lock(descriptor_data->mutex_);
+
+  op_queue<operation> ops;
+  for (int i = 0; i < max_ops; ++i)
+  {
+    while (reactor_op* op = descriptor_data->op_queue_[i].front())
+    {
+      op->ec_ = asio::error::operation_aborted;
+      descriptor_data->op_queue_[i].pop();
+      ops.push(op);
+    }
+  }
+
+  descriptor_lock.unlock();
+
+  scheduler_.post_deferred_completions(ops);
+}
+
+void epoll_reactor::deregister_descriptor(socket_type descriptor,
+    epoll_reactor::per_descriptor_data& descriptor_data, bool closing)
+{
+  if (!descriptor_data)
+    return;
+
+  mutex::scoped_lock descriptor_lock(descriptor_data->mutex_);
+
+  if (!descriptor_data->shutdown_)
+  {
+    if (closing)
+    {
+      // The descriptor will be automatically removed from the epoll set when
+      // it is closed.
+    }
+    else if (descriptor_data->registered_events_ != 0)
+    {
+      epoll_event ev = { 0, { 0 } };
+      epoll_ctl(epoll_fd_, EPOLL_CTL_DEL, descriptor, &ev);
+    }
+
+    op_queue<operation> ops;
+    for (int i = 0; i < max_ops; ++i)
+    {
+      while (reactor_op* op = descriptor_data->op_queue_[i].front())
+      {
+        op->ec_ = asio::error::operation_aborted;
+        descriptor_data->op_queue_[i].pop();
+        ops.push(op);
+      }
+    }
+
+    descriptor_data->descriptor_ = -1;
+    descriptor_data->shutdown_ = true;
+
+    descriptor_lock.unlock();
+
+    ASIO_HANDLER_REACTOR_DEREGISTRATION((
+          context(), static_cast<uintmax_t>(descriptor),
+          reinterpret_cast<uintmax_t>(descriptor_data)));
+
+    scheduler_.post_deferred_completions(ops);
+
+    // Leave descriptor_data set so that it will be freed by the subsequent
+    // call to cleanup_descriptor_data.
+  }
+  else
+  {
+    // We are shutting down, so prevent cleanup_descriptor_data from freeing
+    // the descriptor_data object and let the destructor free it instead.
+    descriptor_data = 0;
+  }
+}
+
+void epoll_reactor::deregister_internal_descriptor(socket_type descriptor,
+    epoll_reactor::per_descriptor_data& descriptor_data)
+{
+  if (!descriptor_data)
+    return;
+
+  mutex::scoped_lock descriptor_lock(descriptor_data->mutex_);
+
+  if (!descriptor_data->shutdown_)
+  {
+    epoll_event ev = { 0, { 0 } };
+    epoll_ctl(epoll_fd_, EPOLL_CTL_DEL, descriptor, &ev);
+
+    op_queue<operation> ops;
+    for (int i = 0; i < max_ops; ++i)
+      ops.push(descriptor_data->op_queue_[i]);
+
+    descriptor_data->descriptor_ = -1;
+    descriptor_data->shutdown_ = true;
+
+    descriptor_lock.unlock();
+
+    ASIO_HANDLER_REACTOR_DEREGISTRATION((
+          context(), static_cast<uintmax_t>(descriptor),
+          reinterpret_cast<uintmax_t>(descriptor_data)));
+
+    // Leave descriptor_data set so that it will be freed by the subsequent
+    // call to cleanup_descriptor_data.
+  }
+  else
+  {
+    // We are shutting down, so prevent cleanup_descriptor_data from freeing
+    // the descriptor_data object and let the destructor free it instead.
+    descriptor_data = 0;
+  }
+}
+
+void epoll_reactor::cleanup_descriptor_data(
+    per_descriptor_data& descriptor_data)
+{
+  if (descriptor_data)
+  {
+    free_descriptor_state(descriptor_data);
+    descriptor_data = 0;
+  }
+}
+
+void epoll_reactor::run(long usec, op_queue<operation>& ops)
+{
+  // This code relies on the fact that the scheduler queues the reactor task
+  // behind all descriptor operations generated by this function. This means,
+  // that by the time we reach this point, any previously returned descriptor
+  // operations have already been dequeued. Therefore it is now safe for us to
+  // reuse and return them for the scheduler to queue again.
+
+  // Calculate timeout. Check the timer queues only if timerfd is not in use.
+  int timeout;
+  if (usec == 0)
+    timeout = 0;
+  else
+  {
+    timeout = (usec < 0) ? -1 : ((usec - 1) / 1000 + 1);
+    if (timer_fd_ == -1)
+    {
+      mutex::scoped_lock lock(mutex_);
+      timeout = get_timeout(timeout);
+    }
+  }
+
+  // Block on the epoll descriptor.
+  epoll_event events[128];
+  int num_events = epoll_wait(epoll_fd_, events, 128, timeout);
+
+#if defined(ASIO_ENABLE_HANDLER_TRACKING)
+  // Trace the waiting events.
+  for (int i = 0; i < num_events; ++i)
+  {
+    void* ptr = events[i].data.ptr;
+    if (ptr == &interrupter_)
+    {
+      // Ignore.
+    }
+# if defined(ASIO_HAS_TIMERFD)
+    else if (ptr == &timer_fd_)
+    {
+      // Ignore.
+    }
+# endif // defined(ASIO_HAS_TIMERFD)
+    else
+    {
+      unsigned event_mask = 0;
+      if ((events[i].events & EPOLLIN) != 0)
+        event_mask |= ASIO_HANDLER_REACTOR_READ_EVENT;
+      if ((events[i].events & EPOLLOUT))
+        event_mask |= ASIO_HANDLER_REACTOR_WRITE_EVENT;
+      if ((events[i].events & (EPOLLERR | EPOLLHUP)) != 0)
+        event_mask |= ASIO_HANDLER_REACTOR_ERROR_EVENT;
+      ASIO_HANDLER_REACTOR_EVENTS((context(),
+            reinterpret_cast<uintmax_t>(ptr), event_mask));
+    }
+  }
+#endif // defined(ASIO_ENABLE_HANDLER_TRACKING)
+
+#if defined(ASIO_HAS_TIMERFD)
+  bool check_timers = (timer_fd_ == -1);
+#else // defined(ASIO_HAS_TIMERFD)
+  bool check_timers = true;
+#endif // defined(ASIO_HAS_TIMERFD)
+
+  // Dispatch the waiting events.
+  for (int i = 0; i < num_events; ++i)
+  {
+    void* ptr = events[i].data.ptr;
+    if (ptr == &interrupter_)
+    {
+      // No need to reset the interrupter since we're leaving the descriptor
+      // in a ready-to-read state and relying on edge-triggered notifications
+      // to make it so that we only get woken up when the descriptor's epoll
+      // registration is updated.
+
+#if defined(ASIO_HAS_TIMERFD)
+      if (timer_fd_ == -1)
+        check_timers = true;
+#else // defined(ASIO_HAS_TIMERFD)
+      check_timers = true;
+#endif // defined(ASIO_HAS_TIMERFD)
+    }
+#if defined(ASIO_HAS_TIMERFD)
+    else if (ptr == &timer_fd_)
+    {
+      check_timers = true;
+    }
+#endif // defined(ASIO_HAS_TIMERFD)
+    else
+    {
+      // The descriptor operation doesn't count as work in and of itself, so we
+      // don't call work_started() here. This still allows the scheduler to
+      // stop if the only remaining operations are descriptor operations.
+      descriptor_state* descriptor_data = static_cast<descriptor_state*>(ptr);
+      if (!ops.is_enqueued(descriptor_data))
+      {
+        descriptor_data->set_ready_events(events[i].events);
+        ops.push(descriptor_data);
+      }
+      else
+      {
+        descriptor_data->add_ready_events(events[i].events);
+      }
+    }
+  }
+
+  if (check_timers)
+  {
+    mutex::scoped_lock common_lock(mutex_);
+    timer_queues_.get_ready_timers(ops);
+
+#if defined(ASIO_HAS_TIMERFD)
+    if (timer_fd_ != -1)
+    {
+      itimerspec new_timeout;
+      itimerspec old_timeout;
+      int flags = get_timeout(new_timeout);
+      timerfd_settime(timer_fd_, flags, &new_timeout, &old_timeout);
+    }
+#endif // defined(ASIO_HAS_TIMERFD)
+  }
+}
+
+void epoll_reactor::interrupt()
+{
+  epoll_event ev = { 0, { 0 } };
+  ev.events = EPOLLIN | EPOLLERR | EPOLLET;
+  ev.data.ptr = &interrupter_;
+  epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, interrupter_.read_descriptor(), &ev);
+}
+
+int epoll_reactor::do_epoll_create()
+{
+#if defined(EPOLL_CLOEXEC)
+  int fd = epoll_create1(EPOLL_CLOEXEC);
+#else // defined(EPOLL_CLOEXEC)
+  int fd = -1;
+  errno = EINVAL;
+#endif // defined(EPOLL_CLOEXEC)
+
+  if (fd == -1 && (errno == EINVAL || errno == ENOSYS))
+  {
+    fd = epoll_create(epoll_size);
+    if (fd != -1)
+      ::fcntl(fd, F_SETFD, FD_CLOEXEC);
+  }
+
+  if (fd == -1)
+  {
+    asio::error_code ec(errno,
+        asio::error::get_system_category());
+    asio::detail::throw_error(ec, "epoll");
+  }
+
+  return fd;
+}
+
+int epoll_reactor::do_timerfd_create()
+{
+#if defined(ASIO_HAS_TIMERFD)
+# if defined(TFD_CLOEXEC)
+  int fd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC);
+# else // defined(TFD_CLOEXEC)
+  int fd = -1;
+  errno = EINVAL;
+# endif // defined(TFD_CLOEXEC)
+
+  if (fd == -1 && errno == EINVAL)
+  {
+    fd = timerfd_create(CLOCK_MONOTONIC, 0);
+    if (fd != -1)
+      ::fcntl(fd, F_SETFD, FD_CLOEXEC);
+  }
+
+  return fd;
+#else // defined(ASIO_HAS_TIMERFD)
+  return -1;
+#endif // defined(ASIO_HAS_TIMERFD)
+}
+
+epoll_reactor::descriptor_state* epoll_reactor::allocate_descriptor_state()
+{
+  mutex::scoped_lock descriptors_lock(registered_descriptors_mutex_);
+  return registered_descriptors_.alloc(ASIO_CONCURRENCY_HINT_IS_LOCKING(
+        REACTOR_IO, scheduler_.concurrency_hint()));
+}
+
+void epoll_reactor::free_descriptor_state(epoll_reactor::descriptor_state* s)
+{
+  mutex::scoped_lock descriptors_lock(registered_descriptors_mutex_);
+  registered_descriptors_.free(s);
+}
+
+void epoll_reactor::do_add_timer_queue(timer_queue_base& queue)
+{
+  mutex::scoped_lock lock(mutex_);
+  timer_queues_.insert(&queue);
+}
+
+void epoll_reactor::do_remove_timer_queue(timer_queue_base& queue)
+{
+  mutex::scoped_lock lock(mutex_);
+  timer_queues_.erase(&queue);
+}
+
+void epoll_reactor::update_timeout()
+{
+#if defined(ASIO_HAS_TIMERFD)
+  if (timer_fd_ != -1)
+  {
+    itimerspec new_timeout;
+    itimerspec old_timeout;
+    int flags = get_timeout(new_timeout);
+    timerfd_settime(timer_fd_, flags, &new_timeout, &old_timeout);
+    return;
+  }
+#endif // defined(ASIO_HAS_TIMERFD)
+  interrupt();
+}
+
+int epoll_reactor::get_timeout(int msec)
+{
+  // By default we will wait no longer than 5 minutes. This will ensure that
+  // any changes to the system clock are detected after no longer than this.
+  const int max_msec = 5 * 60 * 1000;
+  return timer_queues_.wait_duration_msec(
+      (msec < 0 || max_msec < msec) ? max_msec : msec);
+}
+
+#if defined(ASIO_HAS_TIMERFD)
+int epoll_reactor::get_timeout(itimerspec& ts)
+{
+  ts.it_interval.tv_sec = 0;
+  ts.it_interval.tv_nsec = 0;
+
+  long usec = timer_queues_.wait_duration_usec(5 * 60 * 1000 * 1000);
+  ts.it_value.tv_sec = usec / 1000000;
+  ts.it_value.tv_nsec = usec ? (usec % 1000000) * 1000 : 1;
+
+  return usec ? 0 : TFD_TIMER_ABSTIME;
+}
+#endif // defined(ASIO_HAS_TIMERFD)
+
+struct epoll_reactor::perform_io_cleanup_on_block_exit
+{
+  explicit perform_io_cleanup_on_block_exit(epoll_reactor* r)
+    : reactor_(r), first_op_(0)
+  {
+  }
+
+  ~perform_io_cleanup_on_block_exit()
+  {
+    if (first_op_)
+    {
+      // Post the remaining completed operations for invocation.
+      if (!ops_.empty())
+        reactor_->scheduler_.post_deferred_completions(ops_);
+
+      // A user-initiated operation has completed, but there's no need to
+      // explicitly call work_finished() here. Instead, we'll take advantage of
+      // the fact that the scheduler will call work_finished() once we return.
+    }
+    else
+    {
+      // No user-initiated operations have completed, so we need to compensate
+      // for the work_finished() call that the scheduler will make once this
+      // operation returns.
+      reactor_->scheduler_.compensating_work_started();
+    }
+  }
+
+  epoll_reactor* reactor_;
+  op_queue<operation> ops_;
+  operation* first_op_;
+};
+
+epoll_reactor::descriptor_state::descriptor_state(bool locking)
+  : operation(&epoll_reactor::descriptor_state::do_complete),
+    mutex_(locking)
+{
+}
+
+operation* epoll_reactor::descriptor_state::perform_io(uint32_t events)
+{
+  mutex_.lock();
+  perform_io_cleanup_on_block_exit io_cleanup(reactor_);
+  mutex::scoped_lock descriptor_lock(mutex_, mutex::scoped_lock::adopt_lock);
+
+  // Exception operations must be processed first to ensure that any
+  // out-of-band data is read before normal data.
+  static const int flag[max_ops] = { EPOLLIN, EPOLLOUT, EPOLLPRI };
+  for (int j = max_ops - 1; j >= 0; --j)
+  {
+    if (events & (flag[j] | EPOLLERR | EPOLLHUP))
+    {
+      try_speculative_[j] = true;
+      while (reactor_op* op = op_queue_[j].front())
+      {
+        if (reactor_op::status status = op->perform())
+        {
+          op_queue_[j].pop();
+          io_cleanup.ops_.push(op);
+          if (status == reactor_op::done_and_exhausted)
+          {
+            try_speculative_[j] = false;
+            break;
+          }
+        }
+        else
+          break;
+      }
+    }
+  }
+
+  // The first operation will be returned for completion now. The others will
+  // be posted for later by the io_cleanup object's destructor.
+  io_cleanup.first_op_ = io_cleanup.ops_.front();
+  io_cleanup.ops_.pop();
+  return io_cleanup.first_op_;
+}
+
+void epoll_reactor::descriptor_state::do_complete(
+    void* owner, operation* base,
+    const asio::error_code& ec, std::size_t bytes_transferred)
+{
+  if (owner)
+  {
+    descriptor_state* descriptor_data = static_cast<descriptor_state*>(base);
+    uint32_t events = static_cast<uint32_t>(bytes_transferred);
+    if (operation* op = descriptor_data->perform_io(events))
+    {
+      op->complete(owner, ec, 0);
+    }
+  }
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_EPOLL)
+
+#endif // ASIO_DETAIL_IMPL_EPOLL_REACTOR_IPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/impl/eventfd_select_interrupter.ipp b/link/modules/asio-standalone/asio/include/asio/detail/impl/eventfd_select_interrupter.ipp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/impl/eventfd_select_interrupter.ipp
@@ -0,0 +1,169 @@
+//
+// detail/impl/eventfd_select_interrupter.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2008 Roelof Naude (roelof.naude at gmail 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 ASIO_DETAIL_IMPL_EVENTFD_SELECT_INTERRUPTER_IPP
+#define ASIO_DETAIL_IMPL_EVENTFD_SELECT_INTERRUPTER_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_EVENTFD)
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#if __GLIBC__ == 2 && __GLIBC_MINOR__ < 8
+# include <asm/unistd.h>
+#else // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8
+# include <sys/eventfd.h>
+#endif // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8
+#include "asio/detail/cstdint.hpp"
+#include "asio/detail/eventfd_select_interrupter.hpp"
+#include "asio/detail/throw_error.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+eventfd_select_interrupter::eventfd_select_interrupter()
+{
+  open_descriptors();
+}
+
+void eventfd_select_interrupter::open_descriptors()
+{
+#if __GLIBC__ == 2 && __GLIBC_MINOR__ < 8
+  write_descriptor_ = read_descriptor_ = syscall(__NR_eventfd, 0);
+  if (read_descriptor_ != -1)
+  {
+    ::fcntl(read_descriptor_, F_SETFL, O_NONBLOCK);
+    ::fcntl(read_descriptor_, F_SETFD, FD_CLOEXEC);
+  }
+#else // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8
+# if defined(EFD_CLOEXEC) && defined(EFD_NONBLOCK)
+  write_descriptor_ = read_descriptor_ =
+    ::eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
+# else // defined(EFD_CLOEXEC) && defined(EFD_NONBLOCK)
+  errno = EINVAL;
+  write_descriptor_ = read_descriptor_ = -1;
+# endif // defined(EFD_CLOEXEC) && defined(EFD_NONBLOCK)
+  if (read_descriptor_ == -1 && errno == EINVAL)
+  {
+    write_descriptor_ = read_descriptor_ = ::eventfd(0, 0);
+    if (read_descriptor_ != -1)
+    {
+      ::fcntl(read_descriptor_, F_SETFL, O_NONBLOCK);
+      ::fcntl(read_descriptor_, F_SETFD, FD_CLOEXEC);
+    }
+  }
+#endif // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8
+
+  if (read_descriptor_ == -1)
+  {
+    int pipe_fds[2];
+    if (pipe(pipe_fds) == 0)
+    {
+      read_descriptor_ = pipe_fds[0];
+      ::fcntl(read_descriptor_, F_SETFL, O_NONBLOCK);
+      ::fcntl(read_descriptor_, F_SETFD, FD_CLOEXEC);
+      write_descriptor_ = pipe_fds[1];
+      ::fcntl(write_descriptor_, F_SETFL, O_NONBLOCK);
+      ::fcntl(write_descriptor_, F_SETFD, FD_CLOEXEC);
+    }
+    else
+    {
+      asio::error_code ec(errno,
+          asio::error::get_system_category());
+      asio::detail::throw_error(ec, "eventfd_select_interrupter");
+    }
+  }
+}
+
+eventfd_select_interrupter::~eventfd_select_interrupter()
+{
+  close_descriptors();
+}
+
+void eventfd_select_interrupter::close_descriptors()
+{
+  if (write_descriptor_ != -1 && write_descriptor_ != read_descriptor_)
+    ::close(write_descriptor_);
+  if (read_descriptor_ != -1)
+    ::close(read_descriptor_);
+}
+
+void eventfd_select_interrupter::recreate()
+{
+  close_descriptors();
+
+  write_descriptor_ = -1;
+  read_descriptor_ = -1;
+
+  open_descriptors();
+}
+
+void eventfd_select_interrupter::interrupt()
+{
+  uint64_t counter(1UL);
+  int result = ::write(write_descriptor_, &counter, sizeof(uint64_t));
+  (void)result;
+}
+
+bool eventfd_select_interrupter::reset()
+{
+  if (write_descriptor_ == read_descriptor_)
+  {
+    for (;;)
+    {
+      // Only perform one read. The kernel maintains an atomic counter.
+      uint64_t counter(0);
+      errno = 0;
+      int bytes_read = ::read(read_descriptor_, &counter, sizeof(uint64_t));
+      if (bytes_read < 0 && errno == EINTR)
+        continue;
+      return true;
+    }
+  }
+  else
+  {
+    for (;;)
+    {
+      // Clear all data from the pipe.
+      char data[1024];
+      int bytes_read = ::read(read_descriptor_, data, sizeof(data));
+      if (bytes_read == sizeof(data))
+        continue;
+      if (bytes_read > 0)
+        return true;
+      if (bytes_read == 0)
+        return false;
+      if (errno == EINTR)
+        continue;
+      if (errno == EWOULDBLOCK || errno == EAGAIN)
+        return true;
+      return false;
+    }
+  }
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_EVENTFD)
+
+#endif // ASIO_DETAIL_IMPL_EVENTFD_SELECT_INTERRUPTER_IPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/impl/handler_tracking.ipp b/link/modules/asio-standalone/asio/include/asio/detail/impl/handler_tracking.ipp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/impl/handler_tracking.ipp
@@ -0,0 +1,396 @@
+//
+// detail/impl/handler_tracking.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_IMPL_HANDLER_TRACKING_IPP
+#define ASIO_DETAIL_IMPL_HANDLER_TRACKING_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_CUSTOM_HANDLER_TRACKING)
+
+// The handler tracking implementation is provided by the user-specified header.
+
+#elif defined(ASIO_ENABLE_HANDLER_TRACKING)
+
+#include <cstdarg>
+#include <cstdio>
+#include "asio/detail/handler_tracking.hpp"
+
+#if defined(ASIO_HAS_BOOST_DATE_TIME)
+# include "asio/time_traits.hpp"
+#elif defined(ASIO_HAS_CHRONO)
+# include "asio/detail/chrono.hpp"
+# include "asio/detail/chrono_time_traits.hpp"
+# include "asio/wait_traits.hpp"
+#endif // defined(ASIO_HAS_BOOST_DATE_TIME)
+
+#if defined(ASIO_WINDOWS_RUNTIME)
+# include "asio/detail/socket_types.hpp"
+#elif !defined(ASIO_WINDOWS)
+# include <unistd.h>
+#endif // !defined(ASIO_WINDOWS)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+struct handler_tracking_timestamp
+{
+  uint64_t seconds;
+  uint64_t microseconds;
+
+  handler_tracking_timestamp()
+  {
+#if defined(ASIO_HAS_BOOST_DATE_TIME)
+    boost::posix_time::ptime epoch(boost::gregorian::date(1970, 1, 1));
+    boost::posix_time::time_duration now =
+      boost::posix_time::microsec_clock::universal_time() - epoch;
+#elif defined(ASIO_HAS_CHRONO)
+    typedef chrono_time_traits<chrono::system_clock,
+        asio::wait_traits<chrono::system_clock> > traits_helper;
+    traits_helper::posix_time_duration now(
+        chrono::system_clock::now().time_since_epoch());
+#endif
+    seconds = static_cast<uint64_t>(now.total_seconds());
+    microseconds = static_cast<uint64_t>(now.total_microseconds() % 1000000);
+  }
+};
+
+struct handler_tracking::tracking_state
+{
+  static_mutex mutex_;
+  uint64_t next_id_;
+  tss_ptr<completion>* current_completion_;
+  tss_ptr<location>* current_location_;
+};
+
+handler_tracking::tracking_state* handler_tracking::get_state()
+{
+  static tracking_state state = { ASIO_STATIC_MUTEX_INIT, 1, 0, 0 };
+  return &state;
+}
+
+void handler_tracking::init()
+{
+  static tracking_state* state = get_state();
+
+  state->mutex_.init();
+
+  static_mutex::scoped_lock lock(state->mutex_);
+  if (state->current_completion_ == 0)
+    state->current_completion_ = new tss_ptr<completion>;
+  if (state->current_location_ == 0)
+    state->current_location_ = new tss_ptr<location>;
+}
+
+handler_tracking::location::location(
+    const char* file, int line, const char* func)
+  : file_(file),
+    line_(line),
+    func_(func),
+    next_(*get_state()->current_location_)
+{
+  if (file_)
+    *get_state()->current_location_ = this;
+}
+
+handler_tracking::location::~location()
+{
+  if (file_)
+    *get_state()->current_location_ = next_;
+}
+
+void handler_tracking::creation(execution_context&,
+    handler_tracking::tracked_handler& h,
+    const char* object_type, void* object,
+    uintmax_t /*native_handle*/, const char* op_name)
+{
+  static tracking_state* state = get_state();
+
+  static_mutex::scoped_lock lock(state->mutex_);
+  h.id_ = state->next_id_++;
+  lock.unlock();
+
+  handler_tracking_timestamp timestamp;
+
+  uint64_t current_id = 0;
+  if (completion* current_completion = *state->current_completion_)
+    current_id = current_completion->id_;
+
+  for (location* current_location = *state->current_location_;
+      current_location; current_location = current_location->next_)
+  {
+    write_line(
+#if defined(ASIO_WINDOWS)
+        "@asio|%I64u.%06I64u|%I64u^%I64u|%s%s%.80s%s(%.80s:%d)\n",
+#else // defined(ASIO_WINDOWS)
+        "@asio|%llu.%06llu|%llu^%llu|%s%s%.80s%s(%.80s:%d)\n",
+#endif // defined(ASIO_WINDOWS)
+        timestamp.seconds, timestamp.microseconds,
+        current_id, h.id_,
+        current_location == *state->current_location_ ? "in " : "called from ",
+        current_location->func_ ? "'" : "",
+        current_location->func_ ? current_location->func_ : "",
+        current_location->func_ ? "' " : "",
+        current_location->file_, current_location->line_);
+  }
+
+  write_line(
+#if defined(ASIO_WINDOWS)
+      "@asio|%I64u.%06I64u|%I64u*%I64u|%.20s@%p.%.50s\n",
+#else // defined(ASIO_WINDOWS)
+      "@asio|%llu.%06llu|%llu*%llu|%.20s@%p.%.50s\n",
+#endif // defined(ASIO_WINDOWS)
+      timestamp.seconds, timestamp.microseconds,
+      current_id, h.id_, object_type, object, op_name);
+}
+
+handler_tracking::completion::completion(
+    const handler_tracking::tracked_handler& h)
+  : id_(h.id_),
+    invoked_(false),
+    next_(*get_state()->current_completion_)
+{
+  *get_state()->current_completion_ = this;
+}
+
+handler_tracking::completion::~completion()
+{
+  if (id_)
+  {
+    handler_tracking_timestamp timestamp;
+
+    write_line(
+#if defined(ASIO_WINDOWS)
+        "@asio|%I64u.%06I64u|%c%I64u|\n",
+#else // defined(ASIO_WINDOWS)
+        "@asio|%llu.%06llu|%c%llu|\n",
+#endif // defined(ASIO_WINDOWS)
+        timestamp.seconds, timestamp.microseconds,
+        invoked_ ? '!' : '~', id_);
+  }
+
+  *get_state()->current_completion_ = next_;
+}
+
+void handler_tracking::completion::invocation_begin()
+{
+  handler_tracking_timestamp timestamp;
+
+  write_line(
+#if defined(ASIO_WINDOWS)
+      "@asio|%I64u.%06I64u|>%I64u|\n",
+#else // defined(ASIO_WINDOWS)
+      "@asio|%llu.%06llu|>%llu|\n",
+#endif // defined(ASIO_WINDOWS)
+      timestamp.seconds, timestamp.microseconds, id_);
+
+  invoked_ = true;
+}
+
+void handler_tracking::completion::invocation_begin(
+    const asio::error_code& ec)
+{
+  handler_tracking_timestamp timestamp;
+
+  write_line(
+#if defined(ASIO_WINDOWS)
+      "@asio|%I64u.%06I64u|>%I64u|ec=%.20s:%d\n",
+#else // defined(ASIO_WINDOWS)
+      "@asio|%llu.%06llu|>%llu|ec=%.20s:%d\n",
+#endif // defined(ASIO_WINDOWS)
+      timestamp.seconds, timestamp.microseconds,
+      id_, ec.category().name(), ec.value());
+
+  invoked_ = true;
+}
+
+void handler_tracking::completion::invocation_begin(
+    const asio::error_code& ec, std::size_t bytes_transferred)
+{
+  handler_tracking_timestamp timestamp;
+
+  write_line(
+#if defined(ASIO_WINDOWS)
+      "@asio|%I64u.%06I64u|>%I64u|ec=%.20s:%d,bytes_transferred=%I64u\n",
+#else // defined(ASIO_WINDOWS)
+      "@asio|%llu.%06llu|>%llu|ec=%.20s:%d,bytes_transferred=%llu\n",
+#endif // defined(ASIO_WINDOWS)
+      timestamp.seconds, timestamp.microseconds,
+      id_, ec.category().name(), ec.value(),
+      static_cast<uint64_t>(bytes_transferred));
+
+  invoked_ = true;
+}
+
+void handler_tracking::completion::invocation_begin(
+    const asio::error_code& ec, int signal_number)
+{
+  handler_tracking_timestamp timestamp;
+
+  write_line(
+#if defined(ASIO_WINDOWS)
+      "@asio|%I64u.%06I64u|>%I64u|ec=%.20s:%d,signal_number=%d\n",
+#else // defined(ASIO_WINDOWS)
+      "@asio|%llu.%06llu|>%llu|ec=%.20s:%d,signal_number=%d\n",
+#endif // defined(ASIO_WINDOWS)
+      timestamp.seconds, timestamp.microseconds,
+      id_, ec.category().name(), ec.value(), signal_number);
+
+  invoked_ = true;
+}
+
+void handler_tracking::completion::invocation_begin(
+    const asio::error_code& ec, const char* arg)
+{
+  handler_tracking_timestamp timestamp;
+
+  write_line(
+#if defined(ASIO_WINDOWS)
+      "@asio|%I64u.%06I64u|>%I64u|ec=%.20s:%d,%.50s\n",
+#else // defined(ASIO_WINDOWS)
+      "@asio|%llu.%06llu|>%llu|ec=%.20s:%d,%.50s\n",
+#endif // defined(ASIO_WINDOWS)
+      timestamp.seconds, timestamp.microseconds,
+      id_, ec.category().name(), ec.value(), arg);
+
+  invoked_ = true;
+}
+
+void handler_tracking::completion::invocation_end()
+{
+  if (id_)
+  {
+    handler_tracking_timestamp timestamp;
+
+    write_line(
+#if defined(ASIO_WINDOWS)
+        "@asio|%I64u.%06I64u|<%I64u|\n",
+#else // defined(ASIO_WINDOWS)
+        "@asio|%llu.%06llu|<%llu|\n",
+#endif // defined(ASIO_WINDOWS)
+        timestamp.seconds, timestamp.microseconds, id_);
+
+    id_ = 0;
+  }
+}
+
+void handler_tracking::operation(execution_context&,
+    const char* object_type, void* object,
+    uintmax_t /*native_handle*/, const char* op_name)
+{
+  static tracking_state* state = get_state();
+
+  handler_tracking_timestamp timestamp;
+
+  unsigned long long current_id = 0;
+  if (completion* current_completion = *state->current_completion_)
+    current_id = current_completion->id_;
+
+  write_line(
+#if defined(ASIO_WINDOWS)
+      "@asio|%I64u.%06I64u|%I64u|%.20s@%p.%.50s\n",
+#else // defined(ASIO_WINDOWS)
+      "@asio|%llu.%06llu|%llu|%.20s@%p.%.50s\n",
+#endif // defined(ASIO_WINDOWS)
+      timestamp.seconds, timestamp.microseconds,
+      current_id, object_type, object, op_name);
+}
+
+void handler_tracking::reactor_registration(execution_context& /*context*/,
+    uintmax_t /*native_handle*/, uintmax_t /*registration*/)
+{
+}
+
+void handler_tracking::reactor_deregistration(execution_context& /*context*/,
+    uintmax_t /*native_handle*/, uintmax_t /*registration*/)
+{
+}
+
+void handler_tracking::reactor_events(execution_context& /*context*/,
+    uintmax_t /*native_handle*/, unsigned /*events*/)
+{
+}
+
+void handler_tracking::reactor_operation(
+    const tracked_handler& h, const char* op_name,
+    const asio::error_code& ec)
+{
+  handler_tracking_timestamp timestamp;
+
+  write_line(
+#if defined(ASIO_WINDOWS)
+      "@asio|%I64u.%06I64u|.%I64u|%s,ec=%.20s:%d\n",
+#else // defined(ASIO_WINDOWS)
+      "@asio|%llu.%06llu|.%llu|%s,ec=%.20s:%d\n",
+#endif // defined(ASIO_WINDOWS)
+      timestamp.seconds, timestamp.microseconds,
+      h.id_, op_name, ec.category().name(), ec.value());
+}
+
+void handler_tracking::reactor_operation(
+    const tracked_handler& h, const char* op_name,
+    const asio::error_code& ec, std::size_t bytes_transferred)
+{
+  handler_tracking_timestamp timestamp;
+
+  write_line(
+#if defined(ASIO_WINDOWS)
+      "@asio|%I64u.%06I64u|.%I64u|%s,ec=%.20s:%d,bytes_transferred=%I64u\n",
+#else // defined(ASIO_WINDOWS)
+      "@asio|%llu.%06llu|.%llu|%s,ec=%.20s:%d,bytes_transferred=%llu\n",
+#endif // defined(ASIO_WINDOWS)
+      timestamp.seconds, timestamp.microseconds,
+      h.id_, op_name, ec.category().name(), ec.value(),
+      static_cast<uint64_t>(bytes_transferred));
+}
+
+void handler_tracking::write_line(const char* format, ...)
+{
+  using namespace std; // For sprintf (or equivalent).
+
+  va_list args;
+  va_start(args, format);
+
+  char line[256] = "";
+#if defined(ASIO_HAS_SECURE_RTL)
+  int length = vsprintf_s(line, sizeof(line), format, args);
+#else // defined(ASIO_HAS_SECURE_RTL)
+  int length = vsprintf(line, format, args);
+#endif // defined(ASIO_HAS_SECURE_RTL)
+
+  va_end(args);
+
+#if defined(ASIO_WINDOWS_RUNTIME)
+  wchar_t wline[256] = L"";
+  mbstowcs_s(0, wline, sizeof(wline) / sizeof(wchar_t), line, length);
+  ::OutputDebugStringW(wline);
+#elif defined(ASIO_WINDOWS)
+  HANDLE stderr_handle = ::GetStdHandle(STD_ERROR_HANDLE);
+  DWORD bytes_written = 0;
+  ::WriteFile(stderr_handle, line, length, &bytes_written, 0);
+#else // defined(ASIO_WINDOWS)
+  ::write(STDERR_FILENO, line, length);
+#endif // defined(ASIO_WINDOWS)
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_ENABLE_HANDLER_TRACKING)
+
+#endif // ASIO_DETAIL_IMPL_HANDLER_TRACKING_IPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/impl/kqueue_reactor.hpp b/link/modules/asio-standalone/asio/include/asio/detail/impl/kqueue_reactor.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/impl/kqueue_reactor.hpp
@@ -0,0 +1,93 @@
+//
+// detail/impl/kqueue_reactor.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2005 Stefan Arentz (stefan at soze 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 ASIO_DETAIL_IMPL_KQUEUE_REACTOR_HPP
+#define ASIO_DETAIL_IMPL_KQUEUE_REACTOR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_KQUEUE)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Time_Traits>
+void kqueue_reactor::add_timer_queue(timer_queue<Time_Traits>& queue)
+{
+  do_add_timer_queue(queue);
+}
+
+// Remove a timer queue from the reactor.
+template <typename Time_Traits>
+void kqueue_reactor::remove_timer_queue(timer_queue<Time_Traits>& queue)
+{
+  do_remove_timer_queue(queue);
+}
+
+template <typename Time_Traits>
+void kqueue_reactor::schedule_timer(timer_queue<Time_Traits>& queue,
+    const typename Time_Traits::time_type& time,
+    typename timer_queue<Time_Traits>::per_timer_data& timer, wait_op* op)
+{
+  mutex::scoped_lock lock(mutex_);
+
+  if (shutdown_)
+  {
+    scheduler_.post_immediate_completion(op, false);
+    return;
+  }
+
+  bool earliest = queue.enqueue_timer(time, timer, op);
+  scheduler_.work_started();
+  if (earliest)
+    interrupt();
+}
+
+template <typename Time_Traits>
+std::size_t kqueue_reactor::cancel_timer(timer_queue<Time_Traits>& queue,
+    typename timer_queue<Time_Traits>::per_timer_data& timer,
+    std::size_t max_cancelled)
+{
+  mutex::scoped_lock lock(mutex_);
+  op_queue<operation> ops;
+  std::size_t n = queue.cancel_timer(timer, ops, max_cancelled);
+  lock.unlock();
+  scheduler_.post_deferred_completions(ops);
+  return n;
+}
+
+template <typename Time_Traits>
+void kqueue_reactor::move_timer(timer_queue<Time_Traits>& queue,
+    typename timer_queue<Time_Traits>::per_timer_data& target,
+    typename timer_queue<Time_Traits>::per_timer_data& source)
+{
+  mutex::scoped_lock lock(mutex_);
+  op_queue<operation> ops;
+  queue.cancel_timer(target, ops);
+  queue.move_timer(target, source);
+  lock.unlock();
+  scheduler_.post_deferred_completions(ops);
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_KQUEUE)
+
+#endif // ASIO_DETAIL_IMPL_KQUEUE_REACTOR_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/impl/kqueue_reactor.ipp b/link/modules/asio-standalone/asio/include/asio/detail/impl/kqueue_reactor.ipp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/impl/kqueue_reactor.ipp
@@ -0,0 +1,570 @@
+//
+// detail/impl/kqueue_reactor.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2005 Stefan Arentz (stefan at soze 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 ASIO_DETAIL_IMPL_KQUEUE_REACTOR_IPP
+#define ASIO_DETAIL_IMPL_KQUEUE_REACTOR_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_KQUEUE)
+
+#include "asio/detail/kqueue_reactor.hpp"
+#include "asio/detail/scheduler.hpp"
+#include "asio/detail/throw_error.hpp"
+#include "asio/error.hpp"
+
+#if defined(__NetBSD__)
+# include <sys/param.h>
+#endif
+
+#include "asio/detail/push_options.hpp"
+
+#if defined(__NetBSD__) && __NetBSD_Version__ < 999001500
+# define ASIO_KQUEUE_EV_SET(ev, ident, filt, flags, fflags, data, udata) \
+    EV_SET(ev, ident, filt, flags, fflags, data, \
+      reinterpret_cast<intptr_t>(static_cast<void*>(udata)))
+#else
+# define ASIO_KQUEUE_EV_SET(ev, ident, filt, flags, fflags, data, udata) \
+    EV_SET(ev, ident, filt, flags, fflags, data, udata)
+#endif
+
+namespace asio {
+namespace detail {
+
+kqueue_reactor::kqueue_reactor(asio::execution_context& ctx)
+  : execution_context_service_base<kqueue_reactor>(ctx),
+    scheduler_(use_service<scheduler>(ctx)),
+    mutex_(ASIO_CONCURRENCY_HINT_IS_LOCKING(
+          REACTOR_REGISTRATION, scheduler_.concurrency_hint())),
+    kqueue_fd_(do_kqueue_create()),
+    interrupter_(),
+    shutdown_(false),
+    registered_descriptors_mutex_(mutex_.enabled())
+{
+  struct kevent events[1];
+  ASIO_KQUEUE_EV_SET(&events[0], interrupter_.read_descriptor(),
+      EVFILT_READ, EV_ADD, 0, 0, &interrupter_);
+  if (::kevent(kqueue_fd_, events, 1, 0, 0, 0) == -1)
+  {
+    asio::error_code error(errno,
+        asio::error::get_system_category());
+    asio::detail::throw_error(error);
+  }
+}
+
+kqueue_reactor::~kqueue_reactor()
+{
+  close(kqueue_fd_);
+}
+
+void kqueue_reactor::shutdown()
+{
+  mutex::scoped_lock lock(mutex_);
+  shutdown_ = true;
+  lock.unlock();
+
+  op_queue<operation> ops;
+
+  while (descriptor_state* state = registered_descriptors_.first())
+  {
+    for (int i = 0; i < max_ops; ++i)
+      ops.push(state->op_queue_[i]);
+    state->shutdown_ = true;
+    registered_descriptors_.free(state);
+  }
+
+  timer_queues_.get_all_timers(ops);
+
+  scheduler_.abandon_operations(ops);
+}
+
+void kqueue_reactor::notify_fork(
+    asio::execution_context::fork_event fork_ev)
+{
+  if (fork_ev == asio::execution_context::fork_child)
+  {
+    // The kqueue descriptor is automatically closed in the child.
+    kqueue_fd_ = -1;
+    kqueue_fd_ = do_kqueue_create();
+
+    interrupter_.recreate();
+
+    struct kevent events[2];
+    ASIO_KQUEUE_EV_SET(&events[0], interrupter_.read_descriptor(),
+        EVFILT_READ, EV_ADD, 0, 0, &interrupter_);
+    if (::kevent(kqueue_fd_, events, 1, 0, 0, 0) == -1)
+    {
+      asio::error_code ec(errno,
+          asio::error::get_system_category());
+      asio::detail::throw_error(ec, "kqueue interrupter registration");
+    }
+
+    // Re-register all descriptors with kqueue.
+    mutex::scoped_lock descriptors_lock(registered_descriptors_mutex_);
+    for (descriptor_state* state = registered_descriptors_.first();
+        state != 0; state = state->next_)
+    {
+      if (state->num_kevents_ > 0)
+      {
+        ASIO_KQUEUE_EV_SET(&events[0], state->descriptor_,
+            EVFILT_READ, EV_ADD | EV_CLEAR, 0, 0, state);
+        ASIO_KQUEUE_EV_SET(&events[1], state->descriptor_,
+            EVFILT_WRITE, EV_ADD | EV_CLEAR, 0, 0, state);
+        if (::kevent(kqueue_fd_, events, state->num_kevents_, 0, 0, 0) == -1)
+        {
+          asio::error_code ec(errno,
+              asio::error::get_system_category());
+          asio::detail::throw_error(ec, "kqueue re-registration");
+        }
+      }
+    }
+  }
+}
+
+void kqueue_reactor::init_task()
+{
+  scheduler_.init_task();
+}
+
+int kqueue_reactor::register_descriptor(socket_type descriptor,
+    kqueue_reactor::per_descriptor_data& descriptor_data)
+{
+  descriptor_data = allocate_descriptor_state();
+
+  ASIO_HANDLER_REACTOR_REGISTRATION((
+        context(), static_cast<uintmax_t>(descriptor),
+        reinterpret_cast<uintmax_t>(descriptor_data)));
+
+  mutex::scoped_lock lock(descriptor_data->mutex_);
+
+  descriptor_data->descriptor_ = descriptor;
+  descriptor_data->num_kevents_ = 0;
+  descriptor_data->shutdown_ = false;
+
+  return 0;
+}
+
+int kqueue_reactor::register_internal_descriptor(
+    int op_type, socket_type descriptor,
+    kqueue_reactor::per_descriptor_data& descriptor_data, reactor_op* op)
+{
+  descriptor_data = allocate_descriptor_state();
+
+  ASIO_HANDLER_REACTOR_REGISTRATION((
+        context(), static_cast<uintmax_t>(descriptor),
+        reinterpret_cast<uintmax_t>(descriptor_data)));
+
+  mutex::scoped_lock lock(descriptor_data->mutex_);
+
+  descriptor_data->descriptor_ = descriptor;
+  descriptor_data->num_kevents_ = 1;
+  descriptor_data->shutdown_ = false;
+  descriptor_data->op_queue_[op_type].push(op);
+
+  struct kevent events[1];
+  ASIO_KQUEUE_EV_SET(&events[0], descriptor, EVFILT_READ,
+      EV_ADD | EV_CLEAR, 0, 0, descriptor_data);
+  if (::kevent(kqueue_fd_, events, 1, 0, 0, 0) == -1)
+    return errno;
+
+  return 0;
+}
+
+void kqueue_reactor::move_descriptor(socket_type,
+    kqueue_reactor::per_descriptor_data& target_descriptor_data,
+    kqueue_reactor::per_descriptor_data& source_descriptor_data)
+{
+  target_descriptor_data = source_descriptor_data;
+  source_descriptor_data = 0;
+}
+
+void kqueue_reactor::start_op(int op_type, socket_type descriptor,
+    kqueue_reactor::per_descriptor_data& descriptor_data, reactor_op* op,
+    bool is_continuation, bool allow_speculative)
+{
+  if (!descriptor_data)
+  {
+    op->ec_ = asio::error::bad_descriptor;
+    post_immediate_completion(op, is_continuation);
+    return;
+  }
+
+  mutex::scoped_lock descriptor_lock(descriptor_data->mutex_);
+
+  if (descriptor_data->shutdown_)
+  {
+    post_immediate_completion(op, is_continuation);
+    return;
+  }
+
+  if (descriptor_data->op_queue_[op_type].empty())
+  {
+    static const int num_kevents[max_ops] = { 1, 2, 1 };
+
+    if (allow_speculative
+        && (op_type != read_op
+          || descriptor_data->op_queue_[except_op].empty()))
+    {
+      if (op->perform())
+      {
+        descriptor_lock.unlock();
+        scheduler_.post_immediate_completion(op, is_continuation);
+        return;
+      }
+
+      if (descriptor_data->num_kevents_ < num_kevents[op_type])
+      {
+        struct kevent events[2];
+        ASIO_KQUEUE_EV_SET(&events[0], descriptor, EVFILT_READ,
+            EV_ADD | EV_CLEAR, 0, 0, descriptor_data);
+        ASIO_KQUEUE_EV_SET(&events[1], descriptor, EVFILT_WRITE,
+            EV_ADD | EV_CLEAR, 0, 0, descriptor_data);
+        if (::kevent(kqueue_fd_, events, num_kevents[op_type], 0, 0, 0) != -1)
+        {
+          descriptor_data->num_kevents_ = num_kevents[op_type];
+        }
+        else
+        {
+          op->ec_ = asio::error_code(errno,
+              asio::error::get_system_category());
+          scheduler_.post_immediate_completion(op, is_continuation);
+          return;
+        }
+      }
+    }
+    else
+    {
+      if (descriptor_data->num_kevents_ < num_kevents[op_type])
+        descriptor_data->num_kevents_ = num_kevents[op_type];
+
+      struct kevent events[2];
+      ASIO_KQUEUE_EV_SET(&events[0], descriptor, EVFILT_READ,
+          EV_ADD | EV_CLEAR, 0, 0, descriptor_data);
+      ASIO_KQUEUE_EV_SET(&events[1], descriptor, EVFILT_WRITE,
+          EV_ADD | EV_CLEAR, 0, 0, descriptor_data);
+      ::kevent(kqueue_fd_, events, descriptor_data->num_kevents_, 0, 0, 0);
+    }
+  }
+
+  descriptor_data->op_queue_[op_type].push(op);
+  scheduler_.work_started();
+}
+
+void kqueue_reactor::cancel_ops(socket_type,
+    kqueue_reactor::per_descriptor_data& descriptor_data)
+{
+  if (!descriptor_data)
+    return;
+
+  mutex::scoped_lock descriptor_lock(descriptor_data->mutex_);
+
+  op_queue<operation> ops;
+  for (int i = 0; i < max_ops; ++i)
+  {
+    while (reactor_op* op = descriptor_data->op_queue_[i].front())
+    {
+      op->ec_ = asio::error::operation_aborted;
+      descriptor_data->op_queue_[i].pop();
+      ops.push(op);
+    }
+  }
+
+  descriptor_lock.unlock();
+
+  scheduler_.post_deferred_completions(ops);
+}
+
+void kqueue_reactor::deregister_descriptor(socket_type descriptor,
+    kqueue_reactor::per_descriptor_data& descriptor_data, bool closing)
+{
+  if (!descriptor_data)
+    return;
+
+  mutex::scoped_lock descriptor_lock(descriptor_data->mutex_);
+
+  if (!descriptor_data->shutdown_)
+  {
+    if (closing)
+    {
+      // The descriptor will be automatically removed from the kqueue when it
+      // is closed.
+    }
+    else
+    {
+      struct kevent events[2];
+      ASIO_KQUEUE_EV_SET(&events[0], descriptor,
+          EVFILT_READ, EV_DELETE, 0, 0, 0);
+      ASIO_KQUEUE_EV_SET(&events[1], descriptor,
+          EVFILT_WRITE, EV_DELETE, 0, 0, 0);
+      ::kevent(kqueue_fd_, events, descriptor_data->num_kevents_, 0, 0, 0);
+    }
+
+    op_queue<operation> ops;
+    for (int i = 0; i < max_ops; ++i)
+    {
+      while (reactor_op* op = descriptor_data->op_queue_[i].front())
+      {
+        op->ec_ = asio::error::operation_aborted;
+        descriptor_data->op_queue_[i].pop();
+        ops.push(op);
+      }
+    }
+
+    descriptor_data->descriptor_ = -1;
+    descriptor_data->shutdown_ = true;
+
+    descriptor_lock.unlock();
+
+    ASIO_HANDLER_REACTOR_DEREGISTRATION((
+          context(), static_cast<uintmax_t>(descriptor),
+          reinterpret_cast<uintmax_t>(descriptor_data)));
+
+    scheduler_.post_deferred_completions(ops);
+
+    // Leave descriptor_data set so that it will be freed by the subsequent
+    // call to cleanup_descriptor_data.
+  }
+  else
+  {
+    // We are shutting down, so prevent cleanup_descriptor_data from freeing
+    // the descriptor_data object and let the destructor free it instead.
+    descriptor_data = 0;
+  }
+}
+
+void kqueue_reactor::deregister_internal_descriptor(socket_type descriptor,
+    kqueue_reactor::per_descriptor_data& descriptor_data)
+{
+  if (!descriptor_data)
+    return;
+
+  mutex::scoped_lock descriptor_lock(descriptor_data->mutex_);
+
+  if (!descriptor_data->shutdown_)
+  {
+    struct kevent events[2];
+    ASIO_KQUEUE_EV_SET(&events[0], descriptor,
+        EVFILT_READ, EV_DELETE, 0, 0, 0);
+    ASIO_KQUEUE_EV_SET(&events[1], descriptor,
+        EVFILT_WRITE, EV_DELETE, 0, 0, 0);
+    ::kevent(kqueue_fd_, events, descriptor_data->num_kevents_, 0, 0, 0);
+
+    op_queue<operation> ops;
+    for (int i = 0; i < max_ops; ++i)
+      ops.push(descriptor_data->op_queue_[i]);
+
+    descriptor_data->descriptor_ = -1;
+    descriptor_data->shutdown_ = true;
+
+    descriptor_lock.unlock();
+
+    ASIO_HANDLER_REACTOR_DEREGISTRATION((
+          context(), static_cast<uintmax_t>(descriptor),
+          reinterpret_cast<uintmax_t>(descriptor_data)));
+
+    // Leave descriptor_data set so that it will be freed by the subsequent
+    // call to cleanup_descriptor_data.
+  }
+  else
+  {
+    // We are shutting down, so prevent cleanup_descriptor_data from freeing
+    // the descriptor_data object and let the destructor free it instead.
+    descriptor_data = 0;
+  }
+}
+
+void kqueue_reactor::cleanup_descriptor_data(
+    per_descriptor_data& descriptor_data)
+{
+  if (descriptor_data)
+  {
+    free_descriptor_state(descriptor_data);
+    descriptor_data = 0;
+  }
+}
+
+void kqueue_reactor::run(long usec, op_queue<operation>& ops)
+{
+  mutex::scoped_lock lock(mutex_);
+
+  // Determine how long to block while waiting for events.
+  timespec timeout_buf = { 0, 0 };
+  timespec* timeout = usec ? get_timeout(usec, timeout_buf) : &timeout_buf;
+
+  lock.unlock();
+
+  // Block on the kqueue descriptor.
+  struct kevent events[128];
+  int num_events = kevent(kqueue_fd_, 0, 0, events, 128, timeout);
+
+#if defined(ASIO_ENABLE_HANDLER_TRACKING)
+  // Trace the waiting events.
+  for (int i = 0; i < num_events; ++i)
+  {
+    void* ptr = reinterpret_cast<void*>(events[i].udata);
+    if (ptr != &interrupter_)
+    {
+      unsigned event_mask = 0;
+      switch (events[i].filter)
+      {
+      case EVFILT_READ:
+        event_mask |= ASIO_HANDLER_REACTOR_READ_EVENT;
+        break;
+      case EVFILT_WRITE:
+        event_mask |= ASIO_HANDLER_REACTOR_WRITE_EVENT;
+        break;
+      }
+      if ((events[i].flags & (EV_ERROR | EV_OOBAND)) != 0)
+        event_mask |= ASIO_HANDLER_REACTOR_ERROR_EVENT;
+      ASIO_HANDLER_REACTOR_EVENTS((context(),
+            reinterpret_cast<uintmax_t>(ptr), event_mask));
+    }
+  }
+#endif // defined(ASIO_ENABLE_HANDLER_TRACKING)
+
+  // Dispatch the waiting events.
+  for (int i = 0; i < num_events; ++i)
+  {
+    void* ptr = reinterpret_cast<void*>(events[i].udata);
+    if (ptr == &interrupter_)
+    {
+      interrupter_.reset();
+    }
+    else
+    {
+      descriptor_state* descriptor_data = static_cast<descriptor_state*>(ptr);
+      mutex::scoped_lock descriptor_lock(descriptor_data->mutex_);
+
+      if (events[i].filter == EVFILT_WRITE
+          && descriptor_data->num_kevents_ == 2
+          && descriptor_data->op_queue_[write_op].empty())
+      {
+        // Some descriptor types, like serial ports, don't seem to support
+        // EV_CLEAR with EVFILT_WRITE. Since we have no pending write
+        // operations we'll remove the EVFILT_WRITE registration here so that
+        // we don't end up in a tight spin.
+        struct kevent delete_events[1];
+        ASIO_KQUEUE_EV_SET(&delete_events[0],
+            descriptor_data->descriptor_, EVFILT_WRITE, EV_DELETE, 0, 0, 0);
+        ::kevent(kqueue_fd_, delete_events, 1, 0, 0, 0);
+        descriptor_data->num_kevents_ = 1;
+      }
+
+      // Exception operations must be processed first to ensure that any
+      // out-of-band data is read before normal data.
+#if defined(__NetBSD__)
+      static const unsigned int filter[max_ops] =
+#else
+      static const int filter[max_ops] =
+#endif
+        { EVFILT_READ, EVFILT_WRITE, EVFILT_READ };
+      for (int j = max_ops - 1; j >= 0; --j)
+      {
+        if (events[i].filter == filter[j])
+        {
+          if (j != except_op || events[i].flags & EV_OOBAND)
+          {
+            while (reactor_op* op = descriptor_data->op_queue_[j].front())
+            {
+              if (events[i].flags & EV_ERROR)
+              {
+                op->ec_ = asio::error_code(
+                    static_cast<int>(events[i].data),
+                    asio::error::get_system_category());
+                descriptor_data->op_queue_[j].pop();
+                ops.push(op);
+              }
+              if (op->perform())
+              {
+                descriptor_data->op_queue_[j].pop();
+                ops.push(op);
+              }
+              else
+                break;
+            }
+          }
+        }
+      }
+    }
+  }
+
+  lock.lock();
+  timer_queues_.get_ready_timers(ops);
+}
+
+void kqueue_reactor::interrupt()
+{
+  interrupter_.interrupt();
+}
+
+int kqueue_reactor::do_kqueue_create()
+{
+  int fd = ::kqueue();
+  if (fd == -1)
+  {
+    asio::error_code ec(errno,
+        asio::error::get_system_category());
+    asio::detail::throw_error(ec, "kqueue");
+  }
+  return fd;
+}
+
+kqueue_reactor::descriptor_state* kqueue_reactor::allocate_descriptor_state()
+{
+  mutex::scoped_lock descriptors_lock(registered_descriptors_mutex_);
+  return registered_descriptors_.alloc(ASIO_CONCURRENCY_HINT_IS_LOCKING(
+        REACTOR_IO, scheduler_.concurrency_hint()));
+}
+
+void kqueue_reactor::free_descriptor_state(kqueue_reactor::descriptor_state* s)
+{
+  mutex::scoped_lock descriptors_lock(registered_descriptors_mutex_);
+  registered_descriptors_.free(s);
+}
+
+void kqueue_reactor::do_add_timer_queue(timer_queue_base& queue)
+{
+  mutex::scoped_lock lock(mutex_);
+  timer_queues_.insert(&queue);
+}
+
+void kqueue_reactor::do_remove_timer_queue(timer_queue_base& queue)
+{
+  mutex::scoped_lock lock(mutex_);
+  timer_queues_.erase(&queue);
+}
+
+timespec* kqueue_reactor::get_timeout(long usec, timespec& ts)
+{
+  // By default we will wait no longer than 5 minutes. This will ensure that
+  // any changes to the system clock are detected after no longer than this.
+  const long max_usec = 5 * 60 * 1000 * 1000;
+  usec = timer_queues_.wait_duration_usec(
+      (usec < 0 || max_usec < usec) ? max_usec : usec);
+  ts.tv_sec = usec / 1000000;
+  ts.tv_nsec = (usec % 1000000) * 1000;
+  return &ts;
+}
+
+} // namespace detail
+} // namespace asio
+
+#undef ASIO_KQUEUE_EV_SET
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_KQUEUE)
+
+#endif // ASIO_DETAIL_IMPL_KQUEUE_REACTOR_IPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/impl/null_event.ipp b/link/modules/asio-standalone/asio/include/asio/detail/impl/null_event.ipp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/impl/null_event.ipp
@@ -0,0 +1,74 @@
+//
+// detail/impl/null_event.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_IMPL_NULL_EVENT_IPP
+#define ASIO_DETAIL_IMPL_NULL_EVENT_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_WINDOWS_RUNTIME)
+# include <thread>
+#elif defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+# include "asio/detail/socket_types.hpp"
+#else
+# include <unistd.h>
+# if defined(__hpux)
+#  include <sys/time.h>
+# endif
+# if !defined(__hpux) || defined(__SELECT)
+#  include <sys/select.h>
+# endif
+#endif
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+void null_event::do_wait()
+{
+#if defined(ASIO_WINDOWS_RUNTIME)
+  std::this_thread::sleep_until((std::chrono::steady_clock::time_point::max)());
+#elif defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+  ::Sleep(INFINITE);
+#else
+  ::pause();
+#endif
+}
+
+void null_event::do_wait_for_usec(long usec)
+{
+#if defined(ASIO_WINDOWS_RUNTIME)
+  std::this_thread::sleep_for(std::chrono::microseconds(usec));
+#elif defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+  ::Sleep(usec / 1000);
+#elif defined(__hpux) && defined(__SELECT)
+  timespec ts;
+  ts.tv_sec = usec / 1000000;
+  ts.tv_nsec = (usec % 1000000) * 1000;
+  ::pselect(0, 0, 0, 0, &ts, 0);
+#else
+  timeval tv;
+  tv.tv_sec = usec / 1000000;
+  tv.tv_usec = usec % 1000000;
+  ::select(0, 0, 0, 0, &tv);
+#endif
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_IMPL_NULL_EVENT_IPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/impl/pipe_select_interrupter.ipp b/link/modules/asio-standalone/asio/include/asio/detail/impl/pipe_select_interrupter.ipp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/impl/pipe_select_interrupter.ipp
@@ -0,0 +1,129 @@
+//
+// detail/impl/pipe_select_interrupter.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_IMPL_PIPE_SELECT_INTERRUPTER_IPP
+#define ASIO_DETAIL_IMPL_PIPE_SELECT_INTERRUPTER_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if !defined(ASIO_WINDOWS_RUNTIME)
+#if !defined(ASIO_WINDOWS)
+#if !defined(__CYGWIN__)
+#if !defined(__SYMBIAN32__)
+#if !defined(ASIO_HAS_EVENTFD)
+
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include "asio/detail/pipe_select_interrupter.hpp"
+#include "asio/detail/socket_types.hpp"
+#include "asio/detail/throw_error.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+pipe_select_interrupter::pipe_select_interrupter()
+{
+  open_descriptors();
+}
+
+void pipe_select_interrupter::open_descriptors()
+{
+  int pipe_fds[2];
+  if (pipe(pipe_fds) == 0)
+  {
+    read_descriptor_ = pipe_fds[0];
+    ::fcntl(read_descriptor_, F_SETFL, O_NONBLOCK);
+    write_descriptor_ = pipe_fds[1];
+    ::fcntl(write_descriptor_, F_SETFL, O_NONBLOCK);
+
+#if defined(FD_CLOEXEC)
+    ::fcntl(read_descriptor_, F_SETFD, FD_CLOEXEC);
+    ::fcntl(write_descriptor_, F_SETFD, FD_CLOEXEC);
+#endif // defined(FD_CLOEXEC)
+  }
+  else
+  {
+    asio::error_code ec(errno,
+        asio::error::get_system_category());
+    asio::detail::throw_error(ec, "pipe_select_interrupter");
+  }
+}
+
+pipe_select_interrupter::~pipe_select_interrupter()
+{
+  close_descriptors();
+}
+
+void pipe_select_interrupter::close_descriptors()
+{
+  if (read_descriptor_ != -1)
+    ::close(read_descriptor_);
+  if (write_descriptor_ != -1)
+    ::close(write_descriptor_);
+}
+
+void pipe_select_interrupter::recreate()
+{
+  close_descriptors();
+
+  write_descriptor_ = -1;
+  read_descriptor_ = -1;
+
+  open_descriptors();
+}
+
+void pipe_select_interrupter::interrupt()
+{
+  char byte = 0;
+  signed_size_type result = ::write(write_descriptor_, &byte, 1);
+  (void)result;
+}
+
+bool pipe_select_interrupter::reset()
+{
+  for (;;)
+  {
+    char data[1024];
+    signed_size_type bytes_read = ::read(read_descriptor_, data, sizeof(data));
+    if (bytes_read == sizeof(data))
+      continue;
+    if (bytes_read > 0)
+      return true;
+    if (bytes_read == 0)
+      return false;
+    if (errno == EINTR)
+      continue;
+    if (errno == EWOULDBLOCK || errno == EAGAIN)
+      return true;
+    return false;
+  }
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // !defined(ASIO_HAS_EVENTFD)
+#endif // !defined(__SYMBIAN32__)
+#endif // !defined(__CYGWIN__)
+#endif // !defined(ASIO_WINDOWS)
+#endif // !defined(ASIO_WINDOWS_RUNTIME)
+
+#endif // ASIO_DETAIL_IMPL_PIPE_SELECT_INTERRUPTER_IPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/impl/posix_event.ipp b/link/modules/asio-standalone/asio/include/asio/detail/impl/posix_event.ipp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/impl/posix_event.ipp
@@ -0,0 +1,59 @@
+//
+// detail/impl/posix_event.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_IMPL_POSIX_EVENT_IPP
+#define ASIO_DETAIL_IMPL_POSIX_EVENT_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_PTHREADS)
+
+#include "asio/detail/posix_event.hpp"
+#include "asio/detail/throw_error.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+posix_event::posix_event()
+  : state_(0)
+{
+#if (defined(__MACH__) && defined(__APPLE__)) \
+      || (defined(__ANDROID__) && (__ANDROID_API__ < 21))
+  int error = ::pthread_cond_init(&cond_, 0);
+#else // (defined(__MACH__) && defined(__APPLE__))
+      // || (defined(__ANDROID__) && (__ANDROID_API__ < 21))
+  ::pthread_condattr_t attr;
+  ::pthread_condattr_init(&attr);
+  int error = ::pthread_condattr_setclock(&attr, CLOCK_MONOTONIC);
+  if (error == 0)
+    error = ::pthread_cond_init(&cond_, &attr);
+#endif // (defined(__MACH__) && defined(__APPLE__))
+       // || (defined(__ANDROID__) && (__ANDROID_API__ < 21))
+
+  asio::error_code ec(error,
+      asio::error::get_system_category());
+  asio::detail::throw_error(ec, "event");
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_PTHREADS)
+
+#endif // ASIO_DETAIL_IMPL_POSIX_EVENT_IPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/impl/posix_mutex.ipp b/link/modules/asio-standalone/asio/include/asio/detail/impl/posix_mutex.ipp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/impl/posix_mutex.ipp
@@ -0,0 +1,46 @@
+//
+// detail/impl/posix_mutex.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_IMPL_POSIX_MUTEX_IPP
+#define ASIO_DETAIL_IMPL_POSIX_MUTEX_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_PTHREADS)
+
+#include "asio/detail/posix_mutex.hpp"
+#include "asio/detail/throw_error.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+posix_mutex::posix_mutex()
+{
+  int error = ::pthread_mutex_init(&mutex_, 0);
+  asio::error_code ec(error,
+      asio::error::get_system_category());
+  asio::detail::throw_error(ec, "mutex");
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_PTHREADS)
+
+#endif // ASIO_DETAIL_IMPL_POSIX_MUTEX_IPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/impl/posix_thread.ipp b/link/modules/asio-standalone/asio/include/asio/detail/impl/posix_thread.ipp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/impl/posix_thread.ipp
@@ -0,0 +1,84 @@
+//
+// detail/impl/posix_thread.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_IMPL_POSIX_THREAD_IPP
+#define ASIO_DETAIL_IMPL_POSIX_THREAD_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_PTHREADS)
+
+#include "asio/detail/posix_thread.hpp"
+#include "asio/detail/throw_error.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+posix_thread::~posix_thread()
+{
+  if (!joined_)
+    ::pthread_detach(thread_);
+}
+
+void posix_thread::join()
+{
+  if (!joined_)
+  {
+    ::pthread_join(thread_, 0);
+    joined_ = true;
+  }
+}
+
+std::size_t posix_thread::hardware_concurrency()
+{
+#if defined(_SC_NPROCESSORS_ONLN)
+  long result = sysconf(_SC_NPROCESSORS_ONLN);
+  if (result > 0)
+    return result;
+#endif // defined(_SC_NPROCESSORS_ONLN)
+  return 0;
+}
+
+void posix_thread::start_thread(func_base* arg)
+{
+  int error = ::pthread_create(&thread_, 0,
+        asio_detail_posix_thread_function, arg);
+  if (error != 0)
+  {
+    delete arg;
+    asio::error_code ec(error,
+        asio::error::get_system_category());
+    asio::detail::throw_error(ec, "thread");
+  }
+}
+
+void* asio_detail_posix_thread_function(void* arg)
+{
+  posix_thread::auto_func_base_ptr func = {
+      static_cast<posix_thread::func_base*>(arg) };
+  func.ptr->run();
+  return 0;
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_PTHREADS)
+
+#endif // ASIO_DETAIL_IMPL_POSIX_THREAD_IPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/impl/posix_tss_ptr.ipp b/link/modules/asio-standalone/asio/include/asio/detail/impl/posix_tss_ptr.ipp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/impl/posix_tss_ptr.ipp
@@ -0,0 +1,46 @@
+//
+// detail/impl/posix_tss_ptr.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_IMPL_POSIX_TSS_PTR_IPP
+#define ASIO_DETAIL_IMPL_POSIX_TSS_PTR_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_PTHREADS)
+
+#include "asio/detail/posix_tss_ptr.hpp"
+#include "asio/detail/throw_error.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+void posix_tss_ptr_create(pthread_key_t& key)
+{
+  int error = ::pthread_key_create(&key, 0);
+  asio::error_code ec(error,
+      asio::error::get_system_category());
+  asio::detail::throw_error(ec, "tss");
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_PTHREADS)
+
+#endif // ASIO_DETAIL_IMPL_POSIX_TSS_PTR_IPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/impl/reactive_descriptor_service.ipp b/link/modules/asio-standalone/asio/include/asio/detail/impl/reactive_descriptor_service.ipp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/impl/reactive_descriptor_service.ipp
@@ -0,0 +1,223 @@
+//
+// detail/impl/reactive_descriptor_service.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_IMPL_REACTIVE_DESCRIPTOR_SERVICE_IPP
+#define ASIO_DETAIL_IMPL_REACTIVE_DESCRIPTOR_SERVICE_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if !defined(ASIO_WINDOWS) \
+  && !defined(ASIO_WINDOWS_RUNTIME) \
+  && !defined(__CYGWIN__)
+
+#include "asio/error.hpp"
+#include "asio/detail/reactive_descriptor_service.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+reactive_descriptor_service::reactive_descriptor_service(
+    execution_context& context)
+  : execution_context_service_base<reactive_descriptor_service>(context),
+    reactor_(asio::use_service<reactor>(context))
+{
+  reactor_.init_task();
+}
+
+void reactive_descriptor_service::shutdown()
+{
+}
+
+void reactive_descriptor_service::construct(
+    reactive_descriptor_service::implementation_type& impl)
+{
+  impl.descriptor_ = -1;
+  impl.state_ = 0;
+}
+
+void reactive_descriptor_service::move_construct(
+    reactive_descriptor_service::implementation_type& impl,
+    reactive_descriptor_service::implementation_type& other_impl)
+  ASIO_NOEXCEPT
+{
+  impl.descriptor_ = other_impl.descriptor_;
+  other_impl.descriptor_ = -1;
+
+  impl.state_ = other_impl.state_;
+  other_impl.state_ = 0;
+
+  reactor_.move_descriptor(impl.descriptor_,
+      impl.reactor_data_, other_impl.reactor_data_);
+}
+
+void reactive_descriptor_service::move_assign(
+    reactive_descriptor_service::implementation_type& impl,
+    reactive_descriptor_service& other_service,
+    reactive_descriptor_service::implementation_type& other_impl)
+{
+  destroy(impl);
+
+  impl.descriptor_ = other_impl.descriptor_;
+  other_impl.descriptor_ = -1;
+
+  impl.state_ = other_impl.state_;
+  other_impl.state_ = 0;
+
+  other_service.reactor_.move_descriptor(impl.descriptor_,
+      impl.reactor_data_, other_impl.reactor_data_);
+}
+
+void reactive_descriptor_service::destroy(
+    reactive_descriptor_service::implementation_type& impl)
+{
+  if (is_open(impl))
+  {
+    ASIO_HANDLER_OPERATION((reactor_.context(),
+          "descriptor", &impl, impl.descriptor_, "close"));
+
+    reactor_.deregister_descriptor(impl.descriptor_, impl.reactor_data_,
+        (impl.state_ & descriptor_ops::possible_dup) == 0);
+
+    asio::error_code ignored_ec;
+    descriptor_ops::close(impl.descriptor_, impl.state_, ignored_ec);
+
+    reactor_.cleanup_descriptor_data(impl.reactor_data_);
+  }
+}
+
+asio::error_code reactive_descriptor_service::assign(
+    reactive_descriptor_service::implementation_type& impl,
+    const native_handle_type& native_descriptor, asio::error_code& ec)
+{
+  if (is_open(impl))
+  {
+    ec = asio::error::already_open;
+    return ec;
+  }
+
+  if (int err = reactor_.register_descriptor(
+        native_descriptor, impl.reactor_data_))
+  {
+    ec = asio::error_code(err,
+        asio::error::get_system_category());
+    return ec;
+  }
+
+  impl.descriptor_ = native_descriptor;
+  impl.state_ = descriptor_ops::possible_dup;
+  ec = asio::error_code();
+  return ec;
+}
+
+asio::error_code reactive_descriptor_service::close(
+    reactive_descriptor_service::implementation_type& impl,
+    asio::error_code& ec)
+{
+  if (is_open(impl))
+  {
+    ASIO_HANDLER_OPERATION((reactor_.context(),
+          "descriptor", &impl, impl.descriptor_, "close"));
+
+    reactor_.deregister_descriptor(impl.descriptor_, impl.reactor_data_,
+        (impl.state_ & descriptor_ops::possible_dup) == 0);
+
+    descriptor_ops::close(impl.descriptor_, impl.state_, ec);
+
+    reactor_.cleanup_descriptor_data(impl.reactor_data_);
+  }
+  else
+  {
+    ec = asio::error_code();
+  }
+
+  // The descriptor is closed by the OS even if close() returns an error.
+  //
+  // (Actually, POSIX says the state of the descriptor is unspecified. On
+  // Linux the descriptor is apparently closed anyway; e.g. see
+  //   http://lkml.org/lkml/2005/9/10/129
+  // We'll just have to assume that other OSes follow the same behaviour.)
+  construct(impl);
+
+  return ec;
+}
+
+reactive_descriptor_service::native_handle_type
+reactive_descriptor_service::release(
+    reactive_descriptor_service::implementation_type& impl)
+{
+  native_handle_type descriptor = impl.descriptor_;
+
+  if (is_open(impl))
+  {
+    ASIO_HANDLER_OPERATION((reactor_.context(),
+          "descriptor", &impl, impl.descriptor_, "release"));
+
+    reactor_.deregister_descriptor(impl.descriptor_, impl.reactor_data_, false);
+    reactor_.cleanup_descriptor_data(impl.reactor_data_);
+    construct(impl);
+  }
+
+  return descriptor;
+}
+
+asio::error_code reactive_descriptor_service::cancel(
+    reactive_descriptor_service::implementation_type& impl,
+    asio::error_code& ec)
+{
+  if (!is_open(impl))
+  {
+    ec = asio::error::bad_descriptor;
+    return ec;
+  }
+
+  ASIO_HANDLER_OPERATION((reactor_.context(),
+        "descriptor", &impl, impl.descriptor_, "cancel"));
+
+  reactor_.cancel_ops(impl.descriptor_, impl.reactor_data_);
+  ec = asio::error_code();
+  return ec;
+}
+
+void reactive_descriptor_service::start_op(
+    reactive_descriptor_service::implementation_type& impl,
+    int op_type, reactor_op* op, bool is_continuation,
+    bool is_non_blocking, bool noop)
+{
+  if (!noop)
+  {
+    if ((impl.state_ & descriptor_ops::non_blocking) ||
+        descriptor_ops::set_internal_non_blocking(
+          impl.descriptor_, impl.state_, true, op->ec_))
+    {
+      reactor_.start_op(op_type, impl.descriptor_,
+          impl.reactor_data_, op, is_continuation, is_non_blocking);
+      return;
+    }
+  }
+
+  reactor_.post_immediate_completion(op, is_continuation);
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // !defined(ASIO_WINDOWS)
+       //   && !defined(ASIO_WINDOWS_RUNTIME)
+       //   && !defined(__CYGWIN__)
+
+#endif // ASIO_DETAIL_IMPL_REACTIVE_DESCRIPTOR_SERVICE_IPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/impl/reactive_serial_port_service.ipp b/link/modules/asio-standalone/asio/include/asio/detail/impl/reactive_serial_port_service.ipp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/impl/reactive_serial_port_service.ipp
@@ -0,0 +1,149 @@
+//
+// detail/impl/reactive_serial_port_service.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.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 ASIO_DETAIL_IMPL_REACTIVE_SERIAL_PORT_SERVICE_IPP
+#define ASIO_DETAIL_IMPL_REACTIVE_SERIAL_PORT_SERVICE_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_SERIAL_PORT)
+#if !defined(ASIO_WINDOWS) && !defined(__CYGWIN__)
+
+#include <cstring>
+#include "asio/detail/reactive_serial_port_service.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+reactive_serial_port_service::reactive_serial_port_service(
+    execution_context& context)
+  : execution_context_service_base<reactive_serial_port_service>(context),
+    descriptor_service_(context)
+{
+}
+
+void reactive_serial_port_service::shutdown()
+{
+  descriptor_service_.shutdown();
+}
+
+asio::error_code reactive_serial_port_service::open(
+    reactive_serial_port_service::implementation_type& impl,
+    const std::string& device, asio::error_code& ec)
+{
+  if (is_open(impl))
+  {
+    ec = asio::error::already_open;
+    return ec;
+  }
+
+  descriptor_ops::state_type state = 0;
+  int fd = descriptor_ops::open(device.c_str(),
+      O_RDWR | O_NONBLOCK | O_NOCTTY, ec);
+  if (fd < 0)
+    return ec;
+
+  int s = descriptor_ops::fcntl(fd, F_GETFL, ec);
+  if (s >= 0)
+    s = descriptor_ops::fcntl(fd, F_SETFL, s | O_NONBLOCK, ec);
+  if (s < 0)
+  {
+    asio::error_code ignored_ec;
+    descriptor_ops::close(fd, state, ignored_ec);
+    return ec;
+  }
+
+  // Set up default serial port options.
+  termios ios;
+  s = ::tcgetattr(fd, &ios);
+  descriptor_ops::get_last_error(ec, s < 0);
+  if (s >= 0)
+  {
+#if defined(_BSD_SOURCE) || defined(_DEFAULT_SOURCE)
+    ::cfmakeraw(&ios);
+#else
+    ios.c_iflag &= ~(IGNBRK | BRKINT | PARMRK
+        | ISTRIP | INLCR | IGNCR | ICRNL | IXON);
+    ios.c_oflag &= ~OPOST;
+    ios.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
+    ios.c_cflag &= ~(CSIZE | PARENB);
+    ios.c_cflag |= CS8;
+#endif
+    ios.c_iflag |= IGNPAR;
+    ios.c_cflag |= CREAD | CLOCAL;
+    s = ::tcsetattr(fd, TCSANOW, &ios);
+    descriptor_ops::get_last_error(ec, s < 0);
+  }
+  if (s < 0)
+  {
+    asio::error_code ignored_ec;
+    descriptor_ops::close(fd, state, ignored_ec);
+    return ec;
+  }
+
+  // We're done. Take ownership of the serial port descriptor.
+  if (descriptor_service_.assign(impl, fd, ec))
+  {
+    asio::error_code ignored_ec;
+    descriptor_ops::close(fd, state, ignored_ec);
+  }
+
+  return ec;
+}
+
+asio::error_code reactive_serial_port_service::do_set_option(
+    reactive_serial_port_service::implementation_type& impl,
+    reactive_serial_port_service::store_function_type store,
+    const void* option, asio::error_code& ec)
+{
+  termios ios;
+  int s = ::tcgetattr(descriptor_service_.native_handle(impl), &ios);
+  descriptor_ops::get_last_error(ec, s < 0);
+  if (s < 0)
+    return ec;
+
+  if (store(option, ios, ec))
+    return ec;
+
+  s = ::tcsetattr(descriptor_service_.native_handle(impl), TCSANOW, &ios);
+  descriptor_ops::get_last_error(ec, s < 0);
+  return ec;
+}
+
+asio::error_code reactive_serial_port_service::do_get_option(
+    const reactive_serial_port_service::implementation_type& impl,
+    reactive_serial_port_service::load_function_type load,
+    void* option, asio::error_code& ec) const
+{
+  termios ios;
+  int s = ::tcgetattr(descriptor_service_.native_handle(impl), &ios);
+  descriptor_ops::get_last_error(ec, s < 0);
+  if (s < 0)
+    return ec;
+
+  return load(option, ios, ec);
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // !defined(ASIO_WINDOWS) && !defined(__CYGWIN__)
+#endif // defined(ASIO_HAS_SERIAL_PORT)
+
+#endif // ASIO_DETAIL_IMPL_REACTIVE_SERIAL_PORT_SERVICE_IPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/impl/reactive_socket_service_base.ipp b/link/modules/asio-standalone/asio/include/asio/detail/impl/reactive_socket_service_base.ipp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/impl/reactive_socket_service_base.ipp
@@ -0,0 +1,300 @@
+//
+// detail/reactive_socket_service_base.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_IMPL_REACTIVE_SOCKET_SERVICE_BASE_IPP
+#define ASIO_DETAIL_IMPL_REACTIVE_SOCKET_SERVICE_BASE_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if !defined(ASIO_HAS_IOCP) \
+  && !defined(ASIO_WINDOWS_RUNTIME)
+
+#include "asio/detail/reactive_socket_service_base.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+reactive_socket_service_base::reactive_socket_service_base(
+    execution_context& context)
+  : reactor_(use_service<reactor>(context))
+{
+  reactor_.init_task();
+}
+
+void reactive_socket_service_base::base_shutdown()
+{
+}
+
+void reactive_socket_service_base::construct(
+    reactive_socket_service_base::base_implementation_type& impl)
+{
+  impl.socket_ = invalid_socket;
+  impl.state_ = 0;
+}
+
+void reactive_socket_service_base::base_move_construct(
+    reactive_socket_service_base::base_implementation_type& impl,
+    reactive_socket_service_base::base_implementation_type& other_impl)
+  ASIO_NOEXCEPT
+{
+  impl.socket_ = other_impl.socket_;
+  other_impl.socket_ = invalid_socket;
+
+  impl.state_ = other_impl.state_;
+  other_impl.state_ = 0;
+
+  reactor_.move_descriptor(impl.socket_,
+      impl.reactor_data_, other_impl.reactor_data_);
+}
+
+void reactive_socket_service_base::base_move_assign(
+    reactive_socket_service_base::base_implementation_type& impl,
+    reactive_socket_service_base& other_service,
+    reactive_socket_service_base::base_implementation_type& other_impl)
+{
+  destroy(impl);
+
+  impl.socket_ = other_impl.socket_;
+  other_impl.socket_ = invalid_socket;
+
+  impl.state_ = other_impl.state_;
+  other_impl.state_ = 0;
+
+  other_service.reactor_.move_descriptor(impl.socket_,
+      impl.reactor_data_, other_impl.reactor_data_);
+}
+
+void reactive_socket_service_base::destroy(
+    reactive_socket_service_base::base_implementation_type& impl)
+{
+  if (impl.socket_ != invalid_socket)
+  {
+    ASIO_HANDLER_OPERATION((reactor_.context(),
+          "socket", &impl, impl.socket_, "close"));
+
+    reactor_.deregister_descriptor(impl.socket_, impl.reactor_data_,
+        (impl.state_ & socket_ops::possible_dup) == 0);
+
+    asio::error_code ignored_ec;
+    socket_ops::close(impl.socket_, impl.state_, true, ignored_ec);
+
+    reactor_.cleanup_descriptor_data(impl.reactor_data_);
+  }
+}
+
+asio::error_code reactive_socket_service_base::close(
+    reactive_socket_service_base::base_implementation_type& impl,
+    asio::error_code& ec)
+{
+  if (is_open(impl))
+  {
+    ASIO_HANDLER_OPERATION((reactor_.context(),
+          "socket", &impl, impl.socket_, "close"));
+
+    reactor_.deregister_descriptor(impl.socket_, impl.reactor_data_,
+        (impl.state_ & socket_ops::possible_dup) == 0);
+
+    socket_ops::close(impl.socket_, impl.state_, false, ec);
+
+    reactor_.cleanup_descriptor_data(impl.reactor_data_);
+  }
+  else
+  {
+    ec = asio::error_code();
+  }
+
+  // The descriptor is closed by the OS even if close() returns an error.
+  //
+  // (Actually, POSIX says the state of the descriptor is unspecified. On
+  // Linux the descriptor is apparently closed anyway; e.g. see
+  //   http://lkml.org/lkml/2005/9/10/129
+  // We'll just have to assume that other OSes follow the same behaviour. The
+  // known exception is when Windows's closesocket() function fails with
+  // WSAEWOULDBLOCK, but this case is handled inside socket_ops::close().
+  construct(impl);
+
+  return ec;
+}
+
+socket_type reactive_socket_service_base::release(
+    reactive_socket_service_base::base_implementation_type& impl,
+    asio::error_code& ec)
+{
+  if (!is_open(impl))
+  {
+    ec = asio::error::bad_descriptor;
+    return invalid_socket;
+  }
+
+  ASIO_HANDLER_OPERATION((reactor_.context(),
+        "socket", &impl, impl.socket_, "release"));
+
+  reactor_.deregister_descriptor(impl.socket_, impl.reactor_data_, false);
+  reactor_.cleanup_descriptor_data(impl.reactor_data_);
+  socket_type sock = impl.socket_;
+  construct(impl);
+  ec = asio::error_code();
+  return sock;
+}
+
+asio::error_code reactive_socket_service_base::cancel(
+    reactive_socket_service_base::base_implementation_type& impl,
+    asio::error_code& ec)
+{
+  if (!is_open(impl))
+  {
+    ec = asio::error::bad_descriptor;
+    return ec;
+  }
+
+  ASIO_HANDLER_OPERATION((reactor_.context(),
+        "socket", &impl, impl.socket_, "cancel"));
+
+  reactor_.cancel_ops(impl.socket_, impl.reactor_data_);
+  ec = asio::error_code();
+  return ec;
+}
+
+asio::error_code reactive_socket_service_base::do_open(
+    reactive_socket_service_base::base_implementation_type& impl,
+    int af, int type, int protocol, asio::error_code& ec)
+{
+  if (is_open(impl))
+  {
+    ec = asio::error::already_open;
+    return ec;
+  }
+
+  socket_holder sock(socket_ops::socket(af, type, protocol, ec));
+  if (sock.get() == invalid_socket)
+    return ec;
+
+  if (int err = reactor_.register_descriptor(sock.get(), impl.reactor_data_))
+  {
+    ec = asio::error_code(err,
+        asio::error::get_system_category());
+    return ec;
+  }
+
+  impl.socket_ = sock.release();
+  switch (type)
+  {
+  case SOCK_STREAM: impl.state_ = socket_ops::stream_oriented; break;
+  case SOCK_DGRAM: impl.state_ = socket_ops::datagram_oriented; break;
+  default: impl.state_ = 0; break;
+  }
+  ec = asio::error_code();
+  return ec;
+}
+
+asio::error_code reactive_socket_service_base::do_assign(
+    reactive_socket_service_base::base_implementation_type& impl, int type,
+    const reactive_socket_service_base::native_handle_type& native_socket,
+    asio::error_code& ec)
+{
+  if (is_open(impl))
+  {
+    ec = asio::error::already_open;
+    return ec;
+  }
+
+  if (int err = reactor_.register_descriptor(
+        native_socket, impl.reactor_data_))
+  {
+    ec = asio::error_code(err,
+        asio::error::get_system_category());
+    return ec;
+  }
+
+  impl.socket_ = native_socket;
+  switch (type)
+  {
+  case SOCK_STREAM: impl.state_ = socket_ops::stream_oriented; break;
+  case SOCK_DGRAM: impl.state_ = socket_ops::datagram_oriented; break;
+  default: impl.state_ = 0; break;
+  }
+  impl.state_ |= socket_ops::possible_dup;
+  ec = asio::error_code();
+  return ec;
+}
+
+void reactive_socket_service_base::start_op(
+    reactive_socket_service_base::base_implementation_type& impl,
+    int op_type, reactor_op* op, bool is_continuation,
+    bool is_non_blocking, bool noop)
+{
+  if (!noop)
+  {
+    if ((impl.state_ & socket_ops::non_blocking)
+        || socket_ops::set_internal_non_blocking(
+          impl.socket_, impl.state_, true, op->ec_))
+    {
+      reactor_.start_op(op_type, impl.socket_,
+          impl.reactor_data_, op, is_continuation, is_non_blocking);
+      return;
+    }
+  }
+
+  reactor_.post_immediate_completion(op, is_continuation);
+}
+
+void reactive_socket_service_base::start_accept_op(
+    reactive_socket_service_base::base_implementation_type& impl,
+    reactor_op* op, bool is_continuation, bool peer_is_open)
+{
+  if (!peer_is_open)
+    start_op(impl, reactor::read_op, op, is_continuation, true, false);
+  else
+  {
+    op->ec_ = asio::error::already_open;
+    reactor_.post_immediate_completion(op, is_continuation);
+  }
+}
+
+void reactive_socket_service_base::start_connect_op(
+    reactive_socket_service_base::base_implementation_type& impl,
+    reactor_op* op, bool is_continuation,
+    const socket_addr_type* addr, size_t addrlen)
+{
+  if ((impl.state_ & socket_ops::non_blocking)
+      || socket_ops::set_internal_non_blocking(
+        impl.socket_, impl.state_, true, op->ec_))
+  {
+    if (socket_ops::connect(impl.socket_, addr, addrlen, op->ec_) != 0)
+    {
+      if (op->ec_ == asio::error::in_progress
+          || op->ec_ == asio::error::would_block)
+      {
+        op->ec_ = asio::error_code();
+        reactor_.start_op(reactor::connect_op, impl.socket_,
+            impl.reactor_data_, op, is_continuation, false);
+        return;
+      }
+    }
+  }
+
+  reactor_.post_immediate_completion(op, is_continuation);
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // !defined(ASIO_HAS_IOCP)
+       //   && !defined(ASIO_WINDOWS_RUNTIME)
+
+#endif // ASIO_DETAIL_IMPL_REACTIVE_SOCKET_SERVICE_BASE_IPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/impl/resolver_service_base.ipp b/link/modules/asio-standalone/asio/include/asio/detail/impl/resolver_service_base.ipp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/impl/resolver_service_base.ipp
@@ -0,0 +1,158 @@
+//
+// detail/impl/resolver_service_base.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_IMPL_RESOLVER_SERVICE_BASE_IPP
+#define ASIO_DETAIL_IMPL_RESOLVER_SERVICE_BASE_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/resolver_service_base.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class resolver_service_base::work_scheduler_runner
+{
+public:
+  work_scheduler_runner(scheduler_impl& work_scheduler)
+    : work_scheduler_(work_scheduler)
+  {
+  }
+
+  void operator()()
+  {
+    asio::error_code ec;
+    work_scheduler_.run(ec);
+  }
+
+private:
+  scheduler_impl& work_scheduler_;
+};
+
+resolver_service_base::resolver_service_base(execution_context& context)
+  : scheduler_(asio::use_service<scheduler_impl>(context)),
+    work_scheduler_(new scheduler_impl(context, -1, false)),
+    work_thread_(0)
+{
+  work_scheduler_->work_started();
+}
+
+resolver_service_base::~resolver_service_base()
+{
+  base_shutdown();
+}
+
+void resolver_service_base::base_shutdown()
+{
+  if (work_scheduler_.get())
+  {
+    work_scheduler_->work_finished();
+    work_scheduler_->stop();
+    if (work_thread_.get())
+    {
+      work_thread_->join();
+      work_thread_.reset();
+    }
+    work_scheduler_.reset();
+  }
+}
+
+void resolver_service_base::base_notify_fork(
+    execution_context::fork_event fork_ev)
+{
+  if (work_thread_.get())
+  {
+    if (fork_ev == execution_context::fork_prepare)
+    {
+      work_scheduler_->stop();
+      work_thread_->join();
+      work_thread_.reset();
+    }
+  }
+  else if (fork_ev != execution_context::fork_prepare)
+  {
+    work_scheduler_->restart();
+  }
+}
+
+void resolver_service_base::construct(
+    resolver_service_base::implementation_type& impl)
+{
+  impl.reset(static_cast<void*>(0), socket_ops::noop_deleter());
+}
+
+void resolver_service_base::destroy(
+    resolver_service_base::implementation_type& impl)
+{
+  ASIO_HANDLER_OPERATION((scheduler_.context(),
+        "resolver", &impl, 0, "cancel"));
+
+  impl.reset();
+}
+
+void resolver_service_base::move_construct(implementation_type& impl,
+    implementation_type& other_impl)
+{
+  impl = ASIO_MOVE_CAST(implementation_type)(other_impl);
+}
+
+void resolver_service_base::move_assign(implementation_type& impl,
+    resolver_service_base&, implementation_type& other_impl)
+{
+  destroy(impl);
+  impl = ASIO_MOVE_CAST(implementation_type)(other_impl);
+}
+
+void resolver_service_base::cancel(
+    resolver_service_base::implementation_type& impl)
+{
+  ASIO_HANDLER_OPERATION((scheduler_.context(),
+        "resolver", &impl, 0, "cancel"));
+
+  impl.reset(static_cast<void*>(0), socket_ops::noop_deleter());
+}
+
+void resolver_service_base::start_resolve_op(resolve_op* op)
+{
+  if (ASIO_CONCURRENCY_HINT_IS_LOCKING(SCHEDULER,
+        scheduler_.concurrency_hint()))
+  {
+    start_work_thread();
+    scheduler_.work_started();
+    work_scheduler_->post_immediate_completion(op, false);
+  }
+  else
+  {
+    op->ec_ = asio::error::operation_not_supported;
+    scheduler_.post_immediate_completion(op, false);
+  }
+}
+
+void resolver_service_base::start_work_thread()
+{
+  asio::detail::mutex::scoped_lock lock(mutex_);
+  if (!work_thread_.get())
+  {
+    work_thread_.reset(new asio::detail::thread(
+          work_scheduler_runner(*work_scheduler_)));
+  }
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_IMPL_RESOLVER_SERVICE_BASE_IPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/impl/scheduler.ipp b/link/modules/asio-standalone/asio/include/asio/detail/impl/scheduler.ipp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/impl/scheduler.ipp
@@ -0,0 +1,654 @@
+//
+// detail/impl/scheduler.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_IMPL_SCHEDULER_IPP
+#define ASIO_DETAIL_IMPL_SCHEDULER_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#include "asio/detail/concurrency_hint.hpp"
+#include "asio/detail/event.hpp"
+#include "asio/detail/limits.hpp"
+#include "asio/detail/reactor.hpp"
+#include "asio/detail/scheduler.hpp"
+#include "asio/detail/scheduler_thread_info.hpp"
+#include "asio/detail/signal_blocker.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class scheduler::thread_function
+{
+public:
+  explicit thread_function(scheduler* s)
+    : this_(s)
+  {
+  }
+
+  void operator()()
+  {
+    asio::error_code ec;
+    this_->run(ec);
+  }
+
+private:
+  scheduler* this_;
+};
+
+struct scheduler::task_cleanup
+{
+  ~task_cleanup()
+  {
+    if (this_thread_->private_outstanding_work > 0)
+    {
+      asio::detail::increment(
+          scheduler_->outstanding_work_,
+          this_thread_->private_outstanding_work);
+    }
+    this_thread_->private_outstanding_work = 0;
+
+    // Enqueue the completed operations and reinsert the task at the end of
+    // the operation queue.
+    lock_->lock();
+    scheduler_->task_interrupted_ = true;
+    scheduler_->op_queue_.push(this_thread_->private_op_queue);
+    scheduler_->op_queue_.push(&scheduler_->task_operation_);
+  }
+
+  scheduler* scheduler_;
+  mutex::scoped_lock* lock_;
+  thread_info* this_thread_;
+};
+
+struct scheduler::work_cleanup
+{
+  ~work_cleanup()
+  {
+    if (this_thread_->private_outstanding_work > 1)
+    {
+      asio::detail::increment(
+          scheduler_->outstanding_work_,
+          this_thread_->private_outstanding_work - 1);
+    }
+    else if (this_thread_->private_outstanding_work < 1)
+    {
+      scheduler_->work_finished();
+    }
+    this_thread_->private_outstanding_work = 0;
+
+#if defined(ASIO_HAS_THREADS)
+    if (!this_thread_->private_op_queue.empty())
+    {
+      lock_->lock();
+      scheduler_->op_queue_.push(this_thread_->private_op_queue);
+    }
+#endif // defined(ASIO_HAS_THREADS)
+  }
+
+  scheduler* scheduler_;
+  mutex::scoped_lock* lock_;
+  thread_info* this_thread_;
+};
+
+scheduler::scheduler(asio::execution_context& ctx,
+    int concurrency_hint, bool own_thread)
+  : asio::detail::execution_context_service_base<scheduler>(ctx),
+    one_thread_(concurrency_hint == 1
+        || !ASIO_CONCURRENCY_HINT_IS_LOCKING(
+          SCHEDULER, concurrency_hint)
+        || !ASIO_CONCURRENCY_HINT_IS_LOCKING(
+          REACTOR_IO, concurrency_hint)),
+    mutex_(ASIO_CONCURRENCY_HINT_IS_LOCKING(
+          SCHEDULER, concurrency_hint)),
+    task_(0),
+    task_interrupted_(true),
+    outstanding_work_(0),
+    stopped_(false),
+    shutdown_(false),
+    concurrency_hint_(concurrency_hint),
+    thread_(0)
+{
+  ASIO_HANDLER_TRACKING_INIT;
+
+  if (own_thread)
+  {
+    ++outstanding_work_;
+    asio::detail::signal_blocker sb;
+    thread_ = new asio::detail::thread(thread_function(this));
+  }
+}
+
+scheduler::~scheduler()
+{
+  if (thread_)
+  {
+    mutex::scoped_lock lock(mutex_);
+    shutdown_ = true;
+    stop_all_threads(lock);
+    lock.unlock();
+    thread_->join();
+    delete thread_;
+  }
+}
+
+void scheduler::shutdown()
+{
+  mutex::scoped_lock lock(mutex_);
+  shutdown_ = true;
+  if (thread_)
+    stop_all_threads(lock);
+  lock.unlock();
+
+  // Join thread to ensure task operation is returned to queue.
+  if (thread_)
+  {
+    thread_->join();
+    delete thread_;
+    thread_ = 0;
+  }
+
+  // Destroy handler objects.
+  while (!op_queue_.empty())
+  {
+    operation* o = op_queue_.front();
+    op_queue_.pop();
+    if (o != &task_operation_)
+      o->destroy();
+  }
+
+  // Reset to initial state.
+  task_ = 0;
+}
+
+void scheduler::init_task()
+{
+  mutex::scoped_lock lock(mutex_);
+  if (!shutdown_ && !task_)
+  {
+    task_ = &use_service<reactor>(this->context());
+    op_queue_.push(&task_operation_);
+    wake_one_thread_and_unlock(lock);
+  }
+}
+
+std::size_t scheduler::run(asio::error_code& ec)
+{
+  ec = asio::error_code();
+  if (outstanding_work_ == 0)
+  {
+    stop();
+    return 0;
+  }
+
+  thread_info this_thread;
+  this_thread.private_outstanding_work = 0;
+  thread_call_stack::context ctx(this, this_thread);
+
+  mutex::scoped_lock lock(mutex_);
+
+  std::size_t n = 0;
+  for (; do_run_one(lock, this_thread, ec); lock.lock())
+    if (n != (std::numeric_limits<std::size_t>::max)())
+      ++n;
+  return n;
+}
+
+std::size_t scheduler::run_one(asio::error_code& ec)
+{
+  ec = asio::error_code();
+  if (outstanding_work_ == 0)
+  {
+    stop();
+    return 0;
+  }
+
+  thread_info this_thread;
+  this_thread.private_outstanding_work = 0;
+  thread_call_stack::context ctx(this, this_thread);
+
+  mutex::scoped_lock lock(mutex_);
+
+  return do_run_one(lock, this_thread, ec);
+}
+
+std::size_t scheduler::wait_one(long usec, asio::error_code& ec)
+{
+  ec = asio::error_code();
+  if (outstanding_work_ == 0)
+  {
+    stop();
+    return 0;
+  }
+
+  thread_info this_thread;
+  this_thread.private_outstanding_work = 0;
+  thread_call_stack::context ctx(this, this_thread);
+
+  mutex::scoped_lock lock(mutex_);
+
+  return do_wait_one(lock, this_thread, usec, ec);
+}
+
+std::size_t scheduler::poll(asio::error_code& ec)
+{
+  ec = asio::error_code();
+  if (outstanding_work_ == 0)
+  {
+    stop();
+    return 0;
+  }
+
+  thread_info this_thread;
+  this_thread.private_outstanding_work = 0;
+  thread_call_stack::context ctx(this, this_thread);
+
+  mutex::scoped_lock lock(mutex_);
+
+#if defined(ASIO_HAS_THREADS)
+  // We want to support nested calls to poll() and poll_one(), so any handlers
+  // that are already on a thread-private queue need to be put on to the main
+  // queue now.
+  if (one_thread_)
+    if (thread_info* outer_info = static_cast<thread_info*>(ctx.next_by_key()))
+      op_queue_.push(outer_info->private_op_queue);
+#endif // defined(ASIO_HAS_THREADS)
+
+  std::size_t n = 0;
+  for (; do_poll_one(lock, this_thread, ec); lock.lock())
+    if (n != (std::numeric_limits<std::size_t>::max)())
+      ++n;
+  return n;
+}
+
+std::size_t scheduler::poll_one(asio::error_code& ec)
+{
+  ec = asio::error_code();
+  if (outstanding_work_ == 0)
+  {
+    stop();
+    return 0;
+  }
+
+  thread_info this_thread;
+  this_thread.private_outstanding_work = 0;
+  thread_call_stack::context ctx(this, this_thread);
+
+  mutex::scoped_lock lock(mutex_);
+
+#if defined(ASIO_HAS_THREADS)
+  // We want to support nested calls to poll() and poll_one(), so any handlers
+  // that are already on a thread-private queue need to be put on to the main
+  // queue now.
+  if (one_thread_)
+    if (thread_info* outer_info = static_cast<thread_info*>(ctx.next_by_key()))
+      op_queue_.push(outer_info->private_op_queue);
+#endif // defined(ASIO_HAS_THREADS)
+
+  return do_poll_one(lock, this_thread, ec);
+}
+
+void scheduler::stop()
+{
+  mutex::scoped_lock lock(mutex_);
+  stop_all_threads(lock);
+}
+
+bool scheduler::stopped() const
+{
+  mutex::scoped_lock lock(mutex_);
+  return stopped_;
+}
+
+void scheduler::restart()
+{
+  mutex::scoped_lock lock(mutex_);
+  stopped_ = false;
+}
+
+void scheduler::compensating_work_started()
+{
+  thread_info_base* this_thread = thread_call_stack::contains(this);
+  ++static_cast<thread_info*>(this_thread)->private_outstanding_work;
+}
+
+void scheduler::capture_current_exception()
+{
+  if (thread_info_base* this_thread = thread_call_stack::contains(this))
+    this_thread->capture_current_exception();
+}
+
+void scheduler::post_immediate_completion(
+    scheduler::operation* op, bool is_continuation)
+{
+#if defined(ASIO_HAS_THREADS)
+  if (one_thread_ || is_continuation)
+  {
+    if (thread_info_base* this_thread = thread_call_stack::contains(this))
+    {
+      ++static_cast<thread_info*>(this_thread)->private_outstanding_work;
+      static_cast<thread_info*>(this_thread)->private_op_queue.push(op);
+      return;
+    }
+  }
+#else // defined(ASIO_HAS_THREADS)
+  (void)is_continuation;
+#endif // defined(ASIO_HAS_THREADS)
+
+  work_started();
+  mutex::scoped_lock lock(mutex_);
+  op_queue_.push(op);
+  wake_one_thread_and_unlock(lock);
+}
+
+void scheduler::post_immediate_completions(std::size_t n,
+    op_queue<scheduler::operation>& ops, bool is_continuation)
+{
+#if defined(ASIO_HAS_THREADS)
+  if (one_thread_ || is_continuation)
+  {
+    if (thread_info_base* this_thread = thread_call_stack::contains(this))
+    {
+      static_cast<thread_info*>(this_thread)->private_outstanding_work
+        += static_cast<long>(n);
+      static_cast<thread_info*>(this_thread)->private_op_queue.push(ops);
+      return;
+    }
+  }
+#else // defined(ASIO_HAS_THREADS)
+  (void)is_continuation;
+#endif // defined(ASIO_HAS_THREADS)
+
+  increment(outstanding_work_, static_cast<long>(n));
+  mutex::scoped_lock lock(mutex_);
+  op_queue_.push(ops);
+  wake_one_thread_and_unlock(lock);
+}
+
+void scheduler::post_deferred_completion(scheduler::operation* op)
+{
+#if defined(ASIO_HAS_THREADS)
+  if (one_thread_)
+  {
+    if (thread_info_base* this_thread = thread_call_stack::contains(this))
+    {
+      static_cast<thread_info*>(this_thread)->private_op_queue.push(op);
+      return;
+    }
+  }
+#endif // defined(ASIO_HAS_THREADS)
+
+  mutex::scoped_lock lock(mutex_);
+  op_queue_.push(op);
+  wake_one_thread_and_unlock(lock);
+}
+
+void scheduler::post_deferred_completions(
+    op_queue<scheduler::operation>& ops)
+{
+  if (!ops.empty())
+  {
+#if defined(ASIO_HAS_THREADS)
+    if (one_thread_)
+    {
+      if (thread_info_base* this_thread = thread_call_stack::contains(this))
+      {
+        static_cast<thread_info*>(this_thread)->private_op_queue.push(ops);
+        return;
+      }
+    }
+#endif // defined(ASIO_HAS_THREADS)
+
+    mutex::scoped_lock lock(mutex_);
+    op_queue_.push(ops);
+    wake_one_thread_and_unlock(lock);
+  }
+}
+
+void scheduler::do_dispatch(
+    scheduler::operation* op)
+{
+  work_started();
+  mutex::scoped_lock lock(mutex_);
+  op_queue_.push(op);
+  wake_one_thread_and_unlock(lock);
+}
+
+void scheduler::abandon_operations(
+    op_queue<scheduler::operation>& ops)
+{
+  op_queue<scheduler::operation> ops2;
+  ops2.push(ops);
+}
+
+std::size_t scheduler::do_run_one(mutex::scoped_lock& lock,
+    scheduler::thread_info& this_thread,
+    const asio::error_code& ec)
+{
+  while (!stopped_)
+  {
+    if (!op_queue_.empty())
+    {
+      // Prepare to execute first handler from queue.
+      operation* o = op_queue_.front();
+      op_queue_.pop();
+      bool more_handlers = (!op_queue_.empty());
+
+      if (o == &task_operation_)
+      {
+        task_interrupted_ = more_handlers;
+
+        if (more_handlers && !one_thread_)
+          wakeup_event_.unlock_and_signal_one(lock);
+        else
+          lock.unlock();
+
+        task_cleanup on_exit = { this, &lock, &this_thread };
+        (void)on_exit;
+
+        // Run the task. May throw an exception. Only block if the operation
+        // queue is empty and we're not polling, otherwise we want to return
+        // as soon as possible.
+        task_->run(more_handlers ? 0 : -1, this_thread.private_op_queue);
+      }
+      else
+      {
+        std::size_t task_result = o->task_result_;
+
+        if (more_handlers && !one_thread_)
+          wake_one_thread_and_unlock(lock);
+        else
+          lock.unlock();
+
+        // Ensure the count of outstanding work is decremented on block exit.
+        work_cleanup on_exit = { this, &lock, &this_thread };
+        (void)on_exit;
+
+        // Complete the operation. May throw an exception. Deletes the object.
+        o->complete(this, ec, task_result);
+        this_thread.rethrow_pending_exception();
+
+        return 1;
+      }
+    }
+    else
+    {
+      wakeup_event_.clear(lock);
+      wakeup_event_.wait(lock);
+    }
+  }
+
+  return 0;
+}
+
+std::size_t scheduler::do_wait_one(mutex::scoped_lock& lock,
+    scheduler::thread_info& this_thread, long usec,
+    const asio::error_code& ec)
+{
+  if (stopped_)
+    return 0;
+
+  operation* o = op_queue_.front();
+  if (o == 0)
+  {
+    wakeup_event_.clear(lock);
+    wakeup_event_.wait_for_usec(lock, usec);
+    usec = 0; // Wait at most once.
+    o = op_queue_.front();
+  }
+
+  if (o == &task_operation_)
+  {
+    op_queue_.pop();
+    bool more_handlers = (!op_queue_.empty());
+
+    task_interrupted_ = more_handlers;
+
+    if (more_handlers && !one_thread_)
+      wakeup_event_.unlock_and_signal_one(lock);
+    else
+      lock.unlock();
+
+    {
+      task_cleanup on_exit = { this, &lock, &this_thread };
+      (void)on_exit;
+
+      // Run the task. May throw an exception. Only block if the operation
+      // queue is empty and we're not polling, otherwise we want to return
+      // as soon as possible.
+      task_->run(more_handlers ? 0 : usec, this_thread.private_op_queue);
+    }
+
+    o = op_queue_.front();
+    if (o == &task_operation_)
+    {
+      if (!one_thread_)
+        wakeup_event_.maybe_unlock_and_signal_one(lock);
+      return 0;
+    }
+  }
+
+  if (o == 0)
+    return 0;
+
+  op_queue_.pop();
+  bool more_handlers = (!op_queue_.empty());
+
+  std::size_t task_result = o->task_result_;
+
+  if (more_handlers && !one_thread_)
+    wake_one_thread_and_unlock(lock);
+  else
+    lock.unlock();
+
+  // Ensure the count of outstanding work is decremented on block exit.
+  work_cleanup on_exit = { this, &lock, &this_thread };
+  (void)on_exit;
+
+  // Complete the operation. May throw an exception. Deletes the object.
+  o->complete(this, ec, task_result);
+  this_thread.rethrow_pending_exception();
+
+  return 1;
+}
+
+std::size_t scheduler::do_poll_one(mutex::scoped_lock& lock,
+    scheduler::thread_info& this_thread,
+    const asio::error_code& ec)
+{
+  if (stopped_)
+    return 0;
+
+  operation* o = op_queue_.front();
+  if (o == &task_operation_)
+  {
+    op_queue_.pop();
+    lock.unlock();
+
+    {
+      task_cleanup c = { this, &lock, &this_thread };
+      (void)c;
+
+      // Run the task. May throw an exception. Only block if the operation
+      // queue is empty and we're not polling, otherwise we want to return
+      // as soon as possible.
+      task_->run(0, this_thread.private_op_queue);
+    }
+
+    o = op_queue_.front();
+    if (o == &task_operation_)
+    {
+      wakeup_event_.maybe_unlock_and_signal_one(lock);
+      return 0;
+    }
+  }
+
+  if (o == 0)
+    return 0;
+
+  op_queue_.pop();
+  bool more_handlers = (!op_queue_.empty());
+
+  std::size_t task_result = o->task_result_;
+
+  if (more_handlers && !one_thread_)
+    wake_one_thread_and_unlock(lock);
+  else
+    lock.unlock();
+
+  // Ensure the count of outstanding work is decremented on block exit.
+  work_cleanup on_exit = { this, &lock, &this_thread };
+  (void)on_exit;
+
+  // Complete the operation. May throw an exception. Deletes the object.
+  o->complete(this, ec, task_result);
+  this_thread.rethrow_pending_exception();
+
+  return 1;
+}
+
+void scheduler::stop_all_threads(
+    mutex::scoped_lock& lock)
+{
+  stopped_ = true;
+  wakeup_event_.signal_all(lock);
+
+  if (!task_interrupted_ && task_)
+  {
+    task_interrupted_ = true;
+    task_->interrupt();
+  }
+}
+
+void scheduler::wake_one_thread_and_unlock(
+    mutex::scoped_lock& lock)
+{
+  if (!wakeup_event_.maybe_unlock_and_signal_one(lock))
+  {
+    if (!task_interrupted_ && task_)
+    {
+      task_interrupted_ = true;
+      task_->interrupt();
+    }
+    lock.unlock();
+  }
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_IMPL_SCHEDULER_IPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/impl/select_reactor.hpp b/link/modules/asio-standalone/asio/include/asio/detail/impl/select_reactor.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/impl/select_reactor.hpp
@@ -0,0 +1,100 @@
+//
+// detail/impl/select_reactor.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_IMPL_SELECT_REACTOR_HPP
+#define ASIO_DETAIL_IMPL_SELECT_REACTOR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_IOCP) \
+  || (!defined(ASIO_HAS_DEV_POLL) \
+      && !defined(ASIO_HAS_EPOLL) \
+      && !defined(ASIO_HAS_KQUEUE) \
+      && !defined(ASIO_WINDOWS_RUNTIME))
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Time_Traits>
+void select_reactor::add_timer_queue(timer_queue<Time_Traits>& queue)
+{
+  do_add_timer_queue(queue);
+}
+
+// Remove a timer queue from the reactor.
+template <typename Time_Traits>
+void select_reactor::remove_timer_queue(timer_queue<Time_Traits>& queue)
+{
+  do_remove_timer_queue(queue);
+}
+
+template <typename Time_Traits>
+void select_reactor::schedule_timer(timer_queue<Time_Traits>& queue,
+    const typename Time_Traits::time_type& time,
+    typename timer_queue<Time_Traits>::per_timer_data& timer, wait_op* op)
+{
+  asio::detail::mutex::scoped_lock lock(mutex_);
+
+  if (shutdown_)
+  {
+    scheduler_.post_immediate_completion(op, false);
+    return;
+  }
+
+  bool earliest = queue.enqueue_timer(time, timer, op);
+  scheduler_.work_started();
+  if (earliest)
+    interrupter_.interrupt();
+}
+
+template <typename Time_Traits>
+std::size_t select_reactor::cancel_timer(timer_queue<Time_Traits>& queue,
+    typename timer_queue<Time_Traits>::per_timer_data& timer,
+    std::size_t max_cancelled)
+{
+  asio::detail::mutex::scoped_lock lock(mutex_);
+  op_queue<operation> ops;
+  std::size_t n = queue.cancel_timer(timer, ops, max_cancelled);
+  lock.unlock();
+  scheduler_.post_deferred_completions(ops);
+  return n;
+}
+
+template <typename Time_Traits>
+void select_reactor::move_timer(timer_queue<Time_Traits>& queue,
+    typename timer_queue<Time_Traits>::per_timer_data& target,
+    typename timer_queue<Time_Traits>::per_timer_data& source)
+{
+  asio::detail::mutex::scoped_lock lock(mutex_);
+  op_queue<operation> ops;
+  queue.cancel_timer(target, ops);
+  queue.move_timer(target, source);
+  lock.unlock();
+  scheduler_.post_deferred_completions(ops);
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_IOCP)
+       //   || (!defined(ASIO_HAS_DEV_POLL)
+       //       && !defined(ASIO_HAS_EPOLL)
+       //       && !defined(ASIO_HAS_KQUEUE)
+       //       && !defined(ASIO_WINDOWS_RUNTIME))
+
+#endif // ASIO_DETAIL_IMPL_SELECT_REACTOR_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/impl/select_reactor.ipp b/link/modules/asio-standalone/asio/include/asio/detail/impl/select_reactor.ipp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/impl/select_reactor.ipp
@@ -0,0 +1,338 @@
+//
+// detail/impl/select_reactor.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_IMPL_SELECT_REACTOR_IPP
+#define ASIO_DETAIL_IMPL_SELECT_REACTOR_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_IOCP) \
+  || (!defined(ASIO_HAS_DEV_POLL) \
+      && !defined(ASIO_HAS_EPOLL) \
+      && !defined(ASIO_HAS_KQUEUE) \
+      && !defined(ASIO_WINDOWS_RUNTIME))
+
+#include "asio/detail/fd_set_adapter.hpp"
+#include "asio/detail/select_reactor.hpp"
+#include "asio/detail/signal_blocker.hpp"
+#include "asio/detail/socket_ops.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+#if defined(ASIO_HAS_IOCP)
+class select_reactor::thread_function
+{
+public:
+  explicit thread_function(select_reactor* r)
+    : this_(r)
+  {
+  }
+
+  void operator()()
+  {
+    this_->run_thread();
+  }
+
+private:
+  select_reactor* this_;
+};
+#endif // defined(ASIO_HAS_IOCP)
+
+select_reactor::select_reactor(asio::execution_context& ctx)
+  : execution_context_service_base<select_reactor>(ctx),
+    scheduler_(use_service<scheduler_type>(ctx)),
+    mutex_(),
+    interrupter_(),
+#if defined(ASIO_HAS_IOCP)
+    stop_thread_(false),
+    thread_(0),
+#endif // defined(ASIO_HAS_IOCP)
+    shutdown_(false)
+{
+#if defined(ASIO_HAS_IOCP)
+  asio::detail::signal_blocker sb;
+  thread_ = new asio::detail::thread(thread_function(this));
+#endif // defined(ASIO_HAS_IOCP)
+}
+
+select_reactor::~select_reactor()
+{
+  shutdown();
+}
+
+void select_reactor::shutdown()
+{
+  asio::detail::mutex::scoped_lock lock(mutex_);
+  shutdown_ = true;
+#if defined(ASIO_HAS_IOCP)
+  stop_thread_ = true;
+  if (thread_)
+    interrupter_.interrupt();
+#endif // defined(ASIO_HAS_IOCP)
+  lock.unlock();
+
+#if defined(ASIO_HAS_IOCP)
+  if (thread_)
+  {
+    thread_->join();
+    delete thread_;
+    thread_ = 0;
+  }
+#endif // defined(ASIO_HAS_IOCP)
+
+  op_queue<operation> ops;
+
+  for (int i = 0; i < max_ops; ++i)
+    op_queue_[i].get_all_operations(ops);
+
+  timer_queues_.get_all_timers(ops);
+
+  scheduler_.abandon_operations(ops);
+}
+
+void select_reactor::notify_fork(
+    asio::execution_context::fork_event fork_ev)
+{
+  if (fork_ev == asio::execution_context::fork_child)
+    interrupter_.recreate();
+}
+
+void select_reactor::init_task()
+{
+  scheduler_.init_task();
+}
+
+int select_reactor::register_descriptor(socket_type,
+    select_reactor::per_descriptor_data&)
+{
+  return 0;
+}
+
+int select_reactor::register_internal_descriptor(
+    int op_type, socket_type descriptor,
+    select_reactor::per_descriptor_data&, reactor_op* op)
+{
+  asio::detail::mutex::scoped_lock lock(mutex_);
+
+  op_queue_[op_type].enqueue_operation(descriptor, op);
+  interrupter_.interrupt();
+
+  return 0;
+}
+
+void select_reactor::move_descriptor(socket_type,
+    select_reactor::per_descriptor_data&,
+    select_reactor::per_descriptor_data&)
+{
+}
+
+void select_reactor::start_op(int op_type, socket_type descriptor,
+    select_reactor::per_descriptor_data&, reactor_op* op,
+    bool is_continuation, bool)
+{
+  asio::detail::mutex::scoped_lock lock(mutex_);
+
+  if (shutdown_)
+  {
+    post_immediate_completion(op, is_continuation);
+    return;
+  }
+
+  bool first = op_queue_[op_type].enqueue_operation(descriptor, op);
+  scheduler_.work_started();
+  if (first)
+    interrupter_.interrupt();
+}
+
+void select_reactor::cancel_ops(socket_type descriptor,
+    select_reactor::per_descriptor_data&)
+{
+  asio::detail::mutex::scoped_lock lock(mutex_);
+  cancel_ops_unlocked(descriptor, asio::error::operation_aborted);
+}
+
+void select_reactor::deregister_descriptor(socket_type descriptor,
+    select_reactor::per_descriptor_data&, bool)
+{
+  asio::detail::mutex::scoped_lock lock(mutex_);
+  cancel_ops_unlocked(descriptor, asio::error::operation_aborted);
+}
+
+void select_reactor::deregister_internal_descriptor(
+    socket_type descriptor, select_reactor::per_descriptor_data&)
+{
+  asio::detail::mutex::scoped_lock lock(mutex_);
+  op_queue<operation> ops;
+  for (int i = 0; i < max_ops; ++i)
+    op_queue_[i].cancel_operations(descriptor, ops);
+}
+
+void select_reactor::cleanup_descriptor_data(
+    select_reactor::per_descriptor_data&)
+{
+}
+
+void select_reactor::run(long usec, op_queue<operation>& ops)
+{
+  asio::detail::mutex::scoped_lock lock(mutex_);
+
+#if defined(ASIO_HAS_IOCP)
+  // Check if the thread is supposed to stop.
+  if (stop_thread_)
+    return;
+#endif // defined(ASIO_HAS_IOCP)
+
+  // Set up the descriptor sets.
+  for (int i = 0; i < max_select_ops; ++i)
+    fd_sets_[i].reset();
+  fd_sets_[read_op].set(interrupter_.read_descriptor());
+  socket_type max_fd = 0;
+  bool have_work_to_do = !timer_queues_.all_empty();
+  for (int i = 0; i < max_select_ops; ++i)
+  {
+    have_work_to_do = have_work_to_do || !op_queue_[i].empty();
+    fd_sets_[i].set(op_queue_[i], ops);
+    if (fd_sets_[i].max_descriptor() > max_fd)
+      max_fd = fd_sets_[i].max_descriptor();
+  }
+
+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+  // Connection operations on Windows use both except and write fd_sets.
+  have_work_to_do = have_work_to_do || !op_queue_[connect_op].empty();
+  fd_sets_[write_op].set(op_queue_[connect_op], ops);
+  if (fd_sets_[write_op].max_descriptor() > max_fd)
+    max_fd = fd_sets_[write_op].max_descriptor();
+  fd_sets_[except_op].set(op_queue_[connect_op], ops);
+  if (fd_sets_[except_op].max_descriptor() > max_fd)
+    max_fd = fd_sets_[except_op].max_descriptor();
+#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+
+  // We can return immediately if there's no work to do and the reactor is
+  // not supposed to block.
+  if (!usec && !have_work_to_do)
+    return;
+
+  // Determine how long to block while waiting for events.
+  timeval tv_buf = { 0, 0 };
+  timeval* tv = usec ? get_timeout(usec, tv_buf) : &tv_buf;
+
+  lock.unlock();
+
+  // Block on the select call until descriptors become ready.
+  asio::error_code ec;
+  int retval = socket_ops::select(static_cast<int>(max_fd + 1),
+      fd_sets_[read_op], fd_sets_[write_op], fd_sets_[except_op], tv, ec);
+
+  // Reset the interrupter.
+  if (retval > 0 && fd_sets_[read_op].is_set(interrupter_.read_descriptor()))
+  {
+    if (!interrupter_.reset())
+    {
+      lock.lock();
+      interrupter_.recreate();
+    }
+    --retval;
+  }
+
+  lock.lock();
+
+  // Dispatch all ready operations.
+  if (retval > 0)
+  {
+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+    // Connection operations on Windows use both except and write fd_sets.
+    fd_sets_[except_op].perform(op_queue_[connect_op], ops);
+    fd_sets_[write_op].perform(op_queue_[connect_op], ops);
+#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+
+    // Exception operations must be processed first to ensure that any
+    // out-of-band data is read before normal data.
+    for (int i = max_select_ops - 1; i >= 0; --i)
+      fd_sets_[i].perform(op_queue_[i], ops);
+  }
+  timer_queues_.get_ready_timers(ops);
+}
+
+void select_reactor::interrupt()
+{
+  interrupter_.interrupt();
+}
+
+#if defined(ASIO_HAS_IOCP)
+void select_reactor::run_thread()
+{
+  asio::detail::mutex::scoped_lock lock(mutex_);
+  while (!stop_thread_)
+  {
+    lock.unlock();
+    op_queue<operation> ops;
+    run(true, ops);
+    scheduler_.post_deferred_completions(ops);
+    lock.lock();
+  }
+}
+#endif // defined(ASIO_HAS_IOCP)
+
+void select_reactor::do_add_timer_queue(timer_queue_base& queue)
+{
+  mutex::scoped_lock lock(mutex_);
+  timer_queues_.insert(&queue);
+}
+
+void select_reactor::do_remove_timer_queue(timer_queue_base& queue)
+{
+  mutex::scoped_lock lock(mutex_);
+  timer_queues_.erase(&queue);
+}
+
+timeval* select_reactor::get_timeout(long usec, timeval& tv)
+{
+  // By default we will wait no longer than 5 minutes. This will ensure that
+  // any changes to the system clock are detected after no longer than this.
+  const long max_usec = 5 * 60 * 1000 * 1000;
+  usec = timer_queues_.wait_duration_usec(
+      (usec < 0 || max_usec < usec) ? max_usec : usec);
+  tv.tv_sec = usec / 1000000;
+  tv.tv_usec = usec % 1000000;
+  return &tv;
+}
+
+void select_reactor::cancel_ops_unlocked(socket_type descriptor,
+    const asio::error_code& ec)
+{
+  bool need_interrupt = false;
+  op_queue<operation> ops;
+  for (int i = 0; i < max_ops; ++i)
+    need_interrupt = op_queue_[i].cancel_operations(
+        descriptor, ops, ec) || need_interrupt;
+  scheduler_.post_deferred_completions(ops);
+  if (need_interrupt)
+    interrupter_.interrupt();
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_IOCP)
+       //   || (!defined(ASIO_HAS_DEV_POLL)
+       //       && !defined(ASIO_HAS_EPOLL)
+       //       && !defined(ASIO_HAS_KQUEUE))
+       //       && !defined(ASIO_WINDOWS_RUNTIME))
+
+#endif // ASIO_DETAIL_IMPL_SELECT_REACTOR_IPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/impl/service_registry.hpp b/link/modules/asio-standalone/asio/include/asio/detail/impl/service_registry.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/impl/service_registry.hpp
@@ -0,0 +1,94 @@
+//
+// detail/impl/service_registry.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_IMPL_SERVICE_REGISTRY_HPP
+#define ASIO_DETAIL_IMPL_SERVICE_REGISTRY_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Service>
+Service& service_registry::use_service()
+{
+  execution_context::service::key key;
+  init_key<Service>(key, 0);
+  factory_type factory = &service_registry::create<Service, execution_context>;
+  return *static_cast<Service*>(do_use_service(key, factory, &owner_));
+}
+
+template <typename Service>
+Service& service_registry::use_service(io_context& owner)
+{
+  execution_context::service::key key;
+  init_key<Service>(key, 0);
+  factory_type factory = &service_registry::create<Service, io_context>;
+  return *static_cast<Service*>(do_use_service(key, factory, &owner));
+}
+
+template <typename Service>
+void service_registry::add_service(Service* new_service)
+{
+  execution_context::service::key key;
+  init_key<Service>(key, 0);
+  return do_add_service(key, new_service);
+}
+
+template <typename Service>
+bool service_registry::has_service() const
+{
+  execution_context::service::key key;
+  init_key<Service>(key, 0);
+  return do_has_service(key);
+}
+
+template <typename Service>
+inline void service_registry::init_key(
+    execution_context::service::key& key, ...)
+{
+  init_key_from_id(key, Service::id);
+}
+
+#if !defined(ASIO_NO_TYPEID)
+template <typename Service>
+void service_registry::init_key(execution_context::service::key& key,
+    typename enable_if<
+      is_base_of<typename Service::key_type, Service>::value>::type*)
+{
+  key.type_info_ = &typeid(typeid_wrapper<Service>);
+  key.id_ = 0;
+}
+
+template <typename Service>
+void service_registry::init_key_from_id(execution_context::service::key& key,
+    const service_id<Service>& /*id*/)
+{
+  key.type_info_ = &typeid(typeid_wrapper<Service>);
+  key.id_ = 0;
+}
+#endif // !defined(ASIO_NO_TYPEID)
+
+template <typename Service, typename Owner>
+execution_context::service* service_registry::create(void* owner)
+{
+  return new Service(*static_cast<Owner*>(owner));
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_IMPL_SERVICE_REGISTRY_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/impl/service_registry.ipp b/link/modules/asio-standalone/asio/include/asio/detail/impl/service_registry.ipp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/impl/service_registry.ipp
@@ -0,0 +1,197 @@
+//
+// detail/impl/service_registry.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_IMPL_SERVICE_REGISTRY_IPP
+#define ASIO_DETAIL_IMPL_SERVICE_REGISTRY_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <vector>
+#include "asio/detail/service_registry.hpp"
+#include "asio/detail/throw_exception.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+service_registry::service_registry(execution_context& owner)
+  : owner_(owner),
+    first_service_(0)
+{
+}
+
+service_registry::~service_registry()
+{
+}
+
+void service_registry::shutdown_services()
+{
+  execution_context::service* service = first_service_;
+  while (service)
+  {
+    service->shutdown();
+    service = service->next_;
+  }
+}
+
+void service_registry::destroy_services()
+{
+  while (first_service_)
+  {
+    execution_context::service* next_service = first_service_->next_;
+    destroy(first_service_);
+    first_service_ = next_service;
+  }
+}
+
+void service_registry::notify_fork(execution_context::fork_event fork_ev)
+{
+  // Make a copy of all of the services while holding the lock. We don't want
+  // to hold the lock while calling into each service, as it may try to call
+  // back into this class.
+  std::vector<execution_context::service*> services;
+  {
+    asio::detail::mutex::scoped_lock lock(mutex_);
+    execution_context::service* service = first_service_;
+    while (service)
+    {
+      services.push_back(service);
+      service = service->next_;
+    }
+  }
+
+  // If processing the fork_prepare event, we want to go in reverse order of
+  // service registration, which happens to be the existing order of the
+  // services in the vector. For the other events we want to go in the other
+  // direction.
+  std::size_t num_services = services.size();
+  if (fork_ev == execution_context::fork_prepare)
+    for (std::size_t i = 0; i < num_services; ++i)
+      services[i]->notify_fork(fork_ev);
+  else
+    for (std::size_t i = num_services; i > 0; --i)
+      services[i - 1]->notify_fork(fork_ev);
+}
+
+void service_registry::init_key_from_id(execution_context::service::key& key,
+    const execution_context::id& id)
+{
+  key.type_info_ = 0;
+  key.id_ = &id;
+}
+
+bool service_registry::keys_match(
+    const execution_context::service::key& key1,
+    const execution_context::service::key& key2)
+{
+  if (key1.id_ && key2.id_)
+    if (key1.id_ == key2.id_)
+      return true;
+  if (key1.type_info_ && key2.type_info_)
+    if (*key1.type_info_ == *key2.type_info_)
+      return true;
+  return false;
+}
+
+void service_registry::destroy(execution_context::service* service)
+{
+  delete service;
+}
+
+execution_context::service* service_registry::do_use_service(
+    const execution_context::service::key& key,
+    factory_type factory, void* owner)
+{
+  asio::detail::mutex::scoped_lock lock(mutex_);
+
+  // First see if there is an existing service object with the given key.
+  execution_context::service* service = first_service_;
+  while (service)
+  {
+    if (keys_match(service->key_, key))
+      return service;
+    service = service->next_;
+  }
+
+  // Create a new service object. The service registry's mutex is not locked
+  // at this time to allow for nested calls into this function from the new
+  // service's constructor.
+  lock.unlock();
+  auto_service_ptr new_service = { factory(owner) };
+  new_service.ptr_->key_ = key;
+  lock.lock();
+
+  // Check that nobody else created another service object of the same type
+  // while the lock was released.
+  service = first_service_;
+  while (service)
+  {
+    if (keys_match(service->key_, key))
+      return service;
+    service = service->next_;
+  }
+
+  // Service was successfully initialised, pass ownership to registry.
+  new_service.ptr_->next_ = first_service_;
+  first_service_ = new_service.ptr_;
+  new_service.ptr_ = 0;
+  return first_service_;
+}
+
+void service_registry::do_add_service(
+    const execution_context::service::key& key,
+    execution_context::service* new_service)
+{
+  if (&owner_ != &new_service->context())
+    asio::detail::throw_exception(invalid_service_owner());
+
+  asio::detail::mutex::scoped_lock lock(mutex_);
+
+  // Check if there is an existing service object with the given key.
+  execution_context::service* service = first_service_;
+  while (service)
+  {
+    if (keys_match(service->key_, key))
+      asio::detail::throw_exception(service_already_exists());
+    service = service->next_;
+  }
+
+  // Take ownership of the service object.
+  new_service->key_ = key;
+  new_service->next_ = first_service_;
+  first_service_ = new_service;
+}
+
+bool service_registry::do_has_service(
+    const execution_context::service::key& key) const
+{
+  asio::detail::mutex::scoped_lock lock(mutex_);
+
+  execution_context::service* service = first_service_;
+  while (service)
+  {
+    if (keys_match(service->key_, key))
+      return true;
+    service = service->next_;
+  }
+
+  return false;
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_IMPL_SERVICE_REGISTRY_IPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/impl/signal_set_service.ipp b/link/modules/asio-standalone/asio/include/asio/detail/impl/signal_set_service.ipp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/impl/signal_set_service.ipp
@@ -0,0 +1,668 @@
+//
+// detail/impl/signal_set_service.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_IMPL_SIGNAL_SET_SERVICE_IPP
+#define ASIO_DETAIL_IMPL_SIGNAL_SET_SERVICE_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#include <cstring>
+#include <stdexcept>
+#include "asio/detail/reactor.hpp"
+#include "asio/detail/signal_blocker.hpp"
+#include "asio/detail/signal_set_service.hpp"
+#include "asio/detail/static_mutex.hpp"
+#include "asio/detail/throw_exception.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+struct signal_state
+{
+  // Mutex used for protecting global state.
+  static_mutex mutex_;
+
+  // The read end of the pipe used for signal notifications.
+  int read_descriptor_;
+
+  // The write end of the pipe used for signal notifications.
+  int write_descriptor_;
+
+  // Whether the signal state has been prepared for a fork.
+  bool fork_prepared_;
+
+  // The head of a linked list of all signal_set_service instances.
+  class signal_set_service* service_list_;
+
+  // A count of the number of objects that are registered for each signal.
+  std::size_t registration_count_[max_signal_number];
+};
+
+signal_state* get_signal_state()
+{
+  static signal_state state = {
+    ASIO_STATIC_MUTEX_INIT, -1, -1, false, 0, { 0 } };
+  return &state;
+}
+
+void asio_signal_handler(int signal_number)
+{
+#if defined(ASIO_WINDOWS) \
+  || defined(ASIO_WINDOWS_RUNTIME) \
+  || defined(__CYGWIN__)
+  signal_set_service::deliver_signal(signal_number);
+#else // defined(ASIO_WINDOWS)
+      //   || defined(ASIO_WINDOWS_RUNTIME)
+      //   || defined(__CYGWIN__)
+  int saved_errno = errno;
+  signal_state* state = get_signal_state();
+  signed_size_type result = ::write(state->write_descriptor_,
+      &signal_number, sizeof(signal_number));
+  (void)result;
+  errno = saved_errno;
+#endif // defined(ASIO_WINDOWS)
+       //   || defined(ASIO_WINDOWS_RUNTIME)
+       //   || defined(__CYGWIN__)
+
+#if defined(ASIO_HAS_SIGNAL) && !defined(ASIO_HAS_SIGACTION)
+  ::signal(signal_number, asio_signal_handler);
+#endif // defined(ASIO_HAS_SIGNAL) && !defined(ASIO_HAS_SIGACTION)
+}
+
+#if !defined(ASIO_WINDOWS) \
+  && !defined(ASIO_WINDOWS_RUNTIME) \
+  && !defined(__CYGWIN__)
+class signal_set_service::pipe_read_op : public reactor_op
+{
+public:
+  pipe_read_op()
+    : reactor_op(asio::error_code(),
+        &pipe_read_op::do_perform, pipe_read_op::do_complete)
+  {
+  }
+
+  static status do_perform(reactor_op*)
+  {
+    signal_state* state = get_signal_state();
+
+    int fd = state->read_descriptor_;
+    int signal_number = 0;
+    while (::read(fd, &signal_number, sizeof(int)) == sizeof(int))
+      if (signal_number >= 0 && signal_number < max_signal_number)
+        signal_set_service::deliver_signal(signal_number);
+
+    return not_done;
+  }
+
+  static void do_complete(void* /*owner*/, operation* base,
+      const asio::error_code& /*ec*/,
+      std::size_t /*bytes_transferred*/)
+  {
+    pipe_read_op* o(static_cast<pipe_read_op*>(base));
+    delete o;
+  }
+};
+#endif // !defined(ASIO_WINDOWS)
+       //   && !defined(ASIO_WINDOWS_RUNTIME)
+       //   && !defined(__CYGWIN__)
+
+signal_set_service::signal_set_service(execution_context& context)
+  : execution_context_service_base<signal_set_service>(context),
+    scheduler_(asio::use_service<scheduler_impl>(context)),
+#if !defined(ASIO_WINDOWS) \
+  && !defined(ASIO_WINDOWS_RUNTIME) \
+  && !defined(__CYGWIN__)
+    reactor_(asio::use_service<reactor>(context)),
+#endif // !defined(ASIO_WINDOWS)
+       //   && !defined(ASIO_WINDOWS_RUNTIME)
+       //   && !defined(__CYGWIN__)
+    next_(0),
+    prev_(0)
+{
+  get_signal_state()->mutex_.init();
+
+#if !defined(ASIO_WINDOWS) \
+  && !defined(ASIO_WINDOWS_RUNTIME) \
+  && !defined(__CYGWIN__)
+  reactor_.init_task();
+#endif // !defined(ASIO_WINDOWS)
+       //   && !defined(ASIO_WINDOWS_RUNTIME)
+       //   && !defined(__CYGWIN__)
+
+  for (int i = 0; i < max_signal_number; ++i)
+    registrations_[i] = 0;
+
+  add_service(this);
+}
+
+signal_set_service::~signal_set_service()
+{
+  remove_service(this);
+}
+
+void signal_set_service::shutdown()
+{
+  remove_service(this);
+
+  op_queue<operation> ops;
+
+  for (int i = 0; i < max_signal_number; ++i)
+  {
+    registration* reg = registrations_[i];
+    while (reg)
+    {
+      ops.push(*reg->queue_);
+      reg = reg->next_in_table_;
+    }
+  }
+
+  scheduler_.abandon_operations(ops);
+}
+
+void signal_set_service::notify_fork(execution_context::fork_event fork_ev)
+{
+#if !defined(ASIO_WINDOWS) \
+  && !defined(ASIO_WINDOWS_RUNTIME) \
+  && !defined(__CYGWIN__)
+  signal_state* state = get_signal_state();
+  static_mutex::scoped_lock lock(state->mutex_);
+
+  switch (fork_ev)
+  {
+  case execution_context::fork_prepare:
+    {
+      int read_descriptor = state->read_descriptor_;
+      state->fork_prepared_ = true;
+      lock.unlock();
+      reactor_.deregister_internal_descriptor(read_descriptor, reactor_data_);
+      reactor_.cleanup_descriptor_data(reactor_data_);
+    }
+    break;
+  case execution_context::fork_parent:
+    if (state->fork_prepared_)
+    {
+      int read_descriptor = state->read_descriptor_;
+      state->fork_prepared_ = false;
+      lock.unlock();
+      reactor_.register_internal_descriptor(reactor::read_op,
+          read_descriptor, reactor_data_, new pipe_read_op);
+    }
+    break;
+  case execution_context::fork_child:
+    if (state->fork_prepared_)
+    {
+      asio::detail::signal_blocker blocker;
+      close_descriptors();
+      open_descriptors();
+      int read_descriptor = state->read_descriptor_;
+      state->fork_prepared_ = false;
+      lock.unlock();
+      reactor_.register_internal_descriptor(reactor::read_op,
+          read_descriptor, reactor_data_, new pipe_read_op);
+    }
+    break;
+  default:
+    break;
+  }
+#else // !defined(ASIO_WINDOWS)
+      //   && !defined(ASIO_WINDOWS_RUNTIME)
+      //   && !defined(__CYGWIN__)
+  (void)fork_ev;
+#endif // !defined(ASIO_WINDOWS)
+       //   && !defined(ASIO_WINDOWS_RUNTIME)
+       //   && !defined(__CYGWIN__)
+}
+
+void signal_set_service::construct(
+    signal_set_service::implementation_type& impl)
+{
+  impl.signals_ = 0;
+}
+
+void signal_set_service::destroy(
+    signal_set_service::implementation_type& impl)
+{
+  asio::error_code ignored_ec;
+  clear(impl, ignored_ec);
+  cancel(impl, ignored_ec);
+}
+
+asio::error_code signal_set_service::add(
+    signal_set_service::implementation_type& impl,
+    int signal_number, asio::error_code& ec)
+{
+  // Check that the signal number is valid.
+  if (signal_number < 0 || signal_number >= max_signal_number)
+  {
+    ec = asio::error::invalid_argument;
+    return ec;
+  }
+
+  signal_state* state = get_signal_state();
+  static_mutex::scoped_lock lock(state->mutex_);
+
+  // Find the appropriate place to insert the registration.
+  registration** insertion_point = &impl.signals_;
+  registration* next = impl.signals_;
+  while (next && next->signal_number_ < signal_number)
+  {
+    insertion_point = &next->next_in_set_;
+    next = next->next_in_set_;
+  }
+
+  // Only do something if the signal is not already registered.
+  if (next == 0 || next->signal_number_ != signal_number)
+  {
+    registration* new_registration = new registration;
+
+#if defined(ASIO_HAS_SIGNAL) || defined(ASIO_HAS_SIGACTION)
+    // Register for the signal if we're the first.
+    if (state->registration_count_[signal_number] == 0)
+    {
+# if defined(ASIO_HAS_SIGACTION)
+      using namespace std; // For memset.
+      struct sigaction sa;
+      memset(&sa, 0, sizeof(sa));
+      sa.sa_handler = asio_signal_handler;
+      sigfillset(&sa.sa_mask);
+      if (::sigaction(signal_number, &sa, 0) == -1)
+# else // defined(ASIO_HAS_SIGACTION)
+      if (::signal(signal_number, asio_signal_handler) == SIG_ERR)
+# endif // defined(ASIO_HAS_SIGACTION)
+      {
+# if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+        ec = asio::error::invalid_argument;
+# else // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+        ec = asio::error_code(errno,
+            asio::error::get_system_category());
+# endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+        delete new_registration;
+        return ec;
+      }
+    }
+#endif // defined(ASIO_HAS_SIGNAL) || defined(ASIO_HAS_SIGACTION)
+
+    // Record the new registration in the set.
+    new_registration->signal_number_ = signal_number;
+    new_registration->queue_ = &impl.queue_;
+    new_registration->next_in_set_ = next;
+    *insertion_point = new_registration;
+
+    // Insert registration into the registration table.
+    new_registration->next_in_table_ = registrations_[signal_number];
+    if (registrations_[signal_number])
+      registrations_[signal_number]->prev_in_table_ = new_registration;
+    registrations_[signal_number] = new_registration;
+
+    ++state->registration_count_[signal_number];
+  }
+
+  ec = asio::error_code();
+  return ec;
+}
+
+asio::error_code signal_set_service::remove(
+    signal_set_service::implementation_type& impl,
+    int signal_number, asio::error_code& ec)
+{
+  // Check that the signal number is valid.
+  if (signal_number < 0 || signal_number >= max_signal_number)
+  {
+    ec = asio::error::invalid_argument;
+    return ec;
+  }
+
+  signal_state* state = get_signal_state();
+  static_mutex::scoped_lock lock(state->mutex_);
+
+  // Find the signal number in the list of registrations.
+  registration** deletion_point = &impl.signals_;
+  registration* reg = impl.signals_;
+  while (reg && reg->signal_number_ < signal_number)
+  {
+    deletion_point = &reg->next_in_set_;
+    reg = reg->next_in_set_;
+  }
+
+  if (reg != 0 && reg->signal_number_ == signal_number)
+  {
+#if defined(ASIO_HAS_SIGNAL) || defined(ASIO_HAS_SIGACTION)
+    // Set signal handler back to the default if we're the last.
+    if (state->registration_count_[signal_number] == 1)
+    {
+# if defined(ASIO_HAS_SIGACTION)
+      using namespace std; // For memset.
+      struct sigaction sa;
+      memset(&sa, 0, sizeof(sa));
+      sa.sa_handler = SIG_DFL;
+      if (::sigaction(signal_number, &sa, 0) == -1)
+# else // defined(ASIO_HAS_SIGACTION)
+      if (::signal(signal_number, SIG_DFL) == SIG_ERR)
+# endif // defined(ASIO_HAS_SIGACTION)
+      {
+# if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+        ec = asio::error::invalid_argument;
+# else // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+        ec = asio::error_code(errno,
+            asio::error::get_system_category());
+# endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+        return ec;
+      }
+    }
+#endif // defined(ASIO_HAS_SIGNAL) || defined(ASIO_HAS_SIGACTION)
+
+    // Remove the registration from the set.
+    *deletion_point = reg->next_in_set_;
+
+    // Remove the registration from the registration table.
+    if (registrations_[signal_number] == reg)
+      registrations_[signal_number] = reg->next_in_table_;
+    if (reg->prev_in_table_)
+      reg->prev_in_table_->next_in_table_ = reg->next_in_table_;
+    if (reg->next_in_table_)
+      reg->next_in_table_->prev_in_table_ = reg->prev_in_table_;
+
+    --state->registration_count_[signal_number];
+
+    delete reg;
+  }
+
+  ec = asio::error_code();
+  return ec;
+}
+
+asio::error_code signal_set_service::clear(
+    signal_set_service::implementation_type& impl,
+    asio::error_code& ec)
+{
+  signal_state* state = get_signal_state();
+  static_mutex::scoped_lock lock(state->mutex_);
+
+  while (registration* reg = impl.signals_)
+  {
+#if defined(ASIO_HAS_SIGNAL) || defined(ASIO_HAS_SIGACTION)
+    // Set signal handler back to the default if we're the last.
+    if (state->registration_count_[reg->signal_number_] == 1)
+    {
+# if defined(ASIO_HAS_SIGACTION)
+      using namespace std; // For memset.
+      struct sigaction sa;
+      memset(&sa, 0, sizeof(sa));
+      sa.sa_handler = SIG_DFL;
+      if (::sigaction(reg->signal_number_, &sa, 0) == -1)
+# else // defined(ASIO_HAS_SIGACTION)
+      if (::signal(reg->signal_number_, SIG_DFL) == SIG_ERR)
+# endif // defined(ASIO_HAS_SIGACTION)
+      {
+# if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+        ec = asio::error::invalid_argument;
+# else // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+        ec = asio::error_code(errno,
+            asio::error::get_system_category());
+# endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+        return ec;
+      }
+    }
+#endif // defined(ASIO_HAS_SIGNAL) || defined(ASIO_HAS_SIGACTION)
+
+    // Remove the registration from the registration table.
+    if (registrations_[reg->signal_number_] == reg)
+      registrations_[reg->signal_number_] = reg->next_in_table_;
+    if (reg->prev_in_table_)
+      reg->prev_in_table_->next_in_table_ = reg->next_in_table_;
+    if (reg->next_in_table_)
+      reg->next_in_table_->prev_in_table_ = reg->prev_in_table_;
+
+    --state->registration_count_[reg->signal_number_];
+
+    impl.signals_ = reg->next_in_set_;
+    delete reg;
+  }
+
+  ec = asio::error_code();
+  return ec;
+}
+
+asio::error_code signal_set_service::cancel(
+    signal_set_service::implementation_type& impl,
+    asio::error_code& ec)
+{
+  ASIO_HANDLER_OPERATION((scheduler_.context(),
+        "signal_set", &impl, 0, "cancel"));
+
+  op_queue<operation> ops;
+  {
+    signal_state* state = get_signal_state();
+    static_mutex::scoped_lock lock(state->mutex_);
+
+    while (signal_op* op = impl.queue_.front())
+    {
+      op->ec_ = asio::error::operation_aborted;
+      impl.queue_.pop();
+      ops.push(op);
+    }
+  }
+
+  scheduler_.post_deferred_completions(ops);
+
+  ec = asio::error_code();
+  return ec;
+}
+
+void signal_set_service::deliver_signal(int signal_number)
+{
+  signal_state* state = get_signal_state();
+  static_mutex::scoped_lock lock(state->mutex_);
+
+  signal_set_service* service = state->service_list_;
+  while (service)
+  {
+    op_queue<operation> ops;
+
+    registration* reg = service->registrations_[signal_number];
+    while (reg)
+    {
+      if (reg->queue_->empty())
+      {
+        ++reg->undelivered_;
+      }
+      else
+      {
+        while (signal_op* op = reg->queue_->front())
+        {
+          op->signal_number_ = signal_number;
+          reg->queue_->pop();
+          ops.push(op);
+        }
+      }
+
+      reg = reg->next_in_table_;
+    }
+
+    service->scheduler_.post_deferred_completions(ops);
+
+    service = service->next_;
+  }
+}
+
+void signal_set_service::add_service(signal_set_service* service)
+{
+  signal_state* state = get_signal_state();
+  static_mutex::scoped_lock lock(state->mutex_);
+
+#if !defined(ASIO_WINDOWS) && !defined(__CYGWIN__)
+  // If this is the first service to be created, open a new pipe.
+  if (state->service_list_ == 0)
+    open_descriptors();
+#endif // !defined(ASIO_WINDOWS) && !defined(__CYGWIN__)
+
+  // If a scheduler_ object is thread-unsafe then it must be the only
+  // scheduler used to create signal_set objects.
+  if (state->service_list_ != 0)
+  {
+    if (!ASIO_CONCURRENCY_HINT_IS_LOCKING(SCHEDULER,
+          service->scheduler_.concurrency_hint())
+        || !ASIO_CONCURRENCY_HINT_IS_LOCKING(SCHEDULER,
+          state->service_list_->scheduler_.concurrency_hint()))
+    {
+      std::logic_error ex(
+          "Thread-unsafe execution context objects require "
+          "exclusive access to signal handling.");
+      asio::detail::throw_exception(ex);
+    }
+  }
+
+  // Insert service into linked list of all services.
+  service->next_ = state->service_list_;
+  service->prev_ = 0;
+  if (state->service_list_)
+    state->service_list_->prev_ = service;
+  state->service_list_ = service;
+
+#if !defined(ASIO_WINDOWS) \
+  && !defined(ASIO_WINDOWS_RUNTIME) \
+  && !defined(__CYGWIN__)
+  // Register for pipe readiness notifications.
+  int read_descriptor = state->read_descriptor_;
+  lock.unlock();
+  service->reactor_.register_internal_descriptor(reactor::read_op,
+      read_descriptor, service->reactor_data_, new pipe_read_op);
+#endif // !defined(ASIO_WINDOWS)
+       //   && !defined(ASIO_WINDOWS_RUNTIME)
+       //   && !defined(__CYGWIN__)
+}
+
+void signal_set_service::remove_service(signal_set_service* service)
+{
+  signal_state* state = get_signal_state();
+  static_mutex::scoped_lock lock(state->mutex_);
+
+  if (service->next_ || service->prev_ || state->service_list_ == service)
+  {
+#if !defined(ASIO_WINDOWS) \
+  && !defined(ASIO_WINDOWS_RUNTIME) \
+  && !defined(__CYGWIN__)
+    // Disable the pipe readiness notifications.
+    int read_descriptor = state->read_descriptor_;
+    lock.unlock();
+    service->reactor_.deregister_internal_descriptor(
+        read_descriptor, service->reactor_data_);
+    service->reactor_.cleanup_descriptor_data(service->reactor_data_);
+    lock.lock();
+#endif // !defined(ASIO_WINDOWS)
+       //   && !defined(ASIO_WINDOWS_RUNTIME)
+       //   && !defined(__CYGWIN__)
+
+    // Remove service from linked list of all services.
+    if (state->service_list_ == service)
+      state->service_list_ = service->next_;
+    if (service->prev_)
+      service->prev_->next_ = service->next_;
+    if (service->next_)
+      service->next_->prev_= service->prev_;
+    service->next_ = 0;
+    service->prev_ = 0;
+
+#if !defined(ASIO_WINDOWS) && !defined(__CYGWIN__)
+    // If this is the last service to be removed, close the pipe.
+    if (state->service_list_ == 0)
+      close_descriptors();
+#endif // !defined(ASIO_WINDOWS) && !defined(__CYGWIN__)
+  }
+}
+
+void signal_set_service::open_descriptors()
+{
+#if !defined(ASIO_WINDOWS) \
+  && !defined(ASIO_WINDOWS_RUNTIME) \
+  && !defined(__CYGWIN__)
+  signal_state* state = get_signal_state();
+
+  int pipe_fds[2];
+  if (::pipe(pipe_fds) == 0)
+  {
+    state->read_descriptor_ = pipe_fds[0];
+    ::fcntl(state->read_descriptor_, F_SETFL, O_NONBLOCK);
+
+    state->write_descriptor_ = pipe_fds[1];
+    ::fcntl(state->write_descriptor_, F_SETFL, O_NONBLOCK);
+
+#if defined(FD_CLOEXEC)
+    ::fcntl(state->read_descriptor_, F_SETFD, FD_CLOEXEC);
+    ::fcntl(state->write_descriptor_, F_SETFD, FD_CLOEXEC);
+#endif // defined(FD_CLOEXEC)
+  }
+  else
+  {
+    asio::error_code ec(errno,
+        asio::error::get_system_category());
+    asio::detail::throw_error(ec, "signal_set_service pipe");
+  }
+#endif // !defined(ASIO_WINDOWS)
+       //   && !defined(ASIO_WINDOWS_RUNTIME)
+       //   && !defined(__CYGWIN__)
+}
+
+void signal_set_service::close_descriptors()
+{
+#if !defined(ASIO_WINDOWS) \
+  && !defined(ASIO_WINDOWS_RUNTIME) \
+  && !defined(__CYGWIN__)
+  signal_state* state = get_signal_state();
+
+  if (state->read_descriptor_ != -1)
+    ::close(state->read_descriptor_);
+  state->read_descriptor_ = -1;
+
+  if (state->write_descriptor_ != -1)
+    ::close(state->write_descriptor_);
+  state->write_descriptor_ = -1;
+#endif // !defined(ASIO_WINDOWS)
+       //   && !defined(ASIO_WINDOWS_RUNTIME)
+       //   && !defined(__CYGWIN__)
+}
+
+void signal_set_service::start_wait_op(
+    signal_set_service::implementation_type& impl, signal_op* op)
+{
+  scheduler_.work_started();
+
+  signal_state* state = get_signal_state();
+  static_mutex::scoped_lock lock(state->mutex_);
+
+  registration* reg = impl.signals_;
+  while (reg)
+  {
+    if (reg->undelivered_ > 0)
+    {
+      --reg->undelivered_;
+      op->signal_number_ = reg->signal_number_;
+      scheduler_.post_deferred_completion(op);
+      return;
+    }
+
+    reg = reg->next_in_set_;
+  }
+
+  impl.queue_.push(op);
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_IMPL_SIGNAL_SET_SERVICE_IPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/impl/socket_ops.ipp b/link/modules/asio-standalone/asio/include/asio/detail/impl/socket_ops.ipp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/impl/socket_ops.ipp
@@ -0,0 +1,3962 @@
+//
+// detail/impl/socket_ops.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_SOCKET_OPS_IPP
+#define ASIO_DETAIL_SOCKET_OPS_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#include <cctype>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <cerrno>
+#include <new>
+#include "asio/detail/assert.hpp"
+#include "asio/detail/socket_ops.hpp"
+#include "asio/error.hpp"
+
+#if defined(ASIO_WINDOWS_RUNTIME)
+# include <codecvt>
+# include <locale>
+# include <string>
+#endif // defined(ASIO_WINDOWS_RUNTIME)
+
+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) \
+  || defined(__MACH__) && defined(__APPLE__)
+# if defined(ASIO_HAS_PTHREADS)
+#  include <pthread.h>
+# endif // defined(ASIO_HAS_PTHREADS)
+#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+       // || defined(__MACH__) && defined(__APPLE__)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+namespace socket_ops {
+
+#if !defined(ASIO_WINDOWS_RUNTIME)
+
+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+struct msghdr { int msg_namelen; };
+#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+
+#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)
+
+#endif // !defined(ASIO_WINDOWS_RUNTIME)
+
+inline void clear_last_error()
+{
+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+  WSASetLastError(0);
+#else
+  errno = 0;
+#endif
+}
+
+#if !defined(ASIO_WINDOWS_RUNTIME)
+
+inline void get_last_error(
+    asio::error_code& ec, bool is_error_condition)
+{
+  if (!is_error_condition)
+  {
+    ec.assign(0, ec.category());
+  }
+  else
+  {
+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+    ec = asio::error_code(WSAGetLastError(),
+        asio::error::get_system_category());
+#else
+    ec = asio::error_code(errno,
+        asio::error::get_system_category());
+#endif
+  }
+}
+
+template <typename SockLenType>
+inline socket_type call_accept(SockLenType msghdr::*,
+    socket_type s, socket_addr_type* addr, std::size_t* addrlen)
+{
+  SockLenType tmp_addrlen = addrlen ? (SockLenType)*addrlen : 0;
+  socket_type result = ::accept(s, addr, addrlen ? &tmp_addrlen : 0);
+  if (addrlen)
+    *addrlen = (std::size_t)tmp_addrlen;
+  return result;
+}
+
+socket_type accept(socket_type s, socket_addr_type* addr,
+    std::size_t* addrlen, asio::error_code& ec)
+{
+  if (s == invalid_socket)
+  {
+    ec = asio::error::bad_descriptor;
+    return invalid_socket;
+  }
+
+  socket_type new_s = call_accept(&msghdr::msg_namelen, s, addr, addrlen);
+  get_last_error(ec, new_s == invalid_socket);
+  if (new_s == invalid_socket)
+    return new_s;
+
+#if defined(__MACH__) && defined(__APPLE__) || defined(__FreeBSD__)
+  int optval = 1;
+  int result = ::setsockopt(new_s, SOL_SOCKET,
+      SO_NOSIGPIPE, &optval, sizeof(optval));
+  get_last_error(ec, result != 0);
+  if (result != 0)
+  {
+    ::close(new_s);
+    return invalid_socket;
+  }
+#endif
+
+  ec.assign(0, ec.category());
+  return new_s;
+}
+
+socket_type sync_accept(socket_type s, state_type state,
+    socket_addr_type* addr, std::size_t* addrlen, asio::error_code& ec)
+{
+  // Accept a socket.
+  for (;;)
+  {
+    // Try to complete the operation without blocking.
+    socket_type new_socket = socket_ops::accept(s, addr, addrlen, ec);
+
+    // Check if operation succeeded.
+    if (new_socket != invalid_socket)
+      return new_socket;
+
+    // Operation failed.
+    if (ec == asio::error::would_block
+        || ec == asio::error::try_again)
+    {
+      if (state & user_set_non_blocking)
+        return invalid_socket;
+      // Fall through to retry operation.
+    }
+    else if (ec == asio::error::connection_aborted)
+    {
+      if (state & enable_connection_aborted)
+        return invalid_socket;
+      // Fall through to retry operation.
+    }
+#if defined(EPROTO)
+    else if (ec.value() == EPROTO)
+    {
+      if (state & enable_connection_aborted)
+        return invalid_socket;
+      // Fall through to retry operation.
+    }
+#endif // defined(EPROTO)
+    else
+      return invalid_socket;
+
+    // Wait for socket to become ready.
+    if (socket_ops::poll_read(s, 0, -1, ec) < 0)
+      return invalid_socket;
+  }
+}
+
+#if defined(ASIO_HAS_IOCP)
+
+void complete_iocp_accept(socket_type s,
+    void* output_buffer, DWORD address_length,
+    socket_addr_type* addr, std::size_t* addrlen,
+    socket_type new_socket, asio::error_code& ec)
+{
+  // Map non-portable errors to their portable counterparts.
+  if (ec.value() == ERROR_NETNAME_DELETED)
+    ec = asio::error::connection_aborted;
+
+  if (!ec)
+  {
+    // Get the address of the peer.
+    if (addr && addrlen)
+    {
+      LPSOCKADDR local_addr = 0;
+      int local_addr_length = 0;
+      LPSOCKADDR remote_addr = 0;
+      int remote_addr_length = 0;
+      GetAcceptExSockaddrs(output_buffer, 0, address_length,
+          address_length, &local_addr, &local_addr_length,
+          &remote_addr, &remote_addr_length);
+      if (static_cast<std::size_t>(remote_addr_length) > *addrlen)
+      {
+        ec = asio::error::invalid_argument;
+      }
+      else
+      {
+        using namespace std; // For memcpy.
+        memcpy(addr, remote_addr, remote_addr_length);
+        *addrlen = static_cast<std::size_t>(remote_addr_length);
+      }
+    }
+
+    // Need to set the SO_UPDATE_ACCEPT_CONTEXT option so that getsockname
+    // and getpeername will work on the accepted socket.
+    SOCKET update_ctx_param = s;
+    socket_ops::state_type state = 0;
+    socket_ops::setsockopt(new_socket, state,
+          SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT,
+          &update_ctx_param, sizeof(SOCKET), ec);
+  }
+}
+
+#else // defined(ASIO_HAS_IOCP)
+
+bool non_blocking_accept(socket_type s,
+    state_type state, socket_addr_type* addr, std::size_t* addrlen,
+    asio::error_code& ec, socket_type& new_socket)
+{
+  for (;;)
+  {
+    // Accept the waiting connection.
+    new_socket = socket_ops::accept(s, addr, addrlen, ec);
+
+    // Check if operation succeeded.
+    if (new_socket != invalid_socket)
+      return true;
+
+    // Retry operation if interrupted by signal.
+    if (ec == asio::error::interrupted)
+      continue;
+
+    // Operation failed.
+    if (ec == asio::error::would_block
+        || ec == asio::error::try_again)
+    {
+      // Fall through to retry operation.
+    }
+    else if (ec == asio::error::connection_aborted)
+    {
+      if (state & enable_connection_aborted)
+        return true;
+      // Fall through to retry operation.
+    }
+#if defined(EPROTO)
+    else if (ec.value() == EPROTO)
+    {
+      if (state & enable_connection_aborted)
+        return true;
+      // Fall through to retry operation.
+    }
+#endif // defined(EPROTO)
+    else
+      return true;
+
+    return false;
+  }
+}
+
+#endif // defined(ASIO_HAS_IOCP)
+
+template <typename SockLenType>
+inline int call_bind(SockLenType msghdr::*,
+    socket_type s, const socket_addr_type* addr, std::size_t addrlen)
+{
+  return ::bind(s, addr, (SockLenType)addrlen);
+}
+
+int bind(socket_type s, const socket_addr_type* addr,
+    std::size_t addrlen, asio::error_code& ec)
+{
+  if (s == invalid_socket)
+  {
+    ec = asio::error::bad_descriptor;
+    return socket_error_retval;
+  }
+
+  int result = call_bind(&msghdr::msg_namelen, s, addr, addrlen);
+  get_last_error(ec, result != 0);
+  return result;
+}
+
+int close(socket_type s, state_type& state,
+    bool destruction, asio::error_code& ec)
+{
+  int result = 0;
+  if (s != invalid_socket)
+  {
+    // We don't want the destructor to block, so set the socket to linger in
+    // the background. If the user doesn't like this behaviour then they need
+    // to explicitly close the socket.
+    if (destruction && (state & user_set_linger))
+    {
+      ::linger opt;
+      opt.l_onoff = 0;
+      opt.l_linger = 0;
+      asio::error_code ignored_ec;
+      socket_ops::setsockopt(s, state, SOL_SOCKET,
+          SO_LINGER, &opt, sizeof(opt), ignored_ec);
+    }
+
+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+    result = ::closesocket(s);
+#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+    result = ::close(s);
+#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+    get_last_error(ec, result != 0);
+
+    if (result != 0
+        && (ec == asio::error::would_block
+          || ec == asio::error::try_again))
+    {
+      // According to UNIX Network Programming Vol. 1, it is possible for
+      // close() to fail with EWOULDBLOCK under certain circumstances. What
+      // isn't clear is the state of the descriptor after this error. The one
+      // current OS where this behaviour is seen, Windows, says that the socket
+      // remains open. Therefore we'll put the descriptor back into blocking
+      // mode and have another attempt at closing it.
+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+      ioctl_arg_type arg = 0;
+      ::ioctlsocket(s, FIONBIO, &arg);
+#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+# if defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__)
+      int flags = ::fcntl(s, F_GETFL, 0);
+      if (flags >= 0)
+        ::fcntl(s, F_SETFL, flags & ~O_NONBLOCK);
+# else // defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__)
+      ioctl_arg_type arg = 0;
+      ::ioctl(s, FIONBIO, &arg);
+# endif // defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__)
+#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+      state &= ~non_blocking;
+
+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+      result = ::closesocket(s);
+#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+      result = ::close(s);
+#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+      get_last_error(ec, result != 0);
+    }
+  }
+
+  return result;
+}
+
+bool set_user_non_blocking(socket_type s,
+    state_type& state, bool value, asio::error_code& ec)
+{
+  if (s == invalid_socket)
+  {
+    ec = asio::error::bad_descriptor;
+    return false;
+  }
+
+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+  ioctl_arg_type arg = (value ? 1 : 0);
+  int result = ::ioctlsocket(s, FIONBIO, &arg);
+  get_last_error(ec, result < 0);
+#elif defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__)
+  int result = ::fcntl(s, F_GETFL, 0);
+  get_last_error(ec, result < 0);
+  if (result >= 0)
+  {
+    int flag = (value ? (result | O_NONBLOCK) : (result & ~O_NONBLOCK));
+    result = ::fcntl(s, F_SETFL, flag);
+    get_last_error(ec, result < 0);
+  }
+#else
+  ioctl_arg_type arg = (value ? 1 : 0);
+  int result = ::ioctl(s, FIONBIO, &arg);
+  get_last_error(ec, result < 0);
+#endif
+
+  if (result >= 0)
+  {
+    if (value)
+      state |= user_set_non_blocking;
+    else
+    {
+      // Clearing the user-set non-blocking mode always overrides any
+      // internally-set non-blocking flag. Any subsequent asynchronous
+      // operations will need to re-enable non-blocking I/O.
+      state &= ~(user_set_non_blocking | internal_non_blocking);
+    }
+    return true;
+  }
+
+  return false;
+}
+
+bool set_internal_non_blocking(socket_type s,
+    state_type& state, bool value, asio::error_code& ec)
+{
+  if (s == invalid_socket)
+  {
+    ec = asio::error::bad_descriptor;
+    return false;
+  }
+
+  if (!value && (state & user_set_non_blocking))
+  {
+    // It does not make sense to clear the internal non-blocking flag if the
+    // user still wants non-blocking behaviour. Return an error and let the
+    // caller figure out whether to update the user-set non-blocking flag.
+    ec = asio::error::invalid_argument;
+    return false;
+  }
+
+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+  ioctl_arg_type arg = (value ? 1 : 0);
+  int result = ::ioctlsocket(s, FIONBIO, &arg);
+  get_last_error(ec, result < 0);
+#elif defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__)
+  int result = ::fcntl(s, F_GETFL, 0);
+  get_last_error(ec, result < 0);
+  if (result >= 0)
+  {
+    int flag = (value ? (result | O_NONBLOCK) : (result & ~O_NONBLOCK));
+    result = ::fcntl(s, F_SETFL, flag);
+    get_last_error(ec, result < 0);
+  }
+#else
+  ioctl_arg_type arg = (value ? 1 : 0);
+  int result = ::ioctl(s, FIONBIO, &arg);
+  get_last_error(ec, result < 0);
+#endif
+
+  if (result >= 0)
+  {
+    if (value)
+      state |= internal_non_blocking;
+    else
+      state &= ~internal_non_blocking;
+    return true;
+  }
+
+  return false;
+}
+
+int shutdown(socket_type s, int what, asio::error_code& ec)
+{
+  if (s == invalid_socket)
+  {
+    ec = asio::error::bad_descriptor;
+    return socket_error_retval;
+  }
+
+  int result = ::shutdown(s, what);
+  get_last_error(ec, result != 0);
+  return result;
+}
+
+template <typename SockLenType>
+inline int call_connect(SockLenType msghdr::*,
+    socket_type s, const socket_addr_type* addr, std::size_t addrlen)
+{
+  return ::connect(s, addr, (SockLenType)addrlen);
+}
+
+int connect(socket_type s, const socket_addr_type* addr,
+    std::size_t addrlen, asio::error_code& ec)
+{
+  if (s == invalid_socket)
+  {
+    ec = asio::error::bad_descriptor;
+    return socket_error_retval;
+  }
+
+  int result = call_connect(&msghdr::msg_namelen, s, addr, addrlen);
+  get_last_error(ec, result != 0);
+#if defined(__linux__)
+  if (result != 0 && ec == asio::error::try_again)
+    ec = asio::error::no_buffer_space;
+#endif // defined(__linux__)
+  return result;
+}
+
+void sync_connect(socket_type s, const socket_addr_type* addr,
+    std::size_t addrlen, asio::error_code& ec)
+{
+  // Perform the connect operation.
+  socket_ops::connect(s, addr, addrlen, ec);
+  if (ec != asio::error::in_progress
+      && ec != asio::error::would_block)
+  {
+    // The connect operation finished immediately.
+    return;
+  }
+
+  // Wait for socket to become ready.
+  if (socket_ops::poll_connect(s, -1, ec) < 0)
+    return;
+
+  // Get the error code from the connect operation.
+  int connect_error = 0;
+  size_t connect_error_len = sizeof(connect_error);
+  if (socket_ops::getsockopt(s, 0, SOL_SOCKET, SO_ERROR,
+        &connect_error, &connect_error_len, ec) == socket_error_retval)
+    return;
+
+  // Return the result of the connect operation.
+  ec = asio::error_code(connect_error,
+      asio::error::get_system_category());
+}
+
+#if defined(ASIO_HAS_IOCP)
+
+void complete_iocp_connect(socket_type s, asio::error_code& ec)
+{
+  // Map non-portable errors to their portable counterparts.
+  switch (ec.value())
+  {
+  case ERROR_CONNECTION_REFUSED:
+    ec = asio::error::connection_refused;
+    break;
+  case ERROR_NETWORK_UNREACHABLE:
+    ec = asio::error::network_unreachable;
+    break;
+  case ERROR_HOST_UNREACHABLE:
+    ec = asio::error::host_unreachable;
+    break;
+  case ERROR_SEM_TIMEOUT:
+    ec = asio::error::timed_out;
+    break;
+  default:
+    break;
+  }
+
+  if (!ec)
+  {
+    // Need to set the SO_UPDATE_CONNECT_CONTEXT option so that getsockname
+    // and getpeername will work on the connected socket.
+    socket_ops::state_type state = 0;
+    const int so_update_connect_context = 0x7010;
+    socket_ops::setsockopt(s, state, SOL_SOCKET,
+        so_update_connect_context, 0, 0, ec);
+  }
+}
+
+#endif // defined(ASIO_HAS_IOCP)
+
+bool non_blocking_connect(socket_type s, asio::error_code& ec)
+{
+  // Check if the connect operation has finished. This is required since we may
+  // get spurious readiness notifications from the reactor.
+#if defined(ASIO_WINDOWS) \
+  || defined(__CYGWIN__) \
+  || defined(__SYMBIAN32__)
+  fd_set write_fds;
+  FD_ZERO(&write_fds);
+  FD_SET(s, &write_fds);
+  fd_set except_fds;
+  FD_ZERO(&except_fds);
+  FD_SET(s, &except_fds);
+  timeval zero_timeout;
+  zero_timeout.tv_sec = 0;
+  zero_timeout.tv_usec = 0;
+  int ready = ::select(s + 1, 0, &write_fds, &except_fds, &zero_timeout);
+#else // defined(ASIO_WINDOWS)
+      // || defined(__CYGWIN__)
+      // || defined(__SYMBIAN32__)
+  pollfd fds;
+  fds.fd = s;
+  fds.events = POLLOUT;
+  fds.revents = 0;
+  int ready = ::poll(&fds, 1, 0);
+#endif // defined(ASIO_WINDOWS)
+       // || defined(__CYGWIN__)
+       // || defined(__SYMBIAN32__)
+  if (ready == 0)
+  {
+    // The asynchronous connect operation is still in progress.
+    return false;
+  }
+
+  // Get the error code from the connect operation.
+  int connect_error = 0;
+  size_t connect_error_len = sizeof(connect_error);
+  if (socket_ops::getsockopt(s, 0, SOL_SOCKET, SO_ERROR,
+        &connect_error, &connect_error_len, ec) == 0)
+  {
+    if (connect_error)
+    {
+      ec = asio::error_code(connect_error,
+          asio::error::get_system_category());
+    }
+    else
+      ec.assign(0, ec.category());
+  }
+
+  return true;
+}
+
+int socketpair(int af, int type, int protocol,
+    socket_type sv[2], asio::error_code& ec)
+{
+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+  (void)(af);
+  (void)(type);
+  (void)(protocol);
+  (void)(sv);
+  ec = asio::error::operation_not_supported;
+  return socket_error_retval;
+#else
+  int result = ::socketpair(af, type, protocol, sv);
+  get_last_error(ec, result != 0);
+  return result;
+#endif
+}
+
+bool sockatmark(socket_type s, asio::error_code& ec)
+{
+  if (s == invalid_socket)
+  {
+    ec = asio::error::bad_descriptor;
+    return false;
+  }
+
+#if defined(SIOCATMARK)
+  ioctl_arg_type value = 0;
+# if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+  int result = ::ioctlsocket(s, SIOCATMARK, &value);
+# else // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+  int result = ::ioctl(s, SIOCATMARK, &value);
+# endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+  get_last_error(ec, result < 0);
+# if defined(ENOTTY)
+  if (ec.value() == ENOTTY)
+    ec = asio::error::not_socket;
+# endif // defined(ENOTTY)
+#else // defined(SIOCATMARK)
+  int value = ::sockatmark(s);
+  get_last_error(ec, result < 0);
+#endif // defined(SIOCATMARK)
+
+  return ec ? false : value != 0;
+}
+
+size_t available(socket_type s, asio::error_code& ec)
+{
+  if (s == invalid_socket)
+  {
+    ec = asio::error::bad_descriptor;
+    return 0;
+  }
+
+  ioctl_arg_type value = 0;
+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+  int result = ::ioctlsocket(s, FIONREAD, &value);
+#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+  int result = ::ioctl(s, FIONREAD, &value);
+#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+  get_last_error(ec, result < 0);
+#if defined(ENOTTY)
+  if (ec.value() == ENOTTY)
+    ec = asio::error::not_socket;
+#endif // defined(ENOTTY)
+
+  return ec ? static_cast<size_t>(0) : static_cast<size_t>(value);
+}
+
+int listen(socket_type s, int backlog, asio::error_code& ec)
+{
+  if (s == invalid_socket)
+  {
+    ec = asio::error::bad_descriptor;
+    return socket_error_retval;
+  }
+
+  int result = ::listen(s, backlog);
+  get_last_error(ec, result != 0);
+  return result;
+}
+
+inline void init_buf_iov_base(void*& base, void* addr)
+{
+  base = addr;
+}
+
+template <typename T>
+inline void init_buf_iov_base(T& base, void* addr)
+{
+  base = static_cast<T>(addr);
+}
+
+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+typedef WSABUF buf;
+#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+typedef iovec buf;
+#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+
+void init_buf(buf& b, void* data, size_t size)
+{
+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+  b.buf = static_cast<char*>(data);
+  b.len = static_cast<u_long>(size);
+#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+  init_buf_iov_base(b.iov_base, data);
+  b.iov_len = size;
+#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+}
+
+void init_buf(buf& b, const void* data, size_t size)
+{
+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+  b.buf = static_cast<char*>(const_cast<void*>(data));
+  b.len = static_cast<u_long>(size);
+#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+  init_buf_iov_base(b.iov_base, const_cast<void*>(data));
+  b.iov_len = size;
+#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+}
+
+inline void init_msghdr_msg_name(void*& name, socket_addr_type* addr)
+{
+  name = addr;
+}
+
+inline void init_msghdr_msg_name(void*& name, const socket_addr_type* addr)
+{
+  name = const_cast<socket_addr_type*>(addr);
+}
+
+template <typename T>
+inline void init_msghdr_msg_name(T& name, socket_addr_type* addr)
+{
+  name = reinterpret_cast<T>(addr);
+}
+
+template <typename T>
+inline void init_msghdr_msg_name(T& name, const socket_addr_type* addr)
+{
+  name = reinterpret_cast<T>(const_cast<socket_addr_type*>(addr));
+}
+
+signed_size_type recv(socket_type s, buf* bufs, size_t count,
+    int flags, asio::error_code& ec)
+{
+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+  // Receive some data.
+  DWORD recv_buf_count = static_cast<DWORD>(count);
+  DWORD bytes_transferred = 0;
+  DWORD recv_flags = flags;
+  int result = ::WSARecv(s, bufs, recv_buf_count,
+      &bytes_transferred, &recv_flags, 0, 0);
+  get_last_error(ec, true);
+  if (ec.value() == ERROR_NETNAME_DELETED)
+    ec = asio::error::connection_reset;
+  else if (ec.value() == ERROR_PORT_UNREACHABLE)
+    ec = asio::error::connection_refused;
+  else if (ec.value() == WSAEMSGSIZE || ec.value() == ERROR_MORE_DATA)
+    result = 0;
+  if (result != 0)
+    return socket_error_retval;
+  ec.assign(0, ec.category());
+  return bytes_transferred;
+#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+  msghdr msg = msghdr();
+  msg.msg_iov = bufs;
+  msg.msg_iovlen = static_cast<int>(count);
+  signed_size_type result = ::recvmsg(s, &msg, flags);
+  get_last_error(ec, result < 0);
+  return result;
+#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+}
+
+signed_size_type recv1(socket_type s, void* data, size_t size,
+    int flags, asio::error_code& ec)
+{
+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+  // Receive some data.
+  WSABUF buf;
+  buf.buf = const_cast<char*>(static_cast<const char*>(data));
+  buf.len = static_cast<ULONG>(size);
+  DWORD bytes_transferred = 0;
+  DWORD recv_flags = flags;
+  int result = ::WSARecv(s, &buf, 1,
+      &bytes_transferred, &recv_flags, 0, 0);
+  get_last_error(ec, true);
+  if (ec.value() == ERROR_NETNAME_DELETED)
+    ec = asio::error::connection_reset;
+  else if (ec.value() == ERROR_PORT_UNREACHABLE)
+    ec = asio::error::connection_refused;
+  else if (ec.value() == WSAEMSGSIZE || ec.value() == ERROR_MORE_DATA)
+    result = 0;
+  if (result != 0)
+    return socket_error_retval;
+  ec.assign(0, ec.category());
+  return bytes_transferred;
+#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+  signed_size_type result = ::recv(s, static_cast<char*>(data), size, flags);
+  get_last_error(ec, result < 0);
+  return result;
+#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+}
+
+size_t sync_recv(socket_type s, state_type state, buf* bufs,
+    size_t count, int flags, bool all_empty, asio::error_code& ec)
+{
+  if (s == invalid_socket)
+  {
+    ec = asio::error::bad_descriptor;
+    return 0;
+  }
+
+  // A request to read 0 bytes on a stream is a no-op.
+  if (all_empty && (state & stream_oriented))
+  {
+    ec.assign(0, ec.category());
+    return 0;
+  }
+
+  // Read some data.
+  for (;;)
+  {
+    // Try to complete the operation without blocking.
+    signed_size_type bytes = socket_ops::recv(s, bufs, count, flags, ec);
+
+    // Check for EOF.
+    if ((state & stream_oriented) && bytes == 0)
+    {
+      ec = asio::error::eof;
+      return 0;
+    }
+
+    // Check if operation succeeded.
+    if (bytes >= 0)
+      return bytes;
+
+    // Operation failed.
+    if ((state & user_set_non_blocking)
+        || (ec != asio::error::would_block
+          && ec != asio::error::try_again))
+      return 0;
+
+    // Wait for socket to become ready.
+    if (socket_ops::poll_read(s, 0, -1, ec) < 0)
+      return 0;
+  }
+}
+
+size_t sync_recv1(socket_type s, state_type state, void* data,
+    size_t size, int flags, asio::error_code& ec)
+{
+  if (s == invalid_socket)
+  {
+    ec = asio::error::bad_descriptor;
+    return 0;
+  }
+
+  // A request to read 0 bytes on a stream is a no-op.
+  if (size == 0 && (state & stream_oriented))
+  {
+    ec.assign(0, ec.category());
+    return 0;
+  }
+
+  // Read some data.
+  for (;;)
+  {
+    // Try to complete the operation without blocking.
+    signed_size_type bytes = socket_ops::recv1(s, data, size, flags, ec);
+
+    // Check for EOF.
+    if ((state & stream_oriented) && bytes == 0)
+    {
+      ec = asio::error::eof;
+      return 0;
+    }
+
+    // Check if operation succeeded.
+    if (bytes >= 0)
+      return bytes;
+
+    // Operation failed.
+    if ((state & user_set_non_blocking)
+        || (ec != asio::error::would_block
+          && ec != asio::error::try_again))
+      return 0;
+
+    // Wait for socket to become ready.
+    if (socket_ops::poll_read(s, 0, -1, ec) < 0)
+      return 0;
+  }
+}
+
+#if defined(ASIO_HAS_IOCP)
+
+void complete_iocp_recv(state_type state,
+    const weak_cancel_token_type& cancel_token, bool all_empty,
+    asio::error_code& ec, size_t bytes_transferred)
+{
+  // Map non-portable errors to their portable counterparts.
+  if (ec.value() == ERROR_NETNAME_DELETED)
+  {
+    if (cancel_token.expired())
+      ec = asio::error::operation_aborted;
+    else
+      ec = asio::error::connection_reset;
+  }
+  else if (ec.value() == ERROR_PORT_UNREACHABLE)
+  {
+    ec = asio::error::connection_refused;
+  }
+  else if (ec.value() == WSAEMSGSIZE || ec.value() == ERROR_MORE_DATA)
+  {
+    ec.assign(0, ec.category());
+  }
+
+  // Check for connection closed.
+  else if (!ec && bytes_transferred == 0
+      && (state & stream_oriented) != 0
+      && !all_empty)
+  {
+    ec = asio::error::eof;
+  }
+}
+
+#else // defined(ASIO_HAS_IOCP)
+
+bool non_blocking_recv(socket_type s,
+    buf* bufs, size_t count, int flags, bool is_stream,
+    asio::error_code& ec, size_t& bytes_transferred)
+{
+  for (;;)
+  {
+    // Read some data.
+    signed_size_type bytes = socket_ops::recv(s, bufs, count, flags, ec);
+
+    // Check for end of stream.
+    if (is_stream && bytes == 0)
+    {
+      ec = asio::error::eof;
+      return true;
+    }
+
+    // Check if operation succeeded.
+    if (bytes >= 0)
+    {
+      bytes_transferred = bytes;
+      return true;
+    }
+
+    // Retry operation if interrupted by signal.
+    if (ec == asio::error::interrupted)
+      continue;
+
+    // Check if we need to run the operation again.
+    if (ec == asio::error::would_block
+        || ec == asio::error::try_again)
+      return false;
+
+    // Operation failed.
+    bytes_transferred = 0;
+    return true;
+  }
+}
+
+bool non_blocking_recv1(socket_type s,
+    void* data, size_t size, int flags, bool is_stream,
+    asio::error_code& ec, size_t& bytes_transferred)
+{
+  for (;;)
+  {
+    // Read some data.
+    signed_size_type bytes = socket_ops::recv1(s, data, size, flags, ec);
+
+    // Check for end of stream.
+    if (is_stream && bytes == 0)
+    {
+      ec = asio::error::eof;
+      return true;
+    }
+
+    // Check if operation succeeded.
+    if (bytes >= 0)
+    {
+      bytes_transferred = bytes;
+      return true;
+    }
+
+    // Retry operation if interrupted by signal.
+    if (ec == asio::error::interrupted)
+      continue;
+
+    // Check if we need to run the operation again.
+    if (ec == asio::error::would_block
+        || ec == asio::error::try_again)
+      return false;
+
+    // Operation failed.
+    bytes_transferred = 0;
+    return true;
+  }
+}
+
+#endif // defined(ASIO_HAS_IOCP)
+
+signed_size_type recvfrom(socket_type s, buf* bufs, size_t count,
+    int flags, socket_addr_type* addr, std::size_t* addrlen,
+    asio::error_code& ec)
+{
+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+  // Receive some data.
+  DWORD recv_buf_count = static_cast<DWORD>(count);
+  DWORD bytes_transferred = 0;
+  DWORD recv_flags = flags;
+  int tmp_addrlen = (int)*addrlen;
+  int result = ::WSARecvFrom(s, bufs, recv_buf_count,
+        &bytes_transferred, &recv_flags, addr, &tmp_addrlen, 0, 0);
+  get_last_error(ec, true);
+  *addrlen = (std::size_t)tmp_addrlen;
+  if (ec.value() == ERROR_NETNAME_DELETED)
+    ec = asio::error::connection_reset;
+  else if (ec.value() == ERROR_PORT_UNREACHABLE)
+    ec = asio::error::connection_refused;
+  else if (ec.value() == WSAEMSGSIZE || ec.value() == ERROR_MORE_DATA)
+    result = 0;
+  if (result != 0)
+    return socket_error_retval;
+  ec.assign(0, ec.category());
+  return bytes_transferred;
+#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+  msghdr msg = msghdr();
+  init_msghdr_msg_name(msg.msg_name, addr);
+  msg.msg_namelen = static_cast<int>(*addrlen);
+  msg.msg_iov = bufs;
+  msg.msg_iovlen = static_cast<int>(count);
+  signed_size_type result = ::recvmsg(s, &msg, flags);
+  get_last_error(ec, result < 0);
+  *addrlen = msg.msg_namelen;
+  return result;
+#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+}
+
+template <typename SockLenType>
+inline signed_size_type call_recvfrom(SockLenType msghdr::*,
+    socket_type s, void* data, size_t size, int flags,
+    socket_addr_type* addr, std::size_t* addrlen)
+{
+  SockLenType tmp_addrlen = addrlen ? (SockLenType)*addrlen : 0;
+  signed_size_type result = ::recvfrom(s, static_cast<char*>(data),
+      size, flags, addr, addrlen ? &tmp_addrlen : 0);
+  if (addrlen)
+    *addrlen = (std::size_t)tmp_addrlen;
+  return result;
+}
+
+signed_size_type recvfrom1(socket_type s, void* data, size_t size,
+    int flags, socket_addr_type* addr, std::size_t* addrlen,
+    asio::error_code& ec)
+{
+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+  // Receive some data.
+  WSABUF buf;
+  buf.buf = static_cast<char*>(data);
+  buf.len = static_cast<ULONG>(size);
+  DWORD bytes_transferred = 0;
+  DWORD recv_flags = flags;
+  int tmp_addrlen = (int)*addrlen;
+  int result = ::WSARecvFrom(s, &buf, 1, &bytes_transferred,
+      &recv_flags, addr, &tmp_addrlen, 0, 0);
+  get_last_error(ec, true);
+  *addrlen = (std::size_t)tmp_addrlen;
+  if (ec.value() == ERROR_NETNAME_DELETED)
+    ec = asio::error::connection_reset;
+  else if (ec.value() == ERROR_PORT_UNREACHABLE)
+    ec = asio::error::connection_refused;
+  else if (ec.value() == WSAEMSGSIZE || ec.value() == ERROR_MORE_DATA)
+    result = 0;
+  if (result != 0)
+    return socket_error_retval;
+  ec.assign(0, ec.category());
+  return bytes_transferred;
+#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+  signed_size_type result = call_recvfrom(&msghdr::msg_namelen,
+      s, data, size, flags, addr, addrlen);
+  get_last_error(ec, result < 0);
+  return result;
+#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+}
+
+size_t sync_recvfrom(socket_type s, state_type state, buf* bufs,
+    size_t count, int flags, socket_addr_type* addr,
+    std::size_t* addrlen, asio::error_code& ec)
+{
+  if (s == invalid_socket)
+  {
+    ec = asio::error::bad_descriptor;
+    return 0;
+  }
+
+  // Read some data.
+  for (;;)
+  {
+    // Try to complete the operation without blocking.
+    signed_size_type bytes = socket_ops::recvfrom(
+        s, bufs, count, flags, addr, addrlen, ec);
+
+    // Check if operation succeeded.
+    if (bytes >= 0)
+      return bytes;
+
+    // Operation failed.
+    if ((state & user_set_non_blocking)
+        || (ec != asio::error::would_block
+          && ec != asio::error::try_again))
+      return 0;
+
+    // Wait for socket to become ready.
+    if (socket_ops::poll_read(s, 0, -1, ec) < 0)
+      return 0;
+  }
+}
+
+size_t sync_recvfrom1(socket_type s, state_type state, void* data,
+    size_t size, int flags, socket_addr_type* addr,
+    std::size_t* addrlen, asio::error_code& ec)
+{
+  if (s == invalid_socket)
+  {
+    ec = asio::error::bad_descriptor;
+    return 0;
+  }
+
+  // Read some data.
+  for (;;)
+  {
+    // Try to complete the operation without blocking.
+    signed_size_type bytes = socket_ops::recvfrom1(
+        s, data, size, flags, addr, addrlen, ec);
+
+    // Check if operation succeeded.
+    if (bytes >= 0)
+      return bytes;
+
+    // Operation failed.
+    if ((state & user_set_non_blocking)
+        || (ec != asio::error::would_block
+          && ec != asio::error::try_again))
+      return 0;
+
+    // Wait for socket to become ready.
+    if (socket_ops::poll_read(s, 0, -1, ec) < 0)
+      return 0;
+  }
+}
+
+#if defined(ASIO_HAS_IOCP)
+
+void complete_iocp_recvfrom(
+    const weak_cancel_token_type& cancel_token,
+    asio::error_code& ec)
+{
+  // Map non-portable errors to their portable counterparts.
+  if (ec.value() == ERROR_NETNAME_DELETED)
+  {
+    if (cancel_token.expired())
+      ec = asio::error::operation_aborted;
+    else
+      ec = asio::error::connection_reset;
+  }
+  else if (ec.value() == ERROR_PORT_UNREACHABLE)
+  {
+    ec = asio::error::connection_refused;
+  }
+  else if (ec.value() == WSAEMSGSIZE || ec.value() == ERROR_MORE_DATA)
+  {
+    ec.assign(0, ec.category());
+  }
+}
+
+#else // defined(ASIO_HAS_IOCP)
+
+bool non_blocking_recvfrom(socket_type s,
+    buf* bufs, size_t count, int flags,
+    socket_addr_type* addr, std::size_t* addrlen,
+    asio::error_code& ec, size_t& bytes_transferred)
+{
+  for (;;)
+  {
+    // Read some data.
+    signed_size_type bytes = socket_ops::recvfrom(
+        s, bufs, count, flags, addr, addrlen, ec);
+
+    // Check if operation succeeded.
+    if (bytes >= 0)
+    {
+      bytes_transferred = bytes;
+      return true;
+    }
+
+    // Retry operation if interrupted by signal.
+    if (ec == asio::error::interrupted)
+      continue;
+
+    // Check if we need to run the operation again.
+    if (ec == asio::error::would_block
+        || ec == asio::error::try_again)
+      return false;
+
+    // Operation failed.
+    bytes_transferred = 0;
+    return true;
+  }
+}
+
+bool non_blocking_recvfrom1(socket_type s,
+    void* data, size_t size, int flags,
+    socket_addr_type* addr, std::size_t* addrlen,
+    asio::error_code& ec, size_t& bytes_transferred)
+{
+  for (;;)
+  {
+    // Read some data.
+    signed_size_type bytes = socket_ops::recvfrom1(
+        s, data, size, flags, addr, addrlen, ec);
+
+    // Check if operation succeeded.
+    if (bytes >= 0)
+    {
+      bytes_transferred = bytes;
+      return true;
+    }
+
+    // Retry operation if interrupted by signal.
+    if (ec == asio::error::interrupted)
+      continue;
+
+    // Check if we need to run the operation again.
+    if (ec == asio::error::would_block
+        || ec == asio::error::try_again)
+      return false;
+
+    // Operation failed.
+    bytes_transferred = 0;
+    return true;
+  }
+}
+
+#endif // defined(ASIO_HAS_IOCP)
+
+signed_size_type recvmsg(socket_type s, buf* bufs, size_t count,
+    int in_flags, int& out_flags, asio::error_code& ec)
+{
+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+  out_flags = 0;
+  return socket_ops::recv(s, bufs, count, in_flags, ec);
+#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+  msghdr msg = msghdr();
+  msg.msg_iov = bufs;
+  msg.msg_iovlen = static_cast<int>(count);
+  signed_size_type result = ::recvmsg(s, &msg, in_flags);
+  get_last_error(ec, result < 0);
+  if (result >= 0)
+    out_flags = msg.msg_flags;
+  else
+    out_flags = 0;
+  return result;
+#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+}
+
+size_t sync_recvmsg(socket_type s, state_type state,
+    buf* bufs, size_t count, int in_flags, int& out_flags,
+    asio::error_code& ec)
+{
+  if (s == invalid_socket)
+  {
+    ec = asio::error::bad_descriptor;
+    return 0;
+  }
+
+  // Read some data.
+  for (;;)
+  {
+    // Try to complete the operation without blocking.
+    signed_size_type bytes = socket_ops::recvmsg(
+        s, bufs, count, in_flags, out_flags, ec);
+
+    // Check if operation succeeded.
+    if (bytes >= 0)
+      return bytes;
+
+    // Operation failed.
+    if ((state & user_set_non_blocking)
+        || (ec != asio::error::would_block
+          && ec != asio::error::try_again))
+      return 0;
+
+    // Wait for socket to become ready.
+    if (socket_ops::poll_read(s, 0, -1, ec) < 0)
+      return 0;
+  }
+}
+
+#if defined(ASIO_HAS_IOCP)
+
+void complete_iocp_recvmsg(
+    const weak_cancel_token_type& cancel_token,
+    asio::error_code& ec)
+{
+  // Map non-portable errors to their portable counterparts.
+  if (ec.value() == ERROR_NETNAME_DELETED)
+  {
+    if (cancel_token.expired())
+      ec = asio::error::operation_aborted;
+    else
+      ec = asio::error::connection_reset;
+  }
+  else if (ec.value() == ERROR_PORT_UNREACHABLE)
+  {
+    ec = asio::error::connection_refused;
+  }
+  else if (ec.value() == WSAEMSGSIZE || ec.value() == ERROR_MORE_DATA)
+  {
+    ec.assign(0, ec.category());
+  }
+}
+
+#else // defined(ASIO_HAS_IOCP)
+
+bool non_blocking_recvmsg(socket_type s,
+    buf* bufs, size_t count, int in_flags, int& out_flags,
+    asio::error_code& ec, size_t& bytes_transferred)
+{
+  for (;;)
+  {
+    // Read some data.
+    signed_size_type bytes = socket_ops::recvmsg(
+        s, bufs, count, in_flags, out_flags, ec);
+
+    // Check if operation succeeded.
+    if (bytes >= 0)
+    {
+      bytes_transferred = bytes;
+      return true;
+    }
+
+    // Retry operation if interrupted by signal.
+    if (ec == asio::error::interrupted)
+      continue;
+
+    // Check if we need to run the operation again.
+    if (ec == asio::error::would_block
+        || ec == asio::error::try_again)
+      return false;
+
+    // Operation failed.
+    bytes_transferred = 0;
+    return true;
+  }
+}
+
+#endif // defined(ASIO_HAS_IOCP)
+
+signed_size_type send(socket_type s, const buf* bufs, size_t count,
+    int flags, asio::error_code& ec)
+{
+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+  // Send the data.
+  DWORD send_buf_count = static_cast<DWORD>(count);
+  DWORD bytes_transferred = 0;
+  DWORD send_flags = flags;
+  int result = ::WSASend(s, const_cast<buf*>(bufs),
+        send_buf_count, &bytes_transferred, send_flags, 0, 0);
+  get_last_error(ec, true);
+  if (ec.value() == ERROR_NETNAME_DELETED)
+    ec = asio::error::connection_reset;
+  else if (ec.value() == ERROR_PORT_UNREACHABLE)
+    ec = asio::error::connection_refused;
+  if (result != 0)
+    return socket_error_retval;
+  ec.assign(0, ec.category());
+  return bytes_transferred;
+#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+  msghdr msg = msghdr();
+  msg.msg_iov = const_cast<buf*>(bufs);
+  msg.msg_iovlen = static_cast<int>(count);
+#if defined(__linux__)
+  flags |= MSG_NOSIGNAL;
+#endif // defined(__linux__)
+  signed_size_type result = ::sendmsg(s, &msg, flags);
+  get_last_error(ec, result < 0);
+  return result;
+#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+}
+
+signed_size_type send1(socket_type s, const void* data, size_t size,
+    int flags, asio::error_code& ec)
+{
+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+  // Send the data.
+  WSABUF buf;
+  buf.buf = const_cast<char*>(static_cast<const char*>(data));
+  buf.len = static_cast<ULONG>(size);
+  DWORD bytes_transferred = 0;
+  DWORD send_flags = flags;
+  int result = ::WSASend(s, &buf, 1,
+        &bytes_transferred, send_flags, 0, 0);
+  get_last_error(ec, true);
+  if (ec.value() == ERROR_NETNAME_DELETED)
+    ec = asio::error::connection_reset;
+  else if (ec.value() == ERROR_PORT_UNREACHABLE)
+    ec = asio::error::connection_refused;
+  if (result != 0)
+    return socket_error_retval;
+  ec.assign(0, ec.category());
+  return bytes_transferred;
+#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+#if defined(__linux__)
+  flags |= MSG_NOSIGNAL;
+#endif // defined(__linux__)
+  signed_size_type result = ::send(s,
+      static_cast<const char*>(data), size, flags);
+  get_last_error(ec, result < 0);
+  return result;
+#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+}
+
+size_t sync_send(socket_type s, state_type state, const buf* bufs,
+    size_t count, int flags, bool all_empty, asio::error_code& ec)
+{
+  if (s == invalid_socket)
+  {
+    ec = asio::error::bad_descriptor;
+    return 0;
+  }
+
+  // A request to write 0 bytes to a stream is a no-op.
+  if (all_empty && (state & stream_oriented))
+  {
+    ec.assign(0, ec.category());
+    return 0;
+  }
+
+  // Read some data.
+  for (;;)
+  {
+    // Try to complete the operation without blocking.
+    signed_size_type bytes = socket_ops::send(s, bufs, count, flags, ec);
+
+    // Check if operation succeeded.
+    if (bytes >= 0)
+      return bytes;
+
+    // Operation failed.
+    if ((state & user_set_non_blocking)
+        || (ec != asio::error::would_block
+          && ec != asio::error::try_again))
+      return 0;
+
+    // Wait for socket to become ready.
+    if (socket_ops::poll_write(s, 0, -1, ec) < 0)
+      return 0;
+  }
+}
+
+size_t sync_send1(socket_type s, state_type state, const void* data,
+    size_t size, int flags, asio::error_code& ec)
+{
+  if (s == invalid_socket)
+  {
+    ec = asio::error::bad_descriptor;
+    return 0;
+  }
+
+  // A request to write 0 bytes to a stream is a no-op.
+  if (size == 0 && (state & stream_oriented))
+  {
+    ec.assign(0, ec.category());
+    return 0;
+  }
+
+  // Read some data.
+  for (;;)
+  {
+    // Try to complete the operation without blocking.
+    signed_size_type bytes = socket_ops::send1(s, data, size, flags, ec);
+
+    // Check if operation succeeded.
+    if (bytes >= 0)
+      return bytes;
+
+    // Operation failed.
+    if ((state & user_set_non_blocking)
+        || (ec != asio::error::would_block
+          && ec != asio::error::try_again))
+      return 0;
+
+    // Wait for socket to become ready.
+    if (socket_ops::poll_write(s, 0, -1, ec) < 0)
+      return 0;
+  }
+}
+
+#if defined(ASIO_HAS_IOCP)
+
+void complete_iocp_send(
+    const weak_cancel_token_type& cancel_token,
+    asio::error_code& ec)
+{
+  // Map non-portable errors to their portable counterparts.
+  if (ec.value() == ERROR_NETNAME_DELETED)
+  {
+    if (cancel_token.expired())
+      ec = asio::error::operation_aborted;
+    else
+      ec = asio::error::connection_reset;
+  }
+  else if (ec.value() == ERROR_PORT_UNREACHABLE)
+  {
+    ec = asio::error::connection_refused;
+  }
+}
+
+#else // defined(ASIO_HAS_IOCP)
+
+bool non_blocking_send(socket_type s,
+    const buf* bufs, size_t count, int flags,
+    asio::error_code& ec, size_t& bytes_transferred)
+{
+  for (;;)
+  {
+    // Write some data.
+    signed_size_type bytes = socket_ops::send(s, bufs, count, flags, ec);
+
+    // Check if operation succeeded.
+    if (bytes >= 0)
+    {
+      bytes_transferred = bytes;
+      return true;
+    }
+
+    // Retry operation if interrupted by signal.
+    if (ec == asio::error::interrupted)
+      continue;
+
+    // Check if we need to run the operation again.
+    if (ec == asio::error::would_block
+        || ec == asio::error::try_again)
+      return false;
+
+    // Operation failed.
+    bytes_transferred = 0;
+    return true;
+  }
+}
+
+bool non_blocking_send1(socket_type s,
+    const void* data, size_t size, int flags,
+    asio::error_code& ec, size_t& bytes_transferred)
+{
+  for (;;)
+  {
+    // Write some data.
+    signed_size_type bytes = socket_ops::send1(s, data, size, flags, ec);
+
+    // Check if operation succeeded.
+    if (bytes >= 0)
+    {
+      bytes_transferred = bytes;
+      return true;
+    }
+
+    // Retry operation if interrupted by signal.
+    if (ec == asio::error::interrupted)
+      continue;
+
+    // Check if we need to run the operation again.
+    if (ec == asio::error::would_block
+        || ec == asio::error::try_again)
+      return false;
+
+    // Operation failed.
+    bytes_transferred = 0;
+    return true;
+  }
+}
+
+#endif // defined(ASIO_HAS_IOCP)
+
+signed_size_type sendto(socket_type s, const buf* bufs, size_t count,
+    int flags, const socket_addr_type* addr, std::size_t addrlen,
+    asio::error_code& ec)
+{
+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+  // Send the data.
+  DWORD send_buf_count = static_cast<DWORD>(count);
+  DWORD bytes_transferred = 0;
+  int result = ::WSASendTo(s, const_cast<buf*>(bufs),
+        send_buf_count, &bytes_transferred, flags, addr,
+        static_cast<int>(addrlen), 0, 0);
+  get_last_error(ec, true);
+  if (ec.value() == ERROR_NETNAME_DELETED)
+    ec = asio::error::connection_reset;
+  else if (ec.value() == ERROR_PORT_UNREACHABLE)
+    ec = asio::error::connection_refused;
+  if (result != 0)
+    return socket_error_retval;
+  ec.assign(0, ec.category());
+  return bytes_transferred;
+#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+  msghdr msg = msghdr();
+  init_msghdr_msg_name(msg.msg_name, addr);
+  msg.msg_namelen = static_cast<int>(addrlen);
+  msg.msg_iov = const_cast<buf*>(bufs);
+  msg.msg_iovlen = static_cast<int>(count);
+#if defined(__linux__)
+  flags |= MSG_NOSIGNAL;
+#endif // defined(__linux__)
+  signed_size_type result = ::sendmsg(s, &msg, flags);
+  get_last_error(ec, result < 0);
+  return result;
+#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+}
+
+template <typename SockLenType>
+inline signed_size_type call_sendto(SockLenType msghdr::*,
+    socket_type s, const void* data, size_t size, int flags,
+    const socket_addr_type* addr, std::size_t addrlen)
+{
+  return ::sendto(s, static_cast<char*>(const_cast<void*>(data)),
+      size, flags, addr, (SockLenType)addrlen);
+}
+
+signed_size_type sendto1(socket_type s, const void* data, size_t size,
+    int flags, const socket_addr_type* addr, std::size_t addrlen,
+    asio::error_code& ec)
+{
+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+  // Send the data.
+  WSABUF buf;
+  buf.buf = const_cast<char*>(static_cast<const char*>(data));
+  buf.len = static_cast<ULONG>(size);
+  DWORD bytes_transferred = 0;
+  int result = ::WSASendTo(s, &buf, 1, &bytes_transferred,
+      flags, addr, static_cast<int>(addrlen), 0, 0);
+  get_last_error(ec, true);
+  if (ec.value() == ERROR_NETNAME_DELETED)
+    ec = asio::error::connection_reset;
+  else if (ec.value() == ERROR_PORT_UNREACHABLE)
+    ec = asio::error::connection_refused;
+  if (result != 0)
+    return socket_error_retval;
+  ec.assign(0, ec.category());
+  return bytes_transferred;
+#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+#if defined(__linux__)
+  flags |= MSG_NOSIGNAL;
+#endif // defined(__linux__)
+  signed_size_type result = call_sendto(&msghdr::msg_namelen,
+      s, data, size, flags, addr, addrlen);
+  get_last_error(ec, result < 0);
+  return result;
+#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+}
+
+size_t sync_sendto(socket_type s, state_type state, const buf* bufs,
+    size_t count, int flags, const socket_addr_type* addr,
+    std::size_t addrlen, asio::error_code& ec)
+{
+  if (s == invalid_socket)
+  {
+    ec = asio::error::bad_descriptor;
+    return 0;
+  }
+
+  // Write some data.
+  for (;;)
+  {
+    // Try to complete the operation without blocking.
+    signed_size_type bytes = socket_ops::sendto(
+        s, bufs, count, flags, addr, addrlen, ec);
+
+    // Check if operation succeeded.
+    if (bytes >= 0)
+      return bytes;
+
+    // Operation failed.
+    if ((state & user_set_non_blocking)
+        || (ec != asio::error::would_block
+          && ec != asio::error::try_again))
+      return 0;
+
+    // Wait for socket to become ready.
+    if (socket_ops::poll_write(s, 0, -1, ec) < 0)
+      return 0;
+  }
+}
+
+size_t sync_sendto1(socket_type s, state_type state, const void* data,
+    size_t size, int flags, const socket_addr_type* addr,
+    std::size_t addrlen, asio::error_code& ec)
+{
+  if (s == invalid_socket)
+  {
+    ec = asio::error::bad_descriptor;
+    return 0;
+  }
+
+  // Write some data.
+  for (;;)
+  {
+    // Try to complete the operation without blocking.
+    signed_size_type bytes = socket_ops::sendto1(
+        s, data, size, flags, addr, addrlen, ec);
+
+    // Check if operation succeeded.
+    if (bytes >= 0)
+      return bytes;
+
+    // Operation failed.
+    if ((state & user_set_non_blocking)
+        || (ec != asio::error::would_block
+          && ec != asio::error::try_again))
+      return 0;
+
+    // Wait for socket to become ready.
+    if (socket_ops::poll_write(s, 0, -1, ec) < 0)
+      return 0;
+  }
+}
+
+#if !defined(ASIO_HAS_IOCP)
+
+bool non_blocking_sendto(socket_type s,
+    const buf* bufs, size_t count, int flags,
+    const socket_addr_type* addr, std::size_t addrlen,
+    asio::error_code& ec, size_t& bytes_transferred)
+{
+  for (;;)
+  {
+    // Write some data.
+    signed_size_type bytes = socket_ops::sendto(
+        s, bufs, count, flags, addr, addrlen, ec);
+
+    // Check if operation succeeded.
+    if (bytes >= 0)
+    {
+      bytes_transferred = bytes;
+      return true;
+    }
+
+    // Retry operation if interrupted by signal.
+    if (ec == asio::error::interrupted)
+      continue;
+
+    // Check if we need to run the operation again.
+    if (ec == asio::error::would_block
+        || ec == asio::error::try_again)
+      return false;
+
+    // Operation failed.
+    bytes_transferred = 0;
+    return true;
+  }
+}
+
+bool non_blocking_sendto1(socket_type s,
+    const void* data, size_t size, int flags,
+    const socket_addr_type* addr, std::size_t addrlen,
+    asio::error_code& ec, size_t& bytes_transferred)
+{
+  for (;;)
+  {
+    // Write some data.
+    signed_size_type bytes = socket_ops::sendto1(
+        s, data, size, flags, addr, addrlen, ec);
+
+    // Check if operation succeeded.
+    if (bytes >= 0)
+    {
+      bytes_transferred = bytes;
+      return true;
+    }
+
+    // Retry operation if interrupted by signal.
+    if (ec == asio::error::interrupted)
+      continue;
+
+    // Check if we need to run the operation again.
+    if (ec == asio::error::would_block
+        || ec == asio::error::try_again)
+      return false;
+
+    // Operation failed.
+    bytes_transferred = 0;
+    return true;
+  }
+}
+
+#endif // !defined(ASIO_HAS_IOCP)
+
+socket_type socket(int af, int type, int protocol,
+    asio::error_code& ec)
+{
+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+  socket_type s = ::WSASocketW(af, type, protocol, 0, 0, WSA_FLAG_OVERLAPPED);
+  get_last_error(ec, s == invalid_socket);
+  if (s == invalid_socket)
+    return s;
+
+  if (af == ASIO_OS_DEF(AF_INET6))
+  {
+    // Try to enable the POSIX default behaviour of having IPV6_V6ONLY set to
+    // false. This will only succeed on Windows Vista and later versions of
+    // Windows, where a dual-stack IPv4/v6 implementation is available.
+    DWORD optval = 0;
+    ::setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY,
+        reinterpret_cast<const char*>(&optval), sizeof(optval));
+  }
+
+  return s;
+#elif defined(__MACH__) && defined(__APPLE__) || defined(__FreeBSD__)
+  socket_type s = ::socket(af, type, protocol);
+  get_last_error(ec, s < 0);
+
+  int optval = 1;
+  int result = ::setsockopt(s, SOL_SOCKET,
+      SO_NOSIGPIPE, &optval, sizeof(optval));
+  get_last_error(ec, result != 0);
+  if (result != 0)
+  {
+    ::close(s);
+    return invalid_socket;
+  }
+
+  return s;
+#else
+  int s = ::socket(af, type, protocol);
+  get_last_error(ec, s < 0);
+  return s;
+#endif
+}
+
+template <typename SockLenType>
+inline int call_setsockopt(SockLenType msghdr::*,
+    socket_type s, int level, int optname,
+    const void* optval, std::size_t optlen)
+{
+  return ::setsockopt(s, level, optname,
+      (const char*)optval, (SockLenType)optlen);
+}
+
+int setsockopt(socket_type s, state_type& state, int level, int optname,
+    const void* optval, std::size_t optlen, asio::error_code& ec)
+{
+  if (s == invalid_socket)
+  {
+    ec = asio::error::bad_descriptor;
+    return socket_error_retval;
+  }
+
+  if (level == custom_socket_option_level && optname == always_fail_option)
+  {
+    ec = asio::error::invalid_argument;
+    return socket_error_retval;
+  }
+
+  if (level == custom_socket_option_level
+      && optname == enable_connection_aborted_option)
+  {
+    if (optlen != sizeof(int))
+    {
+      ec = asio::error::invalid_argument;
+      return socket_error_retval;
+    }
+
+    if (*static_cast<const int*>(optval))
+      state |= enable_connection_aborted;
+    else
+      state &= ~enable_connection_aborted;
+    ec.assign(0, ec.category());
+    return 0;
+  }
+
+  if (level == SOL_SOCKET && optname == SO_LINGER)
+    state |= user_set_linger;
+
+#if defined(__BORLANDC__)
+  // Mysteriously, using the getsockopt and setsockopt functions directly with
+  // Borland C++ results in incorrect values being set and read. The bug can be
+  // worked around by using function addresses resolved with GetProcAddress.
+  if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32"))
+  {
+    typedef int (WSAAPI *sso_t)(SOCKET, int, int, const char*, int);
+    if (sso_t sso = (sso_t)::GetProcAddress(winsock_module, "setsockopt"))
+    {
+      int result = sso(s, level, optname,
+            reinterpret_cast<const char*>(optval),
+            static_cast<int>(optlen));
+      get_last_error(ec, result != 0);
+      return result;
+    }
+  }
+  ec = asio::error::fault;
+  return socket_error_retval;
+#else // defined(__BORLANDC__)
+  int result = call_setsockopt(&msghdr::msg_namelen,
+        s, level, optname, optval, optlen);
+  get_last_error(ec, result != 0);
+  if (result == 0)
+  {
+#if defined(__MACH__) && defined(__APPLE__) \
+  || defined(__NetBSD__) || defined(__FreeBSD__) \
+  || defined(__OpenBSD__) || defined(__QNX__)
+    // To implement portable behaviour for SO_REUSEADDR with UDP sockets we
+    // need to also set SO_REUSEPORT on BSD-based platforms.
+    if ((state & datagram_oriented)
+        && level == SOL_SOCKET && optname == SO_REUSEADDR)
+    {
+      call_setsockopt(&msghdr::msg_namelen, s,
+          SOL_SOCKET, SO_REUSEPORT, optval, optlen);
+    }
+#endif
+  }
+
+  return result;
+#endif // defined(__BORLANDC__)
+}
+
+template <typename SockLenType>
+inline int call_getsockopt(SockLenType msghdr::*,
+    socket_type s, int level, int optname,
+    void* optval, std::size_t* optlen)
+{
+  SockLenType tmp_optlen = (SockLenType)*optlen;
+  int result = ::getsockopt(s, level, optname, (char*)optval, &tmp_optlen);
+  *optlen = (std::size_t)tmp_optlen;
+  return result;
+}
+
+int getsockopt(socket_type s, state_type state, int level, int optname,
+    void* optval, size_t* optlen, asio::error_code& ec)
+{
+  if (s == invalid_socket)
+  {
+    ec = asio::error::bad_descriptor;
+    return socket_error_retval;
+  }
+
+  if (level == custom_socket_option_level && optname == always_fail_option)
+  {
+    ec = asio::error::invalid_argument;
+    return socket_error_retval;
+  }
+
+  if (level == custom_socket_option_level
+      && optname == enable_connection_aborted_option)
+  {
+    if (*optlen != sizeof(int))
+    {
+      ec = asio::error::invalid_argument;
+      return socket_error_retval;
+    }
+
+    *static_cast<int*>(optval) = (state & enable_connection_aborted) ? 1 : 0;
+    ec.assign(0, ec.category());
+    return 0;
+  }
+
+#if defined(__BORLANDC__)
+  // Mysteriously, using the getsockopt and setsockopt functions directly with
+  // Borland C++ results in incorrect values being set and read. The bug can be
+  // worked around by using function addresses resolved with GetProcAddress.
+  if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32"))
+  {
+    typedef int (WSAAPI *gso_t)(SOCKET, int, int, char*, int*);
+    if (gso_t gso = (gso_t)::GetProcAddress(winsock_module, "getsockopt"))
+    {
+      int tmp_optlen = static_cast<int>(*optlen);
+      int result = gso(s, level, optname,
+            reinterpret_cast<char*>(optval), &tmp_optlen);
+      get_last_error(ec, result != 0);
+      *optlen = static_cast<size_t>(tmp_optlen);
+      if (result != 0 && level == IPPROTO_IPV6 && optname == IPV6_V6ONLY
+          && ec.value() == WSAENOPROTOOPT && *optlen == sizeof(DWORD))
+      {
+        // Dual-stack IPv4/v6 sockets, and the IPV6_V6ONLY socket option, are
+        // only supported on Windows Vista and later. To simplify program logic
+        // we will fake success of getting this option and specify that the
+        // value is non-zero (i.e. true). This corresponds to the behavior of
+        // IPv6 sockets on Windows platforms pre-Vista.
+        *static_cast<DWORD*>(optval) = 1;
+        ec.assign(0, ec.category());
+      }
+      return result;
+    }
+  }
+  ec = asio::error::fault;
+  return socket_error_retval;
+#elif defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+  int result = call_getsockopt(&msghdr::msg_namelen,
+        s, level, optname, optval, optlen);
+  get_last_error(ec, result != 0);
+  if (result != 0 && level == IPPROTO_IPV6 && optname == IPV6_V6ONLY
+      && ec.value() == WSAENOPROTOOPT && *optlen == sizeof(DWORD))
+  {
+    // Dual-stack IPv4/v6 sockets, and the IPV6_V6ONLY socket option, are only
+    // supported on Windows Vista and later. To simplify program logic we will
+    // fake success of getting this option and specify that the value is
+    // non-zero (i.e. true). This corresponds to the behavior of IPv6 sockets
+    // on Windows platforms pre-Vista.
+    *static_cast<DWORD*>(optval) = 1;
+    ec.assign(0, ec.category());
+  }
+  return result;
+#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+  int result = call_getsockopt(&msghdr::msg_namelen,
+        s, level, optname, optval, optlen);
+  get_last_error(ec, result != 0);
+#if defined(__linux__)
+  if (result == 0 && level == SOL_SOCKET && *optlen == sizeof(int)
+      && (optname == SO_SNDBUF || optname == SO_RCVBUF))
+  {
+    // On Linux, setting SO_SNDBUF or SO_RCVBUF to N actually causes the kernel
+    // to set the buffer size to N*2. Linux puts additional stuff into the
+    // buffers so that only about half is actually available to the application.
+    // The retrieved value is divided by 2 here to make it appear as though the
+    // correct value has been set.
+    *static_cast<int*>(optval) /= 2;
+  }
+#endif // defined(__linux__)
+  return result;
+#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+}
+
+template <typename SockLenType>
+inline int call_getpeername(SockLenType msghdr::*,
+    socket_type s, socket_addr_type* addr, std::size_t* addrlen)
+{
+  SockLenType tmp_addrlen = (SockLenType)*addrlen;
+  int result = ::getpeername(s, addr, &tmp_addrlen);
+  *addrlen = (std::size_t)tmp_addrlen;
+  return result;
+}
+
+int getpeername(socket_type s, socket_addr_type* addr,
+    std::size_t* addrlen, bool cached, asio::error_code& ec)
+{
+  if (s == invalid_socket)
+  {
+    ec = asio::error::bad_descriptor;
+    return socket_error_retval;
+  }
+
+#if defined(ASIO_WINDOWS) && !defined(ASIO_WINDOWS_APP) \
+  || defined(__CYGWIN__)
+  if (cached)
+  {
+    // Check if socket is still connected.
+    DWORD connect_time = 0;
+    size_t connect_time_len = sizeof(connect_time);
+    if (socket_ops::getsockopt(s, 0, SOL_SOCKET, SO_CONNECT_TIME,
+          &connect_time, &connect_time_len, ec) == socket_error_retval)
+    {
+      return socket_error_retval;
+    }
+    if (connect_time == 0xFFFFFFFF)
+    {
+      ec = asio::error::not_connected;
+      return socket_error_retval;
+    }
+
+    // The cached value is still valid.
+    ec.assign(0, ec.category());
+    return 0;
+  }
+#else // defined(ASIO_WINDOWS) && !defined(ASIO_WINDOWS_APP)
+      // || defined(__CYGWIN__)
+  (void)cached;
+#endif // defined(ASIO_WINDOWS) && !defined(ASIO_WINDOWS_APP)
+       // || defined(__CYGWIN__)
+
+  int result = call_getpeername(&msghdr::msg_namelen, s, addr, addrlen);
+  get_last_error(ec, result != 0);
+  return result;
+}
+
+template <typename SockLenType>
+inline int call_getsockname(SockLenType msghdr::*,
+    socket_type s, socket_addr_type* addr, std::size_t* addrlen)
+{
+  SockLenType tmp_addrlen = (SockLenType)*addrlen;
+  int result = ::getsockname(s, addr, &tmp_addrlen);
+  *addrlen = (std::size_t)tmp_addrlen;
+  return result;
+}
+
+int getsockname(socket_type s, socket_addr_type* addr,
+    std::size_t* addrlen, asio::error_code& ec)
+{
+  if (s == invalid_socket)
+  {
+    ec = asio::error::bad_descriptor;
+    return socket_error_retval;
+  }
+
+  int result = call_getsockname(&msghdr::msg_namelen, s, addr, addrlen);
+  get_last_error(ec, result != 0);
+  return result;
+}
+
+int ioctl(socket_type s, state_type& state, int cmd,
+    ioctl_arg_type* arg, asio::error_code& ec)
+{
+  if (s == invalid_socket)
+  {
+    ec = asio::error::bad_descriptor;
+    return socket_error_retval;
+  }
+
+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+  int result = ::ioctlsocket(s, cmd, arg);
+#elif defined(__MACH__) && defined(__APPLE__) \
+  || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__)
+  int result = ::ioctl(s, static_cast<unsigned int>(cmd), arg);
+#else
+  int result = ::ioctl(s, cmd, arg);
+#endif
+  get_last_error(ec, result < 0);
+  if (result >= 0)
+  {
+    // When updating the non-blocking mode we always perform the ioctl syscall,
+    // even if the flags would otherwise indicate that the socket is already in
+    // the correct state. This ensures that the underlying socket is put into
+    // the state that has been requested by the user. If the ioctl syscall was
+    // successful then we need to update the flags to match.
+    if (cmd == static_cast<int>(FIONBIO))
+    {
+      if (*arg)
+      {
+        state |= user_set_non_blocking;
+      }
+      else
+      {
+        // Clearing the non-blocking mode always overrides any internally-set
+        // non-blocking flag. Any subsequent asynchronous operations will need
+        // to re-enable non-blocking I/O.
+        state &= ~(user_set_non_blocking | internal_non_blocking);
+      }
+    }
+  }
+
+  return result;
+}
+
+int select(int nfds, fd_set* readfds, fd_set* writefds,
+    fd_set* exceptfds, timeval* timeout, asio::error_code& ec)
+{
+#if defined(__EMSCRIPTEN__)
+  exceptfds = 0;
+#endif // defined(__EMSCRIPTEN__)
+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+  if (!readfds && !writefds && !exceptfds && timeout)
+  {
+    DWORD milliseconds = timeout->tv_sec * 1000 + timeout->tv_usec / 1000;
+    if (milliseconds == 0)
+      milliseconds = 1; // Force context switch.
+    ::Sleep(milliseconds);
+    ec.assign(0, ec.category());
+    return 0;
+  }
+
+  // The select() call allows timeout values measured in microseconds, but the
+  // system clock (as wrapped by boost::posix_time::microsec_clock) typically
+  // has a resolution of 10 milliseconds. This can lead to a spinning select
+  // reactor, meaning increased CPU usage, when waiting for the earliest
+  // scheduled timeout if it's less than 10 milliseconds away. To avoid a tight
+  // spin we'll use a minimum timeout of 1 millisecond.
+  if (timeout && timeout->tv_sec == 0
+      && timeout->tv_usec > 0 && timeout->tv_usec < 1000)
+    timeout->tv_usec = 1000;
+#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+
+#if defined(__hpux) && defined(__SELECT)
+  timespec ts;
+  ts.tv_sec = timeout ? timeout->tv_sec : 0;
+  ts.tv_nsec = timeout ? timeout->tv_usec * 1000 : 0;
+  int result = ::pselect(nfds, readfds,
+        writefds, exceptfds, timeout ? &ts : 0, 0);
+#else
+  int result = ::select(nfds, readfds, writefds, exceptfds, timeout);
+#endif
+  get_last_error(ec, result < 0);
+  return result;
+}
+
+int poll_read(socket_type s, state_type state,
+    int msec, asio::error_code& ec)
+{
+  if (s == invalid_socket)
+  {
+    ec = asio::error::bad_descriptor;
+    return socket_error_retval;
+  }
+
+#if defined(ASIO_WINDOWS) \
+  || defined(__CYGWIN__) \
+  || defined(__SYMBIAN32__)
+  fd_set fds;
+  FD_ZERO(&fds);
+  FD_SET(s, &fds);
+  timeval timeout_obj;
+  timeval* timeout;
+  if (state & user_set_non_blocking)
+  {
+    timeout_obj.tv_sec = 0;
+    timeout_obj.tv_usec = 0;
+    timeout = &timeout_obj;
+  }
+  else if (msec >= 0)
+  {
+    timeout_obj.tv_sec = msec / 1000;
+    timeout_obj.tv_usec = (msec % 1000) * 1000;
+    timeout = &timeout_obj;
+  }
+  else
+    timeout = 0;
+  int result = ::select(s + 1, &fds, 0, 0, timeout);
+  get_last_error(ec, result < 0);
+#else // defined(ASIO_WINDOWS)
+      // || defined(__CYGWIN__)
+      // || defined(__SYMBIAN32__)
+  pollfd fds;
+  fds.fd = s;
+  fds.events = POLLIN;
+  fds.revents = 0;
+  int timeout = (state & user_set_non_blocking) ? 0 : msec;
+  int result = ::poll(&fds, 1, timeout);
+  get_last_error(ec, result < 0);
+#endif // defined(ASIO_WINDOWS)
+       // || defined(__CYGWIN__)
+       // || defined(__SYMBIAN32__)
+  if (result == 0)
+    if (state & user_set_non_blocking)
+      ec = asio::error::would_block;
+  return result;
+}
+
+int poll_write(socket_type s, state_type state,
+    int msec, asio::error_code& ec)
+{
+  if (s == invalid_socket)
+  {
+    ec = asio::error::bad_descriptor;
+    return socket_error_retval;
+  }
+
+#if defined(ASIO_WINDOWS) \
+  || defined(__CYGWIN__) \
+  || defined(__SYMBIAN32__)
+  fd_set fds;
+  FD_ZERO(&fds);
+  FD_SET(s, &fds);
+  timeval timeout_obj;
+  timeval* timeout;
+  if (state & user_set_non_blocking)
+  {
+    timeout_obj.tv_sec = 0;
+    timeout_obj.tv_usec = 0;
+    timeout = &timeout_obj;
+  }
+  else if (msec >= 0)
+  {
+    timeout_obj.tv_sec = msec / 1000;
+    timeout_obj.tv_usec = (msec % 1000) * 1000;
+    timeout = &timeout_obj;
+  }
+  else
+    timeout = 0;
+  int result = ::select(s + 1, 0, &fds, 0, timeout);
+  get_last_error(ec, result < 0);
+#else // defined(ASIO_WINDOWS)
+      // || defined(__CYGWIN__)
+      // || defined(__SYMBIAN32__)
+  pollfd fds;
+  fds.fd = s;
+  fds.events = POLLOUT;
+  fds.revents = 0;
+  int timeout = (state & user_set_non_blocking) ? 0 : msec;
+  int result = ::poll(&fds, 1, timeout);
+  get_last_error(ec, result < 0);
+#endif // defined(ASIO_WINDOWS)
+       // || defined(__CYGWIN__)
+       // || defined(__SYMBIAN32__)
+  if (result == 0)
+    if (state & user_set_non_blocking)
+      ec = asio::error::would_block;
+  return result;
+}
+
+int poll_error(socket_type s, state_type state,
+    int msec, asio::error_code& ec)
+{
+  if (s == invalid_socket)
+  {
+    ec = asio::error::bad_descriptor;
+    return socket_error_retval;
+  }
+
+#if defined(ASIO_WINDOWS) \
+  || defined(__CYGWIN__) \
+  || defined(__SYMBIAN32__)
+  fd_set fds;
+  FD_ZERO(&fds);
+  FD_SET(s, &fds);
+  timeval timeout_obj;
+  timeval* timeout;
+  if (state & user_set_non_blocking)
+  {
+    timeout_obj.tv_sec = 0;
+    timeout_obj.tv_usec = 0;
+    timeout = &timeout_obj;
+  }
+  else if (msec >= 0)
+  {
+    timeout_obj.tv_sec = msec / 1000;
+    timeout_obj.tv_usec = (msec % 1000) * 1000;
+    timeout = &timeout_obj;
+  }
+  else
+    timeout = 0;
+  int result = ::select(s + 1, 0, 0, &fds, timeout);
+  get_last_error(ec, result < 0);
+#else // defined(ASIO_WINDOWS)
+      // || defined(__CYGWIN__)
+      // || defined(__SYMBIAN32__)
+  pollfd fds;
+  fds.fd = s;
+  fds.events = POLLPRI | POLLERR | POLLHUP;
+  fds.revents = 0;
+  int timeout = (state & user_set_non_blocking) ? 0 : msec;
+  int result = ::poll(&fds, 1, timeout);
+  get_last_error(ec, result < 0);
+#endif // defined(ASIO_WINDOWS)
+       // || defined(__CYGWIN__)
+       // || defined(__SYMBIAN32__)
+  if (result == 0)
+    if (state & user_set_non_blocking)
+      ec = asio::error::would_block;
+  return result;
+}
+
+int poll_connect(socket_type s, int msec, asio::error_code& ec)
+{
+  if (s == invalid_socket)
+  {
+    ec = asio::error::bad_descriptor;
+    return socket_error_retval;
+  }
+
+#if defined(ASIO_WINDOWS) \
+  || defined(__CYGWIN__) \
+  || defined(__SYMBIAN32__)
+  fd_set write_fds;
+  FD_ZERO(&write_fds);
+  FD_SET(s, &write_fds);
+  fd_set except_fds;
+  FD_ZERO(&except_fds);
+  FD_SET(s, &except_fds);
+  timeval timeout_obj;
+  timeval* timeout;
+  if (msec >= 0)
+  {
+    timeout_obj.tv_sec = msec / 1000;
+    timeout_obj.tv_usec = (msec % 1000) * 1000;
+    timeout = &timeout_obj;
+  }
+  else
+    timeout = 0;
+  int result = ::select(s + 1, 0, &write_fds, &except_fds, timeout);
+  get_last_error(ec, result < 0);
+  return result;
+#else // defined(ASIO_WINDOWS)
+      // || defined(__CYGWIN__)
+      // || defined(__SYMBIAN32__)
+  pollfd fds;
+  fds.fd = s;
+  fds.events = POLLOUT;
+  fds.revents = 0;
+  int result = ::poll(&fds, 1, msec);
+  get_last_error(ec, result < 0);
+  return result;
+#endif // defined(ASIO_WINDOWS)
+       // || defined(__CYGWIN__)
+       // || defined(__SYMBIAN32__)
+}
+
+#endif // !defined(ASIO_WINDOWS_RUNTIME)
+
+const char* inet_ntop(int af, const void* src, char* dest, size_t length,
+    unsigned long scope_id, asio::error_code& ec)
+{
+  clear_last_error();
+#if defined(ASIO_WINDOWS_RUNTIME)
+  using namespace std; // For sprintf.
+  const unsigned char* bytes = static_cast<const unsigned char*>(src);
+  if (af == ASIO_OS_DEF(AF_INET))
+  {
+    sprintf_s(dest, length, "%u.%u.%u.%u",
+        bytes[0], bytes[1], bytes[2], bytes[3]);
+    return dest;
+  }
+  else if (af == ASIO_OS_DEF(AF_INET6))
+  {
+    size_t n = 0, b = 0, z = 0;
+    while (n < length && b < 16)
+    {
+      if (bytes[b] == 0 && bytes[b + 1] == 0 && z == 0)
+      {
+        do b += 2; while (b < 16 && bytes[b] == 0 && bytes[b + 1] == 0);
+        n += sprintf_s(dest + n, length - n, ":%s", b < 16 ? "" : ":"), ++z;
+      }
+      else
+      {
+        n += sprintf_s(dest + n, length - n, "%s%x", b ? ":" : "",
+            (static_cast<u_long_type>(bytes[b]) << 8) | bytes[b + 1]);
+        b += 2;
+      }
+    }
+    if (scope_id)
+      n += sprintf_s(dest + n, length - n, "%%%lu", scope_id);
+    return dest;
+  }
+  else
+  {
+    ec = asio::error::address_family_not_supported;
+    return 0;
+  }
+#elif defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+  using namespace std; // For memcpy.
+
+  if (af != ASIO_OS_DEF(AF_INET) && af != ASIO_OS_DEF(AF_INET6))
+  {
+    ec = asio::error::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 == ASIO_OS_DEF(AF_INET))
+  {
+    address_length = sizeof(sockaddr_in4_type);
+    address.v4.sin_family = ASIO_OS_DEF(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 = ASIO_OS_DEF(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<DWORD>(length);
+#if defined(BOOST_NO_ANSI_APIS) || (defined(_MSC_VER) && (_MSC_VER >= 1800))
+  LPWSTR string_buffer = (LPWSTR)_alloca(length * sizeof(WCHAR));
+  int result = ::WSAAddressToStringW(&address.base,
+        address_length, 0, string_buffer, &string_length);
+  get_last_error(ec, true);
+  ::WideCharToMultiByte(CP_ACP, 0, string_buffer, -1,
+      dest, static_cast<int>(length), 0, 0);
+#else
+  int result = ::WSAAddressToStringA(&address.base,
+      address_length, 0, dest, &string_length);
+  get_last_error(ec, true);
+#endif
+
+  // Windows may set error code on success.
+  if (result != socket_error_retval)
+    ec.assign(0, ec.category());
+
+  // Windows may not set an error code on failure.
+  else if (result == socket_error_retval && !ec)
+    ec = asio::error::invalid_argument;
+
+  return result == socket_error_retval ? 0 : dest;
+#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+  const char* result = ::inet_ntop(af, src, dest, static_cast<int>(length));
+  get_last_error(ec, true);
+  if (result == 0 && !ec)
+    ec = asio::error::invalid_argument;
+  if (result != 0 && af == ASIO_OS_DEF(AF_INET6) && scope_id != 0)
+  {
+    using namespace std; // For strcat and sprintf.
+    char if_name[(IF_NAMESIZE > 21 ? IF_NAMESIZE : 21) + 1] = "%";
+    const in6_addr_type* ipv6_address = static_cast<const in6_addr_type*>(src);
+    bool is_link_local = ((ipv6_address->s6_addr[0] == 0xfe)
+        && ((ipv6_address->s6_addr[1] & 0xc0) == 0x80));
+    bool is_multicast_link_local = ((ipv6_address->s6_addr[0] == 0xff)
+        && ((ipv6_address->s6_addr[1] & 0x0f) == 0x02));
+    if ((!is_link_local && !is_multicast_link_local)
+        || if_indextoname(static_cast<unsigned>(scope_id), if_name + 1) == 0)
+      sprintf(if_name + 1, "%lu", scope_id);
+    strcat(dest, if_name);
+  }
+  return result;
+#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+}
+
+int inet_pton(int af, const char* src, void* dest,
+    unsigned long* scope_id, asio::error_code& ec)
+{
+  clear_last_error();
+#if defined(ASIO_WINDOWS_RUNTIME)
+  using namespace std; // For sscanf.
+  unsigned char* bytes = static_cast<unsigned char*>(dest);
+  if (af == ASIO_OS_DEF(AF_INET))
+  {
+    unsigned int b0, b1, b2, b3;
+    if (sscanf_s(src, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) != 4)
+    {
+      ec = asio::error::invalid_argument;
+      return -1;
+    }
+    if (b0 > 255 || b1 > 255 || b2 > 255 || b3 > 255)
+    {
+      ec = asio::error::invalid_argument;
+      return -1;
+    }
+    bytes[0] = static_cast<unsigned char>(b0);
+    bytes[1] = static_cast<unsigned char>(b1);
+    bytes[2] = static_cast<unsigned char>(b2);
+    bytes[3] = static_cast<unsigned char>(b3);
+    ec.assign(), ec.category());
+    return 1;
+  }
+  else if (af == ASIO_OS_DEF(AF_INET6))
+  {
+    unsigned char* bytes = static_cast<unsigned char*>(dest);
+    std::memset(bytes, 0, 16);
+    unsigned char back_bytes[16] = { 0 };
+    int num_front_bytes = 0, num_back_bytes = 0;
+    const char* p = src;
+
+    enum { fword, fcolon, bword, scope, done } state = fword;
+    unsigned long current_word = 0;
+    while (state != done)
+    {
+      if (current_word > 0xFFFF)
+      {
+        ec = asio::error::invalid_argument;
+        return -1;
+      }
+
+      switch (state)
+      {
+      case fword:
+        if (*p >= '0' && *p <= '9')
+          current_word = current_word * 16 + *p++ - '0';
+        else if (*p >= 'a' && *p <= 'f')
+          current_word = current_word * 16 + *p++ - 'a' + 10;
+        else if (*p >= 'A' && *p <= 'F')
+          current_word = current_word * 16 + *p++ - 'A' + 10;
+        else
+        {
+          if (num_front_bytes == 16)
+          {
+            ec = asio::error::invalid_argument;
+            return -1;
+          }
+
+          bytes[num_front_bytes++] = (current_word >> 8) & 0xFF;
+          bytes[num_front_bytes++] = current_word & 0xFF;
+          current_word = 0;
+
+          if (*p == ':')
+            state = fcolon, ++p;
+          else if (*p == '%')
+            state = scope, ++p;
+          else if (*p == 0)
+            state = done;
+          else
+          {
+            ec = asio::error::invalid_argument;
+            return -1;
+          }
+        }
+        break;
+
+      case fcolon:
+        if (*p == ':')
+          state = bword, ++p;
+        else
+          state = fword;
+        break;
+
+      case bword:
+        if (*p >= '0' && *p <= '9')
+          current_word = current_word * 16 + *p++ - '0';
+        else if (*p >= 'a' && *p <= 'f')
+          current_word = current_word * 16 + *p++ - 'a' + 10;
+        else if (*p >= 'A' && *p <= 'F')
+          current_word = current_word * 16 + *p++ - 'A' + 10;
+        else
+        {
+          if (num_front_bytes + num_back_bytes == 16)
+          {
+            ec = asio::error::invalid_argument;
+            return -1;
+          }
+
+          back_bytes[num_back_bytes++] = (current_word >> 8) & 0xFF;
+          back_bytes[num_back_bytes++] = current_word & 0xFF;
+          current_word = 0;
+
+          if (*p == ':')
+            state = bword, ++p;
+          else if (*p == '%')
+            state = scope, ++p;
+          else if (*p == 0)
+            state = done;
+          else
+          {
+            ec = asio::error::invalid_argument;
+            return -1;
+          }
+        }
+        break;
+
+      case scope:
+        if (*p >= '0' && *p <= '9')
+          current_word = current_word * 10 + *p++ - '0';
+        else if (*p == 0)
+          *scope_id = current_word, state = done;
+        else
+        {
+          ec = asio::error::invalid_argument;
+          return -1;
+        }
+        break;
+
+      default:
+        break;
+      }
+    }
+
+    for (int i = 0; i < num_back_bytes; ++i)
+      bytes[16 - num_back_bytes + i] = back_bytes[i];
+
+    ec.assign(0, ec.category());
+    return 1;
+  }
+  else
+  {
+    ec = asio::error::address_family_not_supported;
+    return -1;
+  }
+#elif defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+  using namespace std; // For memcpy and strcmp.
+
+  if (af != ASIO_OS_DEF(AF_INET) && af != ASIO_OS_DEF(AF_INET6))
+  {
+    ec = asio::error::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(BOOST_NO_ANSI_APIS) || (defined(_MSC_VER) && (_MSC_VER >= 1800))
+  int num_wide_chars = static_cast<int>(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 = ::WSAStringToAddressW(wide_buffer,
+      af, 0, &address.base, &address_length);
+  get_last_error(ec, true);
+#else
+  int result = ::WSAStringToAddressA(const_cast<char*>(src),
+      af, 0, &address.base, &address_length);
+  get_last_error(ec, true);
+#endif
+
+  if (af == ASIO_OS_DEF(AF_INET))
+  {
+    if (result != socket_error_retval)
+    {
+      memcpy(dest, &address.v4.sin_addr, sizeof(in4_addr_type));
+      ec.assign(0, ec.category());
+    }
+    else if (strcmp(src, "255.255.255.255") == 0)
+    {
+      static_cast<in4_addr_type*>(dest)->s_addr = INADDR_NONE;
+      ec.assign(0, ec.category());
+    }
+  }
+  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.assign(0, ec.category());
+    }
+  }
+
+  // Windows may not set an error code on failure.
+  if (result == socket_error_retval && !ec)
+    ec = asio::error::invalid_argument;
+
+  if (result != socket_error_retval)
+    ec.assign(0, ec.category());
+
+  return result == socket_error_retval ? -1 : 1;
+#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+  using namespace std; // For strchr, memcpy and atoi.
+
+  // On some platforms, inet_pton fails if an address string contains a scope
+  // id. Detect and remove the scope id before passing the string to inet_pton.
+  const bool is_v6 = (af == ASIO_OS_DEF(AF_INET6));
+  const char* if_name = is_v6 ? strchr(src, '%') : 0;
+  char src_buf[max_addr_v6_str_len + 1];
+  const char* src_ptr = src;
+  if (if_name != 0)
+  {
+    if (if_name - src > max_addr_v6_str_len)
+    {
+      ec = asio::error::invalid_argument;
+      return 0;
+    }
+    memcpy(src_buf, src, if_name - src);
+    src_buf[if_name - src] = 0;
+    src_ptr = src_buf;
+  }
+
+  int result = ::inet_pton(af, src_ptr, dest);
+  get_last_error(ec, true);
+  if (result <= 0 && !ec)
+    ec = asio::error::invalid_argument;
+  if (result > 0 && is_v6 && scope_id)
+  {
+    using namespace std; // For strchr and atoi.
+    *scope_id = 0;
+    if (if_name != 0)
+    {
+      in6_addr_type* ipv6_address = static_cast<in6_addr_type*>(dest);
+      bool is_link_local = ((ipv6_address->s6_addr[0] == 0xfe)
+          && ((ipv6_address->s6_addr[1] & 0xc0) == 0x80));
+      bool is_multicast_link_local = ((ipv6_address->s6_addr[0] == 0xff)
+          && ((ipv6_address->s6_addr[1] & 0x0f) == 0x02));
+      if (is_link_local || is_multicast_link_local)
+        *scope_id = if_nametoindex(if_name + 1);
+      if (*scope_id == 0)
+        *scope_id = atoi(if_name + 1);
+    }
+  }
+  return result;
+#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+}
+
+int gethostname(char* name, int namelen, asio::error_code& ec)
+{
+#if defined(ASIO_WINDOWS_RUNTIME)
+  try
+  {
+    using namespace Windows::Foundation::Collections;
+    using namespace Windows::Networking;
+    using namespace Windows::Networking::Connectivity;
+    IVectorView<HostName^>^ hostnames = NetworkInformation::GetHostNames();
+    for (unsigned i = 0; i < hostnames->Size; ++i)
+    {
+      HostName^ hostname = hostnames->GetAt(i);
+      if (hostname->Type == HostNameType::DomainName)
+      {
+        std::wstring_convert<std::codecvt_utf8<wchar_t>> converter;
+        std::string raw_name = converter.to_bytes(hostname->RawName->Data());
+        if (namelen > 0 && raw_name.size() < static_cast<std::size_t>(namelen))
+        {
+          strcpy_s(name, namelen, raw_name.c_str());
+          return 0;
+        }
+      }
+    }
+    return -1;
+  }
+  catch (Platform::Exception^ e)
+  {
+    ec = asio::error_code(e->HResult,
+        asio::system_category());
+    return -1;
+  }
+#else // defined(ASIO_WINDOWS_RUNTIME)
+  int result = ::gethostname(name, namelen);
+  get_last_error(ec, result != 0);
+  return result;
+#endif // defined(ASIO_WINDOWS_RUNTIME)
+}
+
+#if !defined(ASIO_WINDOWS_RUNTIME)
+
+#if !defined(ASIO_HAS_GETADDRINFO)
+
+// The following functions are only needed for emulation of getaddrinfo and
+// getnameinfo.
+
+inline asio::error_code translate_netdb_error(int error)
+{
+  switch (error)
+  {
+  case 0:
+    return asio::error_code();
+  case HOST_NOT_FOUND:
+    return asio::error::host_not_found;
+  case TRY_AGAIN:
+    return asio::error::host_not_found_try_again;
+  case NO_RECOVERY:
+    return asio::error::no_recovery;
+  case NO_DATA:
+    return asio::error::no_data;
+  default:
+    ASIO_ASSERT(false);
+    return asio::error::invalid_argument;
+  }
+}
+
+inline hostent* gethostbyaddr(const char* addr, int length, int af,
+    hostent* result, char* buffer, int buflength, asio::error_code& ec)
+{
+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+  (void)(buffer);
+  (void)(buflength);
+  hostent* retval = ::gethostbyaddr(addr, length, af);
+  get_last_error(ec, !retval);
+  if (!retval)
+    return 0;
+  *result = *retval;
+  return retval;
+#elif defined(__sun) || defined(__QNX__)
+  int error = 0;
+  hostent* retval = ::gethostbyaddr_r(addr, length,
+      af, result, buffer, buflength, &error);
+  get_last_error(ec, !retval);
+  if (error)
+    ec = translate_netdb_error(error);
+  return retval;
+#elif defined(__MACH__) && defined(__APPLE__)
+  (void)(buffer);
+  (void)(buflength);
+  int error = 0;
+  hostent* retval = ::getipnodebyaddr(addr, length, af, &error);
+  get_last_error(ec, !retval);
+  if (error)
+    ec = translate_netdb_error(error);
+  if (!retval)
+    return 0;
+  *result = *retval;
+  return retval;
+#else
+  hostent* retval = 0;
+  int error = 0;
+  clear_last_error();
+  ::gethostbyaddr_r(addr, length, af, result,
+      buffer, buflength, &retval, &error);
+  get_last_error(ec, true);
+  if (error)
+    ec = translate_netdb_error(error);
+  return retval;
+#endif
+}
+
+inline hostent* gethostbyname(const char* name, int af, struct hostent* result,
+    char* buffer, int buflength, int ai_flags, asio::error_code& ec)
+{
+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+  (void)(buffer);
+  (void)(buflength);
+  (void)(ai_flags);
+  if (af != ASIO_OS_DEF(AF_INET))
+  {
+    ec = asio::error::address_family_not_supported;
+    return 0;
+  }
+  hostent* retval = ::gethostbyname(name);
+  get_last_error(ec, !retval);
+  if (!retval)
+    return 0;
+  *result = *retval;
+  return result;
+#elif defined(__sun) || defined(__QNX__)
+  (void)(ai_flags);
+  if (af != ASIO_OS_DEF(AF_INET))
+  {
+    ec = asio::error::address_family_not_supported;
+    return 0;
+  }
+  int error = 0;
+  hostent* retval = ::gethostbyname_r(name, result, buffer, buflength, &error);
+  get_last_error(ec, !retval);
+  if (error)
+    ec = translate_netdb_error(error);
+  return retval;
+#elif defined(__MACH__) && defined(__APPLE__)
+  (void)(buffer);
+  (void)(buflength);
+  int error = 0;
+  hostent* retval = ::getipnodebyname(name, af, ai_flags, &error);
+  get_last_error(ec, !retval);
+  if (error)
+    ec = translate_netdb_error(error);
+  if (!retval)
+    return 0;
+  *result = *retval;
+  return retval;
+#else
+  (void)(ai_flags);
+  if (af != ASIO_OS_DEF(AF_INET))
+  {
+    ec = asio::error::address_family_not_supported;
+    return 0;
+  }
+  hostent* retval = 0;
+  int error = 0;
+  clear_last_error();
+  ::gethostbyname_r(name, result, buffer, buflength, &retval, &error);
+  get_last_error(ec, true);
+  if (error)
+    ec = translate_netdb_error(error);
+  return retval;
+#endif
+}
+
+inline void freehostent(hostent* h)
+{
+#if defined(__MACH__) && defined(__APPLE__)
+  if (h)
+    ::freehostent(h);
+#else
+  (void)(h);
+#endif
+}
+
+// Emulation of getaddrinfo based on implementation in:
+// Stevens, W. R., UNIX Network Programming Vol. 1, 2nd Ed., Prentice-Hall 1998.
+
+struct gai_search
+{
+  const char* host;
+  int family;
+};
+
+inline int gai_nsearch(const char* host,
+    const addrinfo_type* hints, gai_search (&search)[2])
+{
+  int search_count = 0;
+  if (host == 0 || host[0] == '\0')
+  {
+    if (hints->ai_flags & AI_PASSIVE)
+    {
+      // No host and AI_PASSIVE implies wildcard bind.
+      switch (hints->ai_family)
+      {
+      case ASIO_OS_DEF(AF_INET):
+        search[search_count].host = "0.0.0.0";
+        search[search_count].family = ASIO_OS_DEF(AF_INET);
+        ++search_count;
+        break;
+      case ASIO_OS_DEF(AF_INET6):
+        search[search_count].host = "0::0";
+        search[search_count].family = ASIO_OS_DEF(AF_INET6);
+        ++search_count;
+        break;
+      case ASIO_OS_DEF(AF_UNSPEC):
+        search[search_count].host = "0::0";
+        search[search_count].family = ASIO_OS_DEF(AF_INET6);
+        ++search_count;
+        search[search_count].host = "0.0.0.0";
+        search[search_count].family = ASIO_OS_DEF(AF_INET);
+        ++search_count;
+        break;
+      default:
+        break;
+      }
+    }
+    else
+    {
+      // No host and not AI_PASSIVE means connect to local host.
+      switch (hints->ai_family)
+      {
+      case ASIO_OS_DEF(AF_INET):
+        search[search_count].host = "localhost";
+        search[search_count].family = ASIO_OS_DEF(AF_INET);
+        ++search_count;
+        break;
+      case ASIO_OS_DEF(AF_INET6):
+        search[search_count].host = "localhost";
+        search[search_count].family = ASIO_OS_DEF(AF_INET6);
+        ++search_count;
+        break;
+      case ASIO_OS_DEF(AF_UNSPEC):
+        search[search_count].host = "localhost";
+        search[search_count].family = ASIO_OS_DEF(AF_INET6);
+        ++search_count;
+        search[search_count].host = "localhost";
+        search[search_count].family = ASIO_OS_DEF(AF_INET);
+        ++search_count;
+        break;
+      default:
+        break;
+      }
+    }
+  }
+  else
+  {
+    // Host is specified.
+    switch (hints->ai_family)
+    {
+    case ASIO_OS_DEF(AF_INET):
+      search[search_count].host = host;
+      search[search_count].family = ASIO_OS_DEF(AF_INET);
+      ++search_count;
+      break;
+    case ASIO_OS_DEF(AF_INET6):
+      search[search_count].host = host;
+      search[search_count].family = ASIO_OS_DEF(AF_INET6);
+      ++search_count;
+      break;
+    case ASIO_OS_DEF(AF_UNSPEC):
+      search[search_count].host = host;
+      search[search_count].family = ASIO_OS_DEF(AF_INET6);
+      ++search_count;
+      search[search_count].host = host;
+      search[search_count].family = ASIO_OS_DEF(AF_INET);
+      ++search_count;
+      break;
+    default:
+      break;
+    }
+  }
+  return search_count;
+}
+
+template <typename T>
+inline T* gai_alloc(std::size_t size = sizeof(T))
+{
+  using namespace std;
+  T* p = static_cast<T*>(::operator new(size, std::nothrow));
+  if (p)
+    memset(p, 0, size);
+  return p;
+}
+
+inline void gai_free(void* p)
+{
+  ::operator delete(p);
+}
+
+inline void gai_strcpy(char* target, const char* source, std::size_t max_size)
+{
+  using namespace std;
+#if defined(ASIO_HAS_SECURE_RTL)
+  strcpy_s(target, max_size, source);
+#else // defined(ASIO_HAS_SECURE_RTL)
+  *target = 0;
+  if (max_size > 0)
+    strncat(target, source, max_size - 1);
+#endif // defined(ASIO_HAS_SECURE_RTL)
+}
+
+enum { gai_clone_flag = 1 << 30 };
+
+inline int gai_aistruct(addrinfo_type*** next, const addrinfo_type* hints,
+    const void* addr, int family)
+{
+  using namespace std;
+
+  addrinfo_type* ai = gai_alloc<addrinfo_type>();
+  if (ai == 0)
+    return EAI_MEMORY;
+
+  ai->ai_next = 0;
+  **next = ai;
+  *next = &ai->ai_next;
+
+  ai->ai_canonname = 0;
+  ai->ai_socktype = hints->ai_socktype;
+  if (ai->ai_socktype == 0)
+    ai->ai_flags |= gai_clone_flag;
+  ai->ai_protocol = hints->ai_protocol;
+  ai->ai_family = family;
+
+  switch (ai->ai_family)
+  {
+  case ASIO_OS_DEF(AF_INET):
+    {
+      sockaddr_in4_type* sinptr = gai_alloc<sockaddr_in4_type>();
+      if (sinptr == 0)
+        return EAI_MEMORY;
+      sinptr->sin_family = ASIO_OS_DEF(AF_INET);
+      memcpy(&sinptr->sin_addr, addr, sizeof(in4_addr_type));
+      ai->ai_addr = reinterpret_cast<sockaddr*>(sinptr);
+      ai->ai_addrlen = sizeof(sockaddr_in4_type);
+      break;
+    }
+  case ASIO_OS_DEF(AF_INET6):
+    {
+      sockaddr_in6_type* sin6ptr = gai_alloc<sockaddr_in6_type>();
+      if (sin6ptr == 0)
+        return EAI_MEMORY;
+      sin6ptr->sin6_family = ASIO_OS_DEF(AF_INET6);
+      memcpy(&sin6ptr->sin6_addr, addr, sizeof(in6_addr_type));
+      ai->ai_addr = reinterpret_cast<sockaddr*>(sin6ptr);
+      ai->ai_addrlen = sizeof(sockaddr_in6_type);
+      break;
+    }
+  default:
+    break;
+  }
+
+  return 0;
+}
+
+inline addrinfo_type* gai_clone(addrinfo_type* ai)
+{
+  using namespace std;
+
+  addrinfo_type* new_ai = gai_alloc<addrinfo_type>();
+  if (new_ai == 0)
+    return new_ai;
+
+  new_ai->ai_next = ai->ai_next;
+  ai->ai_next = new_ai;
+
+  new_ai->ai_flags = 0;
+  new_ai->ai_family = ai->ai_family;
+  new_ai->ai_socktype = ai->ai_socktype;
+  new_ai->ai_protocol = ai->ai_protocol;
+  new_ai->ai_canonname = 0;
+  new_ai->ai_addrlen = ai->ai_addrlen;
+  new_ai->ai_addr = gai_alloc<sockaddr>(ai->ai_addrlen);
+  memcpy(new_ai->ai_addr, ai->ai_addr, ai->ai_addrlen);
+
+  return new_ai;
+}
+
+inline int gai_port(addrinfo_type* aihead, int port, int socktype)
+{
+  int num_found = 0;
+
+  for (addrinfo_type* ai = aihead; ai; ai = ai->ai_next)
+  {
+    if (ai->ai_flags & gai_clone_flag)
+    {
+      if (ai->ai_socktype != 0)
+      {
+        ai = gai_clone(ai);
+        if (ai == 0)
+          return -1;
+        // ai now points to newly cloned entry.
+      }
+    }
+    else if (ai->ai_socktype != socktype)
+    {
+      // Ignore if mismatch on socket type.
+      continue;
+    }
+
+    ai->ai_socktype = socktype;
+
+    switch (ai->ai_family)
+    {
+    case ASIO_OS_DEF(AF_INET):
+      {
+        sockaddr_in4_type* sinptr =
+          reinterpret_cast<sockaddr_in4_type*>(ai->ai_addr);
+        sinptr->sin_port = port;
+        ++num_found;
+        break;
+      }
+    case ASIO_OS_DEF(AF_INET6):
+      {
+        sockaddr_in6_type* sin6ptr =
+          reinterpret_cast<sockaddr_in6_type*>(ai->ai_addr);
+        sin6ptr->sin6_port = port;
+        ++num_found;
+        break;
+      }
+    default:
+      break;
+    }
+  }
+
+  return num_found;
+}
+
+inline int gai_serv(addrinfo_type* aihead,
+    const addrinfo_type* hints, const char* serv)
+{
+  using namespace std;
+
+  int num_found = 0;
+
+  if (
+#if defined(AI_NUMERICSERV)
+      (hints->ai_flags & AI_NUMERICSERV) ||
+#endif
+      isdigit(static_cast<unsigned char>(serv[0])))
+  {
+    int port = htons(atoi(serv));
+    if (hints->ai_socktype)
+    {
+      // Caller specifies socket type.
+      int rc = gai_port(aihead, port, hints->ai_socktype);
+      if (rc < 0)
+        return EAI_MEMORY;
+      num_found += rc;
+    }
+    else
+    {
+      // Caller does not specify socket type.
+      int rc = gai_port(aihead, port, SOCK_STREAM);
+      if (rc < 0)
+        return EAI_MEMORY;
+      num_found += rc;
+      rc = gai_port(aihead, port, SOCK_DGRAM);
+      if (rc < 0)
+        return EAI_MEMORY;
+      num_found += rc;
+    }
+  }
+  else
+  {
+    // Try service name with TCP first, then UDP.
+    if (hints->ai_socktype == 0 || hints->ai_socktype == SOCK_STREAM)
+    {
+      servent* sptr = getservbyname(serv, "tcp");
+      if (sptr != 0)
+      {
+        int rc = gai_port(aihead, sptr->s_port, SOCK_STREAM);
+        if (rc < 0)
+          return EAI_MEMORY;
+        num_found += rc;
+      }
+    }
+    if (hints->ai_socktype == 0 || hints->ai_socktype == SOCK_DGRAM)
+    {
+      servent* sptr = getservbyname(serv, "udp");
+      if (sptr != 0)
+      {
+        int rc = gai_port(aihead, sptr->s_port, SOCK_DGRAM);
+        if (rc < 0)
+          return EAI_MEMORY;
+        num_found += rc;
+      }
+    }
+  }
+
+  if (num_found == 0)
+  {
+    if (hints->ai_socktype == 0)
+    {
+      // All calls to getservbyname() failed.
+      return EAI_NONAME;
+    }
+    else
+    {
+      // Service not supported for socket type.
+      return EAI_SERVICE;
+    }
+  }
+
+  return 0;
+}
+
+inline int gai_echeck(const char* host, const char* service,
+    int flags, int family, int socktype, int protocol)
+{
+  (void)(flags);
+  (void)(protocol);
+
+  // Host or service must be specified.
+  if (host == 0 || host[0] == '\0')
+    if (service == 0 || service[0] == '\0')
+      return EAI_NONAME;
+
+  // Check combination of family and socket type.
+  switch (family)
+  {
+  case ASIO_OS_DEF(AF_UNSPEC):
+    break;
+  case ASIO_OS_DEF(AF_INET):
+  case ASIO_OS_DEF(AF_INET6):
+    if (service != 0 && service[0] != '\0')
+      if (socktype != 0 && socktype != SOCK_STREAM && socktype != SOCK_DGRAM)
+        return EAI_SOCKTYPE;
+    break;
+  default:
+    return EAI_FAMILY;
+  }
+
+  return 0;
+}
+
+inline void freeaddrinfo_emulation(addrinfo_type* aihead)
+{
+  addrinfo_type* ai = aihead;
+  while (ai)
+  {
+    gai_free(ai->ai_addr);
+    gai_free(ai->ai_canonname);
+    addrinfo_type* ainext = ai->ai_next;
+    gai_free(ai);
+    ai = ainext;
+  }
+}
+
+inline int getaddrinfo_emulation(const char* host, const char* service,
+    const addrinfo_type* hintsp, addrinfo_type** result)
+{
+  // Set up linked list of addrinfo structures.
+  addrinfo_type* aihead = 0;
+  addrinfo_type** ainext = &aihead;
+  char* canon = 0;
+
+  // Supply default hints if not specified by caller.
+  addrinfo_type hints = addrinfo_type();
+  hints.ai_family = ASIO_OS_DEF(AF_UNSPEC);
+  if (hintsp)
+    hints = *hintsp;
+
+  // If the resolution is not specifically for AF_INET6, remove the AI_V4MAPPED
+  // and AI_ALL flags.
+#if defined(AI_V4MAPPED)
+  if (hints.ai_family != ASIO_OS_DEF(AF_INET6))
+    hints.ai_flags &= ~AI_V4MAPPED;
+#endif
+#if defined(AI_ALL)
+  if (hints.ai_family != ASIO_OS_DEF(AF_INET6))
+    hints.ai_flags &= ~AI_ALL;
+#endif
+
+  // Basic error checking.
+  int rc = gai_echeck(host, service, hints.ai_flags, hints.ai_family,
+      hints.ai_socktype, hints.ai_protocol);
+  if (rc != 0)
+  {
+    freeaddrinfo_emulation(aihead);
+    return rc;
+  }
+
+  gai_search search[2];
+  int search_count = gai_nsearch(host, &hints, search);
+  for (gai_search* sptr = search; sptr < search + search_count; ++sptr)
+  {
+    // Check for IPv4 dotted decimal string.
+    in4_addr_type inaddr;
+    asio::error_code ec;
+    if (socket_ops::inet_pton(ASIO_OS_DEF(AF_INET),
+          sptr->host, &inaddr, 0, ec) == 1)
+    {
+      if (hints.ai_family != ASIO_OS_DEF(AF_UNSPEC)
+          && hints.ai_family != ASIO_OS_DEF(AF_INET))
+      {
+        freeaddrinfo_emulation(aihead);
+        gai_free(canon);
+        return EAI_FAMILY;
+      }
+      if (sptr->family == ASIO_OS_DEF(AF_INET))
+      {
+        rc = gai_aistruct(&ainext, &hints, &inaddr, ASIO_OS_DEF(AF_INET));
+        if (rc != 0)
+        {
+          freeaddrinfo_emulation(aihead);
+          gai_free(canon);
+          return rc;
+        }
+      }
+      continue;
+    }
+
+    // Check for IPv6 hex string.
+    in6_addr_type in6addr;
+    if (socket_ops::inet_pton(ASIO_OS_DEF(AF_INET6),
+          sptr->host, &in6addr, 0, ec) == 1)
+    {
+      if (hints.ai_family != ASIO_OS_DEF(AF_UNSPEC)
+          && hints.ai_family != ASIO_OS_DEF(AF_INET6))
+      {
+        freeaddrinfo_emulation(aihead);
+        gai_free(canon);
+        return EAI_FAMILY;
+      }
+      if (sptr->family == ASIO_OS_DEF(AF_INET6))
+      {
+        rc = gai_aistruct(&ainext, &hints, &in6addr,
+            ASIO_OS_DEF(AF_INET6));
+        if (rc != 0)
+        {
+          freeaddrinfo_emulation(aihead);
+          gai_free(canon);
+          return rc;
+        }
+      }
+      continue;
+    }
+
+    // Look up hostname.
+    hostent hent;
+    char hbuf[8192] = "";
+    hostent* hptr = socket_ops::gethostbyname(sptr->host,
+        sptr->family, &hent, hbuf, sizeof(hbuf), hints.ai_flags, ec);
+    if (hptr == 0)
+    {
+      if (search_count == 2)
+      {
+        // Failure is OK if there are multiple searches.
+        continue;
+      }
+      freeaddrinfo_emulation(aihead);
+      gai_free(canon);
+      if (ec == asio::error::host_not_found)
+        return EAI_NONAME;
+      if (ec == asio::error::host_not_found_try_again)
+        return EAI_AGAIN;
+      if (ec == asio::error::no_recovery)
+        return EAI_FAIL;
+      if (ec == asio::error::no_data)
+        return EAI_NONAME;
+      return EAI_NONAME;
+    }
+
+    // Check for address family mismatch if one was specified.
+    if (hints.ai_family != ASIO_OS_DEF(AF_UNSPEC)
+        && hints.ai_family != hptr->h_addrtype)
+    {
+      freeaddrinfo_emulation(aihead);
+      gai_free(canon);
+      socket_ops::freehostent(hptr);
+      return EAI_FAMILY;
+    }
+
+    // Save canonical name first time.
+    if (host != 0 && host[0] != '\0' && hptr->h_name && hptr->h_name[0]
+        && (hints.ai_flags & AI_CANONNAME) && canon == 0)
+    {
+      std::size_t canon_len = strlen(hptr->h_name) + 1;
+      canon = gai_alloc<char>(canon_len);
+      if (canon == 0)
+      {
+        freeaddrinfo_emulation(aihead);
+        socket_ops::freehostent(hptr);
+        return EAI_MEMORY;
+      }
+      gai_strcpy(canon, hptr->h_name, canon_len);
+    }
+
+    // Create an addrinfo structure for each returned address.
+    for (char** ap = hptr->h_addr_list; *ap; ++ap)
+    {
+      rc = gai_aistruct(&ainext, &hints, *ap, hptr->h_addrtype);
+      if (rc != 0)
+      {
+        freeaddrinfo_emulation(aihead);
+        gai_free(canon);
+        socket_ops::freehostent(hptr);
+        return EAI_FAMILY;
+      }
+    }
+
+    socket_ops::freehostent(hptr);
+  }
+
+  // Check if we found anything.
+  if (aihead == 0)
+  {
+    gai_free(canon);
+    return EAI_NONAME;
+  }
+
+  // Return canonical name in first entry.
+  if (host != 0 && host[0] != '\0' && (hints.ai_flags & AI_CANONNAME))
+  {
+    if (canon)
+    {
+      aihead->ai_canonname = canon;
+      canon = 0;
+    }
+    else
+    {
+      std::size_t canonname_len = strlen(search[0].host) + 1;
+      aihead->ai_canonname = gai_alloc<char>(canonname_len);
+      if (aihead->ai_canonname == 0)
+      {
+        freeaddrinfo_emulation(aihead);
+        return EAI_MEMORY;
+      }
+      gai_strcpy(aihead->ai_canonname, search[0].host, canonname_len);
+    }
+  }
+  gai_free(canon);
+
+  // Process the service name.
+  if (service != 0 && service[0] != '\0')
+  {
+    rc = gai_serv(aihead, &hints, service);
+    if (rc != 0)
+    {
+      freeaddrinfo_emulation(aihead);
+      return rc;
+    }
+  }
+
+  // Return result to caller.
+  *result = aihead;
+  return 0;
+}
+
+inline asio::error_code getnameinfo_emulation(
+    const socket_addr_type* sa, std::size_t salen, char* host,
+    std::size_t hostlen, char* serv, std::size_t servlen, int flags,
+    asio::error_code& ec)
+{
+  using namespace std;
+
+  const char* addr;
+  size_t addr_len;
+  unsigned short port;
+  switch (sa->sa_family)
+  {
+  case ASIO_OS_DEF(AF_INET):
+    if (salen != sizeof(sockaddr_in4_type))
+    {
+      return ec = asio::error::invalid_argument;
+    }
+    addr = reinterpret_cast<const char*>(
+        &reinterpret_cast<const sockaddr_in4_type*>(sa)->sin_addr);
+    addr_len = sizeof(in4_addr_type);
+    port = reinterpret_cast<const sockaddr_in4_type*>(sa)->sin_port;
+    break;
+  case ASIO_OS_DEF(AF_INET6):
+    if (salen != sizeof(sockaddr_in6_type))
+    {
+      return ec = asio::error::invalid_argument;
+    }
+    addr = reinterpret_cast<const char*>(
+        &reinterpret_cast<const sockaddr_in6_type*>(sa)->sin6_addr);
+    addr_len = sizeof(in6_addr_type);
+    port = reinterpret_cast<const sockaddr_in6_type*>(sa)->sin6_port;
+    break;
+  default:
+    return ec = asio::error::address_family_not_supported;
+  }
+
+  if (host && hostlen > 0)
+  {
+    if (flags & NI_NUMERICHOST)
+    {
+      if (socket_ops::inet_ntop(sa->sa_family, addr, host, hostlen, 0, ec) == 0)
+      {
+        return ec;
+      }
+    }
+    else
+    {
+      hostent hent;
+      char hbuf[8192] = "";
+      hostent* hptr = socket_ops::gethostbyaddr(addr,
+          static_cast<int>(addr_len), sa->sa_family,
+          &hent, hbuf, sizeof(hbuf), ec);
+      if (hptr && hptr->h_name && hptr->h_name[0] != '\0')
+      {
+        if (flags & NI_NOFQDN)
+        {
+          char* dot = strchr(hptr->h_name, '.');
+          if (dot)
+          {
+            *dot = 0;
+          }
+        }
+        gai_strcpy(host, hptr->h_name, hostlen);
+        socket_ops::freehostent(hptr);
+      }
+      else
+      {
+        socket_ops::freehostent(hptr);
+        if (flags & NI_NAMEREQD)
+        {
+          return ec = asio::error::host_not_found;
+        }
+        if (socket_ops::inet_ntop(sa->sa_family,
+              addr, host, hostlen, 0, ec) == 0)
+        {
+          return ec;
+        }
+      }
+    }
+  }
+
+  if (serv && servlen > 0)
+  {
+    if (flags & NI_NUMERICSERV)
+    {
+      if (servlen < 6)
+      {
+        return ec = asio::error::no_buffer_space;
+      }
+#if defined(ASIO_HAS_SECURE_RTL)
+      sprintf_s(serv, servlen, "%u", ntohs(port));
+#else // defined(ASIO_HAS_SECURE_RTL)
+      sprintf(serv, "%u", ntohs(port));
+#endif // defined(ASIO_HAS_SECURE_RTL)
+    }
+    else
+    {
+#if defined(ASIO_HAS_PTHREADS)
+      static ::pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+      ::pthread_mutex_lock(&mutex);
+#endif // defined(ASIO_HAS_PTHREADS)
+      servent* sptr = ::getservbyport(port, (flags & NI_DGRAM) ? "udp" : 0);
+      if (sptr && sptr->s_name && sptr->s_name[0] != '\0')
+      {
+        gai_strcpy(serv, sptr->s_name, servlen);
+      }
+      else
+      {
+        if (servlen < 6)
+        {
+          return ec = asio::error::no_buffer_space;
+        }
+#if defined(ASIO_HAS_SECURE_RTL)
+        sprintf_s(serv, servlen, "%u", ntohs(port));
+#else // defined(ASIO_HAS_SECURE_RTL)
+        sprintf(serv, "%u", ntohs(port));
+#endif // defined(ASIO_HAS_SECURE_RTL)
+      }
+#if defined(ASIO_HAS_PTHREADS)
+      ::pthread_mutex_unlock(&mutex);
+#endif // defined(ASIO_HAS_PTHREADS)
+    }
+  }
+
+  ec.assign(0, ec.category());
+  return ec;
+}
+
+#endif // !defined(ASIO_HAS_GETADDRINFO)
+
+inline asio::error_code translate_addrinfo_error(int error)
+{
+  switch (error)
+  {
+  case 0:
+    return asio::error_code();
+  case EAI_AGAIN:
+    return asio::error::host_not_found_try_again;
+  case EAI_BADFLAGS:
+    return asio::error::invalid_argument;
+  case EAI_FAIL:
+    return asio::error::no_recovery;
+  case EAI_FAMILY:
+    return asio::error::address_family_not_supported;
+  case EAI_MEMORY:
+    return asio::error::no_memory;
+  case EAI_NONAME:
+#if defined(EAI_ADDRFAMILY)
+  case EAI_ADDRFAMILY:
+#endif
+#if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME)
+  case EAI_NODATA:
+#endif
+    return asio::error::host_not_found;
+  case EAI_SERVICE:
+    return asio::error::service_not_found;
+  case EAI_SOCKTYPE:
+    return asio::error::socket_type_not_supported;
+  default: // Possibly the non-portable EAI_SYSTEM.
+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+    return asio::error_code(
+        WSAGetLastError(), asio::error::get_system_category());
+#else
+    return asio::error_code(
+        errno, asio::error::get_system_category());
+#endif
+  }
+}
+
+asio::error_code getaddrinfo(const char* host,
+    const char* service, const addrinfo_type& hints,
+    addrinfo_type** result, asio::error_code& ec)
+{
+  host = (host && *host) ? host : 0;
+  service = (service && *service) ? service : 0;
+  clear_last_error();
+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+# if defined(ASIO_HAS_GETADDRINFO)
+  // Building for Windows XP, Windows Server 2003, or later.
+  int error = ::getaddrinfo(host, service, &hints, result);
+  return ec = translate_addrinfo_error(error);
+# else
+  // Building for Windows 2000 or earlier.
+  typedef int (WSAAPI *gai_t)(const char*,
+      const char*, const addrinfo_type*, addrinfo_type**);
+  if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32"))
+  {
+    if (gai_t gai = (gai_t)::GetProcAddress(winsock_module, "getaddrinfo"))
+    {
+      int error = gai(host, service, &hints, result);
+      return ec = translate_addrinfo_error(error);
+    }
+  }
+  int error = getaddrinfo_emulation(host, service, &hints, result);
+  return ec = translate_addrinfo_error(error);
+# endif
+#elif !defined(ASIO_HAS_GETADDRINFO)
+  int error = getaddrinfo_emulation(host, service, &hints, result);
+  return ec = translate_addrinfo_error(error);
+#else
+  int error = ::getaddrinfo(host, service, &hints, result);
+#if defined(__MACH__) && defined(__APPLE__)
+  using namespace std; // For isdigit and atoi.
+  if (error == 0 && service && isdigit(static_cast<unsigned char>(service[0])))
+  {
+    u_short_type port = host_to_network_short(atoi(service));
+    for (addrinfo_type* ai = *result; ai; ai = ai->ai_next)
+    {
+      switch (ai->ai_family)
+      {
+      case ASIO_OS_DEF(AF_INET):
+        {
+          sockaddr_in4_type* sinptr =
+            reinterpret_cast<sockaddr_in4_type*>(ai->ai_addr);
+          if (sinptr->sin_port == 0)
+            sinptr->sin_port = port;
+          break;
+        }
+      case ASIO_OS_DEF(AF_INET6):
+        {
+          sockaddr_in6_type* sin6ptr =
+            reinterpret_cast<sockaddr_in6_type*>(ai->ai_addr);
+          if (sin6ptr->sin6_port == 0)
+            sin6ptr->sin6_port = port;
+          break;
+        }
+      default:
+        break;
+      }
+    }
+  }
+#endif
+  return ec = translate_addrinfo_error(error);
+#endif
+}
+
+asio::error_code background_getaddrinfo(
+    const weak_cancel_token_type& cancel_token, const char* host,
+    const char* service, const addrinfo_type& hints,
+    addrinfo_type** result, asio::error_code& ec)
+{
+  if (cancel_token.expired())
+    ec = asio::error::operation_aborted;
+  else
+    socket_ops::getaddrinfo(host, service, hints, result, ec);
+  return ec;
+}
+
+void freeaddrinfo(addrinfo_type* ai)
+{
+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+# if defined(ASIO_HAS_GETADDRINFO)
+  // Building for Windows XP, Windows Server 2003, or later.
+  ::freeaddrinfo(ai);
+# else
+  // Building for Windows 2000 or earlier.
+  typedef int (WSAAPI *fai_t)(addrinfo_type*);
+  if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32"))
+  {
+    if (fai_t fai = (fai_t)::GetProcAddress(winsock_module, "freeaddrinfo"))
+    {
+      fai(ai);
+      return;
+    }
+  }
+  freeaddrinfo_emulation(ai);
+# endif
+#elif !defined(ASIO_HAS_GETADDRINFO)
+  freeaddrinfo_emulation(ai);
+#else
+  ::freeaddrinfo(ai);
+#endif
+}
+
+asio::error_code getnameinfo(const socket_addr_type* addr,
+    std::size_t addrlen, char* host, std::size_t hostlen,
+    char* serv, std::size_t servlen, int flags, asio::error_code& ec)
+{
+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+# if defined(ASIO_HAS_GETADDRINFO)
+  // Building for Windows XP, Windows Server 2003, or later.
+  clear_last_error();
+  int error = ::getnameinfo(addr, static_cast<socklen_t>(addrlen),
+      host, static_cast<DWORD>(hostlen),
+      serv, static_cast<DWORD>(servlen), flags);
+  return ec = translate_addrinfo_error(error);
+# else
+  // Building for Windows 2000 or earlier.
+  typedef int (WSAAPI *gni_t)(const socket_addr_type*,
+      int, char*, DWORD, char*, DWORD, int);
+  if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32"))
+  {
+    if (gni_t gni = (gni_t)::GetProcAddress(winsock_module, "getnameinfo"))
+    {
+      clear_last_error();
+      int error = gni(addr, static_cast<int>(addrlen),
+          host, static_cast<DWORD>(hostlen),
+          serv, static_cast<DWORD>(servlen), flags);
+      return ec = translate_addrinfo_error(error);
+    }
+  }
+  clear_last_error();
+  return getnameinfo_emulation(addr, addrlen,
+      host, hostlen, serv, servlen, flags, ec);
+# endif
+#elif !defined(ASIO_HAS_GETADDRINFO)
+  using namespace std; // For memcpy.
+  sockaddr_storage_type tmp_addr;
+  memcpy(&tmp_addr, addr, addrlen);
+  addr = reinterpret_cast<socket_addr_type*>(&tmp_addr);
+  clear_last_error();
+  return getnameinfo_emulation(addr, addrlen,
+      host, hostlen, serv, servlen, flags, ec);
+#else
+  clear_last_error();
+  int error = ::getnameinfo(addr, addrlen, host, hostlen, serv, servlen, flags);
+  return ec = translate_addrinfo_error(error);
+#endif
+}
+
+asio::error_code sync_getnameinfo(
+    const socket_addr_type* addr, std::size_t addrlen,
+    char* host, std::size_t hostlen, char* serv,
+    std::size_t servlen, int sock_type, asio::error_code& ec)
+{
+  // First try resolving with the service name. If that fails try resolving
+  // but allow the service to be returned as a number.
+  int flags = (sock_type == SOCK_DGRAM) ? NI_DGRAM : 0;
+  socket_ops::getnameinfo(addr, addrlen, host,
+      hostlen, serv, servlen, flags, ec);
+  if (ec)
+  {
+    socket_ops::getnameinfo(addr, addrlen, host, hostlen,
+        serv, servlen, flags | NI_NUMERICSERV, ec);
+  }
+
+  return ec;
+}
+
+asio::error_code background_getnameinfo(
+    const weak_cancel_token_type& cancel_token,
+    const socket_addr_type* addr, std::size_t addrlen,
+    char* host, std::size_t hostlen, char* serv,
+    std::size_t servlen, int sock_type, asio::error_code& ec)
+{
+  if (cancel_token.expired())
+  {
+    ec = asio::error::operation_aborted;
+  }
+  else
+  {
+    // First try resolving with the service name. If that fails try resolving
+    // but allow the service to be returned as a number.
+    int flags = (sock_type == SOCK_DGRAM) ? NI_DGRAM : 0;
+    socket_ops::getnameinfo(addr, addrlen, host,
+        hostlen, serv, servlen, flags, ec);
+    if (ec)
+    {
+      socket_ops::getnameinfo(addr, addrlen, host, hostlen,
+          serv, servlen, flags | NI_NUMERICSERV, ec);
+    }
+  }
+
+  return ec;
+}
+
+#endif // !defined(ASIO_WINDOWS_RUNTIME)
+
+u_long_type network_to_host_long(u_long_type value)
+{
+#if defined(ASIO_WINDOWS_RUNTIME)
+  unsigned char* value_p = reinterpret_cast<unsigned char*>(&value);
+  u_long_type result = (static_cast<u_long_type>(value_p[0]) << 24)
+    | (static_cast<u_long_type>(value_p[1]) << 16)
+    | (static_cast<u_long_type>(value_p[2]) << 8)
+    | static_cast<u_long_type>(value_p[3]);
+  return result;
+#else // defined(ASIO_WINDOWS_RUNTIME)
+  return ntohl(value);
+#endif // defined(ASIO_WINDOWS_RUNTIME)
+}
+
+u_long_type host_to_network_long(u_long_type value)
+{
+#if defined(ASIO_WINDOWS_RUNTIME)
+  u_long_type result;
+  unsigned char* result_p = reinterpret_cast<unsigned char*>(&result);
+  result_p[0] = static_cast<unsigned char>((value >> 24) & 0xFF);
+  result_p[1] = static_cast<unsigned char>((value >> 16) & 0xFF);
+  result_p[2] = static_cast<unsigned char>((value >> 8) & 0xFF);
+  result_p[3] = static_cast<unsigned char>(value & 0xFF);
+  return result;
+#else // defined(ASIO_WINDOWS_RUNTIME)
+  return htonl(value);
+#endif // defined(ASIO_WINDOWS_RUNTIME)
+}
+
+u_short_type network_to_host_short(u_short_type value)
+{
+#if defined(ASIO_WINDOWS_RUNTIME)
+  unsigned char* value_p = reinterpret_cast<unsigned char*>(&value);
+  u_short_type result = (static_cast<u_short_type>(value_p[0]) << 8)
+    | static_cast<u_short_type>(value_p[1]);
+  return result;
+#else // defined(ASIO_WINDOWS_RUNTIME)
+  return ntohs(value);
+#endif // defined(ASIO_WINDOWS_RUNTIME)
+}
+
+u_short_type host_to_network_short(u_short_type value)
+{
+#if defined(ASIO_WINDOWS_RUNTIME)
+  u_short_type result;
+  unsigned char* result_p = reinterpret_cast<unsigned char*>(&result);
+  result_p[0] = static_cast<unsigned char>((value >> 8) & 0xFF);
+  result_p[1] = static_cast<unsigned char>(value & 0xFF);
+  return result;
+#else // defined(ASIO_WINDOWS_RUNTIME)
+  return htons(value);
+#endif // defined(ASIO_WINDOWS_RUNTIME)
+}
+
+} // namespace socket_ops
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_SOCKET_OPS_IPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/impl/socket_select_interrupter.ipp b/link/modules/asio-standalone/asio/include/asio/detail/impl/socket_select_interrupter.ipp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/impl/socket_select_interrupter.ipp
@@ -0,0 +1,185 @@
+//
+// detail/impl/socket_select_interrupter.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_IMPL_SOCKET_SELECT_INTERRUPTER_IPP
+#define ASIO_DETAIL_IMPL_SOCKET_SELECT_INTERRUPTER_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if !defined(ASIO_WINDOWS_RUNTIME)
+
+#if defined(ASIO_WINDOWS) \
+  || defined(__CYGWIN__) \
+  || defined(__SYMBIAN32__)
+
+#include <cstdlib>
+#include "asio/detail/socket_holder.hpp"
+#include "asio/detail/socket_ops.hpp"
+#include "asio/detail/socket_select_interrupter.hpp"
+#include "asio/detail/throw_error.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+socket_select_interrupter::socket_select_interrupter()
+{
+  open_descriptors();
+}
+
+void socket_select_interrupter::open_descriptors()
+{
+  asio::error_code ec;
+  socket_holder acceptor(socket_ops::socket(
+        AF_INET, SOCK_STREAM, IPPROTO_TCP, ec));
+  if (acceptor.get() == invalid_socket)
+    asio::detail::throw_error(ec, "socket_select_interrupter");
+
+  int opt = 1;
+  socket_ops::state_type acceptor_state = 0;
+  socket_ops::setsockopt(acceptor.get(), acceptor_state,
+      SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt), ec);
+
+  using namespace std; // For memset.
+  sockaddr_in4_type addr;
+  std::size_t addr_len = sizeof(addr);
+  memset(&addr, 0, sizeof(addr));
+  addr.sin_family = AF_INET;
+  addr.sin_addr.s_addr = socket_ops::host_to_network_long(INADDR_LOOPBACK);
+  addr.sin_port = 0;
+  if (socket_ops::bind(acceptor.get(), (const socket_addr_type*)&addr,
+        addr_len, ec) == socket_error_retval)
+    asio::detail::throw_error(ec, "socket_select_interrupter");
+
+  if (socket_ops::getsockname(acceptor.get(), (socket_addr_type*)&addr,
+        &addr_len, ec) == socket_error_retval)
+    asio::detail::throw_error(ec, "socket_select_interrupter");
+
+  // Some broken firewalls on Windows will intermittently cause getsockname to
+  // return 0.0.0.0 when the socket is actually bound to 127.0.0.1. We
+  // explicitly specify the target address here to work around this problem.
+  if (addr.sin_addr.s_addr == socket_ops::host_to_network_long(INADDR_ANY))
+    addr.sin_addr.s_addr = socket_ops::host_to_network_long(INADDR_LOOPBACK);
+
+  if (socket_ops::listen(acceptor.get(),
+        SOMAXCONN, ec) == socket_error_retval)
+    asio::detail::throw_error(ec, "socket_select_interrupter");
+
+  socket_holder client(socket_ops::socket(
+        AF_INET, SOCK_STREAM, IPPROTO_TCP, ec));
+  if (client.get() == invalid_socket)
+    asio::detail::throw_error(ec, "socket_select_interrupter");
+
+  if (socket_ops::connect(client.get(), (const socket_addr_type*)&addr,
+        addr_len, ec) == socket_error_retval)
+    asio::detail::throw_error(ec, "socket_select_interrupter");
+
+  socket_holder server(socket_ops::accept(acceptor.get(), 0, 0, ec));
+  if (server.get() == invalid_socket)
+    asio::detail::throw_error(ec, "socket_select_interrupter");
+  
+  ioctl_arg_type non_blocking = 1;
+  socket_ops::state_type client_state = 0;
+  if (socket_ops::ioctl(client.get(), client_state,
+        FIONBIO, &non_blocking, ec))
+    asio::detail::throw_error(ec, "socket_select_interrupter");
+
+  opt = 1;
+  socket_ops::setsockopt(client.get(), client_state,
+      IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt), ec);
+
+  non_blocking = 1;
+  socket_ops::state_type server_state = 0;
+  if (socket_ops::ioctl(server.get(), server_state,
+        FIONBIO, &non_blocking, ec))
+    asio::detail::throw_error(ec, "socket_select_interrupter");
+
+  opt = 1;
+  socket_ops::setsockopt(server.get(), server_state,
+      IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt), ec);
+
+  read_descriptor_ = server.release();
+  write_descriptor_ = client.release();
+}
+
+socket_select_interrupter::~socket_select_interrupter()
+{
+  close_descriptors();
+}
+
+void socket_select_interrupter::close_descriptors()
+{
+  asio::error_code ec;
+  socket_ops::state_type state = socket_ops::internal_non_blocking;
+  if (read_descriptor_ != invalid_socket)
+    socket_ops::close(read_descriptor_, state, true, ec);
+  if (write_descriptor_ != invalid_socket)
+    socket_ops::close(write_descriptor_, state, true, ec);
+}
+
+void socket_select_interrupter::recreate()
+{
+  close_descriptors();
+
+  write_descriptor_ = invalid_socket;
+  read_descriptor_ = invalid_socket;
+
+  open_descriptors();
+}
+
+void socket_select_interrupter::interrupt()
+{
+  char byte = 0;
+  socket_ops::buf b;
+  socket_ops::init_buf(b, &byte, 1);
+  asio::error_code ec;
+  socket_ops::send(write_descriptor_, &b, 1, 0, ec);
+}
+
+bool socket_select_interrupter::reset()
+{
+  char data[1024];
+  socket_ops::buf b;
+  socket_ops::init_buf(b, data, sizeof(data));
+  asio::error_code ec;
+  for (;;)
+  {
+    int bytes_read = socket_ops::recv(read_descriptor_, &b, 1, 0, ec);
+    if (bytes_read == sizeof(data))
+      continue;
+    if (bytes_read > 0)
+      return true;
+    if (bytes_read == 0)
+      return false;
+    if (ec == asio::error::would_block
+        || ec == asio::error::try_again)
+      return true;
+    return false;
+  }
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_WINDOWS)
+       // || defined(__CYGWIN__)
+       // || defined(__SYMBIAN32__)
+
+#endif // !defined(ASIO_WINDOWS_RUNTIME)
+
+#endif // ASIO_DETAIL_IMPL_SOCKET_SELECT_INTERRUPTER_IPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/impl/strand_executor_service.hpp b/link/modules/asio-standalone/asio/include/asio/detail/impl/strand_executor_service.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/impl/strand_executor_service.hpp
@@ -0,0 +1,385 @@
+//
+// detail/impl/strand_executor_service.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_IMPL_STRAND_EXECUTOR_SERVICE_HPP
+#define ASIO_DETAIL_IMPL_STRAND_EXECUTOR_SERVICE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/call_stack.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/recycling_allocator.hpp"
+#include "asio/executor_work_guard.hpp"
+#include "asio/defer.hpp"
+#include "asio/dispatch.hpp"
+#include "asio/post.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename F, typename Allocator>
+class strand_executor_service::allocator_binder
+{
+public:
+  typedef Allocator allocator_type;
+
+  allocator_binder(ASIO_MOVE_ARG(F) f, const Allocator& a)
+    : f_(ASIO_MOVE_CAST(F)(f)),
+      allocator_(a)
+  {
+  }
+
+  allocator_binder(const allocator_binder& other)
+    : f_(other.f_),
+      allocator_(other.allocator_)
+  {
+  }
+
+#if defined(ASIO_HAS_MOVE)
+  allocator_binder(allocator_binder&& other)
+    : f_(ASIO_MOVE_CAST(F)(other.f_)),
+      allocator_(ASIO_MOVE_CAST(allocator_type)(other.allocator_))
+  {
+  }
+#endif // defined(ASIO_HAS_MOVE)
+
+  allocator_type get_allocator() const ASIO_NOEXCEPT
+  {
+    return allocator_;
+  }
+
+  void operator()()
+  {
+    f_();
+  }
+
+private:
+  F f_;
+  allocator_type allocator_;
+};
+
+template <typename Executor>
+class strand_executor_service::invoker<Executor,
+    typename enable_if<
+      execution::is_executor<Executor>::value
+    >::type>
+{
+public:
+  invoker(const implementation_type& impl, Executor& ex)
+    : impl_(impl),
+      executor_(asio::prefer(ex, execution::outstanding_work.tracked))
+  {
+  }
+
+  invoker(const invoker& other)
+    : impl_(other.impl_),
+      executor_(other.executor_)
+  {
+  }
+
+#if defined(ASIO_HAS_MOVE)
+  invoker(invoker&& other)
+    : impl_(ASIO_MOVE_CAST(implementation_type)(other.impl_)),
+      executor_(ASIO_MOVE_CAST(executor_type)(other.executor_))
+  {
+  }
+#endif // defined(ASIO_HAS_MOVE)
+
+  struct on_invoker_exit
+  {
+    invoker* this_;
+
+    ~on_invoker_exit()
+    {
+      this_->impl_->mutex_->lock();
+      this_->impl_->ready_queue_.push(this_->impl_->waiting_queue_);
+      bool more_handlers = this_->impl_->locked_ =
+        !this_->impl_->ready_queue_.empty();
+      this_->impl_->mutex_->unlock();
+
+      if (more_handlers)
+      {
+        recycling_allocator<void> allocator;
+        execution::execute(
+            asio::prefer(
+              asio::require(this_->executor_,
+                execution::blocking.never),
+            execution::allocator(allocator)),
+            ASIO_MOVE_CAST(invoker)(*this_));
+      }
+    }
+  };
+
+  void operator()()
+  {
+    // Indicate that this strand is executing on the current thread.
+    call_stack<strand_impl>::context ctx(impl_.get());
+
+    // Ensure the next handler, if any, is scheduled on block exit.
+    on_invoker_exit on_exit = { this };
+    (void)on_exit;
+
+    // Run all ready handlers. No lock is required since the ready queue is
+    // accessed only within the strand.
+    asio::error_code ec;
+    while (scheduler_operation* o = impl_->ready_queue_.front())
+    {
+      impl_->ready_queue_.pop();
+      o->complete(impl_.get(), ec, 0);
+    }
+  }
+
+private:
+  typedef typename decay<
+      typename prefer_result<
+        Executor,
+        execution::outstanding_work_t::tracked_t
+      >::type
+    >::type executor_type;
+
+  implementation_type impl_;
+  executor_type executor_;
+};
+
+#if !defined(ASIO_NO_TS_EXECUTORS)
+
+template <typename Executor>
+class strand_executor_service::invoker<Executor,
+    typename enable_if<
+      !execution::is_executor<Executor>::value
+    >::type>
+{
+public:
+  invoker(const implementation_type& impl, Executor& ex)
+    : impl_(impl),
+      work_(ex)
+  {
+  }
+
+  invoker(const invoker& other)
+    : impl_(other.impl_),
+      work_(other.work_)
+  {
+  }
+
+#if defined(ASIO_HAS_MOVE)
+  invoker(invoker&& other)
+    : impl_(ASIO_MOVE_CAST(implementation_type)(other.impl_)),
+      work_(ASIO_MOVE_CAST(executor_work_guard<Executor>)(other.work_))
+  {
+  }
+#endif // defined(ASIO_HAS_MOVE)
+
+  struct on_invoker_exit
+  {
+    invoker* this_;
+
+    ~on_invoker_exit()
+    {
+      this_->impl_->mutex_->lock();
+      this_->impl_->ready_queue_.push(this_->impl_->waiting_queue_);
+      bool more_handlers = this_->impl_->locked_ =
+        !this_->impl_->ready_queue_.empty();
+      this_->impl_->mutex_->unlock();
+
+      if (more_handlers)
+      {
+        Executor ex(this_->work_.get_executor());
+        recycling_allocator<void> allocator;
+        ex.post(ASIO_MOVE_CAST(invoker)(*this_), allocator);
+      }
+    }
+  };
+
+  void operator()()
+  {
+    // Indicate that this strand is executing on the current thread.
+    call_stack<strand_impl>::context ctx(impl_.get());
+
+    // Ensure the next handler, if any, is scheduled on block exit.
+    on_invoker_exit on_exit = { this };
+    (void)on_exit;
+
+    // Run all ready handlers. No lock is required since the ready queue is
+    // accessed only within the strand.
+    asio::error_code ec;
+    while (scheduler_operation* o = impl_->ready_queue_.front())
+    {
+      impl_->ready_queue_.pop();
+      o->complete(impl_.get(), ec, 0);
+    }
+  }
+
+private:
+  implementation_type impl_;
+  executor_work_guard<Executor> work_;
+};
+
+#endif // !defined(ASIO_NO_TS_EXECUTORS)
+
+template <typename Executor, typename Function>
+inline void strand_executor_service::execute(const implementation_type& impl,
+    Executor& ex, ASIO_MOVE_ARG(Function) function,
+    typename enable_if<
+      can_query<Executor, execution::allocator_t<void> >::value
+    >::type*)
+{
+  return strand_executor_service::do_execute(impl, ex,
+      ASIO_MOVE_CAST(Function)(function),
+      asio::query(ex, execution::allocator));
+}
+
+template <typename Executor, typename Function>
+inline void strand_executor_service::execute(const implementation_type& impl,
+    Executor& ex, ASIO_MOVE_ARG(Function) function,
+    typename enable_if<
+      !can_query<Executor, execution::allocator_t<void> >::value
+    >::type*)
+{
+  return strand_executor_service::do_execute(impl, ex,
+      ASIO_MOVE_CAST(Function)(function),
+      std::allocator<void>());
+}
+
+template <typename Executor, typename Function, typename Allocator>
+void strand_executor_service::do_execute(const implementation_type& impl,
+    Executor& ex, ASIO_MOVE_ARG(Function) function, const Allocator& a)
+{
+  typedef typename decay<Function>::type function_type;
+
+  // If the executor is not never-blocking, and we are already in the strand,
+  // then the function can run immediately.
+  if (asio::query(ex, execution::blocking) != execution::blocking.never
+      && call_stack<strand_impl>::contains(impl.get()))
+  {
+    // Make a local, non-const copy of the function.
+    function_type tmp(ASIO_MOVE_CAST(Function)(function));
+
+    fenced_block b(fenced_block::full);
+    asio_handler_invoke_helpers::invoke(tmp, tmp);
+    return;
+  }
+
+  // Allocate and construct an operation to wrap the function.
+  typedef executor_op<function_type, Allocator> op;
+  typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 };
+  p.p = new (p.v) op(ASIO_MOVE_CAST(Function)(function), a);
+
+  ASIO_HANDLER_CREATION((impl->service_->context(), *p.p,
+        "strand_executor", impl.get(), 0, "execute"));
+
+  // Add the function to the strand and schedule the strand if required.
+  bool first = enqueue(impl, p.p);
+  p.v = p.p = 0;
+  if (first)
+  {
+    execution::execute(ex, invoker<Executor>(impl, ex));
+  }
+}
+
+template <typename Executor, typename Function, typename Allocator>
+void strand_executor_service::dispatch(const implementation_type& impl,
+    Executor& ex, ASIO_MOVE_ARG(Function) function, const Allocator& a)
+{
+  typedef typename decay<Function>::type function_type;
+
+  // If we are already in the strand then the function can run immediately.
+  if (call_stack<strand_impl>::contains(impl.get()))
+  {
+    // Make a local, non-const copy of the function.
+    function_type tmp(ASIO_MOVE_CAST(Function)(function));
+
+    fenced_block b(fenced_block::full);
+    asio_handler_invoke_helpers::invoke(tmp, tmp);
+    return;
+  }
+
+  // Allocate and construct an operation to wrap the function.
+  typedef executor_op<function_type, Allocator> op;
+  typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 };
+  p.p = new (p.v) op(ASIO_MOVE_CAST(Function)(function), a);
+
+  ASIO_HANDLER_CREATION((impl->service_->context(), *p.p,
+        "strand_executor", impl.get(), 0, "dispatch"));
+
+  // Add the function to the strand and schedule the strand if required.
+  bool first = enqueue(impl, p.p);
+  p.v = p.p = 0;
+  if (first)
+  {
+    asio::dispatch(ex,
+        allocator_binder<invoker<Executor>, Allocator>(
+          invoker<Executor>(impl, ex), a));
+  }
+}
+
+// Request invocation of the given function and return immediately.
+template <typename Executor, typename Function, typename Allocator>
+void strand_executor_service::post(const implementation_type& impl,
+    Executor& ex, ASIO_MOVE_ARG(Function) function, const Allocator& a)
+{
+  typedef typename decay<Function>::type function_type;
+
+  // Allocate and construct an operation to wrap the function.
+  typedef executor_op<function_type, Allocator> op;
+  typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 };
+  p.p = new (p.v) op(ASIO_MOVE_CAST(Function)(function), a);
+
+  ASIO_HANDLER_CREATION((impl->service_->context(), *p.p,
+        "strand_executor", impl.get(), 0, "post"));
+
+  // Add the function to the strand and schedule the strand if required.
+  bool first = enqueue(impl, p.p);
+  p.v = p.p = 0;
+  if (first)
+  {
+    asio::post(ex,
+        allocator_binder<invoker<Executor>, Allocator>(
+          invoker<Executor>(impl, ex), a));
+  }
+}
+
+// Request invocation of the given function and return immediately.
+template <typename Executor, typename Function, typename Allocator>
+void strand_executor_service::defer(const implementation_type& impl,
+    Executor& ex, ASIO_MOVE_ARG(Function) function, const Allocator& a)
+{
+  typedef typename decay<Function>::type function_type;
+
+  // Allocate and construct an operation to wrap the function.
+  typedef executor_op<function_type, Allocator> op;
+  typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 };
+  p.p = new (p.v) op(ASIO_MOVE_CAST(Function)(function), a);
+
+  ASIO_HANDLER_CREATION((impl->service_->context(), *p.p,
+        "strand_executor", impl.get(), 0, "defer"));
+
+  // Add the function to the strand and schedule the strand if required.
+  bool first = enqueue(impl, p.p);
+  p.v = p.p = 0;
+  if (first)
+  {
+    asio::defer(ex,
+        allocator_binder<invoker<Executor>, Allocator>(
+          invoker<Executor>(impl, ex), a));
+  }
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_IMPL_STRAND_EXECUTOR_SERVICE_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/impl/strand_executor_service.ipp b/link/modules/asio-standalone/asio/include/asio/detail/impl/strand_executor_service.ipp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/impl/strand_executor_service.ipp
@@ -0,0 +1,134 @@
+//
+// detail/impl/strand_executor_service.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_IMPL_STRAND_EXECUTOR_SERVICE_IPP
+#define ASIO_DETAIL_IMPL_STRAND_EXECUTOR_SERVICE_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/strand_executor_service.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+strand_executor_service::strand_executor_service(execution_context& ctx)
+  : execution_context_service_base<strand_executor_service>(ctx),
+    mutex_(),
+    salt_(0),
+    impl_list_(0)
+{
+}
+
+void strand_executor_service::shutdown()
+{
+  op_queue<scheduler_operation> ops;
+
+  asio::detail::mutex::scoped_lock lock(mutex_);
+
+  strand_impl* impl = impl_list_;
+  while (impl)
+  {
+    impl->mutex_->lock();
+    impl->shutdown_ = true;
+    ops.push(impl->waiting_queue_);
+    ops.push(impl->ready_queue_);
+    impl->mutex_->unlock();
+    impl = impl->next_;
+  }
+}
+
+strand_executor_service::implementation_type
+strand_executor_service::create_implementation()
+{
+  implementation_type new_impl(new strand_impl);
+  new_impl->locked_ = false;
+  new_impl->shutdown_ = false;
+
+  asio::detail::mutex::scoped_lock lock(mutex_);
+
+  // Select a mutex from the pool of shared mutexes.
+  std::size_t salt = salt_++;
+  std::size_t mutex_index = reinterpret_cast<std::size_t>(new_impl.get());
+  mutex_index += (reinterpret_cast<std::size_t>(new_impl.get()) >> 3);
+  mutex_index ^= salt + 0x9e3779b9 + (mutex_index << 6) + (mutex_index >> 2);
+  mutex_index = mutex_index % num_mutexes;
+  if (!mutexes_[mutex_index].get())
+    mutexes_[mutex_index].reset(new mutex);
+  new_impl->mutex_ = mutexes_[mutex_index].get();
+
+  // Insert implementation into linked list of all implementations.
+  new_impl->next_ = impl_list_;
+  new_impl->prev_ = 0;
+  if (impl_list_)
+    impl_list_->prev_ = new_impl.get();
+  impl_list_ = new_impl.get();
+  new_impl->service_ = this;
+
+  return new_impl;
+}
+
+strand_executor_service::strand_impl::~strand_impl()
+{
+  asio::detail::mutex::scoped_lock lock(service_->mutex_);
+
+  // Remove implementation from linked list of all implementations.
+  if (service_->impl_list_ == this)
+    service_->impl_list_ = next_;
+  if (prev_)
+    prev_->next_ = next_;
+  if (next_)
+    next_->prev_= prev_;
+}
+
+bool strand_executor_service::enqueue(const implementation_type& impl,
+    scheduler_operation* op)
+{
+  impl->mutex_->lock();
+  if (impl->shutdown_)
+  {
+    impl->mutex_->unlock();
+    op->destroy();
+    return false;
+  }
+  else if (impl->locked_)
+  {
+    // Some other function already holds the strand lock. Enqueue for later.
+    impl->waiting_queue_.push(op);
+    impl->mutex_->unlock();
+    return false;
+  }
+  else
+  {
+    // The function is acquiring the strand lock and so is responsible for
+    // scheduling the strand.
+    impl->locked_ = true;
+    impl->mutex_->unlock();
+    impl->ready_queue_.push(op);
+    return true;
+  }
+}
+
+bool strand_executor_service::running_in_this_thread(
+    const implementation_type& impl)
+{
+  return !!call_stack<strand_impl>::contains(impl.get());
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_IMPL_STRAND_EXECUTOR_SERVICE_IPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/impl/strand_service.hpp b/link/modules/asio-standalone/asio/include/asio/detail/impl/strand_service.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/impl/strand_service.hpp
@@ -0,0 +1,117 @@
+//
+// detail/impl/strand_service.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_IMPL_STRAND_SERVICE_HPP
+#define ASIO_DETAIL_IMPL_STRAND_SERVICE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/call_stack.hpp"
+#include "asio/detail/completion_handler.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/memory.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+inline strand_service::strand_impl::strand_impl()
+  : operation(&strand_service::do_complete),
+    locked_(false)
+{
+}
+
+struct strand_service::on_dispatch_exit
+{
+  io_context_impl* io_context_impl_;
+  strand_impl* impl_;
+
+  ~on_dispatch_exit()
+  {
+    impl_->mutex_.lock();
+    impl_->ready_queue_.push(impl_->waiting_queue_);
+    bool more_handlers = impl_->locked_ = !impl_->ready_queue_.empty();
+    impl_->mutex_.unlock();
+
+    if (more_handlers)
+      io_context_impl_->post_immediate_completion(impl_, false);
+  }
+};
+
+template <typename Handler>
+void strand_service::dispatch(strand_service::implementation_type& impl,
+    Handler& handler)
+{
+  // If we are already in the strand then the handler can run immediately.
+  if (call_stack<strand_impl>::contains(impl))
+  {
+    fenced_block b(fenced_block::full);
+    asio_handler_invoke_helpers::invoke(handler, handler);
+    return;
+  }
+
+  // Allocate and construct an operation to wrap the handler.
+  typedef completion_handler<Handler, io_context::executor_type> op;
+  typename op::ptr p = { asio::detail::addressof(handler),
+    op::ptr::allocate(handler), 0 };
+  p.p = new (p.v) op(handler, io_context_.get_executor());
+
+  ASIO_HANDLER_CREATION((this->context(),
+        *p.p, "strand", impl, 0, "dispatch"));
+
+  bool dispatch_immediately = do_dispatch(impl, p.p);
+  operation* o = p.p;
+  p.v = p.p = 0;
+
+  if (dispatch_immediately)
+  {
+    // Indicate that this strand is executing on the current thread.
+    call_stack<strand_impl>::context ctx(impl);
+
+    // Ensure the next handler, if any, is scheduled on block exit.
+    on_dispatch_exit on_exit = { &io_context_impl_, impl };
+    (void)on_exit;
+
+    op::do_complete(&io_context_impl_, o, asio::error_code(), 0);
+  }
+}
+
+// Request the io_context to invoke the given handler and return immediately.
+template <typename Handler>
+void strand_service::post(strand_service::implementation_type& impl,
+    Handler& handler)
+{
+  bool is_continuation =
+    asio_handler_cont_helpers::is_continuation(handler);
+
+  // Allocate and construct an operation to wrap the handler.
+  typedef completion_handler<Handler, io_context::executor_type> op;
+  typename op::ptr p = { asio::detail::addressof(handler),
+    op::ptr::allocate(handler), 0 };
+  p.p = new (p.v) op(handler, io_context_.get_executor());
+
+  ASIO_HANDLER_CREATION((this->context(),
+        *p.p, "strand", impl, 0, "post"));
+
+  do_post(impl, p.p, is_continuation);
+  p.v = p.p = 0;
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_IMPL_STRAND_SERVICE_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/impl/strand_service.ipp b/link/modules/asio-standalone/asio/include/asio/detail/impl/strand_service.ipp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/impl/strand_service.ipp
@@ -0,0 +1,178 @@
+//
+// detail/impl/strand_service.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_IMPL_STRAND_SERVICE_IPP
+#define ASIO_DETAIL_IMPL_STRAND_SERVICE_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/call_stack.hpp"
+#include "asio/detail/strand_service.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+struct strand_service::on_do_complete_exit
+{
+  io_context_impl* owner_;
+  strand_impl* impl_;
+
+  ~on_do_complete_exit()
+  {
+    impl_->mutex_.lock();
+    impl_->ready_queue_.push(impl_->waiting_queue_);
+    bool more_handlers = impl_->locked_ = !impl_->ready_queue_.empty();
+    impl_->mutex_.unlock();
+
+    if (more_handlers)
+      owner_->post_immediate_completion(impl_, true);
+  }
+};
+
+strand_service::strand_service(asio::io_context& io_context)
+  : asio::detail::service_base<strand_service>(io_context),
+    io_context_(io_context),
+    io_context_impl_(asio::use_service<io_context_impl>(io_context)),
+    mutex_(),
+    salt_(0)
+{
+}
+
+void strand_service::shutdown()
+{
+  op_queue<operation> ops;
+
+  asio::detail::mutex::scoped_lock lock(mutex_);
+
+  for (std::size_t i = 0; i < num_implementations; ++i)
+  {
+    if (strand_impl* impl = implementations_[i].get())
+    {
+      ops.push(impl->waiting_queue_);
+      ops.push(impl->ready_queue_);
+    }
+  }
+}
+
+void strand_service::construct(strand_service::implementation_type& impl)
+{
+  asio::detail::mutex::scoped_lock lock(mutex_);
+
+  std::size_t salt = salt_++;
+#if defined(ASIO_ENABLE_SEQUENTIAL_STRAND_ALLOCATION)
+  std::size_t index = salt;
+#else // defined(ASIO_ENABLE_SEQUENTIAL_STRAND_ALLOCATION)
+  std::size_t index = reinterpret_cast<std::size_t>(&impl);
+  index += (reinterpret_cast<std::size_t>(&impl) >> 3);
+  index ^= salt + 0x9e3779b9 + (index << 6) + (index >> 2);
+#endif // defined(ASIO_ENABLE_SEQUENTIAL_STRAND_ALLOCATION)
+  index = index % num_implementations;
+
+  if (!implementations_[index].get())
+    implementations_[index].reset(new strand_impl);
+  impl = implementations_[index].get();
+}
+
+bool strand_service::running_in_this_thread(
+    const implementation_type& impl) const
+{
+  return call_stack<strand_impl>::contains(impl) != 0;
+}
+
+bool strand_service::do_dispatch(implementation_type& impl, operation* op)
+{
+  // If we are running inside the io_context, and no other handler already
+  // holds the strand lock, then the handler can run immediately.
+  bool can_dispatch = io_context_impl_.can_dispatch();
+  impl->mutex_.lock();
+  if (can_dispatch && !impl->locked_)
+  {
+    // Immediate invocation is allowed.
+    impl->locked_ = true;
+    impl->mutex_.unlock();
+    return true;
+  }
+
+  if (impl->locked_)
+  {
+    // Some other handler already holds the strand lock. Enqueue for later.
+    impl->waiting_queue_.push(op);
+    impl->mutex_.unlock();
+  }
+  else
+  {
+    // The handler is acquiring the strand lock and so is responsible for
+    // scheduling the strand.
+    impl->locked_ = true;
+    impl->mutex_.unlock();
+    impl->ready_queue_.push(op);
+    io_context_impl_.post_immediate_completion(impl, false);
+  }
+
+  return false;
+}
+
+void strand_service::do_post(implementation_type& impl,
+    operation* op, bool is_continuation)
+{
+  impl->mutex_.lock();
+  if (impl->locked_)
+  {
+    // Some other handler already holds the strand lock. Enqueue for later.
+    impl->waiting_queue_.push(op);
+    impl->mutex_.unlock();
+  }
+  else
+  {
+    // The handler is acquiring the strand lock and so is responsible for
+    // scheduling the strand.
+    impl->locked_ = true;
+    impl->mutex_.unlock();
+    impl->ready_queue_.push(op);
+    io_context_impl_.post_immediate_completion(impl, is_continuation);
+  }
+}
+
+void strand_service::do_complete(void* owner, operation* base,
+    const asio::error_code& ec, std::size_t /*bytes_transferred*/)
+{
+  if (owner)
+  {
+    strand_impl* impl = static_cast<strand_impl*>(base);
+
+    // Indicate that this strand is executing on the current thread.
+    call_stack<strand_impl>::context ctx(impl);
+
+    // Ensure the next handler, if any, is scheduled on block exit.
+    on_do_complete_exit on_exit;
+    on_exit.owner_ = static_cast<io_context_impl*>(owner);
+    on_exit.impl_ = impl;
+
+    // Run all ready handlers. No lock is required since the ready queue is
+    // accessed only within the strand.
+    while (operation* o = impl->ready_queue_.front())
+    {
+      impl->ready_queue_.pop();
+      o->complete(owner, ec, 0);
+    }
+  }
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_IMPL_STRAND_SERVICE_IPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/impl/throw_error.ipp b/link/modules/asio-standalone/asio/include/asio/detail/impl/throw_error.ipp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/impl/throw_error.ipp
@@ -0,0 +1,60 @@
+//
+// detail/impl/throw_error.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_IMPL_THROW_ERROR_IPP
+#define ASIO_DETAIL_IMPL_THROW_ERROR_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/throw_error.hpp"
+#include "asio/detail/throw_exception.hpp"
+#include "asio/system_error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+void do_throw_error(const asio::error_code& err)
+{
+  asio::system_error e(err);
+  asio::detail::throw_exception(e);
+}
+
+void do_throw_error(const asio::error_code& err, const char* location)
+{
+  // boostify: non-boost code starts here
+#if defined(ASIO_MSVC) && defined(ASIO_HAS_STD_SYSTEM_ERROR)
+  // Microsoft's implementation of std::system_error is non-conformant in that
+  // it ignores the error code's message when a "what" string is supplied. We'll
+  // work around this by explicitly formatting the "what" string.
+  std::string what_msg = location;
+  what_msg += ": ";
+  what_msg += err.message();
+  asio::system_error e(err, what_msg);
+  asio::detail::throw_exception(e);
+#else // defined(ASIO_MSVC) && defined(ASIO_HAS_STD_SYSTEM_ERROR)
+  // boostify: non-boost code ends here
+  asio::system_error e(err, location);
+  asio::detail::throw_exception(e);
+  // boostify: non-boost code starts here
+#endif // defined(ASIO_MSVC) && defined(ASIO_HAS_STD_SYSTEM_ERROR)
+  // boostify: non-boost code ends here
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_IMPL_THROW_ERROR_IPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/impl/timer_queue_ptime.ipp b/link/modules/asio-standalone/asio/include/asio/detail/impl/timer_queue_ptime.ipp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/impl/timer_queue_ptime.ipp
@@ -0,0 +1,91 @@
+//
+// detail/impl/timer_queue_ptime.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_IMPL_TIMER_QUEUE_PTIME_IPP
+#define ASIO_DETAIL_IMPL_TIMER_QUEUE_PTIME_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_BOOST_DATE_TIME)
+
+#include "asio/detail/timer_queue_ptime.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+timer_queue<time_traits<boost::posix_time::ptime> >::timer_queue()
+{
+}
+
+timer_queue<time_traits<boost::posix_time::ptime> >::~timer_queue()
+{
+}
+
+bool timer_queue<time_traits<boost::posix_time::ptime> >::enqueue_timer(
+    const time_type& time, per_timer_data& timer, wait_op* op)
+{
+  return impl_.enqueue_timer(time, timer, op);
+}
+
+bool timer_queue<time_traits<boost::posix_time::ptime> >::empty() const
+{
+  return impl_.empty();
+}
+
+long timer_queue<time_traits<boost::posix_time::ptime> >::wait_duration_msec(
+    long max_duration) const
+{
+  return impl_.wait_duration_msec(max_duration);
+}
+
+long timer_queue<time_traits<boost::posix_time::ptime> >::wait_duration_usec(
+    long max_duration) const
+{
+  return impl_.wait_duration_usec(max_duration);
+}
+
+void timer_queue<time_traits<boost::posix_time::ptime> >::get_ready_timers(
+    op_queue<operation>& ops)
+{
+  impl_.get_ready_timers(ops);
+}
+
+void timer_queue<time_traits<boost::posix_time::ptime> >::get_all_timers(
+    op_queue<operation>& ops)
+{
+  impl_.get_all_timers(ops);
+}
+
+std::size_t timer_queue<time_traits<boost::posix_time::ptime> >::cancel_timer(
+    per_timer_data& timer, op_queue<operation>& ops, std::size_t max_cancelled)
+{
+  return impl_.cancel_timer(timer, ops, max_cancelled);
+}
+
+void timer_queue<time_traits<boost::posix_time::ptime> >::move_timer(
+    per_timer_data& target, per_timer_data& source)
+{
+  impl_.move_timer(target, source);
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_BOOST_DATE_TIME)
+
+#endif // ASIO_DETAIL_IMPL_TIMER_QUEUE_PTIME_IPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/impl/timer_queue_set.ipp b/link/modules/asio-standalone/asio/include/asio/detail/impl/timer_queue_set.ipp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/impl/timer_queue_set.ipp
@@ -0,0 +1,101 @@
+//
+// detail/impl/timer_queue_set.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_IMPL_TIMER_QUEUE_SET_IPP
+#define ASIO_DETAIL_IMPL_TIMER_QUEUE_SET_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/timer_queue_set.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+timer_queue_set::timer_queue_set()
+  : first_(0)
+{
+}
+
+void timer_queue_set::insert(timer_queue_base* q)
+{
+  q->next_ = first_;
+  first_ = q;
+}
+
+void timer_queue_set::erase(timer_queue_base* q)
+{
+  if (first_)
+  {
+    if (q == first_)
+    {
+      first_ = q->next_;
+      q->next_ = 0;
+      return;
+    }
+
+    for (timer_queue_base* p = first_; p->next_; p = p->next_)
+    {
+      if (p->next_ == q)
+      {
+        p->next_ = q->next_;
+        q->next_ = 0;
+        return;
+      }
+    }
+  }
+}
+
+bool timer_queue_set::all_empty() const
+{
+  for (timer_queue_base* p = first_; p; p = p->next_)
+    if (!p->empty())
+      return false;
+  return true;
+}
+
+long timer_queue_set::wait_duration_msec(long max_duration) const
+{
+  long min_duration = max_duration;
+  for (timer_queue_base* p = first_; p; p = p->next_)
+    min_duration = p->wait_duration_msec(min_duration);
+  return min_duration;
+}
+
+long timer_queue_set::wait_duration_usec(long max_duration) const
+{
+  long min_duration = max_duration;
+  for (timer_queue_base* p = first_; p; p = p->next_)
+    min_duration = p->wait_duration_usec(min_duration);
+  return min_duration;
+}
+
+void timer_queue_set::get_ready_timers(op_queue<operation>& ops)
+{
+  for (timer_queue_base* p = first_; p; p = p->next_)
+    p->get_ready_timers(ops);
+}
+
+void timer_queue_set::get_all_timers(op_queue<operation>& ops)
+{
+  for (timer_queue_base* p = first_; p; p = p->next_)
+    p->get_all_timers(ops);
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_IMPL_TIMER_QUEUE_SET_IPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/impl/win_event.ipp b/link/modules/asio-standalone/asio/include/asio/detail/impl/win_event.ipp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/impl/win_event.ipp
@@ -0,0 +1,76 @@
+//
+// detail/win_event.ipp
+// ~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_IMPL_WIN_EVENT_IPP
+#define ASIO_DETAIL_IMPL_WIN_EVENT_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_WINDOWS)
+
+#include "asio/detail/throw_error.hpp"
+#include "asio/detail/win_event.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+win_event::win_event()
+  : state_(0)
+{
+#if defined(ASIO_WINDOWS_APP)
+  events_[0] = ::CreateEventExW(0, 0,
+      CREATE_EVENT_MANUAL_RESET, EVENT_ALL_ACCESS);
+#else // defined(ASIO_WINDOWS_APP)
+  events_[0] = ::CreateEventW(0, true, false, 0);
+#endif // defined(ASIO_WINDOWS_APP)
+  if (!events_[0])
+  {
+    DWORD last_error = ::GetLastError();
+    asio::error_code ec(last_error,
+        asio::error::get_system_category());
+    asio::detail::throw_error(ec, "event");
+  }
+
+#if defined(ASIO_WINDOWS_APP)
+  events_[1] = ::CreateEventExW(0, 0, 0, EVENT_ALL_ACCESS);
+#else // defined(ASIO_WINDOWS_APP)
+  events_[1] = ::CreateEventW(0, false, false, 0);
+#endif // defined(ASIO_WINDOWS_APP)
+  if (!events_[1])
+  {
+    DWORD last_error = ::GetLastError();
+    ::CloseHandle(events_[0]);
+    asio::error_code ec(last_error,
+        asio::error::get_system_category());
+    asio::detail::throw_error(ec, "event");
+  }
+}
+
+win_event::~win_event()
+{
+  ::CloseHandle(events_[0]);
+  ::CloseHandle(events_[1]);
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_WINDOWS)
+
+#endif // ASIO_DETAIL_IMPL_WIN_EVENT_IPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/impl/win_iocp_handle_service.ipp b/link/modules/asio-standalone/asio/include/asio/detail/impl/win_iocp_handle_service.ipp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/impl/win_iocp_handle_service.ipp
@@ -0,0 +1,525 @@
+//
+// detail/impl/win_iocp_handle_service.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.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 ASIO_DETAIL_IMPL_WIN_IOCP_HANDLE_SERVICE_IPP
+#define ASIO_DETAIL_IMPL_WIN_IOCP_HANDLE_SERVICE_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_IOCP)
+
+#include "asio/detail/win_iocp_handle_service.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class win_iocp_handle_service::overlapped_wrapper
+  : public OVERLAPPED
+{
+public:
+  explicit overlapped_wrapper(asio::error_code& ec)
+  {
+    Internal = 0;
+    InternalHigh = 0;
+    Offset = 0;
+    OffsetHigh = 0;
+
+    // Create a non-signalled manual-reset event, for GetOverlappedResult.
+    hEvent = ::CreateEventW(0, TRUE, FALSE, 0);
+    if (hEvent)
+    {
+      // As documented in GetQueuedCompletionStatus, setting the low order
+      // bit of this event prevents our synchronous writes from being treated
+      // as completion port events.
+      DWORD_PTR tmp = reinterpret_cast<DWORD_PTR>(hEvent);
+      hEvent = reinterpret_cast<HANDLE>(tmp | 1);
+    }
+    else
+    {
+      DWORD last_error = ::GetLastError();
+      ec = asio::error_code(last_error,
+          asio::error::get_system_category());
+    }
+  }
+
+  ~overlapped_wrapper()
+  {
+    if (hEvent)
+    {
+      ::CloseHandle(hEvent);
+    }
+  }
+};
+
+win_iocp_handle_service::win_iocp_handle_service(execution_context& context)
+  : execution_context_service_base<win_iocp_handle_service>(context),
+    iocp_service_(asio::use_service<win_iocp_io_context>(context)),
+    mutex_(),
+    impl_list_(0)
+{
+}
+
+void win_iocp_handle_service::shutdown()
+{
+  // Close all implementations, causing all operations to complete.
+  asio::detail::mutex::scoped_lock lock(mutex_);
+  implementation_type* impl = impl_list_;
+  while (impl)
+  {
+    close_for_destruction(*impl);
+    impl = impl->next_;
+  }
+}
+
+void win_iocp_handle_service::construct(
+    win_iocp_handle_service::implementation_type& impl)
+{
+  impl.handle_ = INVALID_HANDLE_VALUE;
+  impl.safe_cancellation_thread_id_ = 0;
+
+  // Insert implementation into linked list of all implementations.
+  asio::detail::mutex::scoped_lock lock(mutex_);
+  impl.next_ = impl_list_;
+  impl.prev_ = 0;
+  if (impl_list_)
+    impl_list_->prev_ = &impl;
+  impl_list_ = &impl;
+}
+
+void win_iocp_handle_service::move_construct(
+    win_iocp_handle_service::implementation_type& impl,
+    win_iocp_handle_service::implementation_type& other_impl)
+{
+  impl.handle_ = other_impl.handle_;
+  other_impl.handle_ = INVALID_HANDLE_VALUE;
+
+  impl.safe_cancellation_thread_id_ = other_impl.safe_cancellation_thread_id_;
+  other_impl.safe_cancellation_thread_id_ = 0;
+
+  // Insert implementation into linked list of all implementations.
+  asio::detail::mutex::scoped_lock lock(mutex_);
+  impl.next_ = impl_list_;
+  impl.prev_ = 0;
+  if (impl_list_)
+    impl_list_->prev_ = &impl;
+  impl_list_ = &impl;
+}
+
+void win_iocp_handle_service::move_assign(
+    win_iocp_handle_service::implementation_type& impl,
+    win_iocp_handle_service& other_service,
+    win_iocp_handle_service::implementation_type& other_impl)
+{
+  close_for_destruction(impl);
+
+  if (this != &other_service)
+  {
+    // Remove implementation from linked list of all implementations.
+    asio::detail::mutex::scoped_lock lock(mutex_);
+    if (impl_list_ == &impl)
+      impl_list_ = impl.next_;
+    if (impl.prev_)
+      impl.prev_->next_ = impl.next_;
+    if (impl.next_)
+      impl.next_->prev_= impl.prev_;
+    impl.next_ = 0;
+    impl.prev_ = 0;
+  }
+
+  impl.handle_ = other_impl.handle_;
+  other_impl.handle_ = INVALID_HANDLE_VALUE;
+
+  impl.safe_cancellation_thread_id_ = other_impl.safe_cancellation_thread_id_;
+  other_impl.safe_cancellation_thread_id_ = 0;
+
+  if (this != &other_service)
+  {
+    // Insert implementation into linked list of all implementations.
+    asio::detail::mutex::scoped_lock lock(other_service.mutex_);
+    impl.next_ = other_service.impl_list_;
+    impl.prev_ = 0;
+    if (other_service.impl_list_)
+      other_service.impl_list_->prev_ = &impl;
+    other_service.impl_list_ = &impl;
+  }
+}
+
+void win_iocp_handle_service::destroy(
+    win_iocp_handle_service::implementation_type& impl)
+{
+  close_for_destruction(impl);
+  
+  // Remove implementation from linked list of all implementations.
+  asio::detail::mutex::scoped_lock lock(mutex_);
+  if (impl_list_ == &impl)
+    impl_list_ = impl.next_;
+  if (impl.prev_)
+    impl.prev_->next_ = impl.next_;
+  if (impl.next_)
+    impl.next_->prev_= impl.prev_;
+  impl.next_ = 0;
+  impl.prev_ = 0;
+}
+
+asio::error_code win_iocp_handle_service::assign(
+    win_iocp_handle_service::implementation_type& impl,
+    const native_handle_type& handle, asio::error_code& ec)
+{
+  if (is_open(impl))
+  {
+    ec = asio::error::already_open;
+    return ec;
+  }
+
+  if (iocp_service_.register_handle(handle, ec))
+    return ec;
+
+  impl.handle_ = handle;
+  ec = asio::error_code();
+  return ec;
+}
+
+asio::error_code win_iocp_handle_service::close(
+    win_iocp_handle_service::implementation_type& impl,
+    asio::error_code& ec)
+{
+  if (is_open(impl))
+  {
+    ASIO_HANDLER_OPERATION((iocp_service_.context(), "handle",
+          &impl, reinterpret_cast<uintmax_t>(impl.handle_), "close"));
+
+    if (!::CloseHandle(impl.handle_))
+    {
+      DWORD last_error = ::GetLastError();
+      ec = asio::error_code(last_error,
+          asio::error::get_system_category());
+    }
+    else
+    {
+      ec = asio::error_code();
+    }
+
+    impl.handle_ = INVALID_HANDLE_VALUE;
+    impl.safe_cancellation_thread_id_ = 0;
+  }
+  else
+  {
+    ec = asio::error_code();
+  }
+
+  return ec;
+}
+
+asio::error_code win_iocp_handle_service::cancel(
+    win_iocp_handle_service::implementation_type& impl,
+    asio::error_code& ec)
+{
+  if (!is_open(impl))
+  {
+    ec = asio::error::bad_descriptor;
+    return ec;
+  }
+
+  ASIO_HANDLER_OPERATION((iocp_service_.context(), "handle",
+        &impl, reinterpret_cast<uintmax_t>(impl.handle_), "cancel"));
+
+  if (FARPROC cancel_io_ex_ptr = ::GetProcAddress(
+        ::GetModuleHandleA("KERNEL32"), "CancelIoEx"))
+  {
+    // The version of Windows supports cancellation from any thread.
+    typedef BOOL (WINAPI* cancel_io_ex_t)(HANDLE, LPOVERLAPPED);
+    cancel_io_ex_t cancel_io_ex = reinterpret_cast<cancel_io_ex_t>(
+        reinterpret_cast<void*>(cancel_io_ex_ptr));
+    if (!cancel_io_ex(impl.handle_, 0))
+    {
+      DWORD last_error = ::GetLastError();
+      if (last_error == ERROR_NOT_FOUND)
+      {
+        // ERROR_NOT_FOUND means that there were no operations to be
+        // cancelled. We swallow this error to match the behaviour on other
+        // platforms.
+        ec = asio::error_code();
+      }
+      else
+      {
+        ec = asio::error_code(last_error,
+            asio::error::get_system_category());
+      }
+    }
+    else
+    {
+      ec = asio::error_code();
+    }
+  }
+  else if (impl.safe_cancellation_thread_id_ == 0)
+  {
+    // No operations have been started, so there's nothing to cancel.
+    ec = asio::error_code();
+  }
+  else if (impl.safe_cancellation_thread_id_ == ::GetCurrentThreadId())
+  {
+    // Asynchronous operations have been started from the current thread only,
+    // so it is safe to try to cancel them using CancelIo.
+    if (!::CancelIo(impl.handle_))
+    {
+      DWORD last_error = ::GetLastError();
+      ec = asio::error_code(last_error,
+          asio::error::get_system_category());
+    }
+    else
+    {
+      ec = asio::error_code();
+    }
+  }
+  else
+  {
+    // Asynchronous operations have been started from more than one thread,
+    // so cancellation is not safe.
+    ec = asio::error::operation_not_supported;
+  }
+
+  return ec;
+}
+
+size_t win_iocp_handle_service::do_write(
+    win_iocp_handle_service::implementation_type& impl, uint64_t offset,
+    const asio::const_buffer& buffer, asio::error_code& ec)
+{
+  if (!is_open(impl))
+  {
+    ec = asio::error::bad_descriptor;
+    return 0;
+  }
+
+  // A request to write 0 bytes on a handle is a no-op.
+  if (buffer.size() == 0)
+  {
+    ec = asio::error_code();
+    return 0;
+  }
+
+  overlapped_wrapper overlapped(ec);
+  if (ec)
+  {
+    return 0;
+  }
+
+  // Write the data. 
+  overlapped.Offset = offset & 0xFFFFFFFF;
+  overlapped.OffsetHigh = (offset >> 32) & 0xFFFFFFFF;
+  BOOL ok = ::WriteFile(impl.handle_, buffer.data(),
+      static_cast<DWORD>(buffer.size()), 0, &overlapped);
+  if (!ok) 
+  {
+    DWORD last_error = ::GetLastError();
+    if (last_error != ERROR_IO_PENDING)
+    {
+      ec = asio::error_code(last_error,
+          asio::error::get_system_category());
+      return 0;
+    }
+  }
+
+  // Wait for the operation to complete.
+  DWORD bytes_transferred = 0;
+  ok = ::GetOverlappedResult(impl.handle_,
+      &overlapped, &bytes_transferred, TRUE);
+  if (!ok)
+  {
+    DWORD last_error = ::GetLastError();
+    ec = asio::error_code(last_error,
+        asio::error::get_system_category());
+    return 0;
+  }
+
+  ec = asio::error_code();
+  return bytes_transferred;
+}
+
+void win_iocp_handle_service::start_write_op(
+    win_iocp_handle_service::implementation_type& impl, uint64_t offset,
+    const asio::const_buffer& buffer, operation* op)
+{
+  update_cancellation_thread_id(impl);
+  iocp_service_.work_started();
+
+  if (!is_open(impl))
+  {
+    iocp_service_.on_completion(op, asio::error::bad_descriptor);
+  }
+  else if (buffer.size() == 0)
+  {
+    // A request to write 0 bytes on a handle is a no-op.
+    iocp_service_.on_completion(op);
+  }
+  else
+  {
+    DWORD bytes_transferred = 0;
+    op->Offset = offset & 0xFFFFFFFF;
+    op->OffsetHigh = (offset >> 32) & 0xFFFFFFFF;
+    BOOL ok = ::WriteFile(impl.handle_, buffer.data(),
+        static_cast<DWORD>(buffer.size()),
+        &bytes_transferred, op);
+    DWORD last_error = ::GetLastError();
+    if (!ok && last_error != ERROR_IO_PENDING
+        && last_error != ERROR_MORE_DATA)
+    {
+      iocp_service_.on_completion(op, last_error, bytes_transferred);
+    }
+    else
+    {
+      iocp_service_.on_pending(op);
+    }
+  }
+}
+
+size_t win_iocp_handle_service::do_read(
+    win_iocp_handle_service::implementation_type& impl, uint64_t offset,
+    const asio::mutable_buffer& buffer, asio::error_code& ec)
+{
+  if (!is_open(impl))
+  {
+    ec = asio::error::bad_descriptor;
+    return 0;
+  }
+  
+  // A request to read 0 bytes on a stream handle is a no-op.
+  if (buffer.size() == 0)
+  {
+    ec = asio::error_code();
+    return 0;
+  }
+
+  overlapped_wrapper overlapped(ec);
+  if (ec)
+  {
+    return 0;
+  }
+
+  // Read some data.
+  overlapped.Offset = offset & 0xFFFFFFFF;
+  overlapped.OffsetHigh = (offset >> 32) & 0xFFFFFFFF;
+  BOOL ok = ::ReadFile(impl.handle_, buffer.data(),
+      static_cast<DWORD>(buffer.size()), 0, &overlapped);
+  if (!ok) 
+  {
+    DWORD last_error = ::GetLastError();
+    if (last_error != ERROR_IO_PENDING && last_error != ERROR_MORE_DATA)
+    {
+      if (last_error == ERROR_HANDLE_EOF)
+      {
+        ec = asio::error::eof;
+      }
+      else
+      {
+        ec = asio::error_code(last_error,
+            asio::error::get_system_category());
+      }
+      return 0;
+    }
+  }
+
+  // Wait for the operation to complete.
+  DWORD bytes_transferred = 0;
+  ok = ::GetOverlappedResult(impl.handle_,
+      &overlapped, &bytes_transferred, TRUE);
+  if (!ok)
+  {
+    DWORD last_error = ::GetLastError();
+    if (last_error == ERROR_HANDLE_EOF)
+    {
+      ec = asio::error::eof;
+    }
+    else
+    {
+      ec = asio::error_code(last_error,
+          asio::error::get_system_category());
+    }
+    return (last_error == ERROR_MORE_DATA) ? bytes_transferred : 0;
+  }
+
+  ec = asio::error_code();
+  return bytes_transferred;
+}
+
+void win_iocp_handle_service::start_read_op(
+    win_iocp_handle_service::implementation_type& impl, uint64_t offset,
+    const asio::mutable_buffer& buffer, operation* op)
+{
+  update_cancellation_thread_id(impl);
+  iocp_service_.work_started();
+
+  if (!is_open(impl))
+  {
+    iocp_service_.on_completion(op, asio::error::bad_descriptor);
+  }
+  else if (buffer.size() == 0)
+  {
+    // A request to read 0 bytes on a handle is a no-op.
+    iocp_service_.on_completion(op);
+  }
+  else
+  {
+    DWORD bytes_transferred = 0;
+    op->Offset = offset & 0xFFFFFFFF;
+    op->OffsetHigh = (offset >> 32) & 0xFFFFFFFF;
+    BOOL ok = ::ReadFile(impl.handle_, buffer.data(),
+        static_cast<DWORD>(buffer.size()),
+        &bytes_transferred, op);
+    DWORD last_error = ::GetLastError();
+    if (!ok && last_error != ERROR_IO_PENDING
+        && last_error != ERROR_MORE_DATA)
+    {
+      iocp_service_.on_completion(op, last_error, bytes_transferred);
+    }
+    else
+    {
+      iocp_service_.on_pending(op);
+    }
+  }
+}
+
+void win_iocp_handle_service::update_cancellation_thread_id(
+    win_iocp_handle_service::implementation_type& impl)
+{
+  if (impl.safe_cancellation_thread_id_ == 0)
+    impl.safe_cancellation_thread_id_ = ::GetCurrentThreadId();
+  else if (impl.safe_cancellation_thread_id_ != ::GetCurrentThreadId())
+    impl.safe_cancellation_thread_id_ = ~DWORD(0);
+}
+
+void win_iocp_handle_service::close_for_destruction(implementation_type& impl)
+{
+  if (is_open(impl))
+  {
+    ASIO_HANDLER_OPERATION((iocp_service_.context(), "handle",
+          &impl, reinterpret_cast<uintmax_t>(impl.handle_), "close"));
+
+    ::CloseHandle(impl.handle_);
+    impl.handle_ = INVALID_HANDLE_VALUE;
+    impl.safe_cancellation_thread_id_ = 0;
+  }
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_IOCP)
+
+#endif // ASIO_DETAIL_IMPL_WIN_IOCP_HANDLE_SERVICE_IPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/impl/win_iocp_io_context.hpp b/link/modules/asio-standalone/asio/include/asio/detail/impl/win_iocp_io_context.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/impl/win_iocp_io_context.hpp
@@ -0,0 +1,103 @@
+//
+// detail/impl/win_iocp_io_context.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_IMPL_WIN_IOCP_IO_CONTEXT_HPP
+#define ASIO_DETAIL_IMPL_WIN_IOCP_IO_CONTEXT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_IOCP)
+
+#include "asio/detail/completion_handler.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/memory.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Time_Traits>
+void win_iocp_io_context::add_timer_queue(
+    timer_queue<Time_Traits>& queue)
+{
+  do_add_timer_queue(queue);
+}
+
+template <typename Time_Traits>
+void win_iocp_io_context::remove_timer_queue(
+    timer_queue<Time_Traits>& queue)
+{
+  do_remove_timer_queue(queue);
+}
+
+template <typename Time_Traits>
+void win_iocp_io_context::schedule_timer(timer_queue<Time_Traits>& queue,
+    const typename Time_Traits::time_type& time,
+    typename timer_queue<Time_Traits>::per_timer_data& timer, wait_op* op)
+{
+  // If the service has been shut down we silently discard the timer.
+  if (::InterlockedExchangeAdd(&shutdown_, 0) != 0)
+  {
+    post_immediate_completion(op, false);
+    return;
+  }
+
+  mutex::scoped_lock lock(dispatch_mutex_);
+
+  bool earliest = queue.enqueue_timer(time, timer, op);
+  work_started();
+  if (earliest)
+    update_timeout();
+}
+
+template <typename Time_Traits>
+std::size_t win_iocp_io_context::cancel_timer(timer_queue<Time_Traits>& queue,
+    typename timer_queue<Time_Traits>::per_timer_data& timer,
+    std::size_t max_cancelled)
+{
+  // If the service has been shut down we silently ignore the cancellation.
+  if (::InterlockedExchangeAdd(&shutdown_, 0) != 0)
+    return 0;
+
+  mutex::scoped_lock lock(dispatch_mutex_);
+  op_queue<win_iocp_operation> ops;
+  std::size_t n = queue.cancel_timer(timer, ops, max_cancelled);
+  post_deferred_completions(ops);
+  return n;
+}
+
+template <typename Time_Traits>
+void win_iocp_io_context::move_timer(timer_queue<Time_Traits>& queue,
+    typename timer_queue<Time_Traits>::per_timer_data& to,
+    typename timer_queue<Time_Traits>::per_timer_data& from)
+{
+  asio::detail::mutex::scoped_lock lock(dispatch_mutex_);
+  op_queue<operation> ops;
+  queue.cancel_timer(to, ops);
+  queue.move_timer(to, from);
+  lock.unlock();
+  post_deferred_completions(ops);
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_IOCP)
+
+#endif // ASIO_DETAIL_IMPL_WIN_IOCP_IO_CONTEXT_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/impl/win_iocp_io_context.ipp b/link/modules/asio-standalone/asio/include/asio/detail/impl/win_iocp_io_context.ipp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/impl/win_iocp_io_context.ipp
@@ -0,0 +1,603 @@
+//
+// detail/impl/win_iocp_io_context.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_IMPL_WIN_IOCP_IO_CONTEXT_IPP
+#define ASIO_DETAIL_IMPL_WIN_IOCP_IO_CONTEXT_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_IOCP)
+
+#include "asio/error.hpp"
+#include "asio/detail/cstdint.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/limits.hpp"
+#include "asio/detail/thread.hpp"
+#include "asio/detail/throw_error.hpp"
+#include "asio/detail/win_iocp_io_context.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+struct win_iocp_io_context::thread_function
+{
+  explicit thread_function(win_iocp_io_context* s)
+    : this_(s)
+  {
+  }
+
+  void operator()()
+  {
+    asio::error_code ec;
+    this_->run(ec);
+  }
+
+  win_iocp_io_context* this_;
+};
+
+struct win_iocp_io_context::work_finished_on_block_exit
+{
+  ~work_finished_on_block_exit()
+  {
+    io_context_->work_finished();
+  }
+
+  win_iocp_io_context* io_context_;
+};
+
+struct win_iocp_io_context::timer_thread_function
+{
+  void operator()()
+  {
+    while (::InterlockedExchangeAdd(&io_context_->shutdown_, 0) == 0)
+    {
+      if (::WaitForSingleObject(io_context_->waitable_timer_.handle,
+            INFINITE) == WAIT_OBJECT_0)
+      {
+        ::InterlockedExchange(&io_context_->dispatch_required_, 1);
+        ::PostQueuedCompletionStatus(io_context_->iocp_.handle,
+            0, wake_for_dispatch, 0);
+      }
+    }
+  }
+
+  win_iocp_io_context* io_context_;
+};
+
+win_iocp_io_context::win_iocp_io_context(
+    asio::execution_context& ctx, int concurrency_hint, bool own_thread)
+  : execution_context_service_base<win_iocp_io_context>(ctx),
+    iocp_(),
+    outstanding_work_(0),
+    stopped_(0),
+    stop_event_posted_(0),
+    shutdown_(0),
+    gqcs_timeout_(get_gqcs_timeout()),
+    dispatch_required_(0),
+    concurrency_hint_(concurrency_hint)
+{
+  ASIO_HANDLER_TRACKING_INIT;
+
+  iocp_.handle = ::CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0,
+      static_cast<DWORD>(concurrency_hint >= 0 ? concurrency_hint : DWORD(~0)));
+  if (!iocp_.handle)
+  {
+    DWORD last_error = ::GetLastError();
+    asio::error_code ec(last_error,
+        asio::error::get_system_category());
+    asio::detail::throw_error(ec, "iocp");
+  }
+
+  if (own_thread)
+  {
+    ::InterlockedIncrement(&outstanding_work_);
+    thread_.reset(new asio::detail::thread(thread_function(this)));
+  }
+}
+
+win_iocp_io_context::~win_iocp_io_context()
+{
+  if (thread_.get())
+  {
+    stop();
+    thread_->join();
+    thread_.reset();
+  }
+}
+
+void win_iocp_io_context::shutdown()
+{
+  ::InterlockedExchange(&shutdown_, 1);
+
+  if (timer_thread_.get())
+  {
+    LARGE_INTEGER timeout;
+    timeout.QuadPart = 1;
+    ::SetWaitableTimer(waitable_timer_.handle, &timeout, 1, 0, 0, FALSE);
+  }
+
+  if (thread_.get())
+  {
+    stop();
+    thread_->join();
+    thread_.reset();
+    ::InterlockedDecrement(&outstanding_work_);
+  }
+
+  while (::InterlockedExchangeAdd(&outstanding_work_, 0) > 0)
+  {
+    op_queue<win_iocp_operation> ops;
+    timer_queues_.get_all_timers(ops);
+    ops.push(completed_ops_);
+    if (!ops.empty())
+    {
+      while (win_iocp_operation* op = ops.front())
+      {
+        ops.pop();
+        ::InterlockedDecrement(&outstanding_work_);
+        op->destroy();
+      }
+    }
+    else
+    {
+      DWORD bytes_transferred = 0;
+      dword_ptr_t completion_key = 0;
+      LPOVERLAPPED overlapped = 0;
+      ::GetQueuedCompletionStatus(iocp_.handle, &bytes_transferred,
+          &completion_key, &overlapped, gqcs_timeout_);
+      if (overlapped)
+      {
+        ::InterlockedDecrement(&outstanding_work_);
+        static_cast<win_iocp_operation*>(overlapped)->destroy();
+      }
+    }
+  }
+
+  if (timer_thread_.get())
+    timer_thread_->join();
+}
+
+asio::error_code win_iocp_io_context::register_handle(
+    HANDLE handle, asio::error_code& ec)
+{
+  if (::CreateIoCompletionPort(handle, iocp_.handle, 0, 0) == 0)
+  {
+    DWORD last_error = ::GetLastError();
+    ec = asio::error_code(last_error,
+        asio::error::get_system_category());
+  }
+  else
+  {
+    ec = asio::error_code();
+  }
+  return ec;
+}
+
+size_t win_iocp_io_context::run(asio::error_code& ec)
+{
+  if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0)
+  {
+    stop();
+    ec = asio::error_code();
+    return 0;
+  }
+
+  win_iocp_thread_info this_thread;
+  thread_call_stack::context ctx(this, this_thread);
+
+  size_t n = 0;
+  while (do_one(INFINITE, this_thread, ec))
+    if (n != (std::numeric_limits<size_t>::max)())
+      ++n;
+  return n;
+}
+
+size_t win_iocp_io_context::run_one(asio::error_code& ec)
+{
+  if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0)
+  {
+    stop();
+    ec = asio::error_code();
+    return 0;
+  }
+
+  win_iocp_thread_info this_thread;
+  thread_call_stack::context ctx(this, this_thread);
+
+  return do_one(INFINITE, this_thread, ec);
+}
+
+size_t win_iocp_io_context::wait_one(long usec, asio::error_code& ec)
+{
+  if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0)
+  {
+    stop();
+    ec = asio::error_code();
+    return 0;
+  }
+
+  win_iocp_thread_info this_thread;
+  thread_call_stack::context ctx(this, this_thread);
+
+  return do_one(usec < 0 ? INFINITE : ((usec - 1) / 1000 + 1), this_thread, ec);
+}
+
+size_t win_iocp_io_context::poll(asio::error_code& ec)
+{
+  if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0)
+  {
+    stop();
+    ec = asio::error_code();
+    return 0;
+  }
+
+  win_iocp_thread_info this_thread;
+  thread_call_stack::context ctx(this, this_thread);
+
+  size_t n = 0;
+  while (do_one(0, this_thread, ec))
+    if (n != (std::numeric_limits<size_t>::max)())
+      ++n;
+  return n;
+}
+
+size_t win_iocp_io_context::poll_one(asio::error_code& ec)
+{
+  if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0)
+  {
+    stop();
+    ec = asio::error_code();
+    return 0;
+  }
+
+  win_iocp_thread_info this_thread;
+  thread_call_stack::context ctx(this, this_thread);
+
+  return do_one(0, this_thread, ec);
+}
+
+void win_iocp_io_context::stop()
+{
+  if (::InterlockedExchange(&stopped_, 1) == 0)
+  {
+    if (::InterlockedExchange(&stop_event_posted_, 1) == 0)
+    {
+      if (!::PostQueuedCompletionStatus(iocp_.handle, 0, 0, 0))
+      {
+        DWORD last_error = ::GetLastError();
+        asio::error_code ec(last_error,
+            asio::error::get_system_category());
+        asio::detail::throw_error(ec, "pqcs");
+      }
+    }
+  }
+}
+
+void win_iocp_io_context::capture_current_exception()
+{
+  if (thread_info_base* this_thread = thread_call_stack::contains(this))
+    this_thread->capture_current_exception();
+}
+
+void win_iocp_io_context::post_deferred_completion(win_iocp_operation* op)
+{
+  // Flag the operation as ready.
+  op->ready_ = 1;
+
+  // Enqueue the operation on the I/O completion port.
+  if (!::PostQueuedCompletionStatus(iocp_.handle, 0, 0, op))
+  {
+    // Out of resources. Put on completed queue instead.
+    mutex::scoped_lock lock(dispatch_mutex_);
+    completed_ops_.push(op);
+    ::InterlockedExchange(&dispatch_required_, 1);
+  }
+}
+
+void win_iocp_io_context::post_deferred_completions(
+    op_queue<win_iocp_operation>& ops)
+{
+  while (win_iocp_operation* op = ops.front())
+  {
+    ops.pop();
+
+    // Flag the operation as ready.
+    op->ready_ = 1;
+
+    // Enqueue the operation on the I/O completion port.
+    if (!::PostQueuedCompletionStatus(iocp_.handle, 0, 0, op))
+    {
+      // Out of resources. Put on completed queue instead.
+      mutex::scoped_lock lock(dispatch_mutex_);
+      completed_ops_.push(op);
+      completed_ops_.push(ops);
+      ::InterlockedExchange(&dispatch_required_, 1);
+    }
+  }
+}
+
+void win_iocp_io_context::abandon_operations(
+    op_queue<win_iocp_operation>& ops)
+{
+  while (win_iocp_operation* op = ops.front())
+  {
+    ops.pop();
+    ::InterlockedDecrement(&outstanding_work_);
+    op->destroy();
+  }
+}
+
+void win_iocp_io_context::on_pending(win_iocp_operation* op)
+{
+  if (::InterlockedCompareExchange(&op->ready_, 1, 0) == 1)
+  {
+    // Enqueue the operation on the I/O completion port.
+    if (!::PostQueuedCompletionStatus(iocp_.handle,
+          0, overlapped_contains_result, op))
+    {
+      // Out of resources. Put on completed queue instead.
+      mutex::scoped_lock lock(dispatch_mutex_);
+      completed_ops_.push(op);
+      ::InterlockedExchange(&dispatch_required_, 1);
+    }
+  }
+}
+
+void win_iocp_io_context::on_completion(win_iocp_operation* op,
+    DWORD last_error, DWORD bytes_transferred)
+{
+  // Flag that the operation is ready for invocation.
+  op->ready_ = 1;
+
+  // Store results in the OVERLAPPED structure.
+  op->Internal = reinterpret_cast<ulong_ptr_t>(
+      &asio::error::get_system_category());
+  op->Offset = last_error;
+  op->OffsetHigh = bytes_transferred;
+
+  // Enqueue the operation on the I/O completion port.
+  if (!::PostQueuedCompletionStatus(iocp_.handle,
+        0, overlapped_contains_result, op))
+  {
+    // Out of resources. Put on completed queue instead.
+    mutex::scoped_lock lock(dispatch_mutex_);
+    completed_ops_.push(op);
+    ::InterlockedExchange(&dispatch_required_, 1);
+  }
+}
+
+void win_iocp_io_context::on_completion(win_iocp_operation* op,
+    const asio::error_code& ec, DWORD bytes_transferred)
+{
+  // Flag that the operation is ready for invocation.
+  op->ready_ = 1;
+
+  // Store results in the OVERLAPPED structure.
+  op->Internal = reinterpret_cast<ulong_ptr_t>(&ec.category());
+  op->Offset = ec.value();
+  op->OffsetHigh = bytes_transferred;
+
+  // Enqueue the operation on the I/O completion port.
+  if (!::PostQueuedCompletionStatus(iocp_.handle,
+        0, overlapped_contains_result, op))
+  {
+    // Out of resources. Put on completed queue instead.
+    mutex::scoped_lock lock(dispatch_mutex_);
+    completed_ops_.push(op);
+    ::InterlockedExchange(&dispatch_required_, 1);
+  }
+}
+
+size_t win_iocp_io_context::do_one(DWORD msec,
+    win_iocp_thread_info& this_thread, asio::error_code& ec)
+{
+  for (;;)
+  {
+    // Try to acquire responsibility for dispatching timers and completed ops.
+    if (::InterlockedCompareExchange(&dispatch_required_, 0, 1) == 1)
+    {
+      mutex::scoped_lock lock(dispatch_mutex_);
+
+      // Dispatch pending timers and operations.
+      op_queue<win_iocp_operation> ops;
+      ops.push(completed_ops_);
+      timer_queues_.get_ready_timers(ops);
+      post_deferred_completions(ops);
+      update_timeout();
+    }
+
+    // Get the next operation from the queue.
+    DWORD bytes_transferred = 0;
+    dword_ptr_t completion_key = 0;
+    LPOVERLAPPED overlapped = 0;
+    ::SetLastError(0);
+    BOOL ok = ::GetQueuedCompletionStatus(iocp_.handle,
+        &bytes_transferred, &completion_key, &overlapped,
+        msec < gqcs_timeout_ ? msec : gqcs_timeout_);
+    DWORD last_error = ::GetLastError();
+
+    if (overlapped)
+    {
+      win_iocp_operation* op = static_cast<win_iocp_operation*>(overlapped);
+      asio::error_code result_ec(last_error,
+          asio::error::get_system_category());
+
+      // We may have been passed the last_error and bytes_transferred in the
+      // OVERLAPPED structure itself.
+      if (completion_key == overlapped_contains_result)
+      {
+        result_ec = asio::error_code(static_cast<int>(op->Offset),
+            *reinterpret_cast<asio::error_category*>(op->Internal));
+        bytes_transferred = op->OffsetHigh;
+      }
+
+      // Otherwise ensure any result has been saved into the OVERLAPPED
+      // structure.
+      else
+      {
+        op->Internal = reinterpret_cast<ulong_ptr_t>(&result_ec.category());
+        op->Offset = result_ec.value();
+        op->OffsetHigh = bytes_transferred;
+      }
+
+      // Dispatch the operation only if ready. The operation may not be ready
+      // if the initiating function (e.g. a call to WSARecv) has not yet
+      // returned. This is because the initiating function still wants access
+      // to the operation's OVERLAPPED structure.
+      if (::InterlockedCompareExchange(&op->ready_, 1, 0) == 1)
+      {
+        // Ensure the count of outstanding work is decremented on block exit.
+        work_finished_on_block_exit on_exit = { this };
+        (void)on_exit;
+
+        op->complete(this, result_ec, bytes_transferred);
+        this_thread.rethrow_pending_exception();
+        ec = asio::error_code();
+        return 1;
+      }
+    }
+    else if (!ok)
+    {
+      if (last_error != WAIT_TIMEOUT)
+      {
+        ec = asio::error_code(last_error,
+            asio::error::get_system_category());
+        return 0;
+      }
+
+      // If we're waiting indefinitely we need to keep going until we get a
+      // real handler.
+      if (msec == INFINITE)
+        continue;
+
+      ec = asio::error_code();
+      return 0;
+    }
+    else if (completion_key == wake_for_dispatch)
+    {
+      // We have been woken up to try to acquire responsibility for dispatching
+      // timers and completed operations.
+    }
+    else
+    {
+      // Indicate that there is no longer an in-flight stop event.
+      ::InterlockedExchange(&stop_event_posted_, 0);
+
+      // The stopped_ flag is always checked to ensure that any leftover
+      // stop events from a previous run invocation are ignored.
+      if (::InterlockedExchangeAdd(&stopped_, 0) != 0)
+      {
+        // Wake up next thread that is blocked on GetQueuedCompletionStatus.
+        if (::InterlockedExchange(&stop_event_posted_, 1) == 0)
+        {
+          if (!::PostQueuedCompletionStatus(iocp_.handle, 0, 0, 0))
+          {
+            last_error = ::GetLastError();
+            ec = asio::error_code(last_error,
+                asio::error::get_system_category());
+            return 0;
+          }
+        }
+
+        ec = asio::error_code();
+        return 0;
+      }
+    }
+  }
+}
+
+DWORD win_iocp_io_context::get_gqcs_timeout()
+{
+  OSVERSIONINFOEX osvi;
+  ZeroMemory(&osvi, sizeof(osvi));
+  osvi.dwOSVersionInfoSize = sizeof(osvi);
+  osvi.dwMajorVersion = 6ul;
+
+  const uint64_t condition_mask = ::VerSetConditionMask(
+      0, VER_MAJORVERSION, VER_GREATER_EQUAL);
+
+  if (!!::VerifyVersionInfo(&osvi, VER_MAJORVERSION, condition_mask))
+    return INFINITE;
+
+  return default_gqcs_timeout;
+}
+
+void win_iocp_io_context::do_add_timer_queue(timer_queue_base& queue)
+{
+  mutex::scoped_lock lock(dispatch_mutex_);
+
+  timer_queues_.insert(&queue);
+
+  if (!waitable_timer_.handle)
+  {
+    waitable_timer_.handle = ::CreateWaitableTimer(0, FALSE, 0);
+    if (waitable_timer_.handle == 0)
+    {
+      DWORD last_error = ::GetLastError();
+      asio::error_code ec(last_error,
+          asio::error::get_system_category());
+      asio::detail::throw_error(ec, "timer");
+    }
+
+    LARGE_INTEGER timeout;
+    timeout.QuadPart = -max_timeout_usec;
+    timeout.QuadPart *= 10;
+    ::SetWaitableTimer(waitable_timer_.handle,
+        &timeout, max_timeout_msec, 0, 0, FALSE);
+  }
+
+  if (!timer_thread_.get())
+  {
+    timer_thread_function thread_function = { this };
+    timer_thread_.reset(new thread(thread_function, 65536));
+  }
+}
+
+void win_iocp_io_context::do_remove_timer_queue(timer_queue_base& queue)
+{
+  mutex::scoped_lock lock(dispatch_mutex_);
+
+  timer_queues_.erase(&queue);
+}
+
+void win_iocp_io_context::update_timeout()
+{
+  if (timer_thread_.get())
+  {
+    // There's no point updating the waitable timer if the new timeout period
+    // exceeds the maximum timeout. In that case, we might as well wait for the
+    // existing period of the timer to expire.
+    long timeout_usec = timer_queues_.wait_duration_usec(max_timeout_usec);
+    if (timeout_usec < max_timeout_usec)
+    {
+      LARGE_INTEGER timeout;
+      timeout.QuadPart = -timeout_usec;
+      timeout.QuadPart *= 10;
+      ::SetWaitableTimer(waitable_timer_.handle,
+          &timeout, max_timeout_msec, 0, 0, FALSE);
+    }
+  }
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_IOCP)
+
+#endif // ASIO_DETAIL_IMPL_WIN_IOCP_IO_CONTEXT_IPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/impl/win_iocp_serial_port_service.ipp b/link/modules/asio-standalone/asio/include/asio/detail/impl/win_iocp_serial_port_service.ipp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/impl/win_iocp_serial_port_service.ipp
@@ -0,0 +1,192 @@
+//
+// detail/impl/win_iocp_serial_port_service.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.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 ASIO_DETAIL_IMPL_WIN_IOCP_SERIAL_PORT_SERVICE_IPP
+#define ASIO_DETAIL_IMPL_WIN_IOCP_SERIAL_PORT_SERVICE_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_IOCP) && defined(ASIO_HAS_SERIAL_PORT)
+
+#include <cstring>
+#include "asio/detail/win_iocp_serial_port_service.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+win_iocp_serial_port_service::win_iocp_serial_port_service(
+    execution_context& context)
+  : execution_context_service_base<win_iocp_serial_port_service>(context),
+    handle_service_(context)
+{
+}
+
+void win_iocp_serial_port_service::shutdown()
+{
+}
+
+asio::error_code win_iocp_serial_port_service::open(
+    win_iocp_serial_port_service::implementation_type& impl,
+    const std::string& device, asio::error_code& ec)
+{
+  if (is_open(impl))
+  {
+    ec = asio::error::already_open;
+    return ec;
+  }
+
+  // For convenience, add a leading \\.\ sequence if not already present.
+  std::string name = (device[0] == '\\') ? device : "\\\\.\\" + device;
+
+  // Open a handle to the serial port.
+  ::HANDLE handle = ::CreateFileA(name.c_str(),
+      GENERIC_READ | GENERIC_WRITE, 0, 0,
+      OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
+  if (handle == INVALID_HANDLE_VALUE)
+  {
+    DWORD last_error = ::GetLastError();
+    ec = asio::error_code(last_error,
+        asio::error::get_system_category());
+    return ec;
+  }
+
+  // Determine the initial serial port parameters.
+  using namespace std; // For memset.
+  ::DCB dcb;
+  memset(&dcb, 0, sizeof(DCB));
+  dcb.DCBlength = sizeof(DCB);
+  if (!::GetCommState(handle, &dcb))
+  {
+    DWORD last_error = ::GetLastError();
+    ::CloseHandle(handle);
+    ec = asio::error_code(last_error,
+        asio::error::get_system_category());
+    return ec;
+  }
+
+  // Set some default serial port parameters. This implementation does not
+  // support changing all of these, so they might as well be in a known state.
+  dcb.fBinary = TRUE; // Win32 only supports binary mode.
+  dcb.fNull = FALSE; // Do not ignore NULL characters.
+  dcb.fAbortOnError = FALSE; // Ignore serial framing errors.
+  dcb.BaudRate = CBR_9600; // 9600 baud by default
+  dcb.ByteSize = 8; // 8 bit bytes
+  dcb.fOutxCtsFlow = FALSE; // No flow control
+  dcb.fOutxDsrFlow = FALSE;
+  dcb.fDtrControl = DTR_CONTROL_DISABLE;
+  dcb.fDsrSensitivity = FALSE;
+  dcb.fOutX = FALSE;
+  dcb.fInX = FALSE;
+  dcb.fRtsControl = RTS_CONTROL_DISABLE;
+  dcb.fParity = FALSE; // No parity
+  dcb.Parity = NOPARITY;
+  dcb.StopBits = ONESTOPBIT; // One stop bit
+  if (!::SetCommState(handle, &dcb))
+  {
+    DWORD last_error = ::GetLastError();
+    ::CloseHandle(handle);
+    ec = asio::error_code(last_error,
+        asio::error::get_system_category());
+    return ec;
+  }
+
+  // Set up timeouts so that the serial port will behave similarly to a
+  // network socket. Reads wait for at least one byte, then return with
+  // whatever they have. Writes return once everything is out the door.
+  ::COMMTIMEOUTS timeouts;
+  timeouts.ReadIntervalTimeout = 1;
+  timeouts.ReadTotalTimeoutMultiplier = 0;
+  timeouts.ReadTotalTimeoutConstant = 0;
+  timeouts.WriteTotalTimeoutMultiplier = 0;
+  timeouts.WriteTotalTimeoutConstant = 0;
+  if (!::SetCommTimeouts(handle, &timeouts))
+  {
+    DWORD last_error = ::GetLastError();
+    ::CloseHandle(handle);
+    ec = asio::error_code(last_error,
+        asio::error::get_system_category());
+    return ec;
+  }
+
+  // We're done. Take ownership of the serial port handle.
+  if (handle_service_.assign(impl, handle, ec))
+    ::CloseHandle(handle);
+  return ec;
+}
+
+asio::error_code win_iocp_serial_port_service::do_set_option(
+    win_iocp_serial_port_service::implementation_type& impl,
+    win_iocp_serial_port_service::store_function_type store,
+    const void* option, asio::error_code& ec)
+{
+  using namespace std; // For memcpy.
+
+  ::DCB dcb;
+  memset(&dcb, 0, sizeof(DCB));
+  dcb.DCBlength = sizeof(DCB);
+  if (!::GetCommState(handle_service_.native_handle(impl), &dcb))
+  {
+    DWORD last_error = ::GetLastError();
+    ec = asio::error_code(last_error,
+        asio::error::get_system_category());
+    return ec;
+  }
+
+  if (store(option, dcb, ec))
+    return ec;
+
+  if (!::SetCommState(handle_service_.native_handle(impl), &dcb))
+  {
+    DWORD last_error = ::GetLastError();
+    ec = asio::error_code(last_error,
+        asio::error::get_system_category());
+    return ec;
+  }
+
+  ec = asio::error_code();
+  return ec;
+}
+
+asio::error_code win_iocp_serial_port_service::do_get_option(
+    const win_iocp_serial_port_service::implementation_type& impl,
+    win_iocp_serial_port_service::load_function_type load,
+    void* option, asio::error_code& ec) const
+{
+  using namespace std; // For memset.
+
+  ::DCB dcb;
+  memset(&dcb, 0, sizeof(DCB));
+  dcb.DCBlength = sizeof(DCB);
+  if (!::GetCommState(handle_service_.native_handle(impl), &dcb))
+  {
+    DWORD last_error = ::GetLastError();
+    ec = asio::error_code(last_error,
+        asio::error::get_system_category());
+    return ec;
+  }
+
+  return load(option, dcb, ec);
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_IOCP) && defined(ASIO_HAS_SERIAL_PORT)
+
+#endif // ASIO_DETAIL_IMPL_WIN_IOCP_SERIAL_PORT_SERVICE_IPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/impl/win_iocp_socket_service_base.ipp b/link/modules/asio-standalone/asio/include/asio/detail/impl/win_iocp_socket_service_base.ipp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/impl/win_iocp_socket_service_base.ipp
@@ -0,0 +1,801 @@
+//
+// detail/impl/win_iocp_socket_service_base.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_IMPL_WIN_IOCP_SOCKET_SERVICE_BASE_IPP
+#define ASIO_DETAIL_IMPL_WIN_IOCP_SOCKET_SERVICE_BASE_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_IOCP)
+
+#include "asio/detail/win_iocp_socket_service_base.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+win_iocp_socket_service_base::win_iocp_socket_service_base(
+    execution_context& context)
+  : context_(context),
+    iocp_service_(use_service<win_iocp_io_context>(context)),
+    reactor_(0),
+    connect_ex_(0),
+    nt_set_info_(0),
+    mutex_(),
+    impl_list_(0)
+{
+}
+
+void win_iocp_socket_service_base::base_shutdown()
+{
+  // Close all implementations, causing all operations to complete.
+  asio::detail::mutex::scoped_lock lock(mutex_);
+  base_implementation_type* impl = impl_list_;
+  while (impl)
+  {
+    close_for_destruction(*impl);
+    impl = impl->next_;
+  }
+}
+
+void win_iocp_socket_service_base::construct(
+    win_iocp_socket_service_base::base_implementation_type& impl)
+{
+  impl.socket_ = invalid_socket;
+  impl.state_ = 0;
+  impl.cancel_token_.reset();
+#if defined(ASIO_ENABLE_CANCELIO)
+  impl.safe_cancellation_thread_id_ = 0;
+#endif // defined(ASIO_ENABLE_CANCELIO)
+
+  // Insert implementation into linked list of all implementations.
+  asio::detail::mutex::scoped_lock lock(mutex_);
+  impl.next_ = impl_list_;
+  impl.prev_ = 0;
+  if (impl_list_)
+    impl_list_->prev_ = &impl;
+  impl_list_ = &impl;
+}
+
+void win_iocp_socket_service_base::base_move_construct(
+    win_iocp_socket_service_base::base_implementation_type& impl,
+    win_iocp_socket_service_base::base_implementation_type& other_impl)
+  ASIO_NOEXCEPT
+{
+  impl.socket_ = other_impl.socket_;
+  other_impl.socket_ = invalid_socket;
+
+  impl.state_ = other_impl.state_;
+  other_impl.state_ = 0;
+
+  impl.cancel_token_ = other_impl.cancel_token_;
+  other_impl.cancel_token_.reset();
+
+#if defined(ASIO_ENABLE_CANCELIO)
+  impl.safe_cancellation_thread_id_ = other_impl.safe_cancellation_thread_id_;
+  other_impl.safe_cancellation_thread_id_ = 0;
+#endif // defined(ASIO_ENABLE_CANCELIO)
+
+  // Insert implementation into linked list of all implementations.
+  asio::detail::mutex::scoped_lock lock(mutex_);
+  impl.next_ = impl_list_;
+  impl.prev_ = 0;
+  if (impl_list_)
+    impl_list_->prev_ = &impl;
+  impl_list_ = &impl;
+}
+
+void win_iocp_socket_service_base::base_move_assign(
+    win_iocp_socket_service_base::base_implementation_type& impl,
+    win_iocp_socket_service_base& other_service,
+    win_iocp_socket_service_base::base_implementation_type& other_impl)
+{
+  close_for_destruction(impl);
+
+  if (this != &other_service)
+  {
+    // Remove implementation from linked list of all implementations.
+    asio::detail::mutex::scoped_lock lock(mutex_);
+    if (impl_list_ == &impl)
+      impl_list_ = impl.next_;
+    if (impl.prev_)
+      impl.prev_->next_ = impl.next_;
+    if (impl.next_)
+      impl.next_->prev_= impl.prev_;
+    impl.next_ = 0;
+    impl.prev_ = 0;
+  }
+
+  impl.socket_ = other_impl.socket_;
+  other_impl.socket_ = invalid_socket;
+
+  impl.state_ = other_impl.state_;
+  other_impl.state_ = 0;
+
+  impl.cancel_token_ = other_impl.cancel_token_;
+  other_impl.cancel_token_.reset();
+
+#if defined(ASIO_ENABLE_CANCELIO)
+  impl.safe_cancellation_thread_id_ = other_impl.safe_cancellation_thread_id_;
+  other_impl.safe_cancellation_thread_id_ = 0;
+#endif // defined(ASIO_ENABLE_CANCELIO)
+
+  if (this != &other_service)
+  {
+    // Insert implementation into linked list of all implementations.
+    asio::detail::mutex::scoped_lock lock(other_service.mutex_);
+    impl.next_ = other_service.impl_list_;
+    impl.prev_ = 0;
+    if (other_service.impl_list_)
+      other_service.impl_list_->prev_ = &impl;
+    other_service.impl_list_ = &impl;
+  }
+}
+
+void win_iocp_socket_service_base::destroy(
+    win_iocp_socket_service_base::base_implementation_type& impl)
+{
+  close_for_destruction(impl);
+
+  // Remove implementation from linked list of all implementations.
+  asio::detail::mutex::scoped_lock lock(mutex_);
+  if (impl_list_ == &impl)
+    impl_list_ = impl.next_;
+  if (impl.prev_)
+    impl.prev_->next_ = impl.next_;
+  if (impl.next_)
+    impl.next_->prev_= impl.prev_;
+  impl.next_ = 0;
+  impl.prev_ = 0;
+}
+
+asio::error_code win_iocp_socket_service_base::close(
+    win_iocp_socket_service_base::base_implementation_type& impl,
+    asio::error_code& ec)
+{
+  if (is_open(impl))
+  {
+    ASIO_HANDLER_OPERATION((iocp_service_.context(),
+          "socket", &impl, impl.socket_, "close"));
+
+    // Check if the reactor was created, in which case we need to close the
+    // socket on the reactor as well to cancel any operations that might be
+    // running there.
+    select_reactor* r = static_cast<select_reactor*>(
+          interlocked_compare_exchange_pointer(
+            reinterpret_cast<void**>(&reactor_), 0, 0));
+    if (r)
+      r->deregister_descriptor(impl.socket_, impl.reactor_data_, true);
+
+    socket_ops::close(impl.socket_, impl.state_, false, ec);
+
+    if (r)
+      r->cleanup_descriptor_data(impl.reactor_data_);
+  }
+  else
+  {
+    ec = asio::error_code();
+  }
+
+  impl.socket_ = invalid_socket;
+  impl.state_ = 0;
+  impl.cancel_token_.reset();
+#if defined(ASIO_ENABLE_CANCELIO)
+  impl.safe_cancellation_thread_id_ = 0;
+#endif // defined(ASIO_ENABLE_CANCELIO)
+
+  return ec;
+}
+
+socket_type win_iocp_socket_service_base::release(
+    win_iocp_socket_service_base::base_implementation_type& impl,
+    asio::error_code& ec)
+{
+  if (!is_open(impl))
+    return invalid_socket;
+
+  cancel(impl, ec);
+  if (ec)
+    return invalid_socket;
+
+  nt_set_info_fn fn = get_nt_set_info();
+  if (fn == 0)
+  {
+    ec = asio::error::operation_not_supported;
+    return invalid_socket;
+  }
+
+  HANDLE sock_as_handle = reinterpret_cast<HANDLE>(impl.socket_);
+  ULONG_PTR iosb[2] = { 0, 0 };
+  void* info[2] = { 0, 0 };
+  if (fn(sock_as_handle, iosb, &info, sizeof(info),
+        61 /* FileReplaceCompletionInformation */))
+  {
+    ec = asio::error::operation_not_supported;
+    return invalid_socket;
+  }
+
+  socket_type tmp = impl.socket_;
+  impl.socket_ = invalid_socket;
+  return tmp;
+}
+
+asio::error_code win_iocp_socket_service_base::cancel(
+    win_iocp_socket_service_base::base_implementation_type& impl,
+    asio::error_code& ec)
+{
+  if (!is_open(impl))
+  {
+    ec = asio::error::bad_descriptor;
+    return ec;
+  }
+
+  ASIO_HANDLER_OPERATION((iocp_service_.context(),
+        "socket", &impl, impl.socket_, "cancel"));
+
+  if (FARPROC cancel_io_ex_ptr = ::GetProcAddress(
+        ::GetModuleHandleA("KERNEL32"), "CancelIoEx"))
+  {
+    // The version of Windows supports cancellation from any thread.
+    typedef BOOL (WINAPI* cancel_io_ex_t)(HANDLE, LPOVERLAPPED);
+    cancel_io_ex_t cancel_io_ex = reinterpret_cast<cancel_io_ex_t>(
+        reinterpret_cast<void*>(cancel_io_ex_ptr));
+    socket_type sock = impl.socket_;
+    HANDLE sock_as_handle = reinterpret_cast<HANDLE>(sock);
+    if (!cancel_io_ex(sock_as_handle, 0))
+    {
+      DWORD last_error = ::GetLastError();
+      if (last_error == ERROR_NOT_FOUND)
+      {
+        // ERROR_NOT_FOUND means that there were no operations to be
+        // cancelled. We swallow this error to match the behaviour on other
+        // platforms.
+        ec = asio::error_code();
+      }
+      else
+      {
+        ec = asio::error_code(last_error,
+            asio::error::get_system_category());
+      }
+    }
+    else
+    {
+      ec = asio::error_code();
+    }
+  }
+#if defined(ASIO_ENABLE_CANCELIO)
+  else if (impl.safe_cancellation_thread_id_ == 0)
+  {
+    // No operations have been started, so there's nothing to cancel.
+    ec = asio::error_code();
+  }
+  else if (impl.safe_cancellation_thread_id_ == ::GetCurrentThreadId())
+  {
+    // Asynchronous operations have been started from the current thread only,
+    // so it is safe to try to cancel them using CancelIo.
+    socket_type sock = impl.socket_;
+    HANDLE sock_as_handle = reinterpret_cast<HANDLE>(sock);
+    if (!::CancelIo(sock_as_handle))
+    {
+      DWORD last_error = ::GetLastError();
+      ec = asio::error_code(last_error,
+          asio::error::get_system_category());
+    }
+    else
+    {
+      ec = asio::error_code();
+    }
+  }
+  else
+  {
+    // Asynchronous operations have been started from more than one thread,
+    // so cancellation is not safe.
+    ec = asio::error::operation_not_supported;
+  }
+#else // defined(ASIO_ENABLE_CANCELIO)
+  else
+  {
+    // Cancellation is not supported as CancelIo may not be used.
+    ec = asio::error::operation_not_supported;
+  }
+#endif // defined(ASIO_ENABLE_CANCELIO)
+
+  // Cancel any operations started via the reactor.
+  if (!ec)
+  {
+    select_reactor* r = static_cast<select_reactor*>(
+          interlocked_compare_exchange_pointer(
+            reinterpret_cast<void**>(&reactor_), 0, 0));
+    if (r)
+      r->cancel_ops(impl.socket_, impl.reactor_data_);
+  }
+
+  return ec;
+}
+
+asio::error_code win_iocp_socket_service_base::do_open(
+    win_iocp_socket_service_base::base_implementation_type& impl,
+    int family, int type, int protocol, asio::error_code& ec)
+{
+  if (is_open(impl))
+  {
+    ec = asio::error::already_open;
+    return ec;
+  }
+
+  socket_holder sock(socket_ops::socket(family, type, protocol, ec));
+  if (sock.get() == invalid_socket)
+    return ec;
+
+  HANDLE sock_as_handle = reinterpret_cast<HANDLE>(sock.get());
+  if (iocp_service_.register_handle(sock_as_handle, ec))
+    return ec;
+
+  impl.socket_ = sock.release();
+  switch (type)
+  {
+  case SOCK_STREAM: impl.state_ = socket_ops::stream_oriented; break;
+  case SOCK_DGRAM: impl.state_ = socket_ops::datagram_oriented; break;
+  default: impl.state_ = 0; break;
+  }
+  impl.cancel_token_.reset(static_cast<void*>(0), socket_ops::noop_deleter());
+  ec = asio::error_code();
+  return ec;
+}
+
+asio::error_code win_iocp_socket_service_base::do_assign(
+    win_iocp_socket_service_base::base_implementation_type& impl,
+    int type, socket_type native_socket, asio::error_code& ec)
+{
+  if (is_open(impl))
+  {
+    ec = asio::error::already_open;
+    return ec;
+  }
+
+  HANDLE sock_as_handle = reinterpret_cast<HANDLE>(native_socket);
+  if (iocp_service_.register_handle(sock_as_handle, ec))
+    return ec;
+
+  impl.socket_ = native_socket;
+  switch (type)
+  {
+  case SOCK_STREAM: impl.state_ = socket_ops::stream_oriented; break;
+  case SOCK_DGRAM: impl.state_ = socket_ops::datagram_oriented; break;
+  default: impl.state_ = 0; break;
+  }
+  impl.cancel_token_.reset(static_cast<void*>(0), socket_ops::noop_deleter());
+  ec = asio::error_code();
+  return ec;
+}
+
+void win_iocp_socket_service_base::start_send_op(
+    win_iocp_socket_service_base::base_implementation_type& impl,
+    WSABUF* buffers, std::size_t buffer_count,
+    socket_base::message_flags flags, bool noop, operation* op)
+{
+  update_cancellation_thread_id(impl);
+  iocp_service_.work_started();
+
+  if (noop)
+    iocp_service_.on_completion(op);
+  else if (!is_open(impl))
+    iocp_service_.on_completion(op, asio::error::bad_descriptor);
+  else
+  {
+    DWORD bytes_transferred = 0;
+    int result = ::WSASend(impl.socket_, buffers,
+        static_cast<DWORD>(buffer_count), &bytes_transferred, flags, op, 0);
+    DWORD last_error = ::WSAGetLastError();
+    if (last_error == ERROR_PORT_UNREACHABLE)
+      last_error = WSAECONNREFUSED;
+    if (result != 0 && last_error != WSA_IO_PENDING)
+      iocp_service_.on_completion(op, last_error, bytes_transferred);
+    else
+      iocp_service_.on_pending(op);
+  }
+}
+
+void win_iocp_socket_service_base::start_send_to_op(
+    win_iocp_socket_service_base::base_implementation_type& impl,
+    WSABUF* buffers, std::size_t buffer_count,
+    const socket_addr_type* addr, int addrlen,
+    socket_base::message_flags flags, operation* op)
+{
+  update_cancellation_thread_id(impl);
+  iocp_service_.work_started();
+
+  if (!is_open(impl))
+    iocp_service_.on_completion(op, asio::error::bad_descriptor);
+  else
+  {
+    DWORD bytes_transferred = 0;
+    int result = ::WSASendTo(impl.socket_, buffers,
+        static_cast<DWORD>(buffer_count),
+        &bytes_transferred, flags, addr, addrlen, op, 0);
+    DWORD last_error = ::WSAGetLastError();
+    if (last_error == ERROR_PORT_UNREACHABLE)
+      last_error = WSAECONNREFUSED;
+    if (result != 0 && last_error != WSA_IO_PENDING)
+      iocp_service_.on_completion(op, last_error, bytes_transferred);
+    else
+      iocp_service_.on_pending(op);
+  }
+}
+
+void win_iocp_socket_service_base::start_receive_op(
+    win_iocp_socket_service_base::base_implementation_type& impl,
+    WSABUF* buffers, std::size_t buffer_count,
+    socket_base::message_flags flags, bool noop, operation* op)
+{
+  update_cancellation_thread_id(impl);
+  iocp_service_.work_started();
+
+  if (noop)
+    iocp_service_.on_completion(op);
+  else if (!is_open(impl))
+    iocp_service_.on_completion(op, asio::error::bad_descriptor);
+  else
+  {
+    DWORD bytes_transferred = 0;
+    DWORD recv_flags = flags;
+    int result = ::WSARecv(impl.socket_, buffers,
+        static_cast<DWORD>(buffer_count),
+        &bytes_transferred, &recv_flags, op, 0);
+    DWORD last_error = ::WSAGetLastError();
+    if (last_error == ERROR_NETNAME_DELETED)
+      last_error = WSAECONNRESET;
+    else if (last_error == ERROR_PORT_UNREACHABLE)
+      last_error = WSAECONNREFUSED;
+    if (result != 0 && last_error != WSA_IO_PENDING)
+      iocp_service_.on_completion(op, last_error, bytes_transferred);
+    else
+      iocp_service_.on_pending(op);
+  }
+}
+
+void win_iocp_socket_service_base::start_null_buffers_receive_op(
+    win_iocp_socket_service_base::base_implementation_type& impl,
+    socket_base::message_flags flags, reactor_op* op)
+{
+  if ((impl.state_ & socket_ops::stream_oriented) != 0)
+  {
+    // For stream sockets on Windows, we may issue a 0-byte overlapped
+    // WSARecv to wait until there is data available on the socket.
+    ::WSABUF buf = { 0, 0 };
+    start_receive_op(impl, &buf, 1, flags, false, op);
+  }
+  else
+  {
+    start_reactor_op(impl,
+        (flags & socket_base::message_out_of_band)
+          ? select_reactor::except_op : select_reactor::read_op,
+        op);
+  }
+}
+
+void win_iocp_socket_service_base::start_receive_from_op(
+    win_iocp_socket_service_base::base_implementation_type& impl,
+    WSABUF* buffers, std::size_t buffer_count, socket_addr_type* addr,
+    socket_base::message_flags flags, int* addrlen, operation* op)
+{
+  update_cancellation_thread_id(impl);
+  iocp_service_.work_started();
+
+  if (!is_open(impl))
+    iocp_service_.on_completion(op, asio::error::bad_descriptor);
+  else
+  {
+    DWORD bytes_transferred = 0;
+    DWORD recv_flags = flags;
+    int result = ::WSARecvFrom(impl.socket_, buffers,
+        static_cast<DWORD>(buffer_count),
+        &bytes_transferred, &recv_flags, addr, addrlen, op, 0);
+    DWORD last_error = ::WSAGetLastError();
+    if (last_error == ERROR_PORT_UNREACHABLE)
+      last_error = WSAECONNREFUSED;
+    if (result != 0 && last_error != WSA_IO_PENDING)
+      iocp_service_.on_completion(op, last_error, bytes_transferred);
+    else
+      iocp_service_.on_pending(op);
+  }
+}
+
+void win_iocp_socket_service_base::start_accept_op(
+    win_iocp_socket_service_base::base_implementation_type& impl,
+    bool peer_is_open, socket_holder& new_socket, int family, int type,
+    int protocol, void* output_buffer, DWORD address_length, operation* op)
+{
+  update_cancellation_thread_id(impl);
+  iocp_service_.work_started();
+
+  if (!is_open(impl))
+    iocp_service_.on_completion(op, asio::error::bad_descriptor);
+  else if (peer_is_open)
+    iocp_service_.on_completion(op, asio::error::already_open);
+  else
+  {
+    asio::error_code ec;
+    new_socket.reset(socket_ops::socket(family, type, protocol, ec));
+    if (new_socket.get() == invalid_socket)
+      iocp_service_.on_completion(op, ec);
+    else
+    {
+      DWORD bytes_read = 0;
+      BOOL result = ::AcceptEx(impl.socket_, new_socket.get(), output_buffer,
+          0, address_length, address_length, &bytes_read, op);
+      DWORD last_error = ::WSAGetLastError();
+      if (!result && last_error != WSA_IO_PENDING)
+        iocp_service_.on_completion(op, last_error);
+      else
+        iocp_service_.on_pending(op);
+    }
+  }
+}
+
+void win_iocp_socket_service_base::restart_accept_op(
+    socket_type s, socket_holder& new_socket, int family, int type,
+    int protocol, void* output_buffer, DWORD address_length, operation* op)
+{
+  new_socket.reset();
+  iocp_service_.work_started();
+
+  asio::error_code ec;
+  new_socket.reset(socket_ops::socket(family, type, protocol, ec));
+  if (new_socket.get() == invalid_socket)
+    iocp_service_.on_completion(op, ec);
+  else
+  {
+    DWORD bytes_read = 0;
+    BOOL result = ::AcceptEx(s, new_socket.get(), output_buffer,
+        0, address_length, address_length, &bytes_read, op);
+    DWORD last_error = ::WSAGetLastError();
+    if (!result && last_error != WSA_IO_PENDING)
+      iocp_service_.on_completion(op, last_error);
+    else
+      iocp_service_.on_pending(op);
+  }
+}
+
+void win_iocp_socket_service_base::start_reactor_op(
+    win_iocp_socket_service_base::base_implementation_type& impl,
+    int op_type, reactor_op* op)
+{
+  select_reactor& r = get_reactor();
+  update_cancellation_thread_id(impl);
+
+  if (is_open(impl))
+  {
+    r.start_op(op_type, impl.socket_, impl.reactor_data_, op, false, false);
+    return;
+  }
+  else
+    op->ec_ = asio::error::bad_descriptor;
+
+  iocp_service_.post_immediate_completion(op, false);
+}
+
+void win_iocp_socket_service_base::start_connect_op(
+    win_iocp_socket_service_base::base_implementation_type& impl,
+    int family, int type, const socket_addr_type* addr,
+    std::size_t addrlen, win_iocp_socket_connect_op_base* op)
+{
+  // If ConnectEx is available, use that.
+  if (family == ASIO_OS_DEF(AF_INET)
+      || family == ASIO_OS_DEF(AF_INET6))
+  {
+    if (connect_ex_fn connect_ex = get_connect_ex(impl, type))
+    {
+      union address_union
+      {
+        socket_addr_type base;
+        sockaddr_in4_type v4;
+        sockaddr_in6_type v6;
+      } a;
+
+      using namespace std; // For memset.
+      memset(&a, 0, sizeof(a));
+      a.base.sa_family = family;
+
+      socket_ops::bind(impl.socket_, &a.base,
+          family == ASIO_OS_DEF(AF_INET)
+          ? sizeof(a.v4) : sizeof(a.v6), op->ec_);
+      if (op->ec_ && op->ec_ != asio::error::invalid_argument)
+      {
+        iocp_service_.post_immediate_completion(op, false);
+        return;
+      }
+
+      op->connect_ex_ = true;
+      update_cancellation_thread_id(impl);
+      iocp_service_.work_started();
+
+      BOOL result = connect_ex(impl.socket_,
+          addr, static_cast<int>(addrlen), 0, 0, 0, op);
+      DWORD last_error = ::WSAGetLastError();
+      if (!result && last_error != WSA_IO_PENDING)
+        iocp_service_.on_completion(op, last_error);
+      else
+        iocp_service_.on_pending(op);
+      return;
+    }
+  }
+
+  // Otherwise, fall back to a reactor-based implementation.
+  select_reactor& r = get_reactor();
+  update_cancellation_thread_id(impl);
+
+  if ((impl.state_ & socket_ops::non_blocking) != 0
+      || socket_ops::set_internal_non_blocking(
+        impl.socket_, impl.state_, true, op->ec_))
+  {
+    if (socket_ops::connect(impl.socket_, addr, addrlen, op->ec_) != 0)
+    {
+      if (op->ec_ == asio::error::in_progress
+          || op->ec_ == asio::error::would_block)
+      {
+        op->ec_ = asio::error_code();
+        r.start_op(select_reactor::connect_op, impl.socket_,
+            impl.reactor_data_, op, false, false);
+        return;
+      }
+    }
+  }
+
+  r.post_immediate_completion(op, false);
+}
+
+void win_iocp_socket_service_base::close_for_destruction(
+    win_iocp_socket_service_base::base_implementation_type& impl)
+{
+  if (is_open(impl))
+  {
+    ASIO_HANDLER_OPERATION((iocp_service_.context(),
+          "socket", &impl, impl.socket_, "close"));
+
+    // Check if the reactor was created, in which case we need to close the
+    // socket on the reactor as well to cancel any operations that might be
+    // running there.
+    select_reactor* r = static_cast<select_reactor*>(
+          interlocked_compare_exchange_pointer(
+            reinterpret_cast<void**>(&reactor_), 0, 0));
+    if (r)
+      r->deregister_descriptor(impl.socket_, impl.reactor_data_, true);
+
+    asio::error_code ignored_ec;
+    socket_ops::close(impl.socket_, impl.state_, true, ignored_ec);
+
+    if (r)
+      r->cleanup_descriptor_data(impl.reactor_data_);
+  }
+
+  impl.socket_ = invalid_socket;
+  impl.state_ = 0;
+  impl.cancel_token_.reset();
+#if defined(ASIO_ENABLE_CANCELIO)
+  impl.safe_cancellation_thread_id_ = 0;
+#endif // defined(ASIO_ENABLE_CANCELIO)
+}
+
+void win_iocp_socket_service_base::update_cancellation_thread_id(
+    win_iocp_socket_service_base::base_implementation_type& impl)
+{
+#if defined(ASIO_ENABLE_CANCELIO)
+  if (impl.safe_cancellation_thread_id_ == 0)
+    impl.safe_cancellation_thread_id_ = ::GetCurrentThreadId();
+  else if (impl.safe_cancellation_thread_id_ != ::GetCurrentThreadId())
+    impl.safe_cancellation_thread_id_ = ~DWORD(0);
+#else // defined(ASIO_ENABLE_CANCELIO)
+  (void)impl;
+#endif // defined(ASIO_ENABLE_CANCELIO)
+}
+
+select_reactor& win_iocp_socket_service_base::get_reactor()
+{
+  select_reactor* r = static_cast<select_reactor*>(
+        interlocked_compare_exchange_pointer(
+          reinterpret_cast<void**>(&reactor_), 0, 0));
+  if (!r)
+  {
+    r = &(use_service<select_reactor>(context_));
+    interlocked_exchange_pointer(reinterpret_cast<void**>(&reactor_), r);
+  }
+  return *r;
+}
+
+win_iocp_socket_service_base::connect_ex_fn
+win_iocp_socket_service_base::get_connect_ex(
+    win_iocp_socket_service_base::base_implementation_type& impl, int type)
+{
+#if defined(ASIO_DISABLE_CONNECTEX)
+  (void)impl;
+  (void)type;
+  return 0;
+#else // defined(ASIO_DISABLE_CONNECTEX)
+  if (type != ASIO_OS_DEF(SOCK_STREAM)
+      && type != ASIO_OS_DEF(SOCK_SEQPACKET))
+    return 0;
+
+  void* ptr = interlocked_compare_exchange_pointer(&connect_ex_, 0, 0);
+  if (!ptr)
+  {
+    GUID guid = { 0x25a207b9, 0xddf3, 0x4660,
+      { 0x8e, 0xe9, 0x76, 0xe5, 0x8c, 0x74, 0x06, 0x3e } };
+
+    DWORD bytes = 0;
+    if (::WSAIoctl(impl.socket_, SIO_GET_EXTENSION_FUNCTION_POINTER,
+          &guid, sizeof(guid), &ptr, sizeof(ptr), &bytes, 0, 0) != 0)
+    {
+      // Set connect_ex_ to a special value to indicate that ConnectEx is
+      // unavailable. That way we won't bother trying to look it up again.
+      ptr = this;
+    }
+
+    interlocked_exchange_pointer(&connect_ex_, ptr);
+  }
+
+  return reinterpret_cast<connect_ex_fn>(ptr == this ? 0 : ptr);
+#endif // defined(ASIO_DISABLE_CONNECTEX)
+}
+
+win_iocp_socket_service_base::nt_set_info_fn
+win_iocp_socket_service_base::get_nt_set_info()
+{
+  void* ptr = interlocked_compare_exchange_pointer(&nt_set_info_, 0, 0);
+  if (!ptr)
+  {
+    if (HMODULE h = ::GetModuleHandleA("NTDLL.DLL"))
+      ptr = reinterpret_cast<void*>(GetProcAddress(h, "NtSetInformationFile"));
+
+    // On failure, set nt_set_info_ to a special value to indicate that the
+    // NtSetInformationFile function is unavailable. That way we won't bother
+    // trying to look it up again.
+    interlocked_exchange_pointer(&nt_set_info_, ptr ? ptr : this);
+  }
+
+  return reinterpret_cast<nt_set_info_fn>(ptr == this ? 0 : ptr);
+}
+
+void* win_iocp_socket_service_base::interlocked_compare_exchange_pointer(
+    void** dest, void* exch, void* cmp)
+{
+#if defined(_M_IX86)
+  return reinterpret_cast<void*>(InterlockedCompareExchange(
+        reinterpret_cast<PLONG>(dest), reinterpret_cast<LONG>(exch),
+        reinterpret_cast<LONG>(cmp)));
+#else
+  return InterlockedCompareExchangePointer(dest, exch, cmp);
+#endif
+}
+
+void* win_iocp_socket_service_base::interlocked_exchange_pointer(
+    void** dest, void* val)
+{
+#if defined(_M_IX86)
+  return reinterpret_cast<void*>(InterlockedExchange(
+        reinterpret_cast<PLONG>(dest), reinterpret_cast<LONG>(val)));
+#else
+  return InterlockedExchangePointer(dest, val);
+#endif
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_IOCP)
+
+#endif // ASIO_DETAIL_IMPL_WIN_IOCP_SOCKET_SERVICE_BASE_IPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/impl/win_mutex.ipp b/link/modules/asio-standalone/asio/include/asio/detail/impl/win_mutex.ipp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/impl/win_mutex.ipp
@@ -0,0 +1,84 @@
+//
+// detail/impl/win_mutex.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_IMPL_WIN_MUTEX_IPP
+#define ASIO_DETAIL_IMPL_WIN_MUTEX_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_WINDOWS)
+
+#include "asio/detail/throw_error.hpp"
+#include "asio/detail/win_mutex.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+win_mutex::win_mutex()
+{
+  int error = do_init();
+  asio::error_code ec(error,
+      asio::error::get_system_category());
+  asio::detail::throw_error(ec, "mutex");
+}
+
+int win_mutex::do_init()
+{
+#if defined(__MINGW32__)
+  // Not sure if MinGW supports structured exception handling, so for now
+  // we'll just call the Windows API and hope.
+# if defined(UNDER_CE)
+  ::InitializeCriticalSection(&crit_section_);
+# elif defined(ASIO_WINDOWS_APP)
+  if (!::InitializeCriticalSectionEx(&crit_section_, 0, 0))
+    return ::GetLastError();
+# else
+  if (!::InitializeCriticalSectionAndSpinCount(&crit_section_, 0x80000000))
+    return ::GetLastError();
+# endif
+  return 0;
+#else
+  __try
+  {
+# if defined(UNDER_CE)
+    ::InitializeCriticalSection(&crit_section_);
+# elif defined(ASIO_WINDOWS_APP)
+    if (!::InitializeCriticalSectionEx(&crit_section_, 0, 0))
+      return ::GetLastError();
+# else
+    if (!::InitializeCriticalSectionAndSpinCount(&crit_section_, 0x80000000))
+      return ::GetLastError();
+# endif
+  }
+  __except(GetExceptionCode() == STATUS_NO_MEMORY
+      ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
+  {
+    return ERROR_OUTOFMEMORY;
+  }
+
+  return 0;
+#endif
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_WINDOWS)
+
+#endif // ASIO_DETAIL_IMPL_WIN_MUTEX_IPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/impl/win_object_handle_service.ipp b/link/modules/asio-standalone/asio/include/asio/detail/impl/win_object_handle_service.ipp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/impl/win_object_handle_service.ipp
@@ -0,0 +1,448 @@
+//
+// detail/impl/win_object_handle_service.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2011 Boris Schaeling (boris@highscore.de)
+//
+// 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 ASIO_DETAIL_IMPL_WIN_OBJECT_HANDLE_SERVICE_IPP
+#define ASIO_DETAIL_IMPL_WIN_OBJECT_HANDLE_SERVICE_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_WINDOWS_OBJECT_HANDLE)
+
+#include "asio/detail/win_object_handle_service.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+win_object_handle_service::win_object_handle_service(execution_context& context)
+  : execution_context_service_base<win_object_handle_service>(context),
+    scheduler_(asio::use_service<scheduler_impl>(context)),
+    mutex_(),
+    impl_list_(0),
+    shutdown_(false)
+{
+}
+
+void win_object_handle_service::shutdown()
+{
+  mutex::scoped_lock lock(mutex_);
+
+  // Setting this flag to true prevents new objects from being registered, and
+  // new asynchronous wait operations from being started. We only need to worry
+  // about cleaning up the operations that are currently in progress.
+  shutdown_ = true;
+
+  op_queue<operation> ops;
+  for (implementation_type* impl = impl_list_; impl; impl = impl->next_)
+    ops.push(impl->op_queue_);
+
+  lock.unlock();
+
+  scheduler_.abandon_operations(ops);
+}
+
+void win_object_handle_service::construct(
+    win_object_handle_service::implementation_type& impl)
+{
+  impl.handle_ = INVALID_HANDLE_VALUE;
+  impl.wait_handle_ = INVALID_HANDLE_VALUE;
+  impl.owner_ = this;
+
+  // Insert implementation into linked list of all implementations.
+  mutex::scoped_lock lock(mutex_);
+  if (!shutdown_)
+  {
+    impl.next_ = impl_list_;
+    impl.prev_ = 0;
+    if (impl_list_)
+      impl_list_->prev_ = &impl;
+    impl_list_ = &impl;
+  }
+}
+
+void win_object_handle_service::move_construct(
+    win_object_handle_service::implementation_type& impl,
+    win_object_handle_service::implementation_type& other_impl)
+{
+  mutex::scoped_lock lock(mutex_);
+
+  // Insert implementation into linked list of all implementations.
+  if (!shutdown_)
+  {
+    impl.next_ = impl_list_;
+    impl.prev_ = 0;
+    if (impl_list_)
+      impl_list_->prev_ = &impl;
+    impl_list_ = &impl;
+  }
+
+  impl.handle_ = other_impl.handle_;
+  other_impl.handle_ = INVALID_HANDLE_VALUE;
+  impl.wait_handle_ = other_impl.wait_handle_;
+  other_impl.wait_handle_ = INVALID_HANDLE_VALUE;
+  impl.op_queue_.push(other_impl.op_queue_);
+  impl.owner_ = this;
+
+  // We must not hold the lock while calling UnregisterWaitEx. This is because
+  // the registered callback function might be invoked while we are waiting for
+  // UnregisterWaitEx to complete.
+  lock.unlock();
+
+  if (impl.wait_handle_ != INVALID_HANDLE_VALUE)
+    ::UnregisterWaitEx(impl.wait_handle_, INVALID_HANDLE_VALUE);
+
+  if (!impl.op_queue_.empty())
+    register_wait_callback(impl, lock);
+}
+
+void win_object_handle_service::move_assign(
+    win_object_handle_service::implementation_type& impl,
+    win_object_handle_service& other_service,
+    win_object_handle_service::implementation_type& other_impl)
+{
+  asio::error_code ignored_ec;
+  close(impl, ignored_ec);
+
+  mutex::scoped_lock lock(mutex_);
+
+  if (this != &other_service)
+  {
+    // Remove implementation from linked list of all implementations.
+    if (impl_list_ == &impl)
+      impl_list_ = impl.next_;
+    if (impl.prev_)
+      impl.prev_->next_ = impl.next_;
+    if (impl.next_)
+      impl.next_->prev_= impl.prev_;
+    impl.next_ = 0;
+    impl.prev_ = 0;
+  }
+
+  impl.handle_ = other_impl.handle_;
+  other_impl.handle_ = INVALID_HANDLE_VALUE;
+  impl.wait_handle_ = other_impl.wait_handle_;
+  other_impl.wait_handle_ = INVALID_HANDLE_VALUE;
+  impl.op_queue_.push(other_impl.op_queue_);
+  impl.owner_ = this;
+
+  if (this != &other_service)
+  {
+    // Insert implementation into linked list of all implementations.
+    impl.next_ = other_service.impl_list_;
+    impl.prev_ = 0;
+    if (other_service.impl_list_)
+      other_service.impl_list_->prev_ = &impl;
+    other_service.impl_list_ = &impl;
+  }
+
+  // We must not hold the lock while calling UnregisterWaitEx. This is because
+  // the registered callback function might be invoked while we are waiting for
+  // UnregisterWaitEx to complete.
+  lock.unlock();
+
+  if (impl.wait_handle_ != INVALID_HANDLE_VALUE)
+    ::UnregisterWaitEx(impl.wait_handle_, INVALID_HANDLE_VALUE);
+
+  if (!impl.op_queue_.empty())
+    register_wait_callback(impl, lock);
+}
+
+void win_object_handle_service::destroy(
+    win_object_handle_service::implementation_type& impl)
+{
+  mutex::scoped_lock lock(mutex_);
+
+  // Remove implementation from linked list of all implementations.
+  if (impl_list_ == &impl)
+    impl_list_ = impl.next_;
+  if (impl.prev_)
+    impl.prev_->next_ = impl.next_;
+  if (impl.next_)
+    impl.next_->prev_= impl.prev_;
+  impl.next_ = 0;
+  impl.prev_ = 0;
+
+  if (is_open(impl))
+  {
+    ASIO_HANDLER_OPERATION((scheduler_.context(), "object_handle",
+          &impl, reinterpret_cast<uintmax_t>(impl.wait_handle_), "close"));
+
+    HANDLE wait_handle = impl.wait_handle_;
+    impl.wait_handle_ = INVALID_HANDLE_VALUE;
+
+    op_queue<operation> ops;
+    while (wait_op* op = impl.op_queue_.front())
+    {
+      op->ec_ = asio::error::operation_aborted;
+      impl.op_queue_.pop();
+      ops.push(op);
+    }
+
+    // We must not hold the lock while calling UnregisterWaitEx. This is
+    // because the registered callback function might be invoked while we are
+    // waiting for UnregisterWaitEx to complete.
+    lock.unlock();
+
+    if (wait_handle != INVALID_HANDLE_VALUE)
+      ::UnregisterWaitEx(wait_handle, INVALID_HANDLE_VALUE);
+
+    ::CloseHandle(impl.handle_);
+    impl.handle_ = INVALID_HANDLE_VALUE;
+
+    scheduler_.post_deferred_completions(ops);
+  }
+}
+
+asio::error_code win_object_handle_service::assign(
+    win_object_handle_service::implementation_type& impl,
+    const native_handle_type& handle, asio::error_code& ec)
+{
+  if (is_open(impl))
+  {
+    ec = asio::error::already_open;
+    return ec;
+  }
+
+  impl.handle_ = handle;
+  ec = asio::error_code();
+  return ec;
+}
+
+asio::error_code win_object_handle_service::close(
+    win_object_handle_service::implementation_type& impl,
+    asio::error_code& ec)
+{
+  if (is_open(impl))
+  {
+    ASIO_HANDLER_OPERATION((scheduler_.context(), "object_handle",
+          &impl, reinterpret_cast<uintmax_t>(impl.wait_handle_), "close"));
+
+    mutex::scoped_lock lock(mutex_);
+
+    HANDLE wait_handle = impl.wait_handle_;
+    impl.wait_handle_ = INVALID_HANDLE_VALUE;
+
+    op_queue<operation> completed_ops;
+    while (wait_op* op = impl.op_queue_.front())
+    {
+      impl.op_queue_.pop();
+      op->ec_ = asio::error::operation_aborted;
+      completed_ops.push(op);
+    }
+
+    // We must not hold the lock while calling UnregisterWaitEx. This is
+    // because the registered callback function might be invoked while we are
+    // waiting for UnregisterWaitEx to complete.
+    lock.unlock();
+
+    if (wait_handle != INVALID_HANDLE_VALUE)
+      ::UnregisterWaitEx(wait_handle, INVALID_HANDLE_VALUE);
+
+    if (::CloseHandle(impl.handle_))
+    {
+      impl.handle_ = INVALID_HANDLE_VALUE;
+      ec = asio::error_code();
+    }
+    else
+    {
+      DWORD last_error = ::GetLastError();
+      ec = asio::error_code(last_error,
+          asio::error::get_system_category());
+    }
+
+    scheduler_.post_deferred_completions(completed_ops);
+  }
+  else
+  {
+    ec = asio::error_code();
+  }
+
+  return ec;
+}
+
+asio::error_code win_object_handle_service::cancel(
+    win_object_handle_service::implementation_type& impl,
+    asio::error_code& ec)
+{
+  if (is_open(impl))
+  {
+    ASIO_HANDLER_OPERATION((scheduler_.context(), "object_handle",
+          &impl, reinterpret_cast<uintmax_t>(impl.wait_handle_), "cancel"));
+
+    mutex::scoped_lock lock(mutex_);
+
+    HANDLE wait_handle = impl.wait_handle_;
+    impl.wait_handle_ = INVALID_HANDLE_VALUE;
+
+    op_queue<operation> completed_ops;
+    while (wait_op* op = impl.op_queue_.front())
+    {
+      op->ec_ = asio::error::operation_aborted;
+      impl.op_queue_.pop();
+      completed_ops.push(op);
+    }
+
+    // We must not hold the lock while calling UnregisterWaitEx. This is
+    // because the registered callback function might be invoked while we are
+    // waiting for UnregisterWaitEx to complete.
+    lock.unlock();
+
+    if (wait_handle != INVALID_HANDLE_VALUE)
+      ::UnregisterWaitEx(wait_handle, INVALID_HANDLE_VALUE);
+
+    ec = asio::error_code();
+
+    scheduler_.post_deferred_completions(completed_ops);
+  }
+  else
+  {
+    ec = asio::error::bad_descriptor;
+  }
+
+  return ec;
+}
+
+void win_object_handle_service::wait(
+    win_object_handle_service::implementation_type& impl,
+    asio::error_code& ec)
+{
+  switch (::WaitForSingleObject(impl.handle_, INFINITE))
+  {
+  case WAIT_FAILED:
+    {
+      DWORD last_error = ::GetLastError();
+      ec = asio::error_code(last_error,
+          asio::error::get_system_category());
+      break;
+    }
+  case WAIT_OBJECT_0:
+  case WAIT_ABANDONED:
+  default:
+    ec = asio::error_code();
+    break;
+  }
+}
+
+void win_object_handle_service::start_wait_op(
+    win_object_handle_service::implementation_type& impl, wait_op* op)
+{
+  scheduler_.work_started();
+
+  if (is_open(impl))
+  {
+    mutex::scoped_lock lock(mutex_);
+
+    if (!shutdown_)
+    {
+      impl.op_queue_.push(op);
+
+      // Only the first operation to be queued gets to register a wait callback.
+      // Subsequent operations have to wait for the first to finish.
+      if (impl.op_queue_.front() == op)
+        register_wait_callback(impl, lock);
+    }
+    else
+    {
+      lock.unlock();
+      scheduler_.post_deferred_completion(op);
+    }
+  }
+  else
+  {
+    op->ec_ = asio::error::bad_descriptor;
+    scheduler_.post_deferred_completion(op);
+  }
+}
+
+void win_object_handle_service::register_wait_callback(
+    win_object_handle_service::implementation_type& impl,
+    mutex::scoped_lock& lock)
+{
+  lock.lock();
+
+  if (!RegisterWaitForSingleObject(&impl.wait_handle_,
+        impl.handle_, &win_object_handle_service::wait_callback,
+        &impl, INFINITE, WT_EXECUTEONLYONCE))
+  {
+    DWORD last_error = ::GetLastError();
+    asio::error_code ec(last_error,
+        asio::error::get_system_category());
+
+    op_queue<operation> completed_ops;
+    while (wait_op* op = impl.op_queue_.front())
+    {
+      op->ec_ = ec;
+      impl.op_queue_.pop();
+      completed_ops.push(op);
+    }
+
+    lock.unlock();
+    scheduler_.post_deferred_completions(completed_ops);
+  }
+}
+
+void win_object_handle_service::wait_callback(PVOID param, BOOLEAN)
+{
+  implementation_type* impl = static_cast<implementation_type*>(param);
+  mutex::scoped_lock lock(impl->owner_->mutex_);
+
+  if (impl->wait_handle_ != INVALID_HANDLE_VALUE)
+  {
+    ::UnregisterWaitEx(impl->wait_handle_, NULL);
+    impl->wait_handle_ = INVALID_HANDLE_VALUE;
+  }
+
+  if (wait_op* op = impl->op_queue_.front())
+  {
+    op_queue<operation> completed_ops;
+
+    op->ec_ = asio::error_code();
+    impl->op_queue_.pop();
+    completed_ops.push(op);
+
+    if (!impl->op_queue_.empty())
+    {
+      if (!RegisterWaitForSingleObject(&impl->wait_handle_,
+            impl->handle_, &win_object_handle_service::wait_callback,
+            param, INFINITE, WT_EXECUTEONLYONCE))
+      {
+        DWORD last_error = ::GetLastError();
+        asio::error_code ec(last_error,
+            asio::error::get_system_category());
+
+        while ((op = impl->op_queue_.front()) != 0)
+        {
+          op->ec_ = ec;
+          impl->op_queue_.pop();
+          completed_ops.push(op);
+        }
+      }
+    }
+
+    scheduler_impl& sched = impl->owner_->scheduler_;
+    lock.unlock();
+    sched.post_deferred_completions(completed_ops);
+  }
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_WINDOWS_OBJECT_HANDLE)
+
+#endif // ASIO_DETAIL_IMPL_WIN_OBJECT_HANDLE_SERVICE_IPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/impl/win_static_mutex.ipp b/link/modules/asio-standalone/asio/include/asio/detail/impl/win_static_mutex.ipp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/impl/win_static_mutex.ipp
@@ -0,0 +1,136 @@
+//
+// detail/impl/win_static_mutex.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_IMPL_WIN_STATIC_MUTEX_IPP
+#define ASIO_DETAIL_IMPL_WIN_STATIC_MUTEX_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_WINDOWS)
+
+#include <cstdio>
+#include "asio/detail/throw_error.hpp"
+#include "asio/detail/win_static_mutex.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+void win_static_mutex::init()
+{
+  int error = do_init();
+  asio::error_code ec(error,
+      asio::error::get_system_category());
+  asio::detail::throw_error(ec, "static_mutex");
+}
+
+int win_static_mutex::do_init()
+{
+  using namespace std; // For sprintf.
+  wchar_t mutex_name[128];
+#if defined(ASIO_HAS_SECURE_RTL)
+  swprintf_s(
+#else // defined(ASIO_HAS_SECURE_RTL)
+  _snwprintf(
+#endif // defined(ASIO_HAS_SECURE_RTL)
+      mutex_name, 128, L"asio-58CCDC44-6264-4842-90C2-F3C545CB8AA7-%u-%p",
+      static_cast<unsigned int>(::GetCurrentProcessId()), this);
+
+#if defined(ASIO_WINDOWS_APP)
+  HANDLE mutex = ::CreateMutexExW(0, mutex_name, CREATE_MUTEX_INITIAL_OWNER, 0);
+#else // defined(ASIO_WINDOWS_APP)
+  HANDLE mutex = ::CreateMutexW(0, TRUE, mutex_name);
+#endif // defined(ASIO_WINDOWS_APP)
+  DWORD last_error = ::GetLastError();
+  if (mutex == 0)
+    return ::GetLastError();
+
+  if (last_error == ERROR_ALREADY_EXISTS)
+  {
+#if defined(ASIO_WINDOWS_APP)
+    ::WaitForSingleObjectEx(mutex, INFINITE, false);
+#else // defined(ASIO_WINDOWS_APP)
+    ::WaitForSingleObject(mutex, INFINITE);
+#endif // defined(ASIO_WINDOWS_APP)
+  }
+
+  if (initialised_)
+  {
+    ::ReleaseMutex(mutex);
+    ::CloseHandle(mutex);
+    return 0;
+  }
+
+#if defined(__MINGW32__)
+  // Not sure if MinGW supports structured exception handling, so for now
+  // we'll just call the Windows API and hope.
+# if defined(UNDER_CE)
+  ::InitializeCriticalSection(&crit_section_);
+# else
+  if (!::InitializeCriticalSectionAndSpinCount(&crit_section_, 0x80000000))
+  {
+    last_error = ::GetLastError();
+    ::ReleaseMutex(mutex);
+    ::CloseHandle(mutex);
+    return last_error;
+  }
+# endif
+#else
+  __try
+  {
+# if defined(UNDER_CE)
+    ::InitializeCriticalSection(&crit_section_);
+# elif defined(ASIO_WINDOWS_APP)
+    if (!::InitializeCriticalSectionEx(&crit_section_, 0, 0))
+    {
+      last_error = ::GetLastError();
+      ::ReleaseMutex(mutex);
+      ::CloseHandle(mutex);
+      return last_error;
+    }
+# else
+    if (!::InitializeCriticalSectionAndSpinCount(&crit_section_, 0x80000000))
+    {
+      last_error = ::GetLastError();
+      ::ReleaseMutex(mutex);
+      ::CloseHandle(mutex);
+      return last_error;
+    }
+# endif
+  }
+  __except(GetExceptionCode() == STATUS_NO_MEMORY
+      ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
+  {
+    ::ReleaseMutex(mutex);
+    ::CloseHandle(mutex);
+    return ERROR_OUTOFMEMORY;
+  }
+#endif
+
+  initialised_ = true;
+  ::ReleaseMutex(mutex);
+  ::CloseHandle(mutex);
+  return 0;
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_WINDOWS)
+
+#endif // ASIO_DETAIL_IMPL_WIN_STATIC_MUTEX_IPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/impl/win_thread.ipp b/link/modules/asio-standalone/asio/include/asio/detail/impl/win_thread.ipp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/impl/win_thread.ipp
@@ -0,0 +1,150 @@
+//
+// detail/impl/win_thread.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_IMPL_WIN_THREAD_IPP
+#define ASIO_DETAIL_IMPL_WIN_THREAD_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_WINDOWS) \
+  && !defined(ASIO_WINDOWS_APP) \
+  && !defined(UNDER_CE)
+
+#include <process.h>
+#include "asio/detail/throw_error.hpp"
+#include "asio/detail/win_thread.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+win_thread::~win_thread()
+{
+  ::CloseHandle(thread_);
+
+  // The exit_event_ handle is deliberately allowed to leak here since it
+  // is an error for the owner of an internal thread not to join() it.
+}
+
+void win_thread::join()
+{
+  HANDLE handles[2] = { exit_event_, thread_ };
+  ::WaitForMultipleObjects(2, handles, FALSE, INFINITE);
+  ::CloseHandle(exit_event_);
+  if (terminate_threads())
+  {
+    ::TerminateThread(thread_, 0);
+  }
+  else
+  {
+    ::QueueUserAPC(apc_function, thread_, 0);
+    ::WaitForSingleObject(thread_, INFINITE);
+  }
+}
+
+std::size_t win_thread::hardware_concurrency()
+{
+  SYSTEM_INFO system_info;
+  ::GetSystemInfo(&system_info);
+  return system_info.dwNumberOfProcessors;
+}
+
+void win_thread::start_thread(func_base* arg, unsigned int stack_size)
+{
+  ::HANDLE entry_event = 0;
+  arg->entry_event_ = entry_event = ::CreateEventW(0, true, false, 0);
+  if (!entry_event)
+  {
+    DWORD last_error = ::GetLastError();
+    delete arg;
+    asio::error_code ec(last_error,
+        asio::error::get_system_category());
+    asio::detail::throw_error(ec, "thread.entry_event");
+  }
+
+  arg->exit_event_ = exit_event_ = ::CreateEventW(0, true, false, 0);
+  if (!exit_event_)
+  {
+    DWORD last_error = ::GetLastError();
+    delete arg;
+    asio::error_code ec(last_error,
+        asio::error::get_system_category());
+    asio::detail::throw_error(ec, "thread.exit_event");
+  }
+
+  unsigned int thread_id = 0;
+  thread_ = reinterpret_cast<HANDLE>(::_beginthreadex(0,
+        stack_size, win_thread_function, arg, 0, &thread_id));
+  if (!thread_)
+  {
+    DWORD last_error = ::GetLastError();
+    delete arg;
+    if (entry_event)
+      ::CloseHandle(entry_event);
+    if (exit_event_)
+      ::CloseHandle(exit_event_);
+    asio::error_code ec(last_error,
+        asio::error::get_system_category());
+    asio::detail::throw_error(ec, "thread");
+  }
+
+  if (entry_event)
+  {
+    ::WaitForSingleObject(entry_event, INFINITE);
+    ::CloseHandle(entry_event);
+  }
+}
+
+unsigned int __stdcall win_thread_function(void* arg)
+{
+  win_thread::auto_func_base_ptr func = {
+      static_cast<win_thread::func_base*>(arg) };
+
+  ::SetEvent(func.ptr->entry_event_);
+
+  func.ptr->run();
+
+  // Signal that the thread has finished its work, but rather than returning go
+  // to sleep to put the thread into a well known state. If the thread is being
+  // joined during global object destruction then it may be killed using
+  // TerminateThread (to avoid a deadlock in DllMain). Otherwise, the SleepEx
+  // call will be interrupted using QueueUserAPC and the thread will shut down
+  // cleanly.
+  HANDLE exit_event = func.ptr->exit_event_;
+  delete func.ptr;
+  func.ptr = 0;
+  ::SetEvent(exit_event);
+  ::SleepEx(INFINITE, TRUE);
+
+  return 0;
+}
+
+#if defined(WINVER) && (WINVER < 0x0500)
+void __stdcall apc_function(ULONG) {}
+#else
+void __stdcall apc_function(ULONG_PTR) {}
+#endif
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_WINDOWS)
+       // && !defined(ASIO_WINDOWS_APP)
+       // && !defined(UNDER_CE)
+
+#endif // ASIO_DETAIL_IMPL_WIN_THREAD_IPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/impl/win_tss_ptr.ipp b/link/modules/asio-standalone/asio/include/asio/detail/impl/win_tss_ptr.ipp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/impl/win_tss_ptr.ipp
@@ -0,0 +1,57 @@
+//
+// detail/impl/win_tss_ptr.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_IMPL_WIN_TSS_PTR_IPP
+#define ASIO_DETAIL_IMPL_WIN_TSS_PTR_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_WINDOWS)
+
+#include "asio/detail/throw_error.hpp"
+#include "asio/detail/win_tss_ptr.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+DWORD win_tss_ptr_create()
+{
+#if defined(UNDER_CE)
+  const DWORD out_of_indexes = 0xFFFFFFFF;
+#else
+  const DWORD out_of_indexes = TLS_OUT_OF_INDEXES;
+#endif
+
+  DWORD tss_key = ::TlsAlloc();
+  if (tss_key == out_of_indexes)
+  {
+    DWORD last_error = ::GetLastError();
+    asio::error_code ec(last_error,
+        asio::error::get_system_category());
+    asio::detail::throw_error(ec, "tss");
+  }
+  return tss_key;
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_WINDOWS)
+
+#endif // ASIO_DETAIL_IMPL_WIN_TSS_PTR_IPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/impl/winrt_ssocket_service_base.ipp b/link/modules/asio-standalone/asio/include/asio/detail/impl/winrt_ssocket_service_base.ipp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/impl/winrt_ssocket_service_base.ipp
@@ -0,0 +1,626 @@
+//
+// detail/impl/winrt_ssocket_service_base.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_IMPL_WINRT_SSOCKET_SERVICE_BASE_IPP
+#define ASIO_DETAIL_IMPL_WINRT_SSOCKET_SERVICE_BASE_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_WINDOWS_RUNTIME)
+
+#include <cstring>
+#include "asio/detail/winrt_ssocket_service_base.hpp"
+#include "asio/detail/winrt_async_op.hpp"
+#include "asio/detail/winrt_utils.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+winrt_ssocket_service_base::winrt_ssocket_service_base(
+    execution_context& context)
+  : scheduler_(use_service<scheduler_impl>(context)),
+    async_manager_(use_service<winrt_async_manager>(context)),
+    mutex_(),
+    impl_list_(0)
+{
+}
+
+void winrt_ssocket_service_base::base_shutdown()
+{
+  // Close all implementations, causing all operations to complete.
+  asio::detail::mutex::scoped_lock lock(mutex_);
+  base_implementation_type* impl = impl_list_;
+  while (impl)
+  {
+    asio::error_code ignored_ec;
+    close(*impl, ignored_ec);
+    impl = impl->next_;
+  }
+}
+
+void winrt_ssocket_service_base::construct(
+    winrt_ssocket_service_base::base_implementation_type& impl)
+{
+  // Insert implementation into linked list of all implementations.
+  asio::detail::mutex::scoped_lock lock(mutex_);
+  impl.next_ = impl_list_;
+  impl.prev_ = 0;
+  if (impl_list_)
+    impl_list_->prev_ = &impl;
+  impl_list_ = &impl;
+}
+
+void winrt_ssocket_service_base::base_move_construct(
+    winrt_ssocket_service_base::base_implementation_type& impl,
+    winrt_ssocket_service_base::base_implementation_type& other_impl)
+  ASIO_NOEXCEPT
+{
+  impl.socket_ = other_impl.socket_;
+  other_impl.socket_ = nullptr;
+
+  // Insert implementation into linked list of all implementations.
+  asio::detail::mutex::scoped_lock lock(mutex_);
+  impl.next_ = impl_list_;
+  impl.prev_ = 0;
+  if (impl_list_)
+    impl_list_->prev_ = &impl;
+  impl_list_ = &impl;
+}
+
+void winrt_ssocket_service_base::base_move_assign(
+    winrt_ssocket_service_base::base_implementation_type& impl,
+    winrt_ssocket_service_base& other_service,
+    winrt_ssocket_service_base::base_implementation_type& other_impl)
+{
+  asio::error_code ignored_ec;
+  close(impl, ignored_ec);
+
+  if (this != &other_service)
+  {
+    // Remove implementation from linked list of all implementations.
+    asio::detail::mutex::scoped_lock lock(mutex_);
+    if (impl_list_ == &impl)
+      impl_list_ = impl.next_;
+    if (impl.prev_)
+      impl.prev_->next_ = impl.next_;
+    if (impl.next_)
+      impl.next_->prev_= impl.prev_;
+    impl.next_ = 0;
+    impl.prev_ = 0;
+  }
+
+  impl.socket_ = other_impl.socket_;
+  other_impl.socket_ = nullptr;
+
+  if (this != &other_service)
+  {
+    // Insert implementation into linked list of all implementations.
+    asio::detail::mutex::scoped_lock lock(other_service.mutex_);
+    impl.next_ = other_service.impl_list_;
+    impl.prev_ = 0;
+    if (other_service.impl_list_)
+      other_service.impl_list_->prev_ = &impl;
+    other_service.impl_list_ = &impl;
+  }
+}
+
+void winrt_ssocket_service_base::destroy(
+    winrt_ssocket_service_base::base_implementation_type& impl)
+{
+  asio::error_code ignored_ec;
+  close(impl, ignored_ec);
+
+  // Remove implementation from linked list of all implementations.
+  asio::detail::mutex::scoped_lock lock(mutex_);
+  if (impl_list_ == &impl)
+    impl_list_ = impl.next_;
+  if (impl.prev_)
+    impl.prev_->next_ = impl.next_;
+  if (impl.next_)
+    impl.next_->prev_= impl.prev_;
+  impl.next_ = 0;
+  impl.prev_ = 0;
+}
+
+asio::error_code winrt_ssocket_service_base::close(
+    winrt_ssocket_service_base::base_implementation_type& impl,
+    asio::error_code& ec)
+{
+  delete impl.socket_;
+  impl.socket_ = nullptr;
+  ec = asio::error_code();
+  return ec;
+}
+
+winrt_ssocket_service_base::native_handle_type
+winrt_ssocket_service_base::release(
+    winrt_ssocket_service_base::base_implementation_type& impl,
+    asio::error_code& ec)
+{
+  if (!is_open(impl))
+    return nullptr;
+
+  cancel(impl, ec);
+  if (ec)
+    return nullptr;
+
+  native_handle_type tmp = impl.socket_;
+  impl.socket_ = nullptr;
+  return tmp;
+}
+
+std::size_t winrt_ssocket_service_base::do_get_endpoint(
+    const base_implementation_type& impl, bool local,
+    void* addr, std::size_t addr_len, asio::error_code& ec) const
+{
+  if (!is_open(impl))
+  {
+    ec = asio::error::bad_descriptor;
+    return addr_len;
+  }
+
+  try
+  {
+    std::string addr_string = winrt_utils::string(local
+        ? impl.socket_->Information->LocalAddress->CanonicalName
+        : impl.socket_->Information->RemoteAddress->CanonicalName);
+    unsigned short port = winrt_utils::integer(local
+        ? impl.socket_->Information->LocalPort
+        : impl.socket_->Information->RemotePort);
+    unsigned long scope = 0;
+
+    switch (reinterpret_cast<const socket_addr_type*>(addr)->sa_family)
+    {
+    case ASIO_OS_DEF(AF_INET):
+      if (addr_len < sizeof(sockaddr_in4_type))
+      {
+        ec = asio::error::invalid_argument;
+        return addr_len;
+      }
+      else
+      {
+        socket_ops::inet_pton(ASIO_OS_DEF(AF_INET), addr_string.c_str(),
+            &reinterpret_cast<sockaddr_in4_type*>(addr)->sin_addr, &scope, ec);
+        reinterpret_cast<sockaddr_in4_type*>(addr)->sin_port
+          = socket_ops::host_to_network_short(port);
+        ec = asio::error_code();
+        return sizeof(sockaddr_in4_type);
+      }
+    case ASIO_OS_DEF(AF_INET6):
+      if (addr_len < sizeof(sockaddr_in6_type))
+      {
+        ec = asio::error::invalid_argument;
+        return addr_len;
+      }
+      else
+      {
+        socket_ops::inet_pton(ASIO_OS_DEF(AF_INET6), addr_string.c_str(),
+            &reinterpret_cast<sockaddr_in6_type*>(addr)->sin6_addr, &scope, ec);
+        reinterpret_cast<sockaddr_in6_type*>(addr)->sin6_port
+          = socket_ops::host_to_network_short(port);
+        ec = asio::error_code();
+        return sizeof(sockaddr_in6_type);
+      }
+    default:
+      ec = asio::error::address_family_not_supported;
+      return addr_len;
+    }
+  }
+  catch (Platform::Exception^ e)
+  {
+    ec = asio::error_code(e->HResult,
+        asio::system_category());
+    return addr_len;
+  }
+}
+
+asio::error_code winrt_ssocket_service_base::do_set_option(
+    winrt_ssocket_service_base::base_implementation_type& impl,
+    int level, int optname, const void* optval,
+    std::size_t optlen, asio::error_code& ec)
+{
+  if (!is_open(impl))
+  {
+    ec = asio::error::bad_descriptor;
+    return ec;
+  }
+
+  try
+  {
+    if (level == ASIO_OS_DEF(SOL_SOCKET)
+        && optname == ASIO_OS_DEF(SO_KEEPALIVE))
+    {
+      if (optlen == sizeof(int))
+      {
+        int value = 0;
+        std::memcpy(&value, optval, optlen);
+        impl.socket_->Control->KeepAlive = !!value;
+        ec = asio::error_code();
+      }
+      else
+      {
+        ec = asio::error::invalid_argument;
+      }
+    }
+    else if (level == ASIO_OS_DEF(IPPROTO_TCP)
+        && optname == ASIO_OS_DEF(TCP_NODELAY))
+    {
+      if (optlen == sizeof(int))
+      {
+        int value = 0;
+        std::memcpy(&value, optval, optlen);
+        impl.socket_->Control->NoDelay = !!value;
+        ec = asio::error_code();
+      }
+      else
+      {
+        ec = asio::error::invalid_argument;
+      }
+    }
+    else
+    {
+      ec = asio::error::invalid_argument;
+    }
+  }
+  catch (Platform::Exception^ e)
+  {
+    ec = asio::error_code(e->HResult,
+        asio::system_category());
+  }
+
+  return ec;
+}
+
+void winrt_ssocket_service_base::do_get_option(
+    const winrt_ssocket_service_base::base_implementation_type& impl,
+    int level, int optname, void* optval,
+    std::size_t* optlen, asio::error_code& ec) const
+{
+  if (!is_open(impl))
+  {
+    ec = asio::error::bad_descriptor;
+    return;
+  }
+
+  try
+  {
+    if (level == ASIO_OS_DEF(SOL_SOCKET)
+        && optname == ASIO_OS_DEF(SO_KEEPALIVE))
+    {
+      if (*optlen >= sizeof(int))
+      {
+        int value = impl.socket_->Control->KeepAlive ? 1 : 0;
+        std::memcpy(optval, &value, sizeof(int));
+        *optlen = sizeof(int);
+        ec = asio::error_code();
+      }
+      else
+      {
+        ec = asio::error::invalid_argument;
+      }
+    }
+    else if (level == ASIO_OS_DEF(IPPROTO_TCP)
+        && optname == ASIO_OS_DEF(TCP_NODELAY))
+    {
+      if (*optlen >= sizeof(int))
+      {
+        int value = impl.socket_->Control->NoDelay ? 1 : 0;
+        std::memcpy(optval, &value, sizeof(int));
+        *optlen = sizeof(int);
+        ec = asio::error_code();
+      }
+      else
+      {
+        ec = asio::error::invalid_argument;
+      }
+    }
+    else
+    {
+      ec = asio::error::invalid_argument;
+    }
+  }
+  catch (Platform::Exception^ e)
+  {
+    ec = asio::error_code(e->HResult,
+        asio::system_category());
+  }
+}
+
+asio::error_code winrt_ssocket_service_base::do_connect(
+    winrt_ssocket_service_base::base_implementation_type& impl,
+    const void* addr, asio::error_code& ec)
+{
+  if (!is_open(impl))
+  {
+    ec = asio::error::bad_descriptor;
+    return ec;
+  }
+
+  char addr_string[max_addr_v6_str_len];
+  unsigned short port;
+  switch (reinterpret_cast<const socket_addr_type*>(addr)->sa_family)
+  {
+  case ASIO_OS_DEF(AF_INET):
+    socket_ops::inet_ntop(ASIO_OS_DEF(AF_INET),
+        &reinterpret_cast<const sockaddr_in4_type*>(addr)->sin_addr,
+        addr_string, sizeof(addr_string), 0, ec);
+    port = socket_ops::network_to_host_short(
+        reinterpret_cast<const sockaddr_in4_type*>(addr)->sin_port);
+    break;
+  case ASIO_OS_DEF(AF_INET6):
+    socket_ops::inet_ntop(ASIO_OS_DEF(AF_INET6),
+        &reinterpret_cast<const sockaddr_in6_type*>(addr)->sin6_addr,
+        addr_string, sizeof(addr_string), 0, ec);
+    port = socket_ops::network_to_host_short(
+        reinterpret_cast<const sockaddr_in6_type*>(addr)->sin6_port);
+    break;
+  default:
+    ec = asio::error::address_family_not_supported;
+    return ec;
+  }
+
+  if (!ec) try
+  {
+    async_manager_.sync(impl.socket_->ConnectAsync(
+          ref new Windows::Networking::HostName(
+            winrt_utils::string(addr_string)),
+          winrt_utils::string(port)), ec);
+  }
+  catch (Platform::Exception^ e)
+  {
+    ec = asio::error_code(e->HResult,
+        asio::system_category());
+  }
+
+  return ec;
+}
+
+void winrt_ssocket_service_base::start_connect_op(
+    winrt_ssocket_service_base::base_implementation_type& impl,
+    const void* addr, winrt_async_op<void>* op, bool is_continuation)
+{
+  if (!is_open(impl))
+  {
+    op->ec_ = asio::error::bad_descriptor;
+    scheduler_.post_immediate_completion(op, is_continuation);
+    return;
+  }
+
+  char addr_string[max_addr_v6_str_len];
+  unsigned short port = 0;
+  switch (reinterpret_cast<const socket_addr_type*>(addr)->sa_family)
+  {
+  case ASIO_OS_DEF(AF_INET):
+    socket_ops::inet_ntop(ASIO_OS_DEF(AF_INET),
+        &reinterpret_cast<const sockaddr_in4_type*>(addr)->sin_addr,
+        addr_string, sizeof(addr_string), 0, op->ec_);
+    port = socket_ops::network_to_host_short(
+        reinterpret_cast<const sockaddr_in4_type*>(addr)->sin_port);
+    break;
+  case ASIO_OS_DEF(AF_INET6):
+    socket_ops::inet_ntop(ASIO_OS_DEF(AF_INET6),
+        &reinterpret_cast<const sockaddr_in6_type*>(addr)->sin6_addr,
+        addr_string, sizeof(addr_string), 0, op->ec_);
+    port = socket_ops::network_to_host_short(
+        reinterpret_cast<const sockaddr_in6_type*>(addr)->sin6_port);
+    break;
+  default:
+    op->ec_ = asio::error::address_family_not_supported;
+    break;
+  }
+
+  if (op->ec_)
+  {
+    scheduler_.post_immediate_completion(op, is_continuation);
+    return;
+  }
+
+  try
+  {
+    async_manager_.async(impl.socket_->ConnectAsync(
+          ref new Windows::Networking::HostName(
+            winrt_utils::string(addr_string)),
+          winrt_utils::string(port)), op);
+  }
+  catch (Platform::Exception^ e)
+  {
+    op->ec_ = asio::error_code(
+        e->HResult, asio::system_category());
+    scheduler_.post_immediate_completion(op, is_continuation);
+  }
+}
+
+std::size_t winrt_ssocket_service_base::do_send(
+    winrt_ssocket_service_base::base_implementation_type& impl,
+    const asio::const_buffer& data,
+    socket_base::message_flags flags, asio::error_code& ec)
+{
+  if (flags)
+  {
+    ec = asio::error::operation_not_supported;
+    return 0;
+  }
+
+  if (!is_open(impl))
+  {
+    ec = asio::error::bad_descriptor;
+    return 0;
+  }
+
+  try
+  {
+    buffer_sequence_adapter<asio::const_buffer,
+      asio::const_buffer> bufs(asio::buffer(data));
+
+    if (bufs.all_empty())
+    {
+      ec = asio::error_code();
+      return 0;
+    }
+
+    return async_manager_.sync(
+        impl.socket_->OutputStream->WriteAsync(bufs.buffers()[0]), ec);
+  }
+  catch (Platform::Exception^ e)
+  {
+    ec = asio::error_code(e->HResult,
+        asio::system_category());
+    return 0;
+  }
+}
+
+void winrt_ssocket_service_base::start_send_op(
+      winrt_ssocket_service_base::base_implementation_type& impl,
+      const asio::const_buffer& data, socket_base::message_flags flags,
+      winrt_async_op<unsigned int>* op, bool is_continuation)
+{
+  if (flags)
+  {
+    op->ec_ = asio::error::operation_not_supported;
+    scheduler_.post_immediate_completion(op, is_continuation);
+    return;
+  }
+
+  if (!is_open(impl))
+  {
+    op->ec_ = asio::error::bad_descriptor;
+    scheduler_.post_immediate_completion(op, is_continuation);
+    return;
+  }
+
+  try
+  {
+    buffer_sequence_adapter<asio::const_buffer,
+        asio::const_buffer> bufs(asio::buffer(data));
+
+    if (bufs.all_empty())
+    {
+      scheduler_.post_immediate_completion(op, is_continuation);
+      return;
+    }
+
+    async_manager_.async(
+        impl.socket_->OutputStream->WriteAsync(bufs.buffers()[0]), op);
+  }
+  catch (Platform::Exception^ e)
+  {
+    op->ec_ = asio::error_code(e->HResult,
+        asio::system_category());
+    scheduler_.post_immediate_completion(op, is_continuation);
+  }
+}
+
+std::size_t winrt_ssocket_service_base::do_receive(
+    winrt_ssocket_service_base::base_implementation_type& impl,
+    const asio::mutable_buffer& data,
+    socket_base::message_flags flags, asio::error_code& ec)
+{
+  if (flags)
+  {
+    ec = asio::error::operation_not_supported;
+    return 0;
+  }
+
+  if (!is_open(impl))
+  {
+    ec = asio::error::bad_descriptor;
+    return 0;
+  }
+
+  try
+  {
+    buffer_sequence_adapter<asio::mutable_buffer,
+        asio::mutable_buffer> bufs(asio::buffer(data));
+
+    if (bufs.all_empty())
+    {
+      ec = asio::error_code();
+      return 0;
+    }
+
+    async_manager_.sync(
+        impl.socket_->InputStream->ReadAsync(
+          bufs.buffers()[0], bufs.buffers()[0]->Capacity,
+          Windows::Storage::Streams::InputStreamOptions::Partial), ec);
+
+    std::size_t bytes_transferred = bufs.buffers()[0]->Length;
+    if (bytes_transferred == 0 && !ec)
+    {
+      ec = asio::error::eof;
+    }
+
+    return bytes_transferred;
+  }
+  catch (Platform::Exception^ e)
+  {
+    ec = asio::error_code(e->HResult,
+        asio::system_category());
+    return 0;
+  }
+}
+
+void winrt_ssocket_service_base::start_receive_op(
+      winrt_ssocket_service_base::base_implementation_type& impl,
+      const asio::mutable_buffer& data, socket_base::message_flags flags,
+      winrt_async_op<Windows::Storage::Streams::IBuffer^>* op,
+      bool is_continuation)
+{
+  if (flags)
+  {
+    op->ec_ = asio::error::operation_not_supported;
+    scheduler_.post_immediate_completion(op, is_continuation);
+    return;
+  }
+
+  if (!is_open(impl))
+  {
+    op->ec_ = asio::error::bad_descriptor;
+    scheduler_.post_immediate_completion(op, is_continuation);
+    return;
+  }
+
+  try
+  {
+    buffer_sequence_adapter<asio::mutable_buffer,
+        asio::mutable_buffer> bufs(asio::buffer(data));
+
+    if (bufs.all_empty())
+    {
+      scheduler_.post_immediate_completion(op, is_continuation);
+      return;
+    }
+
+    async_manager_.async(
+        impl.socket_->InputStream->ReadAsync(
+          bufs.buffers()[0], bufs.buffers()[0]->Capacity,
+          Windows::Storage::Streams::InputStreamOptions::Partial), op);
+  }
+  catch (Platform::Exception^ e)
+  {
+    op->ec_ = asio::error_code(e->HResult,
+        asio::system_category());
+    scheduler_.post_immediate_completion(op, is_continuation);
+  }
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_WINDOWS_RUNTIME)
+
+#endif // ASIO_DETAIL_IMPL_WINRT_SSOCKET_SERVICE_BASE_IPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/impl/winrt_timer_scheduler.hpp b/link/modules/asio-standalone/asio/include/asio/detail/impl/winrt_timer_scheduler.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/impl/winrt_timer_scheduler.hpp
@@ -0,0 +1,92 @@
+//
+// detail/impl/winrt_timer_scheduler.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_IMPL_WINRT_TIMER_SCHEDULER_HPP
+#define ASIO_DETAIL_IMPL_WINRT_TIMER_SCHEDULER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_WINDOWS_RUNTIME)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Time_Traits>
+void winrt_timer_scheduler::add_timer_queue(timer_queue<Time_Traits>& queue)
+{
+  do_add_timer_queue(queue);
+}
+
+// Remove a timer queue from the reactor.
+template <typename Time_Traits>
+void winrt_timer_scheduler::remove_timer_queue(timer_queue<Time_Traits>& queue)
+{
+  do_remove_timer_queue(queue);
+}
+
+template <typename Time_Traits>
+void winrt_timer_scheduler::schedule_timer(timer_queue<Time_Traits>& queue,
+    const typename Time_Traits::time_type& time,
+    typename timer_queue<Time_Traits>::per_timer_data& timer, wait_op* op)
+{
+  asio::detail::mutex::scoped_lock lock(mutex_);
+
+  if (shutdown_)
+  {
+    scheduler_.post_immediate_completion(op, false);
+    return;
+  }
+
+  bool earliest = queue.enqueue_timer(time, timer, op);
+  scheduler_.work_started();
+  if (earliest)
+    event_.signal(lock);
+}
+
+template <typename Time_Traits>
+std::size_t winrt_timer_scheduler::cancel_timer(timer_queue<Time_Traits>& queue,
+    typename timer_queue<Time_Traits>::per_timer_data& timer,
+    std::size_t max_cancelled)
+{
+  asio::detail::mutex::scoped_lock lock(mutex_);
+  op_queue<operation> ops;
+  std::size_t n = queue.cancel_timer(timer, ops, max_cancelled);
+  lock.unlock();
+  scheduler_.post_deferred_completions(ops);
+  return n;
+}
+
+template <typename Time_Traits>
+void winrt_timer_scheduler::move_timer(timer_queue<Time_Traits>& queue,
+    typename timer_queue<Time_Traits>::per_timer_data& to,
+    typename timer_queue<Time_Traits>::per_timer_data& from)
+{
+  asio::detail::mutex::scoped_lock lock(mutex_);
+  op_queue<operation> ops;
+  queue.cancel_timer(to, ops);
+  queue.move_timer(to, from);
+  lock.unlock();
+  scheduler_.post_deferred_completions(ops);
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_WINDOWS_RUNTIME)
+
+#endif // ASIO_DETAIL_IMPL_WINRT_TIMER_SCHEDULER_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/impl/winrt_timer_scheduler.ipp b/link/modules/asio-standalone/asio/include/asio/detail/impl/winrt_timer_scheduler.ipp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/impl/winrt_timer_scheduler.ipp
@@ -0,0 +1,121 @@
+//
+// detail/impl/winrt_timer_scheduler.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_IMPL_WINRT_TIMER_SCHEDULER_IPP
+#define ASIO_DETAIL_IMPL_WINRT_TIMER_SCHEDULER_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_WINDOWS_RUNTIME)
+
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/winrt_timer_scheduler.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+winrt_timer_scheduler::winrt_timer_scheduler(execution_context& context)
+  : execution_context_service_base<winrt_timer_scheduler>(context),
+    scheduler_(use_service<scheduler_impl>(context)),
+    mutex_(),
+    event_(),
+    timer_queues_(),
+    thread_(0),
+    stop_thread_(false),
+    shutdown_(false)
+{
+  thread_ = new asio::detail::thread(
+      bind_handler(&winrt_timer_scheduler::call_run_thread, this));
+}
+
+winrt_timer_scheduler::~winrt_timer_scheduler()
+{
+  shutdown();
+}
+
+void winrt_timer_scheduler::shutdown()
+{
+  asio::detail::mutex::scoped_lock lock(mutex_);
+  shutdown_ = true;
+  stop_thread_ = true;
+  event_.signal(lock);
+  lock.unlock();
+
+  if (thread_)
+  {
+    thread_->join();
+    delete thread_;
+    thread_ = 0;
+  }
+
+  op_queue<operation> ops;
+  timer_queues_.get_all_timers(ops);
+  scheduler_.abandon_operations(ops);
+}
+
+void winrt_timer_scheduler::notify_fork(execution_context::fork_event)
+{
+}
+
+void winrt_timer_scheduler::init_task()
+{
+}
+
+void winrt_timer_scheduler::run_thread()
+{
+  asio::detail::mutex::scoped_lock lock(mutex_);
+  while (!stop_thread_)
+  {
+    const long max_wait_duration = 5 * 60 * 1000000;
+    long wait_duration = timer_queues_.wait_duration_usec(max_wait_duration);
+    event_.wait_for_usec(lock, wait_duration);
+    event_.clear(lock);
+    op_queue<operation> ops;
+    timer_queues_.get_ready_timers(ops);
+    if (!ops.empty())
+    {
+      lock.unlock();
+      scheduler_.post_deferred_completions(ops);
+      lock.lock();
+    }
+  }
+}
+
+void winrt_timer_scheduler::call_run_thread(winrt_timer_scheduler* scheduler)
+{
+  scheduler->run_thread();
+}
+
+void winrt_timer_scheduler::do_add_timer_queue(timer_queue_base& queue)
+{
+  mutex::scoped_lock lock(mutex_);
+  timer_queues_.insert(&queue);
+}
+
+void winrt_timer_scheduler::do_remove_timer_queue(timer_queue_base& queue)
+{
+  mutex::scoped_lock lock(mutex_);
+  timer_queues_.erase(&queue);
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_WINDOWS_RUNTIME)
+
+#endif // ASIO_DETAIL_IMPL_WINRT_TIMER_SCHEDULER_IPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/impl/winsock_init.ipp b/link/modules/asio-standalone/asio/include/asio/detail/impl/winsock_init.ipp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/impl/winsock_init.ipp
@@ -0,0 +1,82 @@
+//
+// detail/impl/winsock_init.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_IMPL_WINSOCK_INIT_IPP
+#define ASIO_DETAIL_IMPL_WINSOCK_INIT_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+
+#include "asio/detail/socket_types.hpp"
+#include "asio/detail/winsock_init.hpp"
+#include "asio/detail/throw_error.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+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::manual_startup(data& d)
+{
+  if (::InterlockedIncrement(&d.init_count_) == 1)
+  {
+    ::InterlockedExchange(&d.result_, 0);
+  }
+}
+
+void winsock_init_base::cleanup(data& d)
+{
+  if (::InterlockedDecrement(&d.init_count_) == 0)
+  {
+    ::WSACleanup();
+  }
+}
+
+void winsock_init_base::manual_cleanup(data& d)
+{
+  ::InterlockedDecrement(&d.init_count_);
+}
+
+void winsock_init_base::throw_on_error(data& d)
+{
+  long result = ::InterlockedExchangeAdd(&d.result_, 0);
+  if (result != 0)
+  {
+    asio::error_code ec(result,
+        asio::error::get_system_category());
+    asio::detail::throw_error(ec, "winsock");
+  }
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+
+#endif // ASIO_DETAIL_IMPL_WINSOCK_INIT_IPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/io_control.hpp b/link/modules/asio-standalone/asio/include/asio/detail/io_control.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/io_control.hpp
@@ -0,0 +1,84 @@
+//
+// detail/io_control.hpp
+// ~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_IO_CONTROL_HPP
+#define ASIO_DETAIL_IO_CONTROL_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <cstddef>
+#include "asio/detail/socket_types.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+namespace io_control {
+
+// I/O control command for getting number of bytes available.
+class bytes_readable
+{
+public:
+  // Default constructor.
+  bytes_readable()
+    : value_(0)
+  {
+  }
+
+  // Construct with a specific command value.
+  bytes_readable(std::size_t value)
+    : value_(static_cast<detail::ioctl_arg_type>(value))
+  {
+  }
+
+  // Get the name of the IO control command.
+  int name() const
+  {
+    return static_cast<int>(ASIO_OS_DEF(FIONREAD));
+  }
+
+  // Set the value of the I/O control command.
+  void set(std::size_t value)
+  {
+    value_ = static_cast<detail::ioctl_arg_type>(value);
+  }
+
+  // Get the current value of the I/O control command.
+  std::size_t get() const
+  {
+    return static_cast<std::size_t>(value_);
+  }
+
+  // Get the address of the command data.
+  detail::ioctl_arg_type* data()
+  {
+    return &value_;
+  }
+
+  // Get the address of the command data.
+  const detail::ioctl_arg_type* data() const
+  {
+    return &value_;
+  }
+
+private:
+  detail::ioctl_arg_type value_;
+};
+
+} // namespace io_control
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_IO_CONTROL_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/io_object_impl.hpp b/link/modules/asio-standalone/asio/include/asio/detail/io_object_impl.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/io_object_impl.hpp
@@ -0,0 +1,175 @@
+//
+// io_object_impl.hpp
+// ~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_IO_OBJECT_IMPL_HPP
+#define ASIO_DETAIL_IO_OBJECT_IMPL_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <new>
+#include "asio/detail/config.hpp"
+#include "asio/detail/type_traits.hpp"
+#include "asio/execution/executor.hpp"
+#include "asio/execution/context.hpp"
+#include "asio/io_context.hpp"
+#include "asio/query.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename IoObjectService,
+    typename Executor = io_context::executor_type>
+class io_object_impl
+{
+public:
+  // The type of the service that will be used to provide I/O operations.
+  typedef IoObjectService service_type;
+
+  // The underlying implementation type of I/O object.
+  typedef typename service_type::implementation_type implementation_type;
+
+  // The type of the executor associated with the object.
+  typedef Executor executor_type;
+
+  // Construct an I/O object using an executor.
+  explicit io_object_impl(const executor_type& ex)
+    : service_(&asio::use_service<IoObjectService>(
+          io_object_impl::get_context(ex))),
+      executor_(ex)
+  {
+    service_->construct(implementation_);
+  }
+
+  // Construct an I/O object using an execution context.
+  template <typename ExecutionContext>
+  explicit io_object_impl(ExecutionContext& context,
+      typename enable_if<is_convertible<
+        ExecutionContext&, execution_context&>::value>::type* = 0)
+    : service_(&asio::use_service<IoObjectService>(context)),
+      executor_(context.get_executor())
+  {
+    service_->construct(implementation_);
+  }
+
+#if defined(ASIO_HAS_MOVE)
+  // Move-construct an I/O object.
+  io_object_impl(io_object_impl&& other)
+    : service_(&other.get_service()),
+      executor_(other.get_executor())
+  {
+    service_->move_construct(implementation_, other.implementation_);
+  }
+
+  // Perform a converting move-construction of an I/O object.
+  template <typename IoObjectService1, typename Executor1>
+  io_object_impl(io_object_impl<IoObjectService1, Executor1>&& other)
+    : service_(&asio::use_service<IoObjectService>(
+            io_object_impl::get_context(other.get_executor()))),
+      executor_(other.get_executor())
+  {
+    service_->converting_move_construct(implementation_,
+        other.get_service(), other.get_implementation());
+  }
+#endif // defined(ASIO_HAS_MOVE)
+
+  // Destructor.
+  ~io_object_impl()
+  {
+    service_->destroy(implementation_);
+  }
+
+#if defined(ASIO_HAS_MOVE)
+  // Move-assign an I/O object.
+  io_object_impl& operator=(io_object_impl&& other)
+  {
+    if (this != &other)
+    {
+      service_->move_assign(implementation_,
+          *other.service_, other.implementation_);
+      executor_.~executor_type();
+      new (&executor_) executor_type(
+          std::move(other.executor_));
+      service_ = other.service_;
+    }
+    return *this;
+  }
+#endif // defined(ASIO_HAS_MOVE)
+
+  // Get the executor associated with the object.
+  const executor_type& get_executor() ASIO_NOEXCEPT
+  {
+    return executor_;
+  }
+
+  // Get the service associated with the I/O object.
+  service_type& get_service()
+  {
+    return *service_;
+  }
+
+  // Get the service associated with the I/O object.
+  const service_type& get_service() const
+  {
+    return *service_;
+  }
+
+  // Get the underlying implementation of the I/O object.
+  implementation_type& get_implementation()
+  {
+    return implementation_;
+  }
+
+  // Get the underlying implementation of the I/O object.
+  const implementation_type& get_implementation() const
+  {
+    return implementation_;
+  }
+
+private:
+  // Helper function to get an executor's context.
+  template <typename T>
+  static execution_context& get_context(const T& t,
+      typename enable_if<execution::is_executor<T>::value>::type* = 0)
+  {
+    return asio::query(t, execution::context);
+  }
+
+  // Helper function to get an executor's context.
+  template <typename T>
+  static execution_context& get_context(const T& t,
+      typename enable_if<!execution::is_executor<T>::value>::type* = 0)
+  {
+    return t.context();
+  }
+
+  // Disallow copying and copy assignment.
+  io_object_impl(const io_object_impl&);
+  io_object_impl& operator=(const io_object_impl&);
+
+  // The service associated with the I/O object.
+  service_type* service_;
+
+  // The underlying implementation of the I/O object.
+  implementation_type implementation_;
+
+  // The associated executor.
+  executor_type executor_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_IO_OBJECT_IMPL_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/is_buffer_sequence.hpp b/link/modules/asio-standalone/asio/include/asio/detail/is_buffer_sequence.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/is_buffer_sequence.hpp
@@ -0,0 +1,312 @@
+//
+// detail/is_buffer_sequence.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_IS_BUFFER_SEQUENCE_HPP
+#define ASIO_DETAIL_IS_BUFFER_SEQUENCE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/type_traits.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+class mutable_buffer;
+class const_buffer;
+
+namespace detail {
+
+struct buffer_sequence_memfns_base
+{
+  void begin();
+  void end();
+  void size();
+  void max_size();
+  void capacity();
+  void data();
+  void prepare();
+  void commit();
+  void consume();
+  void grow();
+  void shrink();
+};
+
+template <typename T>
+struct buffer_sequence_memfns_derived
+  : T, buffer_sequence_memfns_base
+{
+};
+
+template <typename T, T>
+struct buffer_sequence_memfns_check
+{
+};
+
+#if defined(ASIO_HAS_DECLTYPE)
+
+template <typename>
+char buffer_sequence_begin_helper(...);
+
+template <typename T>
+char (&buffer_sequence_begin_helper(T* t,
+    typename enable_if<!is_same<
+      decltype(asio::buffer_sequence_begin(*t)),
+        void>::value>::type*))[2];
+
+#else // defined(ASIO_HAS_DECLTYPE)
+
+template <typename>
+char (&buffer_sequence_begin_helper(...))[2];
+
+template <typename T>
+char buffer_sequence_begin_helper(T* t,
+    buffer_sequence_memfns_check<
+      void (buffer_sequence_memfns_base::*)(),
+      &buffer_sequence_memfns_derived<T>::begin>*);
+
+#endif // defined(ASIO_HAS_DECLTYPE)
+
+#if defined(ASIO_HAS_DECLTYPE)
+
+template <typename>
+char buffer_sequence_end_helper(...);
+
+template <typename T>
+char (&buffer_sequence_end_helper(T* t,
+    typename enable_if<!is_same<
+      decltype(asio::buffer_sequence_end(*t)),
+        void>::value>::type*))[2];
+
+#else // defined(ASIO_HAS_DECLTYPE)
+
+template <typename>
+char (&buffer_sequence_end_helper(...))[2];
+
+template <typename T>
+char buffer_sequence_end_helper(T* t,
+    buffer_sequence_memfns_check<
+      void (buffer_sequence_memfns_base::*)(),
+      &buffer_sequence_memfns_derived<T>::end>*);
+
+#endif // defined(ASIO_HAS_DECLTYPE)
+
+template <typename>
+char (&size_memfn_helper(...))[2];
+
+template <typename T>
+char size_memfn_helper(
+    buffer_sequence_memfns_check<
+      void (buffer_sequence_memfns_base::*)(),
+      &buffer_sequence_memfns_derived<T>::size>*);
+
+template <typename>
+char (&max_size_memfn_helper(...))[2];
+
+template <typename T>
+char max_size_memfn_helper(
+    buffer_sequence_memfns_check<
+      void (buffer_sequence_memfns_base::*)(),
+      &buffer_sequence_memfns_derived<T>::max_size>*);
+
+template <typename>
+char (&capacity_memfn_helper(...))[2];
+
+template <typename T>
+char capacity_memfn_helper(
+    buffer_sequence_memfns_check<
+      void (buffer_sequence_memfns_base::*)(),
+      &buffer_sequence_memfns_derived<T>::capacity>*);
+
+template <typename>
+char (&data_memfn_helper(...))[2];
+
+template <typename T>
+char data_memfn_helper(
+    buffer_sequence_memfns_check<
+      void (buffer_sequence_memfns_base::*)(),
+      &buffer_sequence_memfns_derived<T>::data>*);
+
+template <typename>
+char (&prepare_memfn_helper(...))[2];
+
+template <typename T>
+char prepare_memfn_helper(
+    buffer_sequence_memfns_check<
+      void (buffer_sequence_memfns_base::*)(),
+      &buffer_sequence_memfns_derived<T>::prepare>*);
+
+template <typename>
+char (&commit_memfn_helper(...))[2];
+
+template <typename T>
+char commit_memfn_helper(
+    buffer_sequence_memfns_check<
+      void (buffer_sequence_memfns_base::*)(),
+      &buffer_sequence_memfns_derived<T>::commit>*);
+
+template <typename>
+char (&consume_memfn_helper(...))[2];
+
+template <typename T>
+char consume_memfn_helper(
+    buffer_sequence_memfns_check<
+      void (buffer_sequence_memfns_base::*)(),
+      &buffer_sequence_memfns_derived<T>::consume>*);
+
+template <typename>
+char (&grow_memfn_helper(...))[2];
+
+template <typename T>
+char grow_memfn_helper(
+    buffer_sequence_memfns_check<
+      void (buffer_sequence_memfns_base::*)(),
+      &buffer_sequence_memfns_derived<T>::grow>*);
+
+template <typename>
+char (&shrink_memfn_helper(...))[2];
+
+template <typename T>
+char shrink_memfn_helper(
+    buffer_sequence_memfns_check<
+      void (buffer_sequence_memfns_base::*)(),
+      &buffer_sequence_memfns_derived<T>::shrink>*);
+
+template <typename, typename>
+char (&buffer_sequence_element_type_helper(...))[2];
+
+#if defined(ASIO_HAS_DECLTYPE)
+
+template <typename T, typename Buffer>
+char buffer_sequence_element_type_helper(T* t,
+    typename enable_if<is_convertible<
+      decltype(*asio::buffer_sequence_begin(*t)),
+        Buffer>::value>::type*);
+
+#else // defined(ASIO_HAS_DECLTYPE)
+
+template <typename T, typename Buffer>
+char buffer_sequence_element_type_helper(
+    typename T::const_iterator*,
+    typename enable_if<is_convertible<
+      typename T::value_type, Buffer>::value>::type*);
+
+#endif // defined(ASIO_HAS_DECLTYPE)
+
+template <typename>
+char (&const_buffers_type_typedef_helper(...))[2];
+
+template <typename T>
+char const_buffers_type_typedef_helper(
+    typename T::const_buffers_type*);
+
+template <typename>
+char (&mutable_buffers_type_typedef_helper(...))[2];
+
+template <typename T>
+char mutable_buffers_type_typedef_helper(
+    typename T::mutable_buffers_type*);
+
+template <typename T, typename Buffer>
+struct is_buffer_sequence_class
+  : integral_constant<bool,
+      sizeof(buffer_sequence_begin_helper<T>(0, 0)) != 1 &&
+      sizeof(buffer_sequence_end_helper<T>(0, 0)) != 1 &&
+      sizeof(buffer_sequence_element_type_helper<T, Buffer>(0, 0)) == 1>
+{
+};
+
+template <typename T, typename Buffer>
+struct is_buffer_sequence
+  : conditional<is_class<T>::value,
+      is_buffer_sequence_class<T, Buffer>,
+      false_type>::type
+{
+};
+
+template <>
+struct is_buffer_sequence<mutable_buffer, mutable_buffer>
+  : true_type
+{
+};
+
+template <>
+struct is_buffer_sequence<mutable_buffer, const_buffer>
+  : true_type
+{
+};
+
+template <>
+struct is_buffer_sequence<const_buffer, const_buffer>
+  : true_type
+{
+};
+
+template <>
+struct is_buffer_sequence<const_buffer, mutable_buffer>
+  : false_type
+{
+};
+
+template <typename T>
+struct is_dynamic_buffer_class_v1
+  : integral_constant<bool,
+      sizeof(size_memfn_helper<T>(0)) != 1 &&
+      sizeof(max_size_memfn_helper<T>(0)) != 1 &&
+      sizeof(capacity_memfn_helper<T>(0)) != 1 &&
+      sizeof(data_memfn_helper<T>(0)) != 1 &&
+      sizeof(consume_memfn_helper<T>(0)) != 1 &&
+      sizeof(prepare_memfn_helper<T>(0)) != 1 &&
+      sizeof(commit_memfn_helper<T>(0)) != 1 &&
+      sizeof(const_buffers_type_typedef_helper<T>(0)) == 1 &&
+      sizeof(mutable_buffers_type_typedef_helper<T>(0)) == 1>
+{
+};
+
+template <typename T>
+struct is_dynamic_buffer_v1
+  : conditional<is_class<T>::value,
+      is_dynamic_buffer_class_v1<T>,
+      false_type>::type
+{
+};
+
+template <typename T>
+struct is_dynamic_buffer_class_v2
+  : integral_constant<bool,
+      sizeof(size_memfn_helper<T>(0)) != 1 &&
+      sizeof(max_size_memfn_helper<T>(0)) != 1 &&
+      sizeof(capacity_memfn_helper<T>(0)) != 1 &&
+      sizeof(data_memfn_helper<T>(0)) != 1 &&
+      sizeof(consume_memfn_helper<T>(0)) != 1 &&
+      sizeof(grow_memfn_helper<T>(0)) != 1 &&
+      sizeof(shrink_memfn_helper<T>(0)) != 1 &&
+      sizeof(const_buffers_type_typedef_helper<T>(0)) == 1 &&
+      sizeof(mutable_buffers_type_typedef_helper<T>(0)) == 1>
+{
+};
+
+template <typename T>
+struct is_dynamic_buffer_v2
+  : conditional<is_class<T>::value,
+      is_dynamic_buffer_class_v2<T>,
+      false_type>::type
+{
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_IS_BUFFER_SEQUENCE_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/is_executor.hpp b/link/modules/asio-standalone/asio/include/asio/detail/is_executor.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/is_executor.hpp
@@ -0,0 +1,126 @@
+//
+// detail/is_executor.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_IS_EXECUTOR_HPP
+#define ASIO_DETAIL_IS_EXECUTOR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/type_traits.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+struct executor_memfns_base
+{
+  void context();
+  void on_work_started();
+  void on_work_finished();
+  void dispatch();
+  void post();
+  void defer();
+};
+
+template <typename T>
+struct executor_memfns_derived
+  : T, executor_memfns_base
+{
+};
+
+template <typename T, T>
+struct executor_memfns_check
+{
+};
+
+template <typename>
+char (&context_memfn_helper(...))[2];
+
+template <typename T>
+char context_memfn_helper(
+    executor_memfns_check<
+      void (executor_memfns_base::*)(),
+      &executor_memfns_derived<T>::context>*);
+
+template <typename>
+char (&on_work_started_memfn_helper(...))[2];
+
+template <typename T>
+char on_work_started_memfn_helper(
+    executor_memfns_check<
+      void (executor_memfns_base::*)(),
+      &executor_memfns_derived<T>::on_work_started>*);
+
+template <typename>
+char (&on_work_finished_memfn_helper(...))[2];
+
+template <typename T>
+char on_work_finished_memfn_helper(
+    executor_memfns_check<
+      void (executor_memfns_base::*)(),
+      &executor_memfns_derived<T>::on_work_finished>*);
+
+template <typename>
+char (&dispatch_memfn_helper(...))[2];
+
+template <typename T>
+char dispatch_memfn_helper(
+    executor_memfns_check<
+      void (executor_memfns_base::*)(),
+      &executor_memfns_derived<T>::dispatch>*);
+
+template <typename>
+char (&post_memfn_helper(...))[2];
+
+template <typename T>
+char post_memfn_helper(
+    executor_memfns_check<
+      void (executor_memfns_base::*)(),
+      &executor_memfns_derived<T>::post>*);
+
+template <typename>
+char (&defer_memfn_helper(...))[2];
+
+template <typename T>
+char defer_memfn_helper(
+    executor_memfns_check<
+      void (executor_memfns_base::*)(),
+      &executor_memfns_derived<T>::defer>*);
+
+template <typename T>
+struct is_executor_class
+  : integral_constant<bool,
+      sizeof(context_memfn_helper<T>(0)) != 1 &&
+      sizeof(on_work_started_memfn_helper<T>(0)) != 1 &&
+      sizeof(on_work_finished_memfn_helper<T>(0)) != 1 &&
+      sizeof(dispatch_memfn_helper<T>(0)) != 1 &&
+      sizeof(post_memfn_helper<T>(0)) != 1 &&
+      sizeof(defer_memfn_helper<T>(0)) != 1>
+{
+};
+
+template <typename T>
+struct is_executor
+  : conditional<is_class<T>::value,
+      is_executor_class<T>,
+      false_type>::type
+{
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_IS_EXECUTOR_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/keyword_tss_ptr.hpp b/link/modules/asio-standalone/asio/include/asio/detail/keyword_tss_ptr.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/keyword_tss_ptr.hpp
@@ -0,0 +1,70 @@
+//
+// detail/keyword_tss_ptr.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_KEYWORD_TSS_PTR_HPP
+#define ASIO_DETAIL_KEYWORD_TSS_PTR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_THREAD_KEYWORD_EXTENSION)
+
+#include "asio/detail/noncopyable.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename T>
+class keyword_tss_ptr
+  : private noncopyable
+{
+public:
+  // Constructor.
+  keyword_tss_ptr()
+  {
+  }
+
+  // Destructor.
+  ~keyword_tss_ptr()
+  {
+  }
+
+  // Get the value.
+  operator T*() const
+  {
+    return value_;
+  }
+
+  // Set the value.
+  void operator=(T* value)
+  {
+    value_ = value;
+  }
+
+private:
+  static ASIO_THREAD_KEYWORD T* value_;
+};
+
+template <typename T>
+ASIO_THREAD_KEYWORD T* keyword_tss_ptr<T>::value_;
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_THREAD_KEYWORD_EXTENSION)
+
+#endif // ASIO_DETAIL_KEYWORD_TSS_PTR_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/kqueue_reactor.hpp b/link/modules/asio-standalone/asio/include/asio/detail/kqueue_reactor.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/kqueue_reactor.hpp
@@ -0,0 +1,242 @@
+//
+// detail/kqueue_reactor.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2005 Stefan Arentz (stefan at soze 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 ASIO_DETAIL_KQUEUE_REACTOR_HPP
+#define ASIO_DETAIL_KQUEUE_REACTOR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_KQUEUE)
+
+#include <cstddef>
+#include <sys/types.h>
+#include <sys/event.h>
+#include <sys/time.h>
+#include "asio/detail/limits.hpp"
+#include "asio/detail/mutex.hpp"
+#include "asio/detail/object_pool.hpp"
+#include "asio/detail/op_queue.hpp"
+#include "asio/detail/reactor_op.hpp"
+#include "asio/detail/select_interrupter.hpp"
+#include "asio/detail/socket_types.hpp"
+#include "asio/detail/timer_queue_base.hpp"
+#include "asio/detail/timer_queue_set.hpp"
+#include "asio/detail/wait_op.hpp"
+#include "asio/error.hpp"
+#include "asio/execution_context.hpp"
+
+// Older versions of Mac OS X may not define EV_OOBAND.
+#if !defined(EV_OOBAND)
+# define EV_OOBAND EV_FLAG1
+#endif // !defined(EV_OOBAND)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class scheduler;
+
+class kqueue_reactor
+  : public execution_context_service_base<kqueue_reactor>
+{
+private:
+  // The mutex type used by this reactor.
+  typedef conditionally_enabled_mutex mutex;
+
+public:
+  enum op_types { read_op = 0, write_op = 1,
+    connect_op = 1, except_op = 2, max_ops = 3 };
+
+  // Per-descriptor queues.
+  struct descriptor_state
+  {
+    descriptor_state(bool locking) : mutex_(locking) {}
+
+    friend class kqueue_reactor;
+    friend class object_pool_access;
+
+    descriptor_state* next_;
+    descriptor_state* prev_;
+
+    mutex mutex_;
+    int descriptor_;
+    int num_kevents_; // 1 == read only, 2 == read and write
+    op_queue<reactor_op> op_queue_[max_ops];
+    bool shutdown_;
+  };
+
+  // Per-descriptor data.
+  typedef descriptor_state* per_descriptor_data;
+
+  // Constructor.
+  ASIO_DECL kqueue_reactor(asio::execution_context& ctx);
+
+  // Destructor.
+  ASIO_DECL ~kqueue_reactor();
+
+  // Destroy all user-defined handler objects owned by the service.
+  ASIO_DECL void shutdown();
+
+  // Recreate internal descriptors following a fork.
+  ASIO_DECL void notify_fork(
+      asio::execution_context::fork_event fork_ev);
+
+  // Initialise the task.
+  ASIO_DECL void init_task();
+
+  // Register a socket with the reactor. Returns 0 on success, system error
+  // code on failure.
+  ASIO_DECL int register_descriptor(socket_type descriptor,
+      per_descriptor_data& descriptor_data);
+
+  // Register a descriptor with an associated single operation. Returns 0 on
+  // success, system error code on failure.
+  ASIO_DECL int register_internal_descriptor(
+      int op_type, socket_type descriptor,
+      per_descriptor_data& descriptor_data, reactor_op* op);
+
+  // Move descriptor registration from one descriptor_data object to another.
+  ASIO_DECL void move_descriptor(socket_type descriptor,
+      per_descriptor_data& target_descriptor_data,
+      per_descriptor_data& source_descriptor_data);
+
+  // Post a reactor operation for immediate completion.
+  void post_immediate_completion(reactor_op* op, bool is_continuation)
+  {
+    scheduler_.post_immediate_completion(op, is_continuation);
+  }
+
+  // Start a new operation. The reactor operation will be performed when the
+  // given descriptor is flagged as ready, or an error has occurred.
+  ASIO_DECL void start_op(int op_type, socket_type descriptor,
+      per_descriptor_data& descriptor_data, reactor_op* op,
+      bool is_continuation, bool allow_speculative);
+
+  // Cancel all operations associated with the given descriptor. The
+  // handlers associated with the descriptor will be invoked with the
+  // operation_aborted error.
+  ASIO_DECL void cancel_ops(socket_type descriptor,
+      per_descriptor_data& descriptor_data);
+
+  // Cancel any operations that are running against the descriptor and remove
+  // its registration from the reactor. The reactor resources associated with
+  // the descriptor must be released by calling cleanup_descriptor_data.
+  ASIO_DECL void deregister_descriptor(socket_type descriptor,
+      per_descriptor_data& descriptor_data, bool closing);
+
+  // Remove the descriptor's registration from the reactor. The reactor
+  // resources associated with the descriptor must be released by calling
+  // cleanup_descriptor_data.
+  ASIO_DECL void deregister_internal_descriptor(
+      socket_type descriptor, per_descriptor_data& descriptor_data);
+
+  // Perform any post-deregistration cleanup tasks associated with the
+  // descriptor data.
+  ASIO_DECL void cleanup_descriptor_data(
+      per_descriptor_data& descriptor_data);
+
+  // Add a new timer queue to the reactor.
+  template <typename Time_Traits>
+  void add_timer_queue(timer_queue<Time_Traits>& queue);
+
+  // Remove a timer queue from the reactor.
+  template <typename Time_Traits>
+  void remove_timer_queue(timer_queue<Time_Traits>& queue);
+
+  // Schedule a new operation in the given timer queue to expire at the
+  // specified absolute time.
+  template <typename Time_Traits>
+  void schedule_timer(timer_queue<Time_Traits>& queue,
+      const typename Time_Traits::time_type& time,
+      typename timer_queue<Time_Traits>::per_timer_data& timer, wait_op* op);
+
+  // Cancel the timer operations associated with the given token. Returns the
+  // number of operations that have been posted or dispatched.
+  template <typename Time_Traits>
+  std::size_t cancel_timer(timer_queue<Time_Traits>& queue,
+      typename timer_queue<Time_Traits>::per_timer_data& timer,
+      std::size_t max_cancelled = (std::numeric_limits<std::size_t>::max)());
+
+  // Move the timer operations associated with the given timer.
+  template <typename Time_Traits>
+  void move_timer(timer_queue<Time_Traits>& queue,
+      typename timer_queue<Time_Traits>::per_timer_data& target,
+      typename timer_queue<Time_Traits>::per_timer_data& source);
+
+  // Run the kqueue loop.
+  ASIO_DECL void run(long usec, op_queue<operation>& ops);
+
+  // Interrupt the kqueue loop.
+  ASIO_DECL void interrupt();
+
+private:
+  // Create the kqueue file descriptor. Throws an exception if the descriptor
+  // cannot be created.
+  ASIO_DECL static int do_kqueue_create();
+
+  // Allocate a new descriptor state object.
+  ASIO_DECL descriptor_state* allocate_descriptor_state();
+
+  // Free an existing descriptor state object.
+  ASIO_DECL void free_descriptor_state(descriptor_state* s);
+
+  // Helper function to add a new timer queue.
+  ASIO_DECL void do_add_timer_queue(timer_queue_base& queue);
+
+  // Helper function to remove a timer queue.
+  ASIO_DECL void do_remove_timer_queue(timer_queue_base& queue);
+
+  // Get the timeout value for the kevent call.
+  ASIO_DECL timespec* get_timeout(long usec, timespec& ts);
+
+  // The scheduler used to post completions.
+  scheduler& scheduler_;
+
+  // Mutex to protect access to internal data.
+  mutex mutex_;
+
+  // The kqueue file descriptor.
+  int kqueue_fd_;
+
+  // The interrupter is used to break a blocking kevent call.
+  select_interrupter interrupter_;
+
+  // The timer queues.
+  timer_queue_set timer_queues_;
+
+  // Whether the service has been shut down.
+  bool shutdown_;
+
+  // Mutex to protect access to the registered descriptors.
+  mutex registered_descriptors_mutex_;
+
+  // Keep track of all registered descriptors.
+  object_pool<descriptor_state> registered_descriptors_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/detail/impl/kqueue_reactor.hpp"
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/kqueue_reactor.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // defined(ASIO_HAS_KQUEUE)
+
+#endif // ASIO_DETAIL_KQUEUE_REACTOR_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/limits.hpp b/link/modules/asio-standalone/asio/include/asio/detail/limits.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/limits.hpp
@@ -0,0 +1,26 @@
+//
+// detail/limits.hpp
+// ~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 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 ASIO_DETAIL_LIMITS_HPP
+#define ASIO_DETAIL_LIMITS_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_BOOST_LIMITS)
+# include <boost/limits.hpp>
+#else // defined(ASIO_HAS_BOOST_LIMITS)
+# include <limits>
+#endif // defined(ASIO_HAS_BOOST_LIMITS)
+
+#endif // ASIO_DETAIL_LIMITS_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/local_free_on_block_exit.hpp b/link/modules/asio-standalone/asio/include/asio/detail/local_free_on_block_exit.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/local_free_on_block_exit.hpp
@@ -0,0 +1,59 @@
+//
+// detail/local_free_on_block_exit.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_LOCAL_FREE_ON_BLOCK_EXIT_HPP
+#define ASIO_DETAIL_LOCAL_FREE_ON_BLOCK_EXIT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+#if !defined(ASIO_WINDOWS_APP)
+
+#include "asio/detail/noncopyable.hpp"
+#include "asio/detail/socket_types.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class local_free_on_block_exit
+  : private noncopyable
+{
+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:
+  void* p_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // !defined(ASIO_WINDOWS_APP)
+#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+
+#endif // ASIO_DETAIL_LOCAL_FREE_ON_BLOCK_EXIT_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/macos_fenced_block.hpp b/link/modules/asio-standalone/asio/include/asio/detail/macos_fenced_block.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/macos_fenced_block.hpp
@@ -0,0 +1,62 @@
+//
+// detail/macos_fenced_block.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_MACOS_FENCED_BLOCK_HPP
+#define ASIO_DETAIL_MACOS_FENCED_BLOCK_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(__MACH__) && defined(__APPLE__)
+
+#include <libkern/OSAtomic.h>
+#include "asio/detail/noncopyable.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class macos_fenced_block
+  : private noncopyable
+{
+public:
+  enum half_t { half };
+  enum full_t { full };
+
+  // Constructor for a half fenced block.
+  explicit macos_fenced_block(half_t)
+  {
+  }
+
+  // Constructor for a full fenced block.
+  explicit macos_fenced_block(full_t)
+  {
+    OSMemoryBarrier();
+  }
+
+  // Destructor.
+  ~macos_fenced_block()
+  {
+    OSMemoryBarrier();
+  }
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(__MACH__) && defined(__APPLE__)
+
+#endif // ASIO_DETAIL_MACOS_FENCED_BLOCK_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/memory.hpp b/link/modules/asio-standalone/asio/include/asio/detail/memory.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/memory.hpp
@@ -0,0 +1,73 @@
+//
+// detail/memory.hpp
+// ~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_MEMORY_HPP
+#define ASIO_DETAIL_MEMORY_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <memory>
+
+#if !defined(ASIO_HAS_STD_SHARED_PTR)
+# include <boost/make_shared.hpp>
+# include <boost/shared_ptr.hpp>
+# include <boost/weak_ptr.hpp>
+#endif // !defined(ASIO_HAS_STD_SHARED_PTR)
+
+#if !defined(ASIO_HAS_STD_ADDRESSOF)
+# include <boost/utility/addressof.hpp>
+#endif // !defined(ASIO_HAS_STD_ADDRESSOF)
+
+namespace asio {
+namespace detail {
+
+#if defined(ASIO_HAS_STD_SHARED_PTR)
+using std::make_shared;
+using std::shared_ptr;
+using std::weak_ptr;
+#else // defined(ASIO_HAS_STD_SHARED_PTR)
+using boost::make_shared;
+using boost::shared_ptr;
+using boost::weak_ptr;
+#endif // defined(ASIO_HAS_STD_SHARED_PTR)
+
+#if defined(ASIO_HAS_STD_ADDRESSOF)
+using std::addressof;
+#else // defined(ASIO_HAS_STD_ADDRESSOF)
+using boost::addressof;
+#endif // defined(ASIO_HAS_STD_ADDRESSOF)
+
+} // namespace detail
+
+#if defined(ASIO_HAS_CXX11_ALLOCATORS)
+using std::allocator_arg_t;
+# define ASIO_USES_ALLOCATOR(t) \
+  namespace std { \
+    template <typename Allocator> \
+    struct uses_allocator<t, Allocator> : true_type {}; \
+  } \
+  /**/
+# define ASIO_REBIND_ALLOC(alloc, t) \
+  typename std::allocator_traits<alloc>::template rebind_alloc<t>
+  /**/
+#else // defined(ASIO_HAS_CXX11_ALLOCATORS)
+struct allocator_arg_t {};
+# define ASIO_USES_ALLOCATOR(t)
+# define ASIO_REBIND_ALLOC(alloc, t) \
+  typename alloc::template rebind<t>::other
+  /**/
+#endif // defined(ASIO_HAS_CXX11_ALLOCATORS)
+
+} // namespace asio
+
+#endif // ASIO_DETAIL_MEMORY_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/mutex.hpp b/link/modules/asio-standalone/asio/include/asio/detail/mutex.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/mutex.hpp
@@ -0,0 +1,48 @@
+//
+// detail/mutex.hpp
+// ~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_MUTEX_HPP
+#define ASIO_DETAIL_MUTEX_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if !defined(ASIO_HAS_THREADS)
+# include "asio/detail/null_mutex.hpp"
+#elif defined(ASIO_WINDOWS)
+# include "asio/detail/win_mutex.hpp"
+#elif defined(ASIO_HAS_PTHREADS)
+# include "asio/detail/posix_mutex.hpp"
+#elif defined(ASIO_HAS_STD_MUTEX_AND_CONDVAR)
+# include "asio/detail/std_mutex.hpp"
+#else
+# error Only Windows, POSIX and std::mutex are supported!
+#endif
+
+namespace asio {
+namespace detail {
+
+#if !defined(ASIO_HAS_THREADS)
+typedef null_mutex mutex;
+#elif defined(ASIO_WINDOWS)
+typedef win_mutex mutex;
+#elif defined(ASIO_HAS_PTHREADS)
+typedef posix_mutex mutex;
+#elif defined(ASIO_HAS_STD_MUTEX_AND_CONDVAR)
+typedef std_mutex mutex;
+#endif
+
+} // namespace detail
+} // namespace asio
+
+#endif // ASIO_DETAIL_MUTEX_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/non_const_lvalue.hpp b/link/modules/asio-standalone/asio/include/asio/detail/non_const_lvalue.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/non_const_lvalue.hpp
@@ -0,0 +1,54 @@
+//
+// detail/non_const_lvalue.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_NON_CONST_LVALUE_HPP
+#define ASIO_DETAIL_NON_CONST_LVALUE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/type_traits.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename T>
+struct non_const_lvalue
+{
+#if defined(ASIO_HAS_MOVE)
+  explicit non_const_lvalue(T& t)
+    : value(static_cast<typename conditional<
+        is_same<T, typename decay<T>::type>::value,
+          typename decay<T>::type&, T&&>::type>(t))
+  {
+  }
+
+  typename conditional<is_same<T, typename decay<T>::type>::value,
+      typename decay<T>::type&, typename decay<T>::type>::type value;
+#else // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+  explicit non_const_lvalue(const typename decay<T>::type& t)
+    : value(t)
+  {
+  }
+
+  typename decay<T>::type value;
+#endif // defined(ASIO_HAS_MOVE)
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_NON_CONST_LVALUE_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/noncopyable.hpp b/link/modules/asio-standalone/asio/include/asio/detail/noncopyable.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/noncopyable.hpp
@@ -0,0 +1,43 @@
+//
+// detail/noncopyable.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_NONCOPYABLE_HPP
+#define ASIO_DETAIL_NONCOPYABLE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class noncopyable
+{
+protected:
+  noncopyable() {}
+  ~noncopyable() {}
+private:
+  noncopyable(const noncopyable&);
+  const noncopyable& operator=(const noncopyable&);
+};
+
+} // namespace detail
+
+using asio::detail::noncopyable;
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_NONCOPYABLE_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/null_event.hpp b/link/modules/asio-standalone/asio/include/asio/detail/null_event.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/null_event.hpp
@@ -0,0 +1,106 @@
+//
+// detail/null_event.hpp
+// ~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_NULL_EVENT_HPP
+#define ASIO_DETAIL_NULL_EVENT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/noncopyable.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class null_event
+  : private noncopyable
+{
+public:
+  // Constructor.
+  null_event()
+  {
+  }
+
+  // Destructor.
+  ~null_event()
+  {
+  }
+
+  // Signal the event. (Retained for backward compatibility.)
+  template <typename Lock>
+  void signal(Lock&)
+  {
+  }
+
+  // Signal all waiters.
+  template <typename Lock>
+  void signal_all(Lock&)
+  {
+  }
+
+  // Unlock the mutex and signal one waiter.
+  template <typename Lock>
+  void unlock_and_signal_one(Lock&)
+  {
+  }
+
+  // Unlock the mutex and signal one waiter who may destroy us.
+  template <typename Lock>
+  void unlock_and_signal_one_for_destruction(Lock&)
+  {
+  }
+
+  // If there's a waiter, unlock the mutex and signal it.
+  template <typename Lock>
+  bool maybe_unlock_and_signal_one(Lock&)
+  {
+    return false;
+  }
+
+  // Reset the event.
+  template <typename Lock>
+  void clear(Lock&)
+  {
+  }
+
+  // Wait for the event to become signalled.
+  template <typename Lock>
+  void wait(Lock&)
+  {
+    do_wait();
+  }
+
+  // Timed wait for the event to become signalled.
+  template <typename Lock>
+  bool wait_for_usec(Lock&, long usec)
+  {
+    do_wait_for_usec(usec);
+    return true;
+  }
+
+private:
+  ASIO_DECL static void do_wait();
+  ASIO_DECL static void do_wait_for_usec(long usec);
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/null_event.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // ASIO_DETAIL_NULL_EVENT_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/null_fenced_block.hpp b/link/modules/asio-standalone/asio/include/asio/detail/null_fenced_block.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/null_fenced_block.hpp
@@ -0,0 +1,47 @@
+//
+// detail/null_fenced_block.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_NULL_FENCED_BLOCK_HPP
+#define ASIO_DETAIL_NULL_FENCED_BLOCK_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/noncopyable.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class null_fenced_block
+  : private noncopyable
+{
+public:
+  enum half_or_full_t { half, full };
+
+  // Constructor.
+  explicit null_fenced_block(half_or_full_t)
+  {
+  }
+
+  // Destructor.
+  ~null_fenced_block()
+  {
+  }
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_NULL_FENCED_BLOCK_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/null_global.hpp b/link/modules/asio-standalone/asio/include/asio/detail/null_global.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/null_global.hpp
@@ -0,0 +1,59 @@
+//
+// detail/null_global.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_NULL_GLOBAL_HPP
+#define ASIO_DETAIL_NULL_GLOBAL_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename T>
+struct null_global_impl
+{
+  null_global_impl()
+    : ptr_(0)
+  {
+  }
+
+  // Destructor automatically cleans up the global.
+  ~null_global_impl()
+  {
+    delete ptr_;
+  }
+
+  static null_global_impl instance_;
+  T* ptr_;
+};
+
+template <typename T>
+null_global_impl<T> null_global_impl<T>::instance_;
+
+template <typename T>
+T& null_global()
+{
+  if (null_global_impl<T>::instance_.ptr_ == 0)
+    null_global_impl<T>::instance_.ptr_ = new T;
+  return *null_global_impl<T>::instance_.ptr_;
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_NULL_GLOBAL_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/null_mutex.hpp b/link/modules/asio-standalone/asio/include/asio/detail/null_mutex.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/null_mutex.hpp
@@ -0,0 +1,64 @@
+//
+// detail/null_mutex.hpp
+// ~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_NULL_MUTEX_HPP
+#define ASIO_DETAIL_NULL_MUTEX_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if !defined(ASIO_HAS_THREADS)
+
+#include "asio/detail/noncopyable.hpp"
+#include "asio/detail/scoped_lock.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class null_mutex
+  : private noncopyable
+{
+public:
+  typedef asio::detail::scoped_lock<null_mutex> scoped_lock;
+
+  // Constructor.
+  null_mutex()
+  {
+  }
+
+  // Destructor.
+  ~null_mutex()
+  {
+  }
+
+  // Lock the mutex.
+  void lock()
+  {
+  }
+
+  // Unlock the mutex.
+  void unlock()
+  {
+  }
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // !defined(ASIO_HAS_THREADS)
+
+#endif // ASIO_DETAIL_NULL_MUTEX_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/null_reactor.hpp b/link/modules/asio-standalone/asio/include/asio/detail/null_reactor.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/null_reactor.hpp
@@ -0,0 +1,68 @@
+//
+// detail/null_reactor.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_NULL_REACTOR_HPP
+#define ASIO_DETAIL_NULL_REACTOR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_IOCP) || defined(ASIO_WINDOWS_RUNTIME)
+
+#include "asio/detail/scheduler_operation.hpp"
+#include "asio/execution_context.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class null_reactor
+  : public execution_context_service_base<null_reactor>
+{
+public:
+  // Constructor.
+  null_reactor(asio::execution_context& ctx)
+    : execution_context_service_base<null_reactor>(ctx)
+  {
+  }
+
+  // Destructor.
+  ~null_reactor()
+  {
+  }
+
+  // Destroy all user-defined handler objects owned by the service.
+  void shutdown()
+  {
+  }
+
+  // No-op because should never be called.
+  void run(long /*usec*/, op_queue<scheduler_operation>& /*ops*/)
+  {
+  }
+
+  // No-op.
+  void interrupt()
+  {
+  }
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_IOCP) || defined(ASIO_WINDOWS_RUNTIME)
+
+#endif // ASIO_DETAIL_NULL_REACTOR_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/null_signal_blocker.hpp b/link/modules/asio-standalone/asio/include/asio/detail/null_signal_blocker.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/null_signal_blocker.hpp
@@ -0,0 +1,69 @@
+//
+// detail/null_signal_blocker.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_NULL_SIGNAL_BLOCKER_HPP
+#define ASIO_DETAIL_NULL_SIGNAL_BLOCKER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if !defined(ASIO_HAS_THREADS) \
+  || defined(ASIO_WINDOWS) \
+  || defined(ASIO_WINDOWS_RUNTIME) \
+  || defined(__CYGWIN__) \
+  || defined(__SYMBIAN32__)
+
+#include "asio/detail/noncopyable.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class null_signal_blocker
+  : private noncopyable
+{
+public:
+  // Constructor blocks all signals for the calling thread.
+  null_signal_blocker()
+  {
+  }
+
+  // Destructor restores the previous signal mask.
+  ~null_signal_blocker()
+  {
+  }
+
+  // Block all signals for the calling thread.
+  void block()
+  {
+  }
+
+  // Restore the previous signal mask.
+  void unblock()
+  {
+  }
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // !defined(ASIO_HAS_THREADS)
+       // || defined(ASIO_WINDOWS)
+       // || defined(ASIO_WINDOWS_RUNTIME)
+       // || defined(__CYGWIN__)
+       // || defined(__SYMBIAN32__)
+
+#endif // ASIO_DETAIL_NULL_SIGNAL_BLOCKER_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/null_socket_service.hpp b/link/modules/asio-standalone/asio/include/asio/detail/null_socket_service.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/null_socket_service.hpp
@@ -0,0 +1,519 @@
+//
+// detail/null_socket_service.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_NULL_SOCKET_SERVICE_HPP
+#define ASIO_DETAIL_NULL_SOCKET_SERVICE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_WINDOWS_RUNTIME)
+
+#include "asio/buffer.hpp"
+#include "asio/error.hpp"
+#include "asio/execution_context.hpp"
+#include "asio/post.hpp"
+#include "asio/socket_base.hpp"
+#include "asio/detail/bind_handler.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Protocol>
+class null_socket_service :
+  public execution_context_service_base<null_socket_service<Protocol> >
+{
+public:
+  // The protocol type.
+  typedef Protocol protocol_type;
+
+  // The endpoint type.
+  typedef typename Protocol::endpoint endpoint_type;
+
+  // The native type of a socket.
+  typedef int native_handle_type;
+
+  // The implementation type of the socket.
+  struct implementation_type
+  {
+  };
+
+  // Constructor.
+  null_socket_service(execution_context& context)
+    : execution_context_service_base<null_socket_service<Protocol> >(context)
+  {
+  }
+
+  // Destroy all user-defined handler objects owned by the service.
+  void shutdown()
+  {
+  }
+
+  // Construct a new socket implementation.
+  void construct(implementation_type&)
+  {
+  }
+
+  // Move-construct a new socket implementation.
+  void move_construct(implementation_type&, implementation_type&)
+  {
+  }
+
+  // Move-assign from another socket implementation.
+  void move_assign(implementation_type&,
+      null_socket_service&, implementation_type&)
+  {
+  }
+
+  // Move-construct a new socket implementation from another protocol type.
+  template <typename Protocol1>
+  void converting_move_construct(implementation_type&,
+      null_socket_service<Protocol1>&,
+      typename null_socket_service<Protocol1>::implementation_type&)
+  {
+  }
+
+  // Destroy a socket implementation.
+  void destroy(implementation_type&)
+  {
+  }
+
+  // Open a new socket implementation.
+  asio::error_code open(implementation_type&,
+      const protocol_type&, asio::error_code& ec)
+  {
+    ec = asio::error::operation_not_supported;
+    return ec;
+  }
+
+  // Assign a native socket to a socket implementation.
+  asio::error_code assign(implementation_type&, const protocol_type&,
+      const native_handle_type&, asio::error_code& ec)
+  {
+    ec = asio::error::operation_not_supported;
+    return ec;
+  }
+
+  // Determine whether the socket is open.
+  bool is_open(const implementation_type&) const
+  {
+    return false;
+  }
+
+  // Destroy a socket implementation.
+  asio::error_code close(implementation_type&,
+      asio::error_code& ec)
+  {
+    ec = asio::error::operation_not_supported;
+    return ec;
+  }
+
+  // Release ownership of the socket.
+  native_handle_type release(implementation_type&,
+      asio::error_code& ec)
+  {
+    ec = asio::error::operation_not_supported;
+    return 0;
+  }
+
+  // Get the native socket representation.
+  native_handle_type native_handle(implementation_type&)
+  {
+    return 0;
+  }
+
+  // Cancel all operations associated with the socket.
+  asio::error_code cancel(implementation_type&,
+      asio::error_code& ec)
+  {
+    ec = asio::error::operation_not_supported;
+    return ec;
+  }
+
+  // Determine whether the socket is at the out-of-band data mark.
+  bool at_mark(const implementation_type&,
+      asio::error_code& ec) const
+  {
+    ec = asio::error::operation_not_supported;
+    return false;
+  }
+
+  // Determine the number of bytes available for reading.
+  std::size_t available(const implementation_type&,
+      asio::error_code& ec) const
+  {
+    ec = asio::error::operation_not_supported;
+    return 0;
+  }
+
+  // Place the socket into the state where it will listen for new connections.
+  asio::error_code listen(implementation_type&,
+      int, asio::error_code& ec)
+  {
+    ec = asio::error::operation_not_supported;
+    return ec;
+  }
+
+  // Perform an IO control command on the socket.
+  template <typename IO_Control_Command>
+  asio::error_code io_control(implementation_type&,
+      IO_Control_Command&, asio::error_code& ec)
+  {
+    ec = asio::error::operation_not_supported;
+    return ec;
+  }
+
+  // Gets the non-blocking mode of the socket.
+  bool non_blocking(const implementation_type&) const
+  {
+    return false;
+  }
+
+  // Sets the non-blocking mode of the socket.
+  asio::error_code non_blocking(implementation_type&,
+      bool, asio::error_code& ec)
+  {
+    ec = asio::error::operation_not_supported;
+    return ec;
+  }
+
+  // Gets the non-blocking mode of the native socket implementation.
+  bool native_non_blocking(const implementation_type&) const
+  {
+    return false;
+  }
+
+  // Sets the non-blocking mode of the native socket implementation.
+  asio::error_code native_non_blocking(implementation_type&,
+      bool, asio::error_code& ec)
+  {
+    ec = asio::error::operation_not_supported;
+    return ec;
+  }
+
+  // Disable sends or receives on the socket.
+  asio::error_code shutdown(implementation_type&,
+      socket_base::shutdown_type, asio::error_code& ec)
+  {
+    ec = asio::error::operation_not_supported;
+    return ec;
+  }
+
+  // Bind the socket to the specified local endpoint.
+  asio::error_code bind(implementation_type&,
+      const endpoint_type&, asio::error_code& ec)
+  {
+    ec = asio::error::operation_not_supported;
+    return ec;
+  }
+
+  // Set a socket option.
+  template <typename Option>
+  asio::error_code set_option(implementation_type&,
+      const Option&, asio::error_code& ec)
+  {
+    ec = asio::error::operation_not_supported;
+    return ec;
+  }
+
+  // Set a socket option.
+  template <typename Option>
+  asio::error_code get_option(const implementation_type&,
+      Option&, asio::error_code& ec) const
+  {
+    ec = asio::error::operation_not_supported;
+    return ec;
+  }
+
+  // Get the local endpoint.
+  endpoint_type local_endpoint(const implementation_type&,
+      asio::error_code& ec) const
+  {
+    ec = asio::error::operation_not_supported;
+    return endpoint_type();
+  }
+
+  // Get the remote endpoint.
+  endpoint_type remote_endpoint(const implementation_type&,
+      asio::error_code& ec) const
+  {
+    ec = asio::error::operation_not_supported;
+    return endpoint_type();
+  }
+
+  // Send the given data to the peer.
+  template <typename ConstBufferSequence>
+  std::size_t send(implementation_type&, const ConstBufferSequence&,
+      socket_base::message_flags, asio::error_code& ec)
+  {
+    ec = asio::error::operation_not_supported;
+    return 0;
+  }
+
+  // Wait until data can be sent without blocking.
+  std::size_t send(implementation_type&, const null_buffers&,
+      socket_base::message_flags, asio::error_code& ec)
+  {
+    ec = asio::error::operation_not_supported;
+    return 0;
+  }
+
+  // Start an asynchronous send. The data being sent must be valid for the
+  // lifetime of the asynchronous operation.
+  template <typename ConstBufferSequence, typename Handler, typename IoExecutor>
+  void async_send(implementation_type&, const ConstBufferSequence&,
+      socket_base::message_flags, Handler& handler, const IoExecutor& io_ex)
+  {
+    asio::error_code ec = asio::error::operation_not_supported;
+    const std::size_t bytes_transferred = 0;
+    asio::post(io_ex, detail::bind_handler(
+          handler, ec, bytes_transferred));
+  }
+
+  // Start an asynchronous wait until data can be sent without blocking.
+  template <typename Handler, typename IoExecutor>
+  void async_send(implementation_type&, const null_buffers&,
+      socket_base::message_flags, Handler& handler, const IoExecutor& io_ex)
+  {
+    asio::error_code ec = asio::error::operation_not_supported;
+    const std::size_t bytes_transferred = 0;
+    asio::post(io_ex, detail::bind_handler(
+          handler, ec, bytes_transferred));
+  }
+
+  // Receive some data from the peer. Returns the number of bytes received.
+  template <typename MutableBufferSequence>
+  std::size_t receive(implementation_type&, const MutableBufferSequence&,
+      socket_base::message_flags, asio::error_code& ec)
+  {
+    ec = asio::error::operation_not_supported;
+    return 0;
+  }
+
+  // Wait until data can be received without blocking.
+  std::size_t receive(implementation_type&, const null_buffers&,
+      socket_base::message_flags, asio::error_code& ec)
+  {
+    ec = asio::error::operation_not_supported;
+    return 0;
+  }
+
+  // Start an asynchronous receive. The buffer for the data being received
+  // must be valid for the lifetime of the asynchronous operation.
+  template <typename MutableBufferSequence,
+      typename Handler, typename IoExecutor>
+  void async_receive(implementation_type&, const MutableBufferSequence&,
+      socket_base::message_flags, Handler& handler, const IoExecutor& io_ex)
+  {
+    asio::error_code ec = asio::error::operation_not_supported;
+    const std::size_t bytes_transferred = 0;
+    asio::post(io_ex, detail::bind_handler(
+          handler, ec, bytes_transferred));
+  }
+
+  // Wait until data can be received without blocking.
+  template <typename Handler, typename IoExecutor>
+  void async_receive(implementation_type&, const null_buffers&,
+      socket_base::message_flags, Handler& handler, const IoExecutor& io_ex)
+  {
+    asio::error_code ec = asio::error::operation_not_supported;
+    const std::size_t bytes_transferred = 0;
+    asio::post(io_ex, detail::bind_handler(
+          handler, ec, bytes_transferred));
+  }
+
+  // Receive some data with associated flags. Returns the number of bytes
+  // received.
+  template <typename MutableBufferSequence>
+  std::size_t receive_with_flags(implementation_type&,
+      const MutableBufferSequence&, socket_base::message_flags,
+      socket_base::message_flags&, asio::error_code& ec)
+  {
+    ec = asio::error::operation_not_supported;
+    return 0;
+  }
+
+  // Wait until data can be received without blocking.
+  std::size_t receive_with_flags(implementation_type&,
+      const null_buffers&, socket_base::message_flags,
+      socket_base::message_flags&, asio::error_code& ec)
+  {
+    ec = asio::error::operation_not_supported;
+    return 0;
+  }
+
+  // Start an asynchronous receive. The buffer for the data being received
+  // must be valid for the lifetime of the asynchronous operation.
+  template <typename MutableBufferSequence,
+      typename Handler, typename IoExecutor>
+  void async_receive_with_flags(implementation_type&,
+      const MutableBufferSequence&, socket_base::message_flags,
+      socket_base::message_flags&, Handler& handler, const IoExecutor& io_ex)
+  {
+    asio::error_code ec = asio::error::operation_not_supported;
+    const std::size_t bytes_transferred = 0;
+    asio::post(io_ex, detail::bind_handler(
+          handler, ec, bytes_transferred));
+  }
+
+  // Wait until data can be received without blocking.
+  template <typename Handler, typename IoExecutor>
+  void async_receive_with_flags(implementation_type&, const null_buffers&,
+      socket_base::message_flags, socket_base::message_flags&,
+      Handler& handler, const IoExecutor& io_ex)
+  {
+    asio::error_code ec = asio::error::operation_not_supported;
+    const std::size_t bytes_transferred = 0;
+    asio::post(io_ex, detail::bind_handler(
+          handler, ec, bytes_transferred));
+  }
+
+  // Send a datagram to the specified endpoint. Returns the number of bytes
+  // sent.
+  template <typename ConstBufferSequence>
+  std::size_t send_to(implementation_type&, const ConstBufferSequence&,
+      const endpoint_type&, socket_base::message_flags,
+      asio::error_code& ec)
+  {
+    ec = asio::error::operation_not_supported;
+    return 0;
+  }
+
+  // Wait until data can be sent without blocking.
+  std::size_t send_to(implementation_type&, const null_buffers&,
+      const endpoint_type&, socket_base::message_flags,
+      asio::error_code& ec)
+  {
+    ec = asio::error::operation_not_supported;
+    return 0;
+  }
+
+  // Start an asynchronous send. The data being sent must be valid for the
+  // lifetime of the asynchronous operation.
+  template <typename ConstBufferSequence, typename Handler, typename IoExecutor>
+  void async_send_to(implementation_type&, const ConstBufferSequence&,
+      const endpoint_type&, socket_base::message_flags,
+      Handler& handler)
+  {
+    asio::error_code ec = asio::error::operation_not_supported;
+    const std::size_t bytes_transferred = 0;
+    asio::post(io_ex, detail::bind_handler(
+          handler, ec, bytes_transferred));
+  }
+
+  // Start an asynchronous wait until data can be sent without blocking.
+  template <typename Handler, typename IoExecutor>
+  void async_send_to(implementation_type&, const null_buffers&,
+      const endpoint_type&, socket_base::message_flags,
+      Handler& handler, const IoExecutor& io_ex)
+  {
+    asio::error_code ec = asio::error::operation_not_supported;
+    const std::size_t bytes_transferred = 0;
+    asio::post(io_ex, detail::bind_handler(
+          handler, ec, bytes_transferred));
+  }
+
+  // Receive a datagram with the endpoint of the sender. Returns the number of
+  // bytes received.
+  template <typename MutableBufferSequence>
+  std::size_t receive_from(implementation_type&, const MutableBufferSequence&,
+      endpoint_type&, socket_base::message_flags,
+      asio::error_code& ec)
+  {
+    ec = asio::error::operation_not_supported;
+    return 0;
+  }
+
+  // Wait until data can be received without blocking.
+  std::size_t receive_from(implementation_type&, const null_buffers&,
+      endpoint_type&, socket_base::message_flags,
+      asio::error_code& ec)
+  {
+    ec = asio::error::operation_not_supported;
+    return 0;
+  }
+
+  // Start an asynchronous receive. The buffer for the data being received and
+  // the sender_endpoint object must both be valid for the lifetime of the
+  // asynchronous operation.
+  template <typename MutableBufferSequence,
+      typename Handler, typename IoExecutor>
+  void async_receive_from(implementation_type&, const MutableBufferSequence&,
+      endpoint_type&, socket_base::message_flags, Handler& handler,
+      const IoExecutor& io_ex)
+  {
+    asio::error_code ec = asio::error::operation_not_supported;
+    const std::size_t bytes_transferred = 0;
+    asio::post(io_ex, detail::bind_handler(
+          handler, ec, bytes_transferred));
+  }
+
+  // Wait until data can be received without blocking.
+  template <typename Handler, typename IoExecutor>
+  void async_receive_from(implementation_type&, const null_buffers&,
+      endpoint_type&, socket_base::message_flags, Handler& handler,
+      const IoExecutor& io_ex)
+  {
+    asio::error_code ec = asio::error::operation_not_supported;
+    const std::size_t bytes_transferred = 0;
+    asio::post(io_ex, detail::bind_handler(
+          handler, ec, bytes_transferred));
+  }
+
+  // Accept a new connection.
+  template <typename Socket>
+  asio::error_code accept(implementation_type&,
+      Socket&, endpoint_type*, asio::error_code& ec)
+  {
+    ec = asio::error::operation_not_supported;
+    return ec;
+  }
+
+  // Start an asynchronous accept. The peer and peer_endpoint objects
+  // must be valid until the accept's handler is invoked.
+  template <typename Socket, typename Handler, typename IoExecutor>
+  void async_accept(implementation_type&, Socket&, endpoint_type*,
+      Handler& handler, const IoExecutor& io_ex)
+  {
+    asio::error_code ec = asio::error::operation_not_supported;
+    asio::post(io_ex, detail::bind_handler(handler, ec));
+  }
+
+  // Connect the socket to the specified endpoint.
+  asio::error_code connect(implementation_type&,
+      const endpoint_type&, asio::error_code& ec)
+  {
+    ec = asio::error::operation_not_supported;
+    return ec;
+  }
+
+  // Start an asynchronous connect.
+  template <typename Handler, typename IoExecutor>
+  void async_connect(implementation_type&, const endpoint_type&,
+      Handler& handler, const IoExecutor& io_ex)
+  {
+    asio::error_code ec = asio::error::operation_not_supported;
+    asio::post(io_ex, detail::bind_handler(handler, ec));
+  }
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_WINDOWS_RUNTIME)
+
+#endif // ASIO_DETAIL_NULL_SOCKET_SERVICE_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/null_static_mutex.hpp b/link/modules/asio-standalone/asio/include/asio/detail/null_static_mutex.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/null_static_mutex.hpp
@@ -0,0 +1,60 @@
+//
+// detail/null_static_mutex.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_NULL_STATIC_MUTEX_HPP
+#define ASIO_DETAIL_NULL_STATIC_MUTEX_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if !defined(ASIO_HAS_THREADS)
+
+#include "asio/detail/scoped_lock.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+struct null_static_mutex
+{
+  typedef asio::detail::scoped_lock<null_static_mutex> scoped_lock;
+
+  // Initialise the mutex.
+  void init()
+  {
+  }
+
+  // Lock the mutex.
+  void lock()
+  {
+  }
+
+  // Unlock the mutex.
+  void unlock()
+  {
+  }
+
+  int unused_;
+};
+
+#define ASIO_NULL_STATIC_MUTEX_INIT { 0 }
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // !defined(ASIO_HAS_THREADS)
+
+#endif // ASIO_DETAIL_NULL_STATIC_MUTEX_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/null_thread.hpp b/link/modules/asio-standalone/asio/include/asio/detail/null_thread.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/null_thread.hpp
@@ -0,0 +1,67 @@
+//
+// detail/null_thread.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_NULL_THREAD_HPP
+#define ASIO_DETAIL_NULL_THREAD_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if !defined(ASIO_HAS_THREADS)
+
+#include "asio/detail/noncopyable.hpp"
+#include "asio/detail/throw_error.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class null_thread
+  : private noncopyable
+{
+public:
+  // Constructor.
+  template <typename Function>
+  null_thread(Function, unsigned int = 0)
+  {
+    asio::detail::throw_error(
+        asio::error::operation_not_supported, "thread");
+  }
+
+  // Destructor.
+  ~null_thread()
+  {
+  }
+
+  // Wait for the thread to exit.
+  void join()
+  {
+  }
+
+  // Get number of CPUs.
+  static std::size_t hardware_concurrency()
+  {
+    return 1;
+  }
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // !defined(ASIO_HAS_THREADS)
+
+#endif // ASIO_DETAIL_NULL_THREAD_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/null_tss_ptr.hpp b/link/modules/asio-standalone/asio/include/asio/detail/null_tss_ptr.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/null_tss_ptr.hpp
@@ -0,0 +1,68 @@
+//
+// detail/null_tss_ptr.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_NULL_TSS_PTR_HPP
+#define ASIO_DETAIL_NULL_TSS_PTR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if !defined(ASIO_HAS_THREADS)
+
+#include "asio/detail/noncopyable.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename T>
+class null_tss_ptr
+  : private noncopyable
+{
+public:
+  // Constructor.
+  null_tss_ptr()
+    : value_(0)
+  {
+  }
+
+  // Destructor.
+  ~null_tss_ptr()
+  {
+  }
+
+  // Get the value.
+  operator T*() const
+  {
+    return value_;
+  }
+
+  // Set the value.
+  void operator=(T* value)
+  {
+    value_ = value;
+  }
+
+private:
+  T* value_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // !defined(ASIO_HAS_THREADS)
+
+#endif // ASIO_DETAIL_NULL_TSS_PTR_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/object_pool.hpp b/link/modules/asio-standalone/asio/include/asio/detail/object_pool.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/object_pool.hpp
@@ -0,0 +1,171 @@
+//
+// detail/object_pool.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_OBJECT_POOL_HPP
+#define ASIO_DETAIL_OBJECT_POOL_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/noncopyable.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Object>
+class object_pool;
+
+class object_pool_access
+{
+public:
+  template <typename Object>
+  static Object* create()
+  {
+    return new Object;
+  }
+
+  template <typename Object, typename Arg>
+  static Object* create(Arg arg)
+  {
+    return new Object(arg);
+  }
+
+  template <typename Object>
+  static void destroy(Object* o)
+  {
+    delete o;
+  }
+
+  template <typename Object>
+  static Object*& next(Object* o)
+  {
+    return o->next_;
+  }
+
+  template <typename Object>
+  static Object*& prev(Object* o)
+  {
+    return o->prev_;
+  }
+};
+
+template <typename Object>
+class object_pool
+  : private noncopyable
+{
+public:
+  // Constructor.
+  object_pool()
+    : live_list_(0),
+      free_list_(0)
+  {
+  }
+
+  // Destructor destroys all objects.
+  ~object_pool()
+  {
+    destroy_list(live_list_);
+    destroy_list(free_list_);
+  }
+
+  // Get the object at the start of the live list.
+  Object* first()
+  {
+    return live_list_;
+  }
+
+  // Allocate a new object.
+  Object* alloc()
+  {
+    Object* o = free_list_;
+    if (o)
+      free_list_ = object_pool_access::next(free_list_);
+    else
+      o = object_pool_access::create<Object>();
+
+    object_pool_access::next(o) = live_list_;
+    object_pool_access::prev(o) = 0;
+    if (live_list_)
+      object_pool_access::prev(live_list_) = o;
+    live_list_ = o;
+
+    return o;
+  }
+
+  // Allocate a new object with an argument.
+  template <typename Arg>
+  Object* alloc(Arg arg)
+  {
+    Object* o = free_list_;
+    if (o)
+      free_list_ = object_pool_access::next(free_list_);
+    else
+      o = object_pool_access::create<Object>(arg);
+
+    object_pool_access::next(o) = live_list_;
+    object_pool_access::prev(o) = 0;
+    if (live_list_)
+      object_pool_access::prev(live_list_) = o;
+    live_list_ = o;
+
+    return o;
+  }
+
+  // Free an object. Moves it to the free list. No destructors are run.
+  void free(Object* o)
+  {
+    if (live_list_ == o)
+      live_list_ = object_pool_access::next(o);
+
+    if (object_pool_access::prev(o))
+    {
+      object_pool_access::next(object_pool_access::prev(o))
+        = object_pool_access::next(o);
+    }
+
+    if (object_pool_access::next(o))
+    {
+      object_pool_access::prev(object_pool_access::next(o))
+        = object_pool_access::prev(o);
+    }
+
+    object_pool_access::next(o) = free_list_;
+    object_pool_access::prev(o) = 0;
+    free_list_ = o;
+  }
+
+private:
+  // Helper function to destroy all elements in a list.
+  void destroy_list(Object* list)
+  {
+    while (list)
+    {
+      Object* o = list;
+      list = object_pool_access::next(o);
+      object_pool_access::destroy(o);
+    }
+  }
+
+  // The list of live objects.
+  Object* live_list_;
+
+  // The free list.
+  Object* free_list_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_OBJECT_POOL_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/old_win_sdk_compat.hpp b/link/modules/asio-standalone/asio/include/asio/detail/old_win_sdk_compat.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/old_win_sdk_compat.hpp
@@ -0,0 +1,214 @@
+//
+// detail/old_win_sdk_compat.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_OLD_WIN_SDK_COMPAT_HPP
+#define ASIO_DETAIL_OLD_WIN_SDK_COMPAT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+
+// Guess whether we are building against on old Platform SDK.
+#if !defined(IN6ADDR_ANY_INIT)
+#define ASIO_HAS_OLD_WIN_SDK 1
+#endif // !defined(IN6ADDR_ANY_INIT)
+
+#if defined(ASIO_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 "asio/detail/push_options.hpp"
+
+namespace asio {
+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 asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_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(ASIO_WINDOWS) || defined(__CYGWIN__)
+
+#endif // ASIO_DETAIL_OLD_WIN_SDK_COMPAT_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/op_queue.hpp b/link/modules/asio-standalone/asio/include/asio/detail/op_queue.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/op_queue.hpp
@@ -0,0 +1,162 @@
+//
+// detail/op_queue.hpp
+// ~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_OP_QUEUE_HPP
+#define ASIO_DETAIL_OP_QUEUE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/noncopyable.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Operation>
+class op_queue;
+
+class op_queue_access
+{
+public:
+  template <typename Operation>
+  static Operation* next(Operation* o)
+  {
+    return static_cast<Operation*>(o->next_);
+  }
+
+  template <typename Operation1, typename Operation2>
+  static void next(Operation1*& o1, Operation2* o2)
+  {
+    o1->next_ = o2;
+  }
+
+  template <typename Operation>
+  static void destroy(Operation* o)
+  {
+    o->destroy();
+  }
+
+  template <typename Operation>
+  static Operation*& front(op_queue<Operation>& q)
+  {
+    return q.front_;
+  }
+
+  template <typename Operation>
+  static Operation*& back(op_queue<Operation>& q)
+  {
+    return q.back_;
+  }
+};
+
+template <typename Operation>
+class op_queue
+  : private noncopyable
+{
+public:
+  // Constructor.
+  op_queue()
+    : front_(0),
+      back_(0)
+  {
+  }
+
+  // Destructor destroys all operations.
+  ~op_queue()
+  {
+    while (Operation* op = front_)
+    {
+      pop();
+      op_queue_access::destroy(op);
+    }
+  }
+
+  // Get the operation at the front of the queue.
+  Operation* front()
+  {
+    return front_;
+  }
+
+  // Pop an operation from the front of the queue.
+  void pop()
+  {
+    if (front_)
+    {
+      Operation* tmp = front_;
+      front_ = op_queue_access::next(front_);
+      if (front_ == 0)
+        back_ = 0;
+      op_queue_access::next(tmp, static_cast<Operation*>(0));
+    }
+  }
+
+  // Push an operation on to the back of the queue.
+  void push(Operation* h)
+  {
+    op_queue_access::next(h, static_cast<Operation*>(0));
+    if (back_)
+    {
+      op_queue_access::next(back_, h);
+      back_ = h;
+    }
+    else
+    {
+      front_ = back_ = h;
+    }
+  }
+
+  // Push all operations from another queue on to the back of the queue. The
+  // source queue may contain operations of a derived type.
+  template <typename OtherOperation>
+  void push(op_queue<OtherOperation>& q)
+  {
+    if (Operation* other_front = op_queue_access::front(q))
+    {
+      if (back_)
+        op_queue_access::next(back_, other_front);
+      else
+        front_ = other_front;
+      back_ = op_queue_access::back(q);
+      op_queue_access::front(q) = 0;
+      op_queue_access::back(q) = 0;
+    }
+  }
+
+  // Whether the queue is empty.
+  bool empty() const
+  {
+    return front_ == 0;
+  }
+
+  // Test whether an operation is already enqueued.
+  bool is_enqueued(Operation* o) const
+  {
+    return op_queue_access::next(o) != 0 || back_ == o;
+  }
+
+private:
+  friend class op_queue_access;
+
+  // The front of the queue.
+  Operation* front_;
+
+  // The back of the queue.
+  Operation* back_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_OP_QUEUE_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/operation.hpp b/link/modules/asio-standalone/asio/include/asio/detail/operation.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/operation.hpp
@@ -0,0 +1,38 @@
+//
+// detail/operation.hpp
+// ~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_OPERATION_HPP
+#define ASIO_DETAIL_OPERATION_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_IOCP)
+# include "asio/detail/win_iocp_operation.hpp"
+#else
+# include "asio/detail/scheduler_operation.hpp"
+#endif
+
+namespace asio {
+namespace detail {
+
+#if defined(ASIO_HAS_IOCP)
+typedef win_iocp_operation operation;
+#else
+typedef scheduler_operation operation;
+#endif
+
+} // namespace detail
+} // namespace asio
+
+#endif // ASIO_DETAIL_OPERATION_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/pipe_select_interrupter.hpp b/link/modules/asio-standalone/asio/include/asio/detail/pipe_select_interrupter.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/pipe_select_interrupter.hpp
@@ -0,0 +1,89 @@
+//
+// detail/pipe_select_interrupter.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_PIPE_SELECT_INTERRUPTER_HPP
+#define ASIO_DETAIL_PIPE_SELECT_INTERRUPTER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if !defined(ASIO_WINDOWS)
+#if !defined(ASIO_WINDOWS_RUNTIME)
+#if !defined(__CYGWIN__)
+#if !defined(__SYMBIAN32__)
+#if !defined(ASIO_HAS_EVENTFD)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class pipe_select_interrupter
+{
+public:
+  // Constructor.
+  ASIO_DECL pipe_select_interrupter();
+
+  // Destructor.
+  ASIO_DECL ~pipe_select_interrupter();
+
+  // Recreate the interrupter's descriptors. Used after a fork.
+  ASIO_DECL void recreate();
+
+  // Interrupt the select call.
+  ASIO_DECL void interrupt();
+
+  // Reset the select interrupter. Returns true if the reset was successful.
+  ASIO_DECL bool reset();
+
+  // Get the read descriptor to be passed to select.
+  int read_descriptor() const
+  {
+    return read_descriptor_;
+  }
+
+private:
+  // Open the descriptors. Throws on error.
+  ASIO_DECL void open_descriptors();
+
+  // Close the descriptors.
+  ASIO_DECL void close_descriptors();
+
+  // The read end of a connection used to interrupt the select call. This file
+  // descriptor is passed to select such that when it is time to stop, a single
+  // byte will be written on the other end of the connection and this
+  // descriptor will become readable.
+  int read_descriptor_;
+
+  // The write end of a connection used to interrupt the select call. A single
+  // byte may be written to this to wake up the select which is waiting for the
+  // other end to become readable.
+  int write_descriptor_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/pipe_select_interrupter.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // !defined(ASIO_HAS_EVENTFD)
+#endif // !defined(__SYMBIAN32__)
+#endif // !defined(__CYGWIN__)
+#endif // !defined(ASIO_WINDOWS_RUNTIME)
+#endif // !defined(ASIO_WINDOWS)
+
+#endif // ASIO_DETAIL_PIPE_SELECT_INTERRUPTER_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/pop_options.hpp b/link/modules/asio-standalone/asio/include/asio/detail/pop_options.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/pop_options.hpp
@@ -0,0 +1,141 @@
+//
+// detail/pop_options.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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++
+
+# if (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)
+#  if !defined(ASIO_DISABLE_VISIBILITY)
+#   pragma GCC visibility pop
+#  endif // !defined(ASIO_DISABLE_VISIBILITY)
+# endif // (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)
+
+#elif defined(__clang__)
+
+// Clang
+
+# if defined(__OBJC__)
+#  if !defined(__APPLE_CC__) || (__APPLE_CC__ <= 1)
+#   if defined(ASIO_OBJC_WORKAROUND)
+#    undef Protocol
+#    undef id
+#    undef ASIO_OBJC_WORKAROUND
+#   endif
+#  endif
+# endif
+
+# if !defined(_WIN32) && !defined(__WIN32__) && !defined(WIN32)
+#  if !defined(ASIO_DISABLE_VISIBILITY)
+#   pragma GCC visibility pop
+#  endif // !defined(ASIO_DISABLE_VISIBILITY)
+# endif // !defined(_WIN32) && !defined(__WIN32__) && !defined(WIN32)
+
+# pragma GCC diagnostic pop
+
+#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(ASIO_OBJC_WORKAROUND)
+#    undef Protocol
+#    undef id
+#    undef ASIO_OBJC_WORKAROUND
+#   endif
+#  endif
+# endif
+
+# if (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)
+#  if !defined(ASIO_DISABLE_VISIBILITY)
+#   pragma GCC visibility pop
+#  endif // !defined(ASIO_DISABLE_VISIBILITY)
+# endif // (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)
+
+# pragma GCC diagnostic pop
+
+#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__) && !defined(__clang__)
+
+// 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)
+
+# if defined(__cplusplus_cli) || defined(__cplusplus_winrt)
+#  if defined(ASIO_CLR_WORKAROUND)
+#   undef generic
+#   undef ASIO_CLR_WORKAROUND
+#  endif
+# endif
+
+#endif
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/posix_event.hpp b/link/modules/asio-standalone/asio/include/asio/detail/posix_event.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/posix_event.hpp
@@ -0,0 +1,175 @@
+//
+// detail/posix_event.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_POSIX_EVENT_HPP
+#define ASIO_DETAIL_POSIX_EVENT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_PTHREADS)
+
+#include <cstddef>
+#include <pthread.h>
+#include "asio/detail/assert.hpp"
+#include "asio/detail/noncopyable.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class posix_event
+  : private noncopyable
+{
+public:
+  // Constructor.
+  ASIO_DECL posix_event();
+
+  // Destructor.
+  ~posix_event()
+  {
+    ::pthread_cond_destroy(&cond_);
+  }
+
+  // Signal the event. (Retained for backward compatibility.)
+  template <typename Lock>
+  void signal(Lock& lock)
+  {
+    this->signal_all(lock);
+  }
+
+  // Signal all waiters.
+  template <typename Lock>
+  void signal_all(Lock& lock)
+  {
+    ASIO_ASSERT(lock.locked());
+    (void)lock;
+    state_ |= 1;
+    ::pthread_cond_broadcast(&cond_); // Ignore EINVAL.
+  }
+
+  // Unlock the mutex and signal one waiter.
+  template <typename Lock>
+  void unlock_and_signal_one(Lock& lock)
+  {
+    ASIO_ASSERT(lock.locked());
+    state_ |= 1;
+    bool have_waiters = (state_ > 1);
+    lock.unlock();
+    if (have_waiters)
+      ::pthread_cond_signal(&cond_); // Ignore EINVAL.
+  }
+
+  // Unlock the mutex and signal one waiter who may destroy us.
+  template <typename Lock>
+  void unlock_and_signal_one_for_destruction(Lock& lock)
+  {
+    ASIO_ASSERT(lock.locked());
+    state_ |= 1;
+    bool have_waiters = (state_ > 1);
+    if (have_waiters)
+      ::pthread_cond_signal(&cond_); // Ignore EINVAL.
+    lock.unlock();
+  }
+
+  // If there's a waiter, unlock the mutex and signal it.
+  template <typename Lock>
+  bool maybe_unlock_and_signal_one(Lock& lock)
+  {
+    ASIO_ASSERT(lock.locked());
+    state_ |= 1;
+    if (state_ > 1)
+    {
+      lock.unlock();
+      ::pthread_cond_signal(&cond_); // Ignore EINVAL.
+      return true;
+    }
+    return false;
+  }
+
+  // Reset the event.
+  template <typename Lock>
+  void clear(Lock& lock)
+  {
+    ASIO_ASSERT(lock.locked());
+    (void)lock;
+    state_ &= ~std::size_t(1);
+  }
+
+  // Wait for the event to become signalled.
+  template <typename Lock>
+  void wait(Lock& lock)
+  {
+    ASIO_ASSERT(lock.locked());
+    while ((state_ & 1) == 0)
+    {
+      state_ += 2;
+      ::pthread_cond_wait(&cond_, &lock.mutex().mutex_); // Ignore EINVAL.
+      state_ -= 2;
+    }
+  }
+
+  // Timed wait for the event to become signalled.
+  template <typename Lock>
+  bool wait_for_usec(Lock& lock, long usec)
+  {
+    ASIO_ASSERT(lock.locked());
+    if ((state_ & 1) == 0)
+    {
+      state_ += 2;
+      timespec ts;
+#if (defined(__MACH__) && defined(__APPLE__)) \
+      || (defined(__ANDROID__) && (__ANDROID_API__ < 21) \
+          && defined(HAVE_PTHREAD_COND_TIMEDWAIT_RELATIVE))
+      ts.tv_sec = usec / 1000000;
+      ts.tv_nsec = (usec % 1000000) * 1000;
+      ::pthread_cond_timedwait_relative_np(
+          &cond_, &lock.mutex().mutex_, &ts); // Ignore EINVAL.
+#else // (defined(__MACH__) && defined(__APPLE__))
+      // || (defined(__ANDROID__) && (__ANDROID_API__ < 21)
+      //     && defined(HAVE_PTHREAD_COND_TIMEDWAIT_RELATIVE))
+      if (::clock_gettime(CLOCK_MONOTONIC, &ts) == 0)
+      {
+        ts.tv_sec += usec / 1000000;
+        ts.tv_nsec += (usec % 1000000) * 1000;
+        ts.tv_sec += ts.tv_nsec / 1000000000;
+        ts.tv_nsec = ts.tv_nsec % 1000000000;
+        ::pthread_cond_timedwait(&cond_,
+            &lock.mutex().mutex_, &ts); // Ignore EINVAL.
+      }
+#endif // (defined(__MACH__) && defined(__APPLE__))
+       // || (defined(__ANDROID__) && (__ANDROID_API__ < 21)
+       //     && defined(HAVE_PTHREAD_COND_TIMEDWAIT_RELATIVE))
+      state_ -= 2;
+    }
+    return (state_ & 1) != 0;
+  }
+
+private:
+  ::pthread_cond_t cond_;
+  std::size_t state_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/posix_event.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // defined(ASIO_HAS_PTHREADS)
+
+#endif // ASIO_DETAIL_POSIX_EVENT_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/posix_fd_set_adapter.hpp b/link/modules/asio-standalone/asio/include/asio/detail/posix_fd_set_adapter.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/posix_fd_set_adapter.hpp
@@ -0,0 +1,118 @@
+//
+// detail/posix_fd_set_adapter.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_POSIX_FD_SET_ADAPTER_HPP
+#define ASIO_DETAIL_POSIX_FD_SET_ADAPTER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if !defined(ASIO_WINDOWS) \
+  && !defined(__CYGWIN__) \
+  && !defined(ASIO_WINDOWS_RUNTIME)
+
+#include <cstring>
+#include "asio/detail/noncopyable.hpp"
+#include "asio/detail/reactor_op_queue.hpp"
+#include "asio/detail/socket_types.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+// Adapts the FD_SET type to meet the Descriptor_Set concept's requirements.
+class posix_fd_set_adapter : noncopyable
+{
+public:
+  posix_fd_set_adapter()
+    : max_descriptor_(invalid_socket)
+  {
+    using namespace std; // Needed for memset on Solaris.
+    FD_ZERO(&fd_set_);
+  }
+
+  void reset()
+  {
+    using namespace std; // Needed for memset on Solaris.
+    FD_ZERO(&fd_set_);
+  }
+
+  bool set(socket_type descriptor)
+  {
+    if (descriptor < (socket_type)FD_SETSIZE)
+    {
+      if (max_descriptor_ == invalid_socket || descriptor > max_descriptor_)
+        max_descriptor_ = descriptor;
+      FD_SET(descriptor, &fd_set_);
+      return true;
+    }
+    return false;
+  }
+
+  void set(reactor_op_queue<socket_type>& operations, op_queue<operation>& ops)
+  {
+    reactor_op_queue<socket_type>::iterator i = operations.begin();
+    while (i != operations.end())
+    {
+      reactor_op_queue<socket_type>::iterator op_iter = i++;
+      if (!set(op_iter->first))
+      {
+        asio::error_code ec(error::fd_set_failure);
+        operations.cancel_operations(op_iter, ops, ec);
+      }
+    }
+  }
+
+  bool is_set(socket_type descriptor) const
+  {
+    return FD_ISSET(descriptor, &fd_set_) != 0;
+  }
+
+  operator fd_set*()
+  {
+    return &fd_set_;
+  }
+
+  socket_type max_descriptor() const
+  {
+    return max_descriptor_;
+  }
+
+  void perform(reactor_op_queue<socket_type>& operations,
+      op_queue<operation>& ops) const
+  {
+    reactor_op_queue<socket_type>::iterator i = operations.begin();
+    while (i != operations.end())
+    {
+      reactor_op_queue<socket_type>::iterator op_iter = i++;
+      if (is_set(op_iter->first))
+        operations.perform_operations(op_iter, ops);
+    }
+  }
+
+private:
+  mutable fd_set fd_set_;
+  socket_type max_descriptor_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // !defined(ASIO_WINDOWS)
+       // && !defined(__CYGWIN__)
+       // && !defined(ASIO_WINDOWS_RUNTIME)
+
+#endif // ASIO_DETAIL_POSIX_FD_SET_ADAPTER_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/posix_global.hpp b/link/modules/asio-standalone/asio/include/asio/detail/posix_global.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/posix_global.hpp
@@ -0,0 +1,80 @@
+//
+// detail/posix_global.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_POSIX_GLOBAL_HPP
+#define ASIO_DETAIL_POSIX_GLOBAL_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_PTHREADS)
+
+#include <exception>
+#include <pthread.h>
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename T>
+struct posix_global_impl
+{
+  // Helper function to perform initialisation.
+  static void do_init()
+  {
+    instance_.static_ptr_ = instance_.ptr_ = new T;
+  }
+
+  // Destructor automatically cleans up the global.
+  ~posix_global_impl()
+  {
+    delete static_ptr_;
+  }
+
+  static ::pthread_once_t init_once_;
+  static T* static_ptr_;
+  static posix_global_impl instance_;
+  T* ptr_;
+};
+
+template <typename T>
+::pthread_once_t posix_global_impl<T>::init_once_ = PTHREAD_ONCE_INIT;
+
+template <typename T>
+T* posix_global_impl<T>::static_ptr_ = 0;
+
+template <typename T>
+posix_global_impl<T> posix_global_impl<T>::instance_;
+
+template <typename T>
+T& posix_global()
+{
+  int result = ::pthread_once(
+      &posix_global_impl<T>::init_once_,
+      &posix_global_impl<T>::do_init);
+
+  if (result != 0)
+    std::terminate();
+
+  return *posix_global_impl<T>::instance_.ptr_;
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_PTHREADS)
+
+#endif // ASIO_DETAIL_POSIX_GLOBAL_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/posix_mutex.hpp b/link/modules/asio-standalone/asio/include/asio/detail/posix_mutex.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/posix_mutex.hpp
@@ -0,0 +1,76 @@
+//
+// detail/posix_mutex.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_POSIX_MUTEX_HPP
+#define ASIO_DETAIL_POSIX_MUTEX_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_PTHREADS)
+
+#include <pthread.h>
+#include "asio/detail/noncopyable.hpp"
+#include "asio/detail/scoped_lock.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class posix_event;
+
+class posix_mutex
+  : private noncopyable
+{
+public:
+  typedef asio::detail::scoped_lock<posix_mutex> scoped_lock;
+
+  // Constructor.
+  ASIO_DECL posix_mutex();
+
+  // Destructor.
+  ~posix_mutex()
+  {
+    ::pthread_mutex_destroy(&mutex_); // Ignore EBUSY.
+  }
+
+  // Lock the mutex.
+  void lock()
+  {
+    (void)::pthread_mutex_lock(&mutex_); // Ignore EINVAL.
+  }
+
+  // Unlock the mutex.
+  void unlock()
+  {
+    (void)::pthread_mutex_unlock(&mutex_); // Ignore EINVAL.
+  }
+
+private:
+  friend class posix_event;
+  ::pthread_mutex_t mutex_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/posix_mutex.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // defined(ASIO_HAS_PTHREADS)
+
+#endif // ASIO_DETAIL_POSIX_MUTEX_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/posix_signal_blocker.hpp b/link/modules/asio-standalone/asio/include/asio/detail/posix_signal_blocker.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/posix_signal_blocker.hpp
@@ -0,0 +1,85 @@
+//
+// detail/posix_signal_blocker.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_POSIX_SIGNAL_BLOCKER_HPP
+#define ASIO_DETAIL_POSIX_SIGNAL_BLOCKER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_PTHREADS)
+
+#include <csignal>
+#include <pthread.h>
+#include <signal.h>
+#include "asio/detail/noncopyable.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class posix_signal_blocker
+  : private noncopyable
+{
+public:
+  // Constructor blocks all signals for the calling thread.
+  posix_signal_blocker()
+    : blocked_(false)
+  {
+    sigset_t new_mask;
+    sigfillset(&new_mask);
+    blocked_ = (pthread_sigmask(SIG_BLOCK, &new_mask, &old_mask_) == 0);
+  }
+
+  // Destructor restores the previous signal mask.
+  ~posix_signal_blocker()
+  {
+    if (blocked_)
+      pthread_sigmask(SIG_SETMASK, &old_mask_, 0);
+  }
+
+  // Block all signals for the calling thread.
+  void block()
+  {
+    if (!blocked_)
+    {
+      sigset_t new_mask;
+      sigfillset(&new_mask);
+      blocked_ = (pthread_sigmask(SIG_BLOCK, &new_mask, &old_mask_) == 0);
+    }
+  }
+
+  // Restore the previous signal mask.
+  void unblock()
+  {
+    if (blocked_)
+      blocked_ = (pthread_sigmask(SIG_SETMASK, &old_mask_, 0) != 0);
+  }
+
+private:
+  // Have signals been blocked.
+  bool blocked_;
+
+  // The previous signal mask.
+  sigset_t old_mask_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_PTHREADS)
+
+#endif // ASIO_DETAIL_POSIX_SIGNAL_BLOCKER_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/posix_static_mutex.hpp b/link/modules/asio-standalone/asio/include/asio/detail/posix_static_mutex.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/posix_static_mutex.hpp
@@ -0,0 +1,64 @@
+//
+// detail/posix_static_mutex.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_POSIX_STATIC_MUTEX_HPP
+#define ASIO_DETAIL_POSIX_STATIC_MUTEX_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_PTHREADS)
+
+#include <pthread.h>
+#include "asio/detail/scoped_lock.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+struct posix_static_mutex
+{
+  typedef asio::detail::scoped_lock<posix_static_mutex> scoped_lock;
+
+  // Initialise the mutex.
+  void init()
+  {
+    // Nothing to do.
+  }
+
+  // Lock the mutex.
+  void lock()
+  {
+    (void)::pthread_mutex_lock(&mutex_); // Ignore EINVAL.
+  }
+
+  // Unlock the mutex.
+  void unlock()
+  {
+    (void)::pthread_mutex_unlock(&mutex_); // Ignore EINVAL.
+  }
+
+  ::pthread_mutex_t mutex_;
+};
+
+#define ASIO_POSIX_STATIC_MUTEX_INIT { PTHREAD_MUTEX_INITIALIZER }
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_PTHREADS)
+
+#endif // ASIO_DETAIL_POSIX_STATIC_MUTEX_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/posix_thread.hpp b/link/modules/asio-standalone/asio/include/asio/detail/posix_thread.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/posix_thread.hpp
@@ -0,0 +1,109 @@
+//
+// detail/posix_thread.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_POSIX_THREAD_HPP
+#define ASIO_DETAIL_POSIX_THREAD_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_PTHREADS)
+
+#include <cstddef>
+#include <pthread.h>
+#include "asio/detail/noncopyable.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+extern "C"
+{
+  ASIO_DECL void* asio_detail_posix_thread_function(void* arg);
+}
+
+class posix_thread
+  : private noncopyable
+{
+public:
+  // Constructor.
+  template <typename Function>
+  posix_thread(Function f, unsigned int = 0)
+    : joined_(false)
+  {
+    start_thread(new func<Function>(f));
+  }
+
+  // Destructor.
+  ASIO_DECL ~posix_thread();
+
+  // Wait for the thread to exit.
+  ASIO_DECL void join();
+
+  // Get number of CPUs.
+  ASIO_DECL static std::size_t hardware_concurrency();
+
+private:
+  friend void* asio_detail_posix_thread_function(void* arg);
+
+  class func_base
+  {
+  public:
+    virtual ~func_base() {}
+    virtual void run() = 0;
+  };
+
+  struct auto_func_base_ptr
+  {
+    func_base* ptr;
+    ~auto_func_base_ptr() { delete ptr; }
+  };
+
+  template <typename Function>
+  class func
+    : public func_base
+  {
+  public:
+    func(Function f)
+      : f_(f)
+    {
+    }
+
+    virtual void run()
+    {
+      f_();
+    }
+
+  private:
+    Function f_;
+  };
+
+  ASIO_DECL void start_thread(func_base* arg);
+
+  ::pthread_t thread_;
+  bool joined_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/posix_thread.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // defined(ASIO_HAS_PTHREADS)
+
+#endif // ASIO_DETAIL_POSIX_THREAD_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/posix_tss_ptr.hpp b/link/modules/asio-standalone/asio/include/asio/detail/posix_tss_ptr.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/posix_tss_ptr.hpp
@@ -0,0 +1,79 @@
+//
+// detail/posix_tss_ptr.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_POSIX_TSS_PTR_HPP
+#define ASIO_DETAIL_POSIX_TSS_PTR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_PTHREADS)
+
+#include <pthread.h>
+#include "asio/detail/noncopyable.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+// Helper function to create thread-specific storage.
+ASIO_DECL void posix_tss_ptr_create(pthread_key_t& key);
+
+template <typename T>
+class posix_tss_ptr
+  : private noncopyable
+{
+public:
+  // Constructor.
+  posix_tss_ptr()
+  {
+    posix_tss_ptr_create(tss_key_);
+  }
+
+  // Destructor.
+  ~posix_tss_ptr()
+  {
+    ::pthread_key_delete(tss_key_);
+  }
+
+  // Get the value.
+  operator T*() const
+  {
+    return static_cast<T*>(::pthread_getspecific(tss_key_));
+  }
+
+  // Set the value.
+  void operator=(T* value)
+  {
+    ::pthread_setspecific(tss_key_, value);
+  }
+
+private:
+  // Thread-specific storage to allow unlocked access to determine whether a
+  // thread is a member of the pool.
+  pthread_key_t tss_key_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/posix_tss_ptr.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // defined(ASIO_HAS_PTHREADS)
+
+#endif // ASIO_DETAIL_POSIX_TSS_PTR_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/push_options.hpp b/link/modules/asio-standalone/asio/include/asio/detail/push_options.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/push_options.hpp
@@ -0,0 +1,185 @@
+//
+// detail/push_options.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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++
+
+# if (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)
+#  if !defined(ASIO_DISABLE_VISIBILITY)
+#   pragma GCC visibility push (default)
+#  endif // !defined(ASIO_DISABLE_VISIBILITY)
+# endif // (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)
+
+#elif defined(__clang__)
+
+// Clang
+
+# if defined(__OBJC__)
+#  if !defined(__APPLE_CC__) || (__APPLE_CC__ <= 1)
+#   if !defined(ASIO_DISABLE_OBJC_WORKAROUND)
+#    if !defined(Protocol) && !defined(id)
+#     define Protocol cpp_Protocol
+#     define id cpp_id
+#     define ASIO_OBJC_WORKAROUND
+#    endif
+#   endif
+#  endif
+# endif
+
+# if !defined(_WIN32) && !defined(__WIN32__) && !defined(WIN32)
+#  if !defined(ASIO_DISABLE_VISIBILITY)
+#   pragma GCC visibility push (default)
+#  endif // !defined(ASIO_DISABLE_VISIBILITY)
+# endif // !defined(_WIN32) && !defined(__WIN32__) && !defined(WIN32)
+
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
+
+#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(ASIO_DISABLE_OBJC_WORKAROUND)
+#    if !defined(Protocol) && !defined(id)
+#     define Protocol cpp_Protocol
+#     define id cpp_id
+#     define ASIO_OBJC_WORKAROUND
+#    endif
+#   endif
+#  endif
+# endif
+
+# if (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)
+#  if !defined(ASIO_DISABLE_VISIBILITY)
+#   pragma GCC visibility push (default)
+#  endif // !defined(ASIO_DISABLE_VISIBILITY)
+# endif // (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)
+
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
+# if (__GNUC__ >= 7)
+#  pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
+# endif // (__GNUC__ >= 7)
+
+#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__) && !defined(__clang__)
+
+// 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:4510)
+# pragma warning (disable:4512)
+# pragma warning (disable:4610)
+# pragma warning (disable:4675)
+# if (_MSC_VER < 1600)
+// Visual Studio 2008 generates spurious warnings about unused parameters.
+#  pragma warning (disable:4100)
+# endif // (_MSC_VER < 1600)
+# 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)
+
+# if defined(__cplusplus_cli) || defined(__cplusplus_winrt)
+#  if !defined(ASIO_DISABLE_CLR_WORKAROUND)
+#   if !defined(generic)
+#    define generic cpp_generic
+#    define ASIO_CLR_WORKAROUND
+#   endif
+#  endif
+# endif
+
+#endif
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/reactive_descriptor_service.hpp b/link/modules/asio-standalone/asio/include/asio/detail/reactive_descriptor_service.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/reactive_descriptor_service.hpp
@@ -0,0 +1,416 @@
+//
+// detail/reactive_descriptor_service.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_REACTIVE_DESCRIPTOR_SERVICE_HPP
+#define ASIO_DETAIL_REACTIVE_DESCRIPTOR_SERVICE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if !defined(ASIO_WINDOWS) \
+  && !defined(ASIO_WINDOWS_RUNTIME) \
+  && !defined(__CYGWIN__)
+
+#include "asio/buffer.hpp"
+#include "asio/execution_context.hpp"
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/buffer_sequence_adapter.hpp"
+#include "asio/detail/descriptor_ops.hpp"
+#include "asio/detail/descriptor_read_op.hpp"
+#include "asio/detail/descriptor_write_op.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/detail/noncopyable.hpp"
+#include "asio/detail/reactive_null_buffers_op.hpp"
+#include "asio/detail/reactive_wait_op.hpp"
+#include "asio/detail/reactor.hpp"
+#include "asio/posix/descriptor_base.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class reactive_descriptor_service :
+  public execution_context_service_base<reactive_descriptor_service>
+{
+public:
+  // The native type of a descriptor.
+  typedef int native_handle_type;
+
+  // The implementation type of the descriptor.
+  class implementation_type
+    : private asio::detail::noncopyable
+  {
+  public:
+    // Default constructor.
+    implementation_type()
+      : descriptor_(-1),
+        state_(0)
+    {
+    }
+
+  private:
+    // Only this service will have access to the internal values.
+    friend class reactive_descriptor_service;
+
+    // The native descriptor representation.
+    int descriptor_;
+
+    // The current state of the descriptor.
+    descriptor_ops::state_type state_;
+
+    // Per-descriptor data used by the reactor.
+    reactor::per_descriptor_data reactor_data_;
+  };
+
+  // Constructor.
+  ASIO_DECL reactive_descriptor_service(execution_context& context);
+
+  // Destroy all user-defined handler objects owned by the service.
+  ASIO_DECL void shutdown();
+
+  // Construct a new descriptor implementation.
+  ASIO_DECL void construct(implementation_type& impl);
+
+  // Move-construct a new descriptor implementation.
+  ASIO_DECL void move_construct(implementation_type& impl,
+      implementation_type& other_impl) ASIO_NOEXCEPT;
+
+  // Move-assign from another descriptor implementation.
+  ASIO_DECL void move_assign(implementation_type& impl,
+      reactive_descriptor_service& other_service,
+      implementation_type& other_impl);
+
+  // Destroy a descriptor implementation.
+  ASIO_DECL void destroy(implementation_type& impl);
+
+  // Assign a native descriptor to a descriptor implementation.
+  ASIO_DECL asio::error_code assign(implementation_type& impl,
+      const native_handle_type& native_descriptor,
+      asio::error_code& ec);
+
+  // Determine whether the descriptor is open.
+  bool is_open(const implementation_type& impl) const
+  {
+    return impl.descriptor_ != -1;
+  }
+
+  // Destroy a descriptor implementation.
+  ASIO_DECL asio::error_code close(implementation_type& impl,
+      asio::error_code& ec);
+
+  // Get the native descriptor representation.
+  native_handle_type native_handle(const implementation_type& impl) const
+  {
+    return impl.descriptor_;
+  }
+
+  // Release ownership of the native descriptor representation.
+  ASIO_DECL native_handle_type release(implementation_type& impl);
+
+  // Cancel all operations associated with the descriptor.
+  ASIO_DECL asio::error_code cancel(implementation_type& impl,
+      asio::error_code& ec);
+
+  // Perform an IO control command on the descriptor.
+  template <typename IO_Control_Command>
+  asio::error_code io_control(implementation_type& impl,
+      IO_Control_Command& command, asio::error_code& ec)
+  {
+    descriptor_ops::ioctl(impl.descriptor_, impl.state_,
+        command.name(), static_cast<ioctl_arg_type*>(command.data()), ec);
+    return ec;
+  }
+
+  // Gets the non-blocking mode of the descriptor.
+  bool non_blocking(const implementation_type& impl) const
+  {
+    return (impl.state_ & descriptor_ops::user_set_non_blocking) != 0;
+  }
+
+  // Sets the non-blocking mode of the descriptor.
+  asio::error_code non_blocking(implementation_type& impl,
+      bool mode, asio::error_code& ec)
+  {
+    descriptor_ops::set_user_non_blocking(
+        impl.descriptor_, impl.state_, mode, ec);
+    return ec;
+  }
+
+  // Gets the non-blocking mode of the native descriptor implementation.
+  bool native_non_blocking(const implementation_type& impl) const
+  {
+    return (impl.state_ & descriptor_ops::internal_non_blocking) != 0;
+  }
+
+  // Sets the non-blocking mode of the native descriptor implementation.
+  asio::error_code native_non_blocking(implementation_type& impl,
+      bool mode, asio::error_code& ec)
+  {
+    descriptor_ops::set_internal_non_blocking(
+        impl.descriptor_, impl.state_, mode, ec);
+    return ec;
+  }
+
+  // Wait for the descriptor to become ready to read, ready to write, or to have
+  // pending error conditions.
+  asio::error_code wait(implementation_type& impl,
+      posix::descriptor_base::wait_type w, asio::error_code& ec)
+  {
+    switch (w)
+    {
+    case posix::descriptor_base::wait_read:
+      descriptor_ops::poll_read(impl.descriptor_, impl.state_, ec);
+      break;
+    case posix::descriptor_base::wait_write:
+      descriptor_ops::poll_write(impl.descriptor_, impl.state_, ec);
+      break;
+    case posix::descriptor_base::wait_error:
+      descriptor_ops::poll_error(impl.descriptor_, impl.state_, ec);
+      break;
+    default:
+      ec = asio::error::invalid_argument;
+      break;
+    }
+
+    return ec;
+  }
+
+  // Asynchronously wait for the descriptor to become ready to read, ready to
+  // write, or to have pending error conditions.
+  template <typename Handler, typename IoExecutor>
+  void async_wait(implementation_type& impl,
+      posix::descriptor_base::wait_type w,
+      Handler& handler, const IoExecutor& io_ex)
+  {
+    bool is_continuation =
+      asio_handler_cont_helpers::is_continuation(handler);
+
+    // Allocate and construct an operation to wrap the handler.
+    typedef reactive_wait_op<Handler, IoExecutor> op;
+    typename op::ptr p = { asio::detail::addressof(handler),
+      op::ptr::allocate(handler), 0 };
+    p.p = new (p.v) op(success_ec_, handler, io_ex);
+
+    ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "descriptor",
+          &impl, impl.descriptor_, "async_wait"));
+
+    int op_type;
+    switch (w)
+    {
+    case posix::descriptor_base::wait_read:
+        op_type = reactor::read_op;
+        break;
+    case posix::descriptor_base::wait_write:
+        op_type = reactor::write_op;
+        break;
+    case posix::descriptor_base::wait_error:
+        op_type = reactor::except_op;
+        break;
+      default:
+        p.p->ec_ = asio::error::invalid_argument;
+        reactor_.post_immediate_completion(p.p, is_continuation);
+        p.v = p.p = 0;
+        return;
+    }
+
+    start_op(impl, op_type, p.p, is_continuation, false, false);
+    p.v = p.p = 0;
+  }
+
+  // Write some data to the descriptor.
+  template <typename ConstBufferSequence>
+  size_t write_some(implementation_type& impl,
+      const ConstBufferSequence& buffers, asio::error_code& ec)
+  {
+    typedef buffer_sequence_adapter<asio::const_buffer,
+        ConstBufferSequence> bufs_type;
+
+    if (bufs_type::is_single_buffer)
+    {
+      return descriptor_ops::sync_write1(impl.descriptor_,
+          impl.state_, bufs_type::first(buffers).data(),
+          bufs_type::first(buffers).size(), ec);
+    }
+    else
+    {
+      bufs_type bufs(buffers);
+
+      return descriptor_ops::sync_write(impl.descriptor_, impl.state_,
+          bufs.buffers(), bufs.count(), bufs.all_empty(), ec);
+    }
+  }
+
+  // Wait until data can be written without blocking.
+  size_t write_some(implementation_type& impl,
+      const null_buffers&, asio::error_code& ec)
+  {
+    // Wait for descriptor to become ready.
+    descriptor_ops::poll_write(impl.descriptor_, impl.state_, ec);
+
+    return 0;
+  }
+
+  // Start an asynchronous write. The data being sent must be valid for the
+  // lifetime of the asynchronous operation.
+  template <typename ConstBufferSequence, typename Handler, typename IoExecutor>
+  void async_write_some(implementation_type& impl,
+      const ConstBufferSequence& buffers, Handler& handler,
+      const IoExecutor& io_ex)
+  {
+    bool is_continuation =
+      asio_handler_cont_helpers::is_continuation(handler);
+
+    // Allocate and construct an operation to wrap the handler.
+    typedef descriptor_write_op<ConstBufferSequence, Handler, IoExecutor> op;
+    typename op::ptr p = { asio::detail::addressof(handler),
+      op::ptr::allocate(handler), 0 };
+    p.p = new (p.v) op(success_ec_, impl.descriptor_, buffers, handler, io_ex);
+
+    ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "descriptor",
+          &impl, impl.descriptor_, "async_write_some"));
+
+    start_op(impl, reactor::write_op, p.p, is_continuation, true,
+        buffer_sequence_adapter<asio::const_buffer,
+          ConstBufferSequence>::all_empty(buffers));
+    p.v = p.p = 0;
+  }
+
+  // Start an asynchronous wait until data can be written without blocking.
+  template <typename Handler, typename IoExecutor>
+  void async_write_some(implementation_type& impl,
+      const null_buffers&, Handler& handler, const IoExecutor& io_ex)
+  {
+    bool is_continuation =
+      asio_handler_cont_helpers::is_continuation(handler);
+
+    // Allocate and construct an operation to wrap the handler.
+    typedef reactive_null_buffers_op<Handler, IoExecutor> op;
+    typename op::ptr p = { asio::detail::addressof(handler),
+      op::ptr::allocate(handler), 0 };
+    p.p = new (p.v) op(success_ec_, handler, io_ex);
+
+    ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "descriptor",
+          &impl, impl.descriptor_, "async_write_some(null_buffers)"));
+
+    start_op(impl, reactor::write_op, p.p, is_continuation, false, false);
+    p.v = p.p = 0;
+  }
+
+  // Read some data from the stream. Returns the number of bytes read.
+  template <typename MutableBufferSequence>
+  size_t read_some(implementation_type& impl,
+      const MutableBufferSequence& buffers, asio::error_code& ec)
+  {
+    typedef buffer_sequence_adapter<asio::mutable_buffer,
+        MutableBufferSequence> bufs_type;
+
+    if (bufs_type::is_single_buffer)
+    {
+      return descriptor_ops::sync_read1(impl.descriptor_,
+          impl.state_, bufs_type::first(buffers).data(),
+          bufs_type::first(buffers).size(), ec);
+    }
+    else
+    {
+      bufs_type bufs(buffers);
+
+      return descriptor_ops::sync_read(impl.descriptor_, impl.state_,
+          bufs.buffers(), bufs.count(), bufs.all_empty(), ec);
+    }
+  }
+
+  // Wait until data can be read without blocking.
+  size_t read_some(implementation_type& impl,
+      const null_buffers&, asio::error_code& ec)
+  {
+    // Wait for descriptor to become ready.
+    descriptor_ops::poll_read(impl.descriptor_, impl.state_, ec);
+
+    return 0;
+  }
+
+  // Start an asynchronous read. The buffer for the data being read must be
+  // valid for the lifetime of the asynchronous operation.
+  template <typename MutableBufferSequence,
+      typename Handler, typename IoExecutor>
+  void async_read_some(implementation_type& impl,
+      const MutableBufferSequence& buffers,
+      Handler& handler, const IoExecutor& io_ex)
+  {
+    bool is_continuation =
+      asio_handler_cont_helpers::is_continuation(handler);
+
+    // Allocate and construct an operation to wrap the handler.
+    typedef descriptor_read_op<MutableBufferSequence, Handler, IoExecutor> op;
+    typename op::ptr p = { asio::detail::addressof(handler),
+      op::ptr::allocate(handler), 0 };
+    p.p = new (p.v) op(success_ec_, impl.descriptor_, buffers, handler, io_ex);
+
+    ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "descriptor",
+          &impl, impl.descriptor_, "async_read_some"));
+
+    start_op(impl, reactor::read_op, p.p, is_continuation, true,
+        buffer_sequence_adapter<asio::mutable_buffer,
+          MutableBufferSequence>::all_empty(buffers));
+    p.v = p.p = 0;
+  }
+
+  // Wait until data can be read without blocking.
+  template <typename Handler, typename IoExecutor>
+  void async_read_some(implementation_type& impl,
+      const null_buffers&, Handler& handler, const IoExecutor& io_ex)
+  {
+    bool is_continuation =
+      asio_handler_cont_helpers::is_continuation(handler);
+
+    // Allocate and construct an operation to wrap the handler.
+    typedef reactive_null_buffers_op<Handler, IoExecutor> op;
+    typename op::ptr p = { asio::detail::addressof(handler),
+      op::ptr::allocate(handler), 0 };
+    p.p = new (p.v) op(success_ec_, handler, io_ex);
+
+    ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "descriptor",
+          &impl, impl.descriptor_, "async_read_some(null_buffers)"));
+
+    start_op(impl, reactor::read_op, p.p, is_continuation, false, false);
+    p.v = p.p = 0;
+  }
+
+private:
+  // Start the asynchronous operation.
+  ASIO_DECL void start_op(implementation_type& impl, int op_type,
+      reactor_op* op, bool is_continuation, bool is_non_blocking, bool noop);
+
+  // The selector that performs event demultiplexing for the service.
+  reactor& reactor_;
+
+  // Cached success value to avoid accessing category singleton.
+  const asio::error_code success_ec_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/reactive_descriptor_service.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // !defined(ASIO_WINDOWS)
+       //   && !defined(ASIO_WINDOWS_RUNTIME)
+       //   && !defined(__CYGWIN__)
+
+#endif // ASIO_DETAIL_REACTIVE_DESCRIPTOR_SERVICE_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/reactive_null_buffers_op.hpp b/link/modules/asio-standalone/asio/include/asio/detail/reactive_null_buffers_op.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/reactive_null_buffers_op.hpp
@@ -0,0 +1,98 @@
+//
+// detail/reactive_null_buffers_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_REACTIVE_NULL_BUFFERS_OP_HPP
+#define ASIO_DETAIL_REACTIVE_NULL_BUFFERS_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/handler_work.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/detail/reactor_op.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Handler, typename IoExecutor>
+class reactive_null_buffers_op : public reactor_op
+{
+public:
+  ASIO_DEFINE_HANDLER_PTR(reactive_null_buffers_op);
+
+  reactive_null_buffers_op(const asio::error_code& success_ec,
+      Handler& handler, const IoExecutor& io_ex)
+    : reactor_op(success_ec, &reactive_null_buffers_op::do_perform,
+        &reactive_null_buffers_op::do_complete),
+      handler_(ASIO_MOVE_CAST(Handler)(handler)),
+      work_(handler_, io_ex)
+  {
+  }
+
+  static status do_perform(reactor_op*)
+  {
+    return done;
+  }
+
+  static void do_complete(void* owner, operation* base,
+      const asio::error_code& /*ec*/,
+      std::size_t /*bytes_transferred*/)
+  {
+    // Take ownership of the handler object.
+    reactive_null_buffers_op* o(static_cast<reactive_null_buffers_op*>(base));
+    ptr p = { asio::detail::addressof(o->handler_), o, o };
+
+    ASIO_HANDLER_COMPLETION((*o));
+
+    // Take ownership of the operation's outstanding work.
+    handler_work<Handler, IoExecutor> w(
+        ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)(
+          o->work_));
+
+    // Make a copy of the handler so that the memory can be deallocated before
+    // the upcall is made. Even if we're not about to make an upcall, a
+    // sub-object of the handler may be the true owner of the memory associated
+    // with the handler. Consequently, a local copy of the handler is required
+    // to ensure that any owning sub-object remains valid until after we have
+    // deallocated the memory here.
+    detail::binder2<Handler, asio::error_code, std::size_t>
+      handler(o->handler_, o->ec_, o->bytes_transferred_);
+    p.h = asio::detail::addressof(handler.handler_);
+    p.reset();
+
+    // Make the upcall if required.
+    if (owner)
+    {
+      fenced_block b(fenced_block::half);
+      ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_));
+      w.complete(handler, handler.handler_);
+      ASIO_HANDLER_INVOCATION_END;
+    }
+  }
+
+private:
+  Handler handler_;
+  handler_work<Handler, IoExecutor> work_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_REACTIVE_NULL_BUFFERS_OP_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/reactive_serial_port_service.hpp b/link/modules/asio-standalone/asio/include/asio/detail/reactive_serial_port_service.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/reactive_serial_port_service.hpp
@@ -0,0 +1,237 @@
+//
+// detail/reactive_serial_port_service.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.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 ASIO_DETAIL_REACTIVE_SERIAL_PORT_SERVICE_HPP
+#define ASIO_DETAIL_REACTIVE_SERIAL_PORT_SERVICE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_SERIAL_PORT)
+#if !defined(ASIO_WINDOWS) && !defined(__CYGWIN__)
+
+#include <string>
+#include "asio/error.hpp"
+#include "asio/execution_context.hpp"
+#include "asio/serial_port_base.hpp"
+#include "asio/detail/descriptor_ops.hpp"
+#include "asio/detail/reactive_descriptor_service.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+// Extend reactive_descriptor_service to provide serial port support.
+class reactive_serial_port_service :
+  public execution_context_service_base<reactive_serial_port_service>
+{
+public:
+  // The native type of a serial port.
+  typedef reactive_descriptor_service::native_handle_type native_handle_type;
+
+  // The implementation type of the serial port.
+  typedef reactive_descriptor_service::implementation_type implementation_type;
+
+  ASIO_DECL reactive_serial_port_service(execution_context& context);
+
+  // Destroy all user-defined handler objects owned by the service.
+  ASIO_DECL void shutdown();
+
+  // Construct a new serial port implementation.
+  void construct(implementation_type& impl)
+  {
+    descriptor_service_.construct(impl);
+  }
+
+  // Move-construct a new serial port implementation.
+  void move_construct(implementation_type& impl,
+      implementation_type& other_impl)
+  {
+    descriptor_service_.move_construct(impl, other_impl);
+  }
+
+  // Move-assign from another serial port implementation.
+  void move_assign(implementation_type& impl,
+      reactive_serial_port_service& other_service,
+      implementation_type& other_impl)
+  {
+    descriptor_service_.move_assign(impl,
+        other_service.descriptor_service_, other_impl);
+  }
+
+  // Destroy a serial port implementation.
+  void destroy(implementation_type& impl)
+  {
+    descriptor_service_.destroy(impl);
+  }
+
+  // Open the serial port using the specified device name.
+  ASIO_DECL asio::error_code open(implementation_type& impl,
+      const std::string& device, asio::error_code& ec);
+
+  // Assign a native descriptor to a serial port implementation.
+  asio::error_code assign(implementation_type& impl,
+      const native_handle_type& native_descriptor,
+      asio::error_code& ec)
+  {
+    return descriptor_service_.assign(impl, native_descriptor, ec);
+  }
+
+  // Determine whether the serial port is open.
+  bool is_open(const implementation_type& impl) const
+  {
+    return descriptor_service_.is_open(impl);
+  }
+
+  // Destroy a serial port implementation.
+  asio::error_code close(implementation_type& impl,
+      asio::error_code& ec)
+  {
+    return descriptor_service_.close(impl, ec);
+  }
+
+  // Get the native serial port representation.
+  native_handle_type native_handle(implementation_type& impl)
+  {
+    return descriptor_service_.native_handle(impl);
+  }
+
+  // Cancel all operations associated with the serial port.
+  asio::error_code cancel(implementation_type& impl,
+      asio::error_code& ec)
+  {
+    return descriptor_service_.cancel(impl, ec);
+  }
+
+  // Set an option on the serial port.
+  template <typename SettableSerialPortOption>
+  asio::error_code set_option(implementation_type& impl,
+      const SettableSerialPortOption& option, asio::error_code& ec)
+  {
+    return do_set_option(impl,
+        &reactive_serial_port_service::store_option<SettableSerialPortOption>,
+        &option, ec);
+  }
+
+  // Get an option from the serial port.
+  template <typename GettableSerialPortOption>
+  asio::error_code get_option(const implementation_type& impl,
+      GettableSerialPortOption& option, asio::error_code& ec) const
+  {
+    return do_get_option(impl,
+        &reactive_serial_port_service::load_option<GettableSerialPortOption>,
+        &option, ec);
+  }
+
+  // Send a break sequence to the serial port.
+  asio::error_code send_break(implementation_type& impl,
+      asio::error_code& ec)
+  {
+    int result = ::tcsendbreak(descriptor_service_.native_handle(impl), 0);
+    descriptor_ops::get_last_error(ec, result < 0);
+    return ec;
+  }
+
+  // Write the given data. Returns the number of bytes sent.
+  template <typename ConstBufferSequence>
+  size_t write_some(implementation_type& impl,
+      const ConstBufferSequence& buffers, asio::error_code& ec)
+  {
+    return descriptor_service_.write_some(impl, buffers, ec);
+  }
+
+  // Start an asynchronous write. The data being written must be valid for the
+  // lifetime of the asynchronous operation.
+  template <typename ConstBufferSequence, typename Handler, typename IoExecutor>
+  void async_write_some(implementation_type& impl,
+      const ConstBufferSequence& buffers,
+      Handler& handler, const IoExecutor& io_ex)
+  {
+    descriptor_service_.async_write_some(impl, buffers, handler, io_ex);
+  }
+
+  // Read some data. Returns the number of bytes received.
+  template <typename MutableBufferSequence>
+  size_t read_some(implementation_type& impl,
+      const MutableBufferSequence& buffers, asio::error_code& ec)
+  {
+    return descriptor_service_.read_some(impl, buffers, ec);
+  }
+
+  // Start an asynchronous read. The buffer for the data being received must be
+  // valid for the lifetime of the asynchronous operation.
+  template <typename MutableBufferSequence,
+      typename Handler, typename IoExecutor>
+  void async_read_some(implementation_type& impl,
+      const MutableBufferSequence& buffers,
+      Handler& handler, const IoExecutor& io_ex)
+  {
+    descriptor_service_.async_read_some(impl, buffers, handler, io_ex);
+  }
+
+private:
+  // Function pointer type for storing a serial port option.
+  typedef asio::error_code (*store_function_type)(
+      const void*, termios&, asio::error_code&);
+
+  // Helper function template to store a serial port option.
+  template <typename SettableSerialPortOption>
+  static asio::error_code store_option(const void* option,
+      termios& storage, asio::error_code& ec)
+  {
+    static_cast<const SettableSerialPortOption*>(option)->store(storage, ec);
+    return ec;
+  }
+
+  // Helper function to set a serial port option.
+  ASIO_DECL asio::error_code do_set_option(
+      implementation_type& impl, store_function_type store,
+      const void* option, asio::error_code& ec);
+
+  // Function pointer type for loading a serial port option.
+  typedef asio::error_code (*load_function_type)(
+      void*, const termios&, asio::error_code&);
+
+  // Helper function template to load a serial port option.
+  template <typename GettableSerialPortOption>
+  static asio::error_code load_option(void* option,
+      const termios& storage, asio::error_code& ec)
+  {
+    static_cast<GettableSerialPortOption*>(option)->load(storage, ec);
+    return ec;
+  }
+
+  // Helper function to get a serial port option.
+  ASIO_DECL asio::error_code do_get_option(
+      const implementation_type& impl, load_function_type load,
+      void* option, asio::error_code& ec) const;
+
+  // The implementation used for initiating asynchronous operations.
+  reactive_descriptor_service descriptor_service_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/reactive_serial_port_service.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // !defined(ASIO_WINDOWS) && !defined(__CYGWIN__)
+#endif // defined(ASIO_HAS_SERIAL_PORT)
+
+#endif // ASIO_DETAIL_REACTIVE_SERIAL_PORT_SERVICE_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/reactive_socket_accept_op.hpp b/link/modules/asio-standalone/asio/include/asio/detail/reactive_socket_accept_op.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/reactive_socket_accept_op.hpp
@@ -0,0 +1,242 @@
+//
+// detail/reactive_socket_accept_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_REACTIVE_SOCKET_ACCEPT_OP_HPP
+#define ASIO_DETAIL_REACTIVE_SOCKET_ACCEPT_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/handler_work.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/detail/reactor_op.hpp"
+#include "asio/detail/socket_holder.hpp"
+#include "asio/detail/socket_ops.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Socket, typename Protocol>
+class reactive_socket_accept_op_base : public reactor_op
+{
+public:
+  reactive_socket_accept_op_base(const asio::error_code& success_ec,
+      socket_type socket, socket_ops::state_type state, Socket& peer,
+      const Protocol& protocol, typename Protocol::endpoint* peer_endpoint,
+      func_type complete_func)
+    : reactor_op(success_ec,
+        &reactive_socket_accept_op_base::do_perform, complete_func),
+      socket_(socket),
+      state_(state),
+      peer_(peer),
+      protocol_(protocol),
+      peer_endpoint_(peer_endpoint),
+      addrlen_(peer_endpoint ? peer_endpoint->capacity() : 0)
+  {
+  }
+
+  static status do_perform(reactor_op* base)
+  {
+    reactive_socket_accept_op_base* o(
+        static_cast<reactive_socket_accept_op_base*>(base));
+
+    socket_type new_socket = invalid_socket;
+    status result = socket_ops::non_blocking_accept(o->socket_,
+        o->state_, o->peer_endpoint_ ? o->peer_endpoint_->data() : 0,
+        o->peer_endpoint_ ? &o->addrlen_ : 0, o->ec_, new_socket)
+    ? done : not_done;
+    o->new_socket_.reset(new_socket);
+
+    ASIO_HANDLER_REACTOR_OPERATION((*o, "non_blocking_accept", o->ec_));
+
+    return result;
+  }
+
+  void do_assign()
+  {
+    if (new_socket_.get() != invalid_socket)
+    {
+      if (peer_endpoint_)
+        peer_endpoint_->resize(addrlen_);
+      peer_.assign(protocol_, new_socket_.get(), ec_);
+      if (!ec_)
+        new_socket_.release();
+    }
+  }
+
+private:
+  socket_type socket_;
+  socket_ops::state_type state_;
+  socket_holder new_socket_;
+  Socket& peer_;
+  Protocol protocol_;
+  typename Protocol::endpoint* peer_endpoint_;
+  std::size_t addrlen_;
+};
+
+template <typename Socket, typename Protocol,
+    typename Handler, typename IoExecutor>
+class reactive_socket_accept_op :
+  public reactive_socket_accept_op_base<Socket, Protocol>
+{
+public:
+  ASIO_DEFINE_HANDLER_PTR(reactive_socket_accept_op);
+
+  reactive_socket_accept_op(const asio::error_code& success_ec,
+      socket_type socket, socket_ops::state_type state, Socket& peer,
+      const Protocol& protocol, typename Protocol::endpoint* peer_endpoint,
+      Handler& handler, const IoExecutor& io_ex)
+    : reactive_socket_accept_op_base<Socket, Protocol>(
+        success_ec, socket, state, peer, protocol, peer_endpoint,
+        &reactive_socket_accept_op::do_complete),
+      handler_(ASIO_MOVE_CAST(Handler)(handler)),
+      work_(handler_, io_ex)
+  {
+  }
+
+  static void do_complete(void* owner, operation* base,
+      const asio::error_code& /*ec*/,
+      std::size_t /*bytes_transferred*/)
+  {
+    // Take ownership of the handler object.
+    reactive_socket_accept_op* o(static_cast<reactive_socket_accept_op*>(base));
+    ptr p = { asio::detail::addressof(o->handler_), o, o };
+
+    // On success, assign new connection to peer socket object.
+    if (owner)
+      o->do_assign();
+
+    ASIO_HANDLER_COMPLETION((*o));
+
+    // Take ownership of the operation's outstanding work.
+    handler_work<Handler, IoExecutor> w(
+        ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)(
+          o->work_));
+
+    // Make a copy of the handler so that the memory can be deallocated before
+    // the upcall is made. Even if we're not about to make an upcall, a
+    // sub-object of the handler may be the true owner of the memory associated
+    // with the handler. Consequently, a local copy of the handler is required
+    // to ensure that any owning sub-object remains valid until after we have
+    // deallocated the memory here.
+    detail::binder1<Handler, asio::error_code>
+      handler(o->handler_, o->ec_);
+    p.h = asio::detail::addressof(handler.handler_);
+    p.reset();
+
+    // Make the upcall if required.
+    if (owner)
+    {
+      fenced_block b(fenced_block::half);
+      ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_));
+      w.complete(handler, handler.handler_);
+      ASIO_HANDLER_INVOCATION_END;
+    }
+  }
+
+private:
+  Handler handler_;
+  handler_work<Handler, IoExecutor> work_;
+};
+
+#if defined(ASIO_HAS_MOVE)
+
+template <typename Protocol, typename PeerIoExecutor,
+    typename Handler, typename IoExecutor>
+class reactive_socket_move_accept_op :
+  private Protocol::socket::template rebind_executor<PeerIoExecutor>::other,
+  public reactive_socket_accept_op_base<
+    typename Protocol::socket::template rebind_executor<PeerIoExecutor>::other,
+    Protocol>
+{
+public:
+  ASIO_DEFINE_HANDLER_PTR(reactive_socket_move_accept_op);
+
+  reactive_socket_move_accept_op(const asio::error_code& success_ec,
+      const PeerIoExecutor& peer_io_ex, socket_type socket,
+      socket_ops::state_type state, const Protocol& protocol,
+      typename Protocol::endpoint* peer_endpoint, Handler& handler,
+      const IoExecutor& io_ex)
+    : peer_socket_type(peer_io_ex),
+      reactive_socket_accept_op_base<peer_socket_type, Protocol>(
+        success_ec, socket, state, *this, protocol, peer_endpoint,
+        &reactive_socket_move_accept_op::do_complete),
+      handler_(ASIO_MOVE_CAST(Handler)(handler)),
+      work_(handler_, io_ex)
+  {
+  }
+
+  static void do_complete(void* owner, operation* base,
+      const asio::error_code& /*ec*/,
+      std::size_t /*bytes_transferred*/)
+  {
+    // Take ownership of the handler object.
+    reactive_socket_move_accept_op* o(
+        static_cast<reactive_socket_move_accept_op*>(base));
+    ptr p = { asio::detail::addressof(o->handler_), o, o };
+
+    // On success, assign new connection to peer socket object.
+    if (owner)
+      o->do_assign();
+
+    ASIO_HANDLER_COMPLETION((*o));
+
+    // Take ownership of the operation's outstanding work.
+    handler_work<Handler, IoExecutor> w(
+        ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)(
+          o->work_));
+
+    // Make a copy of the handler so that the memory can be deallocated before
+    // the upcall is made. Even if we're not about to make an upcall, a
+    // sub-object of the handler may be the true owner of the memory associated
+    // with the handler. Consequently, a local copy of the handler is required
+    // to ensure that any owning sub-object remains valid until after we have
+    // deallocated the memory here.
+    detail::move_binder2<Handler,
+      asio::error_code, peer_socket_type>
+        handler(0, ASIO_MOVE_CAST(Handler)(o->handler_), o->ec_,
+          ASIO_MOVE_CAST(peer_socket_type)(*o));
+    p.h = asio::detail::addressof(handler.handler_);
+    p.reset();
+
+    // Make the upcall if required.
+    if (owner)
+    {
+      fenced_block b(fenced_block::half);
+      ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, "..."));
+      w.complete(handler, handler.handler_);
+      ASIO_HANDLER_INVOCATION_END;
+    }
+  }
+
+private:
+  typedef typename Protocol::socket::template
+    rebind_executor<PeerIoExecutor>::other peer_socket_type;
+
+  Handler handler_;
+  handler_work<Handler, IoExecutor> work_;
+};
+
+#endif // defined(ASIO_HAS_MOVE)
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_REACTIVE_SOCKET_ACCEPT_OP_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/reactive_socket_connect_op.hpp b/link/modules/asio-standalone/asio/include/asio/detail/reactive_socket_connect_op.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/reactive_socket_connect_op.hpp
@@ -0,0 +1,123 @@
+//
+// detail/reactive_socket_connect_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_REACTIVE_SOCKET_CONNECT_OP_HPP
+#define ASIO_DETAIL_REACTIVE_SOCKET_CONNECT_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/handler_work.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/detail/reactor_op.hpp"
+#include "asio/detail/socket_ops.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class reactive_socket_connect_op_base : public reactor_op
+{
+public:
+  reactive_socket_connect_op_base(const asio::error_code& success_ec,
+      socket_type socket, func_type complete_func)
+    : reactor_op(success_ec,
+        &reactive_socket_connect_op_base::do_perform, complete_func),
+      socket_(socket)
+  {
+  }
+
+  static status do_perform(reactor_op* base)
+  {
+    reactive_socket_connect_op_base* o(
+        static_cast<reactive_socket_connect_op_base*>(base));
+
+    status result = socket_ops::non_blocking_connect(
+        o->socket_, o->ec_) ? done : not_done;
+
+    ASIO_HANDLER_REACTOR_OPERATION((*o, "non_blocking_connect", o->ec_));
+
+    return result;
+  }
+
+private:
+  socket_type socket_;
+};
+
+template <typename Handler, typename IoExecutor>
+class reactive_socket_connect_op : public reactive_socket_connect_op_base
+{
+public:
+  ASIO_DEFINE_HANDLER_PTR(reactive_socket_connect_op);
+
+  reactive_socket_connect_op(const asio::error_code& success_ec,
+      socket_type socket, Handler& handler, const IoExecutor& io_ex)
+    : reactive_socket_connect_op_base(success_ec, socket,
+        &reactive_socket_connect_op::do_complete),
+      handler_(ASIO_MOVE_CAST(Handler)(handler)),
+      work_(handler_, io_ex)
+  {
+  }
+
+  static void do_complete(void* owner, operation* base,
+      const asio::error_code& /*ec*/,
+      std::size_t /*bytes_transferred*/)
+  {
+    // Take ownership of the handler object.
+    reactive_socket_connect_op* o
+      (static_cast<reactive_socket_connect_op*>(base));
+    ptr p = { asio::detail::addressof(o->handler_), o, o };
+
+    ASIO_HANDLER_COMPLETION((*o));
+
+    // Take ownership of the operation's outstanding work.
+    handler_work<Handler, IoExecutor> w(
+        ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)(
+          o->work_));
+
+    // Make a copy of the handler so that the memory can be deallocated before
+    // the upcall is made. Even if we're not about to make an upcall, a
+    // sub-object of the handler may be the true owner of the memory associated
+    // with the handler. Consequently, a local copy of the handler is required
+    // to ensure that any owning sub-object remains valid until after we have
+    // deallocated the memory here.
+    detail::binder1<Handler, asio::error_code>
+      handler(o->handler_, o->ec_);
+    p.h = asio::detail::addressof(handler.handler_);
+    p.reset();
+
+    // Make the upcall if required.
+    if (owner)
+    {
+      fenced_block b(fenced_block::half);
+      ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_));
+      w.complete(handler, handler.handler_);
+      ASIO_HANDLER_INVOCATION_END;
+    }
+  }
+
+private:
+  Handler handler_;
+  handler_work<Handler, IoExecutor> work_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_REACTIVE_SOCKET_CONNECT_OP_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/reactive_socket_recv_op.hpp b/link/modules/asio-standalone/asio/include/asio/detail/reactive_socket_recv_op.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/reactive_socket_recv_op.hpp
@@ -0,0 +1,159 @@
+//
+// detail/reactive_socket_recv_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_REACTIVE_SOCKET_RECV_OP_HPP
+#define ASIO_DETAIL_REACTIVE_SOCKET_RECV_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/buffer_sequence_adapter.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/handler_work.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/detail/reactor_op.hpp"
+#include "asio/detail/socket_ops.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename MutableBufferSequence>
+class reactive_socket_recv_op_base : public reactor_op
+{
+public:
+  reactive_socket_recv_op_base(const asio::error_code& success_ec,
+      socket_type socket, socket_ops::state_type state,
+      const MutableBufferSequence& buffers,
+      socket_base::message_flags flags, func_type complete_func)
+    : reactor_op(success_ec,
+        &reactive_socket_recv_op_base::do_perform, complete_func),
+      socket_(socket),
+      state_(state),
+      buffers_(buffers),
+      flags_(flags)
+  {
+  }
+
+  static status do_perform(reactor_op* base)
+  {
+    reactive_socket_recv_op_base* o(
+        static_cast<reactive_socket_recv_op_base*>(base));
+
+    typedef buffer_sequence_adapter<asio::mutable_buffer,
+        MutableBufferSequence> bufs_type;
+
+    status result;
+    if (bufs_type::is_single_buffer)
+    {
+      result = socket_ops::non_blocking_recv1(o->socket_,
+          bufs_type::first(o->buffers_).data(),
+          bufs_type::first(o->buffers_).size(), o->flags_,
+          (o->state_ & socket_ops::stream_oriented) != 0,
+          o->ec_, o->bytes_transferred_) ? done : not_done;
+    }
+    else
+    {
+      bufs_type bufs(o->buffers_);
+      result = socket_ops::non_blocking_recv(o->socket_,
+          bufs.buffers(), bufs.count(), o->flags_,
+          (o->state_ & socket_ops::stream_oriented) != 0,
+          o->ec_, o->bytes_transferred_) ? done : not_done;
+    }
+
+    if (result == done)
+      if ((o->state_ & socket_ops::stream_oriented) != 0)
+        if (o->bytes_transferred_ == 0)
+          result = done_and_exhausted;
+
+    ASIO_HANDLER_REACTOR_OPERATION((*o, "non_blocking_recv",
+          o->ec_, o->bytes_transferred_));
+
+    return result;
+  }
+
+private:
+  socket_type socket_;
+  socket_ops::state_type state_;
+  MutableBufferSequence buffers_;
+  socket_base::message_flags flags_;
+};
+
+template <typename MutableBufferSequence, typename Handler, typename IoExecutor>
+class reactive_socket_recv_op :
+  public reactive_socket_recv_op_base<MutableBufferSequence>
+{
+public:
+  ASIO_DEFINE_HANDLER_PTR(reactive_socket_recv_op);
+
+  reactive_socket_recv_op(const asio::error_code& success_ec,
+      socket_type socket, socket_ops::state_type state,
+      const MutableBufferSequence& buffers, socket_base::message_flags flags,
+      Handler& handler, const IoExecutor& io_ex)
+    : reactive_socket_recv_op_base<MutableBufferSequence>(success_ec, socket,
+        state, buffers, flags, &reactive_socket_recv_op::do_complete),
+      handler_(ASIO_MOVE_CAST(Handler)(handler)),
+      work_(handler_, io_ex)
+  {
+  }
+
+  static void do_complete(void* owner, operation* base,
+      const asio::error_code& /*ec*/,
+      std::size_t /*bytes_transferred*/)
+  {
+    // Take ownership of the handler object.
+    reactive_socket_recv_op* o(static_cast<reactive_socket_recv_op*>(base));
+    ptr p = { asio::detail::addressof(o->handler_), o, o };
+
+    ASIO_HANDLER_COMPLETION((*o));
+
+    // Take ownership of the operation's outstanding work.
+    handler_work<Handler, IoExecutor> w(
+        ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)(
+          o->work_));
+
+    // Make a copy of the handler so that the memory can be deallocated before
+    // the upcall is made. Even if we're not about to make an upcall, a
+    // sub-object of the handler may be the true owner of the memory associated
+    // with the handler. Consequently, a local copy of the handler is required
+    // to ensure that any owning sub-object remains valid until after we have
+    // deallocated the memory here.
+    detail::binder2<Handler, asio::error_code, std::size_t>
+      handler(o->handler_, o->ec_, o->bytes_transferred_);
+    p.h = asio::detail::addressof(handler.handler_);
+    p.reset();
+
+    // Make the upcall if required.
+    if (owner)
+    {
+      fenced_block b(fenced_block::half);
+      ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_));
+      w.complete(handler, handler.handler_);
+      ASIO_HANDLER_INVOCATION_END;
+    }
+  }
+
+private:
+  Handler handler_;
+  handler_work<Handler, IoExecutor> work_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_REACTIVE_SOCKET_RECV_OP_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/reactive_socket_recvfrom_op.hpp b/link/modules/asio-standalone/asio/include/asio/detail/reactive_socket_recvfrom_op.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/reactive_socket_recvfrom_op.hpp
@@ -0,0 +1,164 @@
+//
+// detail/reactive_socket_recvfrom_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_REACTIVE_SOCKET_RECVFROM_OP_HPP
+#define ASIO_DETAIL_REACTIVE_SOCKET_RECVFROM_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/buffer_sequence_adapter.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/handler_work.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/detail/reactor_op.hpp"
+#include "asio/detail/socket_ops.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename MutableBufferSequence, typename Endpoint>
+class reactive_socket_recvfrom_op_base : public reactor_op
+{
+public:
+  reactive_socket_recvfrom_op_base(const asio::error_code& success_ec,
+      socket_type socket, int protocol_type,
+      const MutableBufferSequence& buffers, Endpoint& endpoint,
+      socket_base::message_flags flags, func_type complete_func)
+    : reactor_op(success_ec,
+        &reactive_socket_recvfrom_op_base::do_perform, complete_func),
+      socket_(socket),
+      protocol_type_(protocol_type),
+      buffers_(buffers),
+      sender_endpoint_(endpoint),
+      flags_(flags)
+  {
+  }
+
+  static status do_perform(reactor_op* base)
+  {
+    reactive_socket_recvfrom_op_base* o(
+        static_cast<reactive_socket_recvfrom_op_base*>(base));
+
+    typedef buffer_sequence_adapter<asio::mutable_buffer,
+        MutableBufferSequence> bufs_type;
+
+    std::size_t addr_len = o->sender_endpoint_.capacity();
+    status result;
+    if (bufs_type::is_single_buffer)
+    {
+      result = socket_ops::non_blocking_recvfrom1(
+          o->socket_, bufs_type::first(o->buffers_).data(),
+          bufs_type::first(o->buffers_).size(), o->flags_,
+          o->sender_endpoint_.data(), &addr_len,
+          o->ec_, o->bytes_transferred_) ? done : not_done;
+    }
+    else
+    {
+      bufs_type bufs(o->buffers_);
+      result = socket_ops::non_blocking_recvfrom(o->socket_,
+          bufs.buffers(), bufs.count(), o->flags_,
+          o->sender_endpoint_.data(), &addr_len,
+          o->ec_, o->bytes_transferred_) ? done : not_done;
+    }
+
+    if (result && !o->ec_)
+      o->sender_endpoint_.resize(addr_len);
+
+    ASIO_HANDLER_REACTOR_OPERATION((*o, "non_blocking_recvfrom",
+          o->ec_, o->bytes_transferred_));
+
+    return result;
+  }
+
+private:
+  socket_type socket_;
+  int protocol_type_;
+  MutableBufferSequence buffers_;
+  Endpoint& sender_endpoint_;
+  socket_base::message_flags flags_;
+};
+
+template <typename MutableBufferSequence, typename Endpoint,
+    typename Handler, typename IoExecutor>
+class reactive_socket_recvfrom_op :
+  public reactive_socket_recvfrom_op_base<MutableBufferSequence, Endpoint>
+{
+public:
+  ASIO_DEFINE_HANDLER_PTR(reactive_socket_recvfrom_op);
+
+  reactive_socket_recvfrom_op(const asio::error_code& success_ec,
+      socket_type socket, int protocol_type,
+      const MutableBufferSequence& buffers, Endpoint& endpoint,
+      socket_base::message_flags flags, Handler& handler,
+      const IoExecutor& io_ex)
+    : reactive_socket_recvfrom_op_base<MutableBufferSequence, Endpoint>(
+        success_ec, socket, protocol_type, buffers, endpoint, flags,
+        &reactive_socket_recvfrom_op::do_complete),
+      handler_(ASIO_MOVE_CAST(Handler)(handler)),
+      work_(handler_, io_ex)
+  {
+  }
+
+  static void do_complete(void* owner, operation* base,
+      const asio::error_code& /*ec*/,
+      std::size_t /*bytes_transferred*/)
+  {
+    // Take ownership of the handler object.
+    reactive_socket_recvfrom_op* o(
+        static_cast<reactive_socket_recvfrom_op*>(base));
+    ptr p = { asio::detail::addressof(o->handler_), o, o };
+
+    ASIO_HANDLER_COMPLETION((*o));
+
+    // Take ownership of the operation's outstanding work.
+    handler_work<Handler, IoExecutor> w(
+        ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)(
+          o->work_));
+
+    // Make a copy of the handler so that the memory can be deallocated before
+    // the upcall is made. Even if we're not about to make an upcall, a
+    // sub-object of the handler may be the true owner of the memory associated
+    // with the handler. Consequently, a local copy of the handler is required
+    // to ensure that any owning sub-object remains valid until after we have
+    // deallocated the memory here.
+    detail::binder2<Handler, asio::error_code, std::size_t>
+      handler(o->handler_, o->ec_, o->bytes_transferred_);
+    p.h = asio::detail::addressof(handler.handler_);
+    p.reset();
+
+    // Make the upcall if required.
+    if (owner)
+    {
+      fenced_block b(fenced_block::half);
+      ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_));
+      w.complete(handler, handler.handler_);
+      ASIO_HANDLER_INVOCATION_END;
+    }
+  }
+
+private:
+  Handler handler_;
+  handler_work<Handler, IoExecutor> work_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_REACTIVE_SOCKET_RECVFROM_OP_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/reactive_socket_recvmsg_op.hpp b/link/modules/asio-standalone/asio/include/asio/detail/reactive_socket_recvmsg_op.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/reactive_socket_recvmsg_op.hpp
@@ -0,0 +1,145 @@
+//
+// detail/reactive_socket_recvmsg_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_REACTIVE_SOCKET_RECVMSG_OP_HPP
+#define ASIO_DETAIL_REACTIVE_SOCKET_RECVMSG_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/buffer_sequence_adapter.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/handler_work.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/detail/reactor_op.hpp"
+#include "asio/detail/socket_ops.hpp"
+#include "asio/socket_base.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename MutableBufferSequence>
+class reactive_socket_recvmsg_op_base : public reactor_op
+{
+public:
+  reactive_socket_recvmsg_op_base(const asio::error_code& success_ec,
+      socket_type socket, const MutableBufferSequence& buffers,
+      socket_base::message_flags in_flags,
+      socket_base::message_flags& out_flags, func_type complete_func)
+    : reactor_op(success_ec,
+        &reactive_socket_recvmsg_op_base::do_perform, complete_func),
+      socket_(socket),
+      buffers_(buffers),
+      in_flags_(in_flags),
+      out_flags_(out_flags)
+  {
+  }
+
+  static status do_perform(reactor_op* base)
+  {
+    reactive_socket_recvmsg_op_base* o(
+        static_cast<reactive_socket_recvmsg_op_base*>(base));
+
+    buffer_sequence_adapter<asio::mutable_buffer,
+        MutableBufferSequence> bufs(o->buffers_);
+
+    status result = socket_ops::non_blocking_recvmsg(o->socket_,
+        bufs.buffers(), bufs.count(),
+        o->in_flags_, o->out_flags_,
+        o->ec_, o->bytes_transferred_) ? done : not_done;
+
+    ASIO_HANDLER_REACTOR_OPERATION((*o, "non_blocking_recvmsg",
+          o->ec_, o->bytes_transferred_));
+
+    return result;
+  }
+
+private:
+  socket_type socket_;
+  MutableBufferSequence buffers_;
+  socket_base::message_flags in_flags_;
+  socket_base::message_flags& out_flags_;
+};
+
+template <typename MutableBufferSequence, typename Handler, typename IoExecutor>
+class reactive_socket_recvmsg_op :
+  public reactive_socket_recvmsg_op_base<MutableBufferSequence>
+{
+public:
+  ASIO_DEFINE_HANDLER_PTR(reactive_socket_recvmsg_op);
+
+  reactive_socket_recvmsg_op(const asio::error_code& success_ec,
+      socket_type socket, const MutableBufferSequence& buffers,
+      socket_base::message_flags in_flags,
+      socket_base::message_flags& out_flags, Handler& handler,
+      const IoExecutor& io_ex)
+    : reactive_socket_recvmsg_op_base<MutableBufferSequence>(
+        success_ec, socket, buffers, in_flags, out_flags,
+        &reactive_socket_recvmsg_op::do_complete),
+      handler_(ASIO_MOVE_CAST(Handler)(handler)),
+      work_(handler_, io_ex)
+  {
+  }
+
+  static void do_complete(void* owner, operation* base,
+      const asio::error_code& /*ec*/,
+      std::size_t /*bytes_transferred*/)
+  {
+    // Take ownership of the handler object.
+    reactive_socket_recvmsg_op* o(
+        static_cast<reactive_socket_recvmsg_op*>(base));
+    ptr p = { asio::detail::addressof(o->handler_), o, o };
+
+    ASIO_HANDLER_COMPLETION((*o));
+
+    // Take ownership of the operation's outstanding work.
+    handler_work<Handler, IoExecutor> w(
+        ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)(
+          o->work_));
+
+    // Make a copy of the handler so that the memory can be deallocated before
+    // the upcall is made. Even if we're not about to make an upcall, a
+    // sub-object of the handler may be the true owner of the memory associated
+    // with the handler. Consequently, a local copy of the handler is required
+    // to ensure that any owning sub-object remains valid until after we have
+    // deallocated the memory here.
+    detail::binder2<Handler, asio::error_code, std::size_t>
+      handler(o->handler_, o->ec_, o->bytes_transferred_);
+    p.h = asio::detail::addressof(handler.handler_);
+    p.reset();
+
+    // Make the upcall if required.
+    if (owner)
+    {
+      fenced_block b(fenced_block::half);
+      ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_));
+      w.complete(handler, handler.handler_);
+      ASIO_HANDLER_INVOCATION_END;
+    }
+  }
+
+private:
+  Handler handler_;
+  handler_work<Handler, IoExecutor> work_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_REACTIVE_SOCKET_RECVMSG_OP_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/reactive_socket_send_op.hpp b/link/modules/asio-standalone/asio/include/asio/detail/reactive_socket_send_op.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/reactive_socket_send_op.hpp
@@ -0,0 +1,162 @@
+//
+// detail/reactive_socket_send_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_REACTIVE_SOCKET_SEND_OP_HPP
+#define ASIO_DETAIL_REACTIVE_SOCKET_SEND_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/buffer_sequence_adapter.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/handler_work.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/detail/reactor_op.hpp"
+#include "asio/detail/socket_ops.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename ConstBufferSequence>
+class reactive_socket_send_op_base : public reactor_op
+{
+public:
+  reactive_socket_send_op_base(const asio::error_code& success_ec,
+      socket_type socket, socket_ops::state_type state,
+      const ConstBufferSequence& buffers,
+      socket_base::message_flags flags, func_type complete_func)
+    : reactor_op(success_ec,
+        &reactive_socket_send_op_base::do_perform, complete_func),
+      socket_(socket),
+      state_(state),
+      buffers_(buffers),
+      flags_(flags)
+  {
+  }
+
+  static status do_perform(reactor_op* base)
+  {
+    reactive_socket_send_op_base* o(
+        static_cast<reactive_socket_send_op_base*>(base));
+
+    typedef buffer_sequence_adapter<asio::const_buffer,
+        ConstBufferSequence> bufs_type;
+
+    status result;
+    if (bufs_type::is_single_buffer)
+    {
+      result = socket_ops::non_blocking_send1(o->socket_,
+          bufs_type::first(o->buffers_).data(),
+          bufs_type::first(o->buffers_).size(), o->flags_,
+          o->ec_, o->bytes_transferred_) ? done : not_done;
+
+      if (result == done)
+        if ((o->state_ & socket_ops::stream_oriented) != 0)
+          if (o->bytes_transferred_ < bufs_type::first(o->buffers_).size())
+            result = done_and_exhausted;
+    }
+    else
+    {
+      bufs_type bufs(o->buffers_);
+      result = socket_ops::non_blocking_send(o->socket_,
+            bufs.buffers(), bufs.count(), o->flags_,
+            o->ec_, o->bytes_transferred_) ? done : not_done;
+
+      if (result == done)
+        if ((o->state_ & socket_ops::stream_oriented) != 0)
+          if (o->bytes_transferred_ < bufs.total_size())
+            result = done_and_exhausted;
+    }
+
+    ASIO_HANDLER_REACTOR_OPERATION((*o, "non_blocking_send",
+          o->ec_, o->bytes_transferred_));
+
+    return result;
+  }
+
+private:
+  socket_type socket_;
+  socket_ops::state_type state_;
+  ConstBufferSequence buffers_;
+  socket_base::message_flags flags_;
+};
+
+template <typename ConstBufferSequence, typename Handler, typename IoExecutor>
+class reactive_socket_send_op :
+  public reactive_socket_send_op_base<ConstBufferSequence>
+{
+public:
+  ASIO_DEFINE_HANDLER_PTR(reactive_socket_send_op);
+
+  reactive_socket_send_op(const asio::error_code& success_ec,
+      socket_type socket, socket_ops::state_type state,
+      const ConstBufferSequence& buffers, socket_base::message_flags flags,
+      Handler& handler, const IoExecutor& io_ex)
+    : reactive_socket_send_op_base<ConstBufferSequence>(success_ec, socket,
+        state, buffers, flags, &reactive_socket_send_op::do_complete),
+      handler_(ASIO_MOVE_CAST(Handler)(handler)),
+      work_(handler_, io_ex)
+  {
+  }
+
+  static void do_complete(void* owner, operation* base,
+      const asio::error_code& /*ec*/,
+      std::size_t /*bytes_transferred*/)
+  {
+    // Take ownership of the handler object.
+    reactive_socket_send_op* o(static_cast<reactive_socket_send_op*>(base));
+    ptr p = { asio::detail::addressof(o->handler_), o, o };
+
+    ASIO_HANDLER_COMPLETION((*o));
+
+    // Take ownership of the operation's outstanding work.
+    handler_work<Handler, IoExecutor> w(
+        ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)(
+          o->work_));
+
+    // Make a copy of the handler so that the memory can be deallocated before
+    // the upcall is made. Even if we're not about to make an upcall, a
+    // sub-object of the handler may be the true owner of the memory associated
+    // with the handler. Consequently, a local copy of the handler is required
+    // to ensure that any owning sub-object remains valid until after we have
+    // deallocated the memory here.
+    detail::binder2<Handler, asio::error_code, std::size_t>
+      handler(o->handler_, o->ec_, o->bytes_transferred_);
+    p.h = asio::detail::addressof(handler.handler_);
+    p.reset();
+
+    // Make the upcall if required.
+    if (owner)
+    {
+      fenced_block b(fenced_block::half);
+      ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_));
+      w.complete(handler, handler.handler_);
+      ASIO_HANDLER_INVOCATION_END;
+    }
+  }
+
+private:
+  Handler handler_;
+  handler_work<Handler, IoExecutor> work_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_REACTIVE_SOCKET_SEND_OP_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/reactive_socket_sendto_op.hpp b/link/modules/asio-standalone/asio/include/asio/detail/reactive_socket_sendto_op.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/reactive_socket_sendto_op.hpp
@@ -0,0 +1,156 @@
+//
+// detail/reactive_socket_sendto_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_REACTIVE_SOCKET_SENDTO_OP_HPP
+#define ASIO_DETAIL_REACTIVE_SOCKET_SENDTO_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/buffer_sequence_adapter.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/handler_work.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/detail/reactor_op.hpp"
+#include "asio/detail/socket_ops.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename ConstBufferSequence, typename Endpoint>
+class reactive_socket_sendto_op_base : public reactor_op
+{
+public:
+  reactive_socket_sendto_op_base(const asio::error_code& success_ec,
+      socket_type socket, const ConstBufferSequence& buffers,
+      const Endpoint& endpoint, socket_base::message_flags flags,
+      func_type complete_func)
+    : reactor_op(success_ec,
+        &reactive_socket_sendto_op_base::do_perform, complete_func),
+      socket_(socket),
+      buffers_(buffers),
+      destination_(endpoint),
+      flags_(flags)
+  {
+  }
+
+  static status do_perform(reactor_op* base)
+  {
+    reactive_socket_sendto_op_base* o(
+        static_cast<reactive_socket_sendto_op_base*>(base));
+
+    typedef buffer_sequence_adapter<asio::const_buffer,
+        ConstBufferSequence> bufs_type;
+
+    status result;
+    if (bufs_type::is_single_buffer)
+    {
+      result = socket_ops::non_blocking_sendto1(o->socket_,
+          bufs_type::first(o->buffers_).data(),
+          bufs_type::first(o->buffers_).size(), o->flags_,
+          o->destination_.data(), o->destination_.size(),
+          o->ec_, o->bytes_transferred_) ? done : not_done;
+    }
+    else
+    {
+      bufs_type bufs(o->buffers_);
+      result = socket_ops::non_blocking_sendto(o->socket_,
+          bufs.buffers(), bufs.count(), o->flags_,
+          o->destination_.data(), o->destination_.size(),
+          o->ec_, o->bytes_transferred_) ? done : not_done;
+    }
+
+    ASIO_HANDLER_REACTOR_OPERATION((*o, "non_blocking_sendto",
+          o->ec_, o->bytes_transferred_));
+
+    return result;
+  }
+
+private:
+  socket_type socket_;
+  ConstBufferSequence buffers_;
+  Endpoint destination_;
+  socket_base::message_flags flags_;
+};
+
+template <typename ConstBufferSequence, typename Endpoint,
+    typename Handler, typename IoExecutor>
+class reactive_socket_sendto_op :
+  public reactive_socket_sendto_op_base<ConstBufferSequence, Endpoint>
+{
+public:
+  ASIO_DEFINE_HANDLER_PTR(reactive_socket_sendto_op);
+
+  reactive_socket_sendto_op(const asio::error_code& success_ec,
+      socket_type socket, const ConstBufferSequence& buffers,
+      const Endpoint& endpoint, socket_base::message_flags flags,
+      Handler& handler, const IoExecutor& io_ex)
+    : reactive_socket_sendto_op_base<ConstBufferSequence, Endpoint>(
+        success_ec, socket, buffers, endpoint, flags,
+        &reactive_socket_sendto_op::do_complete),
+      handler_(ASIO_MOVE_CAST(Handler)(handler)),
+      work_(handler_, io_ex)
+  {
+  }
+
+  static void do_complete(void* owner, operation* base,
+      const asio::error_code& /*ec*/,
+      std::size_t /*bytes_transferred*/)
+  {
+    // Take ownership of the handler object.
+    reactive_socket_sendto_op* o(static_cast<reactive_socket_sendto_op*>(base));
+    ptr p = { asio::detail::addressof(o->handler_), o, o };
+
+    ASIO_HANDLER_COMPLETION((*o));
+
+    // Take ownership of the operation's outstanding work.
+    handler_work<Handler, IoExecutor> w(
+        ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)(
+          o->work_));
+
+    // Make a copy of the handler so that the memory can be deallocated before
+    // the upcall is made. Even if we're not about to make an upcall, a
+    // sub-object of the handler may be the true owner of the memory associated
+    // with the handler. Consequently, a local copy of the handler is required
+    // to ensure that any owning sub-object remains valid until after we have
+    // deallocated the memory here.
+    detail::binder2<Handler, asio::error_code, std::size_t>
+      handler(o->handler_, o->ec_, o->bytes_transferred_);
+    p.h = asio::detail::addressof(handler.handler_);
+    p.reset();
+
+    // Make the upcall if required.
+    if (owner)
+    {
+      fenced_block b(fenced_block::half);
+      ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_));
+      w.complete(handler, handler.handler_);
+      ASIO_HANDLER_INVOCATION_END;
+    }
+  }
+
+private:
+  Handler handler_;
+  handler_work<Handler, IoExecutor> work_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_REACTIVE_SOCKET_SENDTO_OP_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/reactive_socket_service.hpp b/link/modules/asio-standalone/asio/include/asio/detail/reactive_socket_service.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/reactive_socket_service.hpp
@@ -0,0 +1,528 @@
+//
+// detail/reactive_socket_service.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_HPP
+#define ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if !defined(ASIO_HAS_IOCP)
+
+#include "asio/buffer.hpp"
+#include "asio/error.hpp"
+#include "asio/execution_context.hpp"
+#include "asio/socket_base.hpp"
+#include "asio/detail/buffer_sequence_adapter.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/detail/noncopyable.hpp"
+#include "asio/detail/reactive_null_buffers_op.hpp"
+#include "asio/detail/reactive_socket_accept_op.hpp"
+#include "asio/detail/reactive_socket_connect_op.hpp"
+#include "asio/detail/reactive_socket_recvfrom_op.hpp"
+#include "asio/detail/reactive_socket_sendto_op.hpp"
+#include "asio/detail/reactive_socket_service_base.hpp"
+#include "asio/detail/reactor.hpp"
+#include "asio/detail/reactor_op.hpp"
+#include "asio/detail/socket_holder.hpp"
+#include "asio/detail/socket_ops.hpp"
+#include "asio/detail/socket_types.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Protocol>
+class reactive_socket_service :
+  public execution_context_service_base<reactive_socket_service<Protocol> >,
+  public reactive_socket_service_base
+{
+public:
+  // The protocol type.
+  typedef Protocol protocol_type;
+
+  // The endpoint type.
+  typedef typename Protocol::endpoint endpoint_type;
+
+  // The native type of a socket.
+  typedef socket_type native_handle_type;
+
+  // The implementation type of the socket.
+  struct implementation_type :
+    reactive_socket_service_base::base_implementation_type
+  {
+    // Default constructor.
+    implementation_type()
+      : protocol_(endpoint_type().protocol())
+    {
+    }
+
+    // The protocol associated with the socket.
+    protocol_type protocol_;
+  };
+
+  // Constructor.
+  reactive_socket_service(execution_context& context)
+    : execution_context_service_base<
+        reactive_socket_service<Protocol> >(context),
+      reactive_socket_service_base(context)
+  {
+  }
+
+  // Destroy all user-defined handler objects owned by the service.
+  void shutdown()
+  {
+    this->base_shutdown();
+  }
+
+  // Move-construct a new socket implementation.
+  void move_construct(implementation_type& impl,
+      implementation_type& other_impl) ASIO_NOEXCEPT
+  {
+    this->base_move_construct(impl, other_impl);
+
+    impl.protocol_ = other_impl.protocol_;
+    other_impl.protocol_ = endpoint_type().protocol();
+  }
+
+  // Move-assign from another socket implementation.
+  void move_assign(implementation_type& impl,
+      reactive_socket_service_base& other_service,
+      implementation_type& other_impl)
+  {
+    this->base_move_assign(impl, other_service, other_impl);
+
+    impl.protocol_ = other_impl.protocol_;
+    other_impl.protocol_ = endpoint_type().protocol();
+  }
+
+  // Move-construct a new socket implementation from another protocol type.
+  template <typename Protocol1>
+  void converting_move_construct(implementation_type& impl,
+      reactive_socket_service<Protocol1>&,
+      typename reactive_socket_service<
+        Protocol1>::implementation_type& other_impl)
+  {
+    this->base_move_construct(impl, other_impl);
+
+    impl.protocol_ = protocol_type(other_impl.protocol_);
+    other_impl.protocol_ = typename Protocol1::endpoint().protocol();
+  }
+
+  // Open a new socket implementation.
+  asio::error_code open(implementation_type& impl,
+      const protocol_type& protocol, asio::error_code& ec)
+  {
+    if (!do_open(impl, protocol.family(),
+          protocol.type(), protocol.protocol(), ec))
+      impl.protocol_ = protocol;
+    return ec;
+  }
+
+  // Assign a native socket to a socket implementation.
+  asio::error_code assign(implementation_type& impl,
+      const protocol_type& protocol, const native_handle_type& native_socket,
+      asio::error_code& ec)
+  {
+    if (!do_assign(impl, protocol.type(), native_socket, ec))
+      impl.protocol_ = protocol;
+    return ec;
+  }
+
+  // Get the native socket representation.
+  native_handle_type native_handle(implementation_type& impl)
+  {
+    return impl.socket_;
+  }
+
+  // Bind the socket to the specified local endpoint.
+  asio::error_code bind(implementation_type& impl,
+      const endpoint_type& endpoint, asio::error_code& ec)
+  {
+    socket_ops::bind(impl.socket_, endpoint.data(), endpoint.size(), ec);
+    return ec;
+  }
+
+  // Set a socket option.
+  template <typename Option>
+  asio::error_code set_option(implementation_type& impl,
+      const Option& option, asio::error_code& ec)
+  {
+    socket_ops::setsockopt(impl.socket_, impl.state_,
+        option.level(impl.protocol_), option.name(impl.protocol_),
+        option.data(impl.protocol_), option.size(impl.protocol_), ec);
+    return ec;
+  }
+
+  // Set a socket option.
+  template <typename Option>
+  asio::error_code get_option(const implementation_type& impl,
+      Option& option, asio::error_code& ec) const
+  {
+    std::size_t size = option.size(impl.protocol_);
+    socket_ops::getsockopt(impl.socket_, impl.state_,
+        option.level(impl.protocol_), option.name(impl.protocol_),
+        option.data(impl.protocol_), &size, ec);
+    if (!ec)
+      option.resize(impl.protocol_, size);
+    return ec;
+  }
+
+  // Get the local endpoint.
+  endpoint_type local_endpoint(const implementation_type& impl,
+      asio::error_code& ec) const
+  {
+    endpoint_type endpoint;
+    std::size_t addr_len = endpoint.capacity();
+    if (socket_ops::getsockname(impl.socket_, endpoint.data(), &addr_len, ec))
+      return endpoint_type();
+    endpoint.resize(addr_len);
+    return endpoint;
+  }
+
+  // Get the remote endpoint.
+  endpoint_type remote_endpoint(const implementation_type& impl,
+      asio::error_code& ec) const
+  {
+    endpoint_type endpoint;
+    std::size_t addr_len = endpoint.capacity();
+    if (socket_ops::getpeername(impl.socket_,
+          endpoint.data(), &addr_len, false, ec))
+      return endpoint_type();
+    endpoint.resize(addr_len);
+    return endpoint;
+  }
+
+  // Disable sends or receives on the socket.
+  asio::error_code shutdown(base_implementation_type& impl,
+      socket_base::shutdown_type what, asio::error_code& ec)
+  {
+    socket_ops::shutdown(impl.socket_, what, ec);
+    return ec;
+  }
+
+  // Send a datagram to the specified endpoint. Returns the number of bytes
+  // sent.
+  template <typename ConstBufferSequence>
+  size_t send_to(implementation_type& impl, const ConstBufferSequence& buffers,
+      const endpoint_type& destination, socket_base::message_flags flags,
+      asio::error_code& ec)
+  {
+    typedef buffer_sequence_adapter<asio::const_buffer,
+        ConstBufferSequence> bufs_type;
+
+    if (bufs_type::is_single_buffer)
+    {
+      return socket_ops::sync_sendto1(impl.socket_, impl.state_,
+          bufs_type::first(buffers).data(),
+          bufs_type::first(buffers).size(), flags,
+          destination.data(), destination.size(), ec);
+    }
+    else
+    {
+      bufs_type bufs(buffers);
+      return socket_ops::sync_sendto(impl.socket_, impl.state_,
+          bufs.buffers(), bufs.count(), flags,
+          destination.data(), destination.size(), ec);
+    }
+  }
+
+  // Wait until data can be sent without blocking.
+  size_t send_to(implementation_type& impl, const null_buffers&,
+      const endpoint_type&, socket_base::message_flags,
+      asio::error_code& ec)
+  {
+    // Wait for socket to become ready.
+    socket_ops::poll_write(impl.socket_, impl.state_, -1, ec);
+
+    return 0;
+  }
+
+  // Start an asynchronous send. The data being sent must be valid for the
+  // lifetime of the asynchronous operation.
+  template <typename ConstBufferSequence, typename Handler, typename IoExecutor>
+  void async_send_to(implementation_type& impl,
+      const ConstBufferSequence& buffers,
+      const endpoint_type& destination, socket_base::message_flags flags,
+      Handler& handler, const IoExecutor& io_ex)
+  {
+    bool is_continuation =
+      asio_handler_cont_helpers::is_continuation(handler);
+
+    // Allocate and construct an operation to wrap the handler.
+    typedef reactive_socket_sendto_op<ConstBufferSequence,
+        endpoint_type, Handler, IoExecutor> op;
+    typename op::ptr p = { asio::detail::addressof(handler),
+      op::ptr::allocate(handler), 0 };
+    p.p = new (p.v) op(success_ec_, impl.socket_,
+        buffers, destination, flags, handler, io_ex);
+
+    ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket",
+          &impl, impl.socket_, "async_send_to"));
+
+    start_op(impl, reactor::write_op, p.p, is_continuation, true, false);
+    p.v = p.p = 0;
+  }
+
+  // Start an asynchronous wait until data can be sent without blocking.
+  template <typename Handler, typename IoExecutor>
+  void async_send_to(implementation_type& impl, const null_buffers&,
+      const endpoint_type&, socket_base::message_flags,
+      Handler& handler, const IoExecutor& io_ex)
+  {
+    bool is_continuation =
+      asio_handler_cont_helpers::is_continuation(handler);
+
+    // Allocate and construct an operation to wrap the handler.
+    typedef reactive_null_buffers_op<Handler, IoExecutor> op;
+    typename op::ptr p = { asio::detail::addressof(handler),
+      op::ptr::allocate(handler), 0 };
+    p.p = new (p.v) op(success_ec_, handler, io_ex);
+
+    ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket",
+          &impl, impl.socket_, "async_send_to(null_buffers)"));
+
+    start_op(impl, reactor::write_op, p.p, is_continuation, false, false);
+    p.v = p.p = 0;
+  }
+
+  // Receive a datagram with the endpoint of the sender. Returns the number of
+  // bytes received.
+  template <typename MutableBufferSequence>
+  size_t receive_from(implementation_type& impl,
+      const MutableBufferSequence& buffers,
+      endpoint_type& sender_endpoint, socket_base::message_flags flags,
+      asio::error_code& ec)
+  {
+    typedef buffer_sequence_adapter<asio::mutable_buffer,
+        MutableBufferSequence> bufs_type;
+
+    std::size_t addr_len = sender_endpoint.capacity();
+    std::size_t bytes_recvd;
+    if (bufs_type::is_single_buffer)
+    {
+      bytes_recvd = socket_ops::sync_recvfrom1(impl.socket_,
+          impl.state_, bufs_type::first(buffers).data(),
+          bufs_type::first(buffers).size(), flags,
+          sender_endpoint.data(), &addr_len, ec);
+    }
+    else
+    {
+      bufs_type bufs(buffers);
+      bytes_recvd = socket_ops::sync_recvfrom(
+          impl.socket_, impl.state_, bufs.buffers(), bufs.count(),
+          flags, sender_endpoint.data(), &addr_len, ec);
+    }
+
+    if (!ec)
+      sender_endpoint.resize(addr_len);
+
+    return bytes_recvd;
+  }
+
+  // Wait until data can be received without blocking.
+  size_t receive_from(implementation_type& impl, const null_buffers&,
+      endpoint_type& sender_endpoint, socket_base::message_flags,
+      asio::error_code& ec)
+  {
+    // Wait for socket to become ready.
+    socket_ops::poll_read(impl.socket_, impl.state_, -1, ec);
+
+    // Reset endpoint since it can be given no sensible value at this time.
+    sender_endpoint = endpoint_type();
+
+    return 0;
+  }
+
+  // Start an asynchronous receive. The buffer for the data being received and
+  // the sender_endpoint object must both be valid for the lifetime of the
+  // asynchronous operation.
+  template <typename MutableBufferSequence,
+      typename Handler, typename IoExecutor>
+  void async_receive_from(implementation_type& impl,
+      const MutableBufferSequence& buffers, endpoint_type& sender_endpoint,
+      socket_base::message_flags flags, Handler& handler,
+      const IoExecutor& io_ex)
+  {
+    bool is_continuation =
+      asio_handler_cont_helpers::is_continuation(handler);
+
+    // Allocate and construct an operation to wrap the handler.
+    typedef reactive_socket_recvfrom_op<MutableBufferSequence,
+        endpoint_type, Handler, IoExecutor> op;
+    typename op::ptr p = { asio::detail::addressof(handler),
+      op::ptr::allocate(handler), 0 };
+    int protocol = impl.protocol_.type();
+    p.p = new (p.v) op(success_ec_, impl.socket_, protocol,
+        buffers, sender_endpoint, flags, handler, io_ex);
+
+    ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket",
+          &impl, impl.socket_, "async_receive_from"));
+
+    start_op(impl,
+        (flags & socket_base::message_out_of_band)
+          ? reactor::except_op : reactor::read_op,
+        p.p, is_continuation, true, false);
+    p.v = p.p = 0;
+  }
+
+  // Wait until data can be received without blocking.
+  template <typename Handler, typename IoExecutor>
+  void async_receive_from(implementation_type& impl, const null_buffers&,
+      endpoint_type& sender_endpoint, socket_base::message_flags flags,
+      Handler& handler, const IoExecutor& io_ex)
+  {
+    bool is_continuation =
+      asio_handler_cont_helpers::is_continuation(handler);
+
+    // Allocate and construct an operation to wrap the handler.
+    typedef reactive_null_buffers_op<Handler, IoExecutor> op;
+    typename op::ptr p = { asio::detail::addressof(handler),
+      op::ptr::allocate(handler), 0 };
+    p.p = new (p.v) op(success_ec_, handler, io_ex);
+
+    ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket",
+          &impl, impl.socket_, "async_receive_from(null_buffers)"));
+
+    // Reset endpoint since it can be given no sensible value at this time.
+    sender_endpoint = endpoint_type();
+
+    start_op(impl,
+        (flags & socket_base::message_out_of_band)
+          ? reactor::except_op : reactor::read_op,
+        p.p, is_continuation, false, false);
+    p.v = p.p = 0;
+  }
+
+  // Accept a new connection.
+  template <typename Socket>
+  asio::error_code accept(implementation_type& impl,
+      Socket& peer, endpoint_type* peer_endpoint, asio::error_code& ec)
+  {
+    // We cannot accept a socket that is already open.
+    if (peer.is_open())
+    {
+      ec = asio::error::already_open;
+      return ec;
+    }
+
+    std::size_t addr_len = peer_endpoint ? peer_endpoint->capacity() : 0;
+    socket_holder new_socket(socket_ops::sync_accept(impl.socket_,
+          impl.state_, peer_endpoint ? peer_endpoint->data() : 0,
+          peer_endpoint ? &addr_len : 0, ec));
+
+    // On success, assign new connection to peer socket object.
+    if (new_socket.get() != invalid_socket)
+    {
+      if (peer_endpoint)
+        peer_endpoint->resize(addr_len);
+      peer.assign(impl.protocol_, new_socket.get(), ec);
+      if (!ec)
+        new_socket.release();
+    }
+
+    return ec;
+  }
+
+  // Start an asynchronous accept. The peer and peer_endpoint objects must be
+  // valid until the accept's handler is invoked.
+  template <typename Socket, typename Handler, typename IoExecutor>
+  void async_accept(implementation_type& impl, Socket& peer,
+      endpoint_type* peer_endpoint, Handler& handler, const IoExecutor& io_ex)
+  {
+    bool is_continuation =
+      asio_handler_cont_helpers::is_continuation(handler);
+
+    // Allocate and construct an operation to wrap the handler.
+    typedef reactive_socket_accept_op<Socket, Protocol, Handler, IoExecutor> op;
+    typename op::ptr p = { asio::detail::addressof(handler),
+      op::ptr::allocate(handler), 0 };
+    p.p = new (p.v) op(success_ec_, impl.socket_, impl.state_,
+        peer, impl.protocol_, peer_endpoint, handler, io_ex);
+
+    ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket",
+          &impl, impl.socket_, "async_accept"));
+
+    start_accept_op(impl, p.p, is_continuation, peer.is_open());
+    p.v = p.p = 0;
+  }
+
+#if defined(ASIO_HAS_MOVE)
+  // Start an asynchronous accept. The peer_endpoint object must be valid until
+  // the accept's handler is invoked.
+  template <typename PeerIoExecutor, typename Handler, typename IoExecutor>
+  void async_move_accept(implementation_type& impl,
+      const PeerIoExecutor& peer_io_ex, endpoint_type* peer_endpoint,
+      Handler& handler, const IoExecutor& io_ex)
+  {
+    bool is_continuation =
+      asio_handler_cont_helpers::is_continuation(handler);
+
+    // Allocate and construct an operation to wrap the handler.
+    typedef reactive_socket_move_accept_op<Protocol,
+        PeerIoExecutor, Handler, IoExecutor> op;
+    typename op::ptr p = { asio::detail::addressof(handler),
+      op::ptr::allocate(handler), 0 };
+    p.p = new (p.v) op(success_ec_, peer_io_ex, impl.socket_,
+        impl.state_, impl.protocol_, peer_endpoint, handler, io_ex);
+
+    ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket",
+          &impl, impl.socket_, "async_accept"));
+
+    start_accept_op(impl, p.p, is_continuation, false);
+    p.v = p.p = 0;
+  }
+#endif // defined(ASIO_HAS_MOVE)
+
+  // Connect the socket to the specified endpoint.
+  asio::error_code connect(implementation_type& impl,
+      const endpoint_type& peer_endpoint, asio::error_code& ec)
+  {
+    socket_ops::sync_connect(impl.socket_,
+        peer_endpoint.data(), peer_endpoint.size(), ec);
+    return ec;
+  }
+
+  // Start an asynchronous connect.
+  template <typename Handler, typename IoExecutor>
+  void async_connect(implementation_type& impl,
+      const endpoint_type& peer_endpoint,
+      Handler& handler, const IoExecutor& io_ex)
+  {
+    bool is_continuation =
+      asio_handler_cont_helpers::is_continuation(handler);
+
+    // Allocate and construct an operation to wrap the handler.
+    typedef reactive_socket_connect_op<Handler, IoExecutor> op;
+    typename op::ptr p = { asio::detail::addressof(handler),
+      op::ptr::allocate(handler), 0 };
+    p.p = new (p.v) op(success_ec_, impl.socket_, handler, io_ex);
+
+    ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket",
+          &impl, impl.socket_, "async_connect"));
+
+    start_connect_op(impl, p.p, is_continuation,
+        peer_endpoint.data(), peer_endpoint.size());
+    p.v = p.p = 0;
+  }
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // !defined(ASIO_HAS_IOCP)
+
+#endif // ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/reactive_socket_service_base.hpp b/link/modules/asio-standalone/asio/include/asio/detail/reactive_socket_service_base.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/reactive_socket_service_base.hpp
@@ -0,0 +1,541 @@
+//
+// detail/reactive_socket_service_base.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_BASE_HPP
+#define ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_BASE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if !defined(ASIO_HAS_IOCP) \
+  && !defined(ASIO_WINDOWS_RUNTIME)
+
+#include "asio/buffer.hpp"
+#include "asio/error.hpp"
+#include "asio/execution_context.hpp"
+#include "asio/socket_base.hpp"
+#include "asio/detail/buffer_sequence_adapter.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/detail/reactive_null_buffers_op.hpp"
+#include "asio/detail/reactive_socket_recv_op.hpp"
+#include "asio/detail/reactive_socket_recvmsg_op.hpp"
+#include "asio/detail/reactive_socket_send_op.hpp"
+#include "asio/detail/reactive_wait_op.hpp"
+#include "asio/detail/reactor.hpp"
+#include "asio/detail/reactor_op.hpp"
+#include "asio/detail/socket_holder.hpp"
+#include "asio/detail/socket_ops.hpp"
+#include "asio/detail/socket_types.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class reactive_socket_service_base
+{
+public:
+  // The native type of a socket.
+  typedef socket_type native_handle_type;
+
+  // The implementation type of the socket.
+  struct base_implementation_type
+  {
+    // The native socket representation.
+    socket_type socket_;
+
+    // The current state of the socket.
+    socket_ops::state_type state_;
+
+    // Per-descriptor data used by the reactor.
+    reactor::per_descriptor_data reactor_data_;
+  };
+
+  // Constructor.
+  ASIO_DECL reactive_socket_service_base(execution_context& context);
+
+  // Destroy all user-defined handler objects owned by the service.
+  ASIO_DECL void base_shutdown();
+
+  // Construct a new socket implementation.
+  ASIO_DECL void construct(base_implementation_type& impl);
+
+  // Move-construct a new socket implementation.
+  ASIO_DECL void base_move_construct(base_implementation_type& impl,
+      base_implementation_type& other_impl) ASIO_NOEXCEPT;
+
+  // Move-assign from another socket implementation.
+  ASIO_DECL void base_move_assign(base_implementation_type& impl,
+      reactive_socket_service_base& other_service,
+      base_implementation_type& other_impl);
+
+  // Destroy a socket implementation.
+  ASIO_DECL void destroy(base_implementation_type& impl);
+
+  // Determine whether the socket is open.
+  bool is_open(const base_implementation_type& impl) const
+  {
+    return impl.socket_ != invalid_socket;
+  }
+
+  // Destroy a socket implementation.
+  ASIO_DECL asio::error_code close(
+      base_implementation_type& impl, asio::error_code& ec);
+
+  // Release ownership of the socket.
+  ASIO_DECL socket_type release(
+      base_implementation_type& impl, asio::error_code& ec);
+
+  // Get the native socket representation.
+  native_handle_type native_handle(base_implementation_type& impl)
+  {
+    return impl.socket_;
+  }
+
+  // Cancel all operations associated with the socket.
+  ASIO_DECL asio::error_code cancel(
+      base_implementation_type& impl, asio::error_code& ec);
+
+  // Determine whether the socket is at the out-of-band data mark.
+  bool at_mark(const base_implementation_type& impl,
+      asio::error_code& ec) const
+  {
+    return socket_ops::sockatmark(impl.socket_, ec);
+  }
+
+  // Determine the number of bytes available for reading.
+  std::size_t available(const base_implementation_type& impl,
+      asio::error_code& ec) const
+  {
+    return socket_ops::available(impl.socket_, ec);
+  }
+
+  // Place the socket into the state where it will listen for new connections.
+  asio::error_code listen(base_implementation_type& impl,
+      int backlog, asio::error_code& ec)
+  {
+    socket_ops::listen(impl.socket_, backlog, ec);
+    return ec;
+  }
+
+  // Perform an IO control command on the socket.
+  template <typename IO_Control_Command>
+  asio::error_code io_control(base_implementation_type& impl,
+      IO_Control_Command& command, asio::error_code& ec)
+  {
+    socket_ops::ioctl(impl.socket_, impl.state_, command.name(),
+        static_cast<ioctl_arg_type*>(command.data()), ec);
+    return ec;
+  }
+
+  // Gets the non-blocking mode of the socket.
+  bool non_blocking(const base_implementation_type& impl) const
+  {
+    return (impl.state_ & socket_ops::user_set_non_blocking) != 0;
+  }
+
+  // Sets the non-blocking mode of the socket.
+  asio::error_code non_blocking(base_implementation_type& impl,
+      bool mode, asio::error_code& ec)
+  {
+    socket_ops::set_user_non_blocking(impl.socket_, impl.state_, mode, ec);
+    return ec;
+  }
+
+  // Gets the non-blocking mode of the native socket implementation.
+  bool native_non_blocking(const base_implementation_type& impl) const
+  {
+    return (impl.state_ & socket_ops::internal_non_blocking) != 0;
+  }
+
+  // Sets the non-blocking mode of the native socket implementation.
+  asio::error_code native_non_blocking(base_implementation_type& impl,
+      bool mode, asio::error_code& ec)
+  {
+    socket_ops::set_internal_non_blocking(impl.socket_, impl.state_, mode, ec);
+    return ec;
+  }
+
+  // Wait for the socket to become ready to read, ready to write, or to have
+  // pending error conditions.
+  asio::error_code wait(base_implementation_type& impl,
+      socket_base::wait_type w, asio::error_code& ec)
+  {
+    switch (w)
+    {
+    case socket_base::wait_read:
+      socket_ops::poll_read(impl.socket_, impl.state_, -1, ec);
+      break;
+    case socket_base::wait_write:
+      socket_ops::poll_write(impl.socket_, impl.state_, -1, ec);
+      break;
+    case socket_base::wait_error:
+      socket_ops::poll_error(impl.socket_, impl.state_, -1, ec);
+      break;
+    default:
+      ec = asio::error::invalid_argument;
+      break;
+    }
+
+    return ec;
+  }
+
+  // Asynchronously wait for the socket to become ready to read, ready to
+  // write, or to have pending error conditions.
+  template <typename Handler, typename IoExecutor>
+  void async_wait(base_implementation_type& impl,
+      socket_base::wait_type w, Handler& handler, const IoExecutor& io_ex)
+  {
+    bool is_continuation =
+      asio_handler_cont_helpers::is_continuation(handler);
+
+    // Allocate and construct an operation to wrap the handler.
+    typedef reactive_wait_op<Handler, IoExecutor> op;
+    typename op::ptr p = { asio::detail::addressof(handler),
+      op::ptr::allocate(handler), 0 };
+    p.p = new (p.v) op(success_ec_, handler, io_ex);
+
+    ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket",
+          &impl, impl.socket_, "async_wait"));
+
+    int op_type;
+    switch (w)
+    {
+      case socket_base::wait_read:
+        op_type = reactor::read_op;
+        break;
+      case socket_base::wait_write:
+        op_type = reactor::write_op;
+        break;
+      case socket_base::wait_error:
+        op_type = reactor::except_op;
+        break;
+      default:
+        p.p->ec_ = asio::error::invalid_argument;
+        reactor_.post_immediate_completion(p.p, is_continuation);
+        p.v = p.p = 0;
+        return;
+    }
+
+    start_op(impl, op_type, p.p, is_continuation, false, false);
+    p.v = p.p = 0;
+  }
+
+  // Send the given data to the peer.
+  template <typename ConstBufferSequence>
+  size_t send(base_implementation_type& impl,
+      const ConstBufferSequence& buffers,
+      socket_base::message_flags flags, asio::error_code& ec)
+  {
+    typedef buffer_sequence_adapter<asio::const_buffer,
+        ConstBufferSequence> bufs_type;
+
+    if (bufs_type::is_single_buffer)
+    {
+      return socket_ops::sync_send1(impl.socket_,
+          impl.state_, bufs_type::first(buffers).data(),
+          bufs_type::first(buffers).size(), flags, ec);
+    }
+    else
+    {
+      bufs_type bufs(buffers);
+      return socket_ops::sync_send(impl.socket_, impl.state_,
+          bufs.buffers(), bufs.count(), flags, bufs.all_empty(), ec);
+    }
+  }
+
+  // Wait until data can be sent without blocking.
+  size_t send(base_implementation_type& impl, const null_buffers&,
+      socket_base::message_flags, asio::error_code& ec)
+  {
+    // Wait for socket to become ready.
+    socket_ops::poll_write(impl.socket_, impl.state_, -1, ec);
+
+    return 0;
+  }
+
+  // Start an asynchronous send. The data being sent must be valid for the
+  // lifetime of the asynchronous operation.
+  template <typename ConstBufferSequence, typename Handler, typename IoExecutor>
+  void async_send(base_implementation_type& impl,
+      const ConstBufferSequence& buffers, socket_base::message_flags flags,
+      Handler& handler, const IoExecutor& io_ex)
+  {
+    bool is_continuation =
+      asio_handler_cont_helpers::is_continuation(handler);
+
+    // Allocate and construct an operation to wrap the handler.
+    typedef reactive_socket_send_op<
+        ConstBufferSequence, Handler, IoExecutor> op;
+    typename op::ptr p = { asio::detail::addressof(handler),
+      op::ptr::allocate(handler), 0 };
+    p.p = new (p.v) op(success_ec_, impl.socket_,
+        impl.state_, buffers, flags, handler, io_ex);
+
+    ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket",
+          &impl, impl.socket_, "async_send"));
+
+    start_op(impl, reactor::write_op, p.p, is_continuation, true,
+        ((impl.state_ & socket_ops::stream_oriented)
+          && buffer_sequence_adapter<asio::const_buffer,
+            ConstBufferSequence>::all_empty(buffers)));
+    p.v = p.p = 0;
+  }
+
+  // Start an asynchronous wait until data can be sent without blocking.
+  template <typename Handler, typename IoExecutor>
+  void async_send(base_implementation_type& impl, const null_buffers&,
+      socket_base::message_flags, Handler& handler, const IoExecutor& io_ex)
+  {
+    bool is_continuation =
+      asio_handler_cont_helpers::is_continuation(handler);
+
+    // Allocate and construct an operation to wrap the handler.
+    typedef reactive_null_buffers_op<Handler, IoExecutor> op;
+    typename op::ptr p = { asio::detail::addressof(handler),
+      op::ptr::allocate(handler), 0 };
+    p.p = new (p.v) op(success_ec_, handler, io_ex);
+
+    ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket",
+          &impl, impl.socket_, "async_send(null_buffers)"));
+
+    start_op(impl, reactor::write_op, p.p, is_continuation, false, false);
+    p.v = p.p = 0;
+  }
+
+  // Receive some data from the peer. Returns the number of bytes received.
+  template <typename MutableBufferSequence>
+  size_t receive(base_implementation_type& impl,
+      const MutableBufferSequence& buffers,
+      socket_base::message_flags flags, asio::error_code& ec)
+  {
+    typedef buffer_sequence_adapter<asio::mutable_buffer,
+        MutableBufferSequence> bufs_type;
+
+    if (bufs_type::is_single_buffer)
+    {
+      return socket_ops::sync_recv1(impl.socket_,
+          impl.state_, bufs_type::first(buffers).data(),
+          bufs_type::first(buffers).size(), flags, ec);
+    }
+    else
+    {
+      bufs_type bufs(buffers);
+      return socket_ops::sync_recv(impl.socket_, impl.state_,
+          bufs.buffers(), bufs.count(), flags, bufs.all_empty(), ec);
+    }
+  }
+
+  // Wait until data can be received without blocking.
+  size_t receive(base_implementation_type& impl, const null_buffers&,
+      socket_base::message_flags, asio::error_code& ec)
+  {
+    // Wait for socket to become ready.
+    socket_ops::poll_read(impl.socket_, impl.state_, -1, ec);
+
+    return 0;
+  }
+
+  // Start an asynchronous receive. The buffer for the data being received
+  // must be valid for the lifetime of the asynchronous operation.
+  template <typename MutableBufferSequence,
+      typename Handler, typename IoExecutor>
+  void async_receive(base_implementation_type& impl,
+      const MutableBufferSequence& buffers, socket_base::message_flags flags,
+      Handler& handler, const IoExecutor& io_ex)
+  {
+    bool is_continuation =
+      asio_handler_cont_helpers::is_continuation(handler);
+
+    // Allocate and construct an operation to wrap the handler.
+    typedef reactive_socket_recv_op<
+        MutableBufferSequence, Handler, IoExecutor> op;
+    typename op::ptr p = { asio::detail::addressof(handler),
+      op::ptr::allocate(handler), 0 };
+    p.p = new (p.v) op(success_ec_, impl.socket_,
+        impl.state_, buffers, flags, handler, io_ex);
+
+    ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket",
+          &impl, impl.socket_, "async_receive"));
+
+    start_op(impl,
+        (flags & socket_base::message_out_of_band)
+          ? reactor::except_op : reactor::read_op,
+        p.p, is_continuation,
+        (flags & socket_base::message_out_of_band) == 0,
+        ((impl.state_ & socket_ops::stream_oriented)
+          && buffer_sequence_adapter<asio::mutable_buffer,
+            MutableBufferSequence>::all_empty(buffers)));
+    p.v = p.p = 0;
+  }
+
+  // Wait until data can be received without blocking.
+  template <typename Handler, typename IoExecutor>
+  void async_receive(base_implementation_type& impl,
+      const null_buffers&, socket_base::message_flags flags,
+      Handler& handler, const IoExecutor& io_ex)
+  {
+    bool is_continuation =
+      asio_handler_cont_helpers::is_continuation(handler);
+
+    // Allocate and construct an operation to wrap the handler.
+    typedef reactive_null_buffers_op<Handler, IoExecutor> op;
+    typename op::ptr p = { asio::detail::addressof(handler),
+      op::ptr::allocate(handler), 0 };
+    p.p = new (p.v) op(success_ec_, handler, io_ex);
+
+    ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket",
+          &impl, impl.socket_, "async_receive(null_buffers)"));
+
+    start_op(impl,
+        (flags & socket_base::message_out_of_band)
+          ? reactor::except_op : reactor::read_op,
+        p.p, is_continuation, false, false);
+    p.v = p.p = 0;
+  }
+
+  // Receive some data with associated flags. Returns the number of bytes
+  // received.
+  template <typename MutableBufferSequence>
+  size_t receive_with_flags(base_implementation_type& impl,
+      const MutableBufferSequence& buffers,
+      socket_base::message_flags in_flags,
+      socket_base::message_flags& out_flags, asio::error_code& ec)
+  {
+    buffer_sequence_adapter<asio::mutable_buffer,
+        MutableBufferSequence> bufs(buffers);
+
+    return socket_ops::sync_recvmsg(impl.socket_, impl.state_,
+        bufs.buffers(), bufs.count(), in_flags, out_flags, ec);
+  }
+
+  // Wait until data can be received without blocking.
+  size_t receive_with_flags(base_implementation_type& impl,
+      const null_buffers&, socket_base::message_flags,
+      socket_base::message_flags& out_flags, asio::error_code& ec)
+  {
+    // Wait for socket to become ready.
+    socket_ops::poll_read(impl.socket_, impl.state_, -1, ec);
+
+    // Clear out_flags, since we cannot give it any other sensible value when
+    // performing a null_buffers operation.
+    out_flags = 0;
+
+    return 0;
+  }
+
+  // Start an asynchronous receive. The buffer for the data being received
+  // must be valid for the lifetime of the asynchronous operation.
+  template <typename MutableBufferSequence,
+      typename Handler, typename IoExecutor>
+  void async_receive_with_flags(base_implementation_type& impl,
+      const MutableBufferSequence& buffers, socket_base::message_flags in_flags,
+      socket_base::message_flags& out_flags, Handler& handler,
+      const IoExecutor& io_ex)
+  {
+    bool is_continuation =
+      asio_handler_cont_helpers::is_continuation(handler);
+
+    // Allocate and construct an operation to wrap the handler.
+    typedef reactive_socket_recvmsg_op<
+        MutableBufferSequence, Handler, IoExecutor> op;
+    typename op::ptr p = { asio::detail::addressof(handler),
+      op::ptr::allocate(handler), 0 };
+    p.p = new (p.v) op(success_ec_, impl.socket_,
+        buffers, in_flags, out_flags, handler, io_ex);
+
+    ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket",
+          &impl, impl.socket_, "async_receive_with_flags"));
+
+    start_op(impl,
+        (in_flags & socket_base::message_out_of_band)
+          ? reactor::except_op : reactor::read_op,
+        p.p, is_continuation,
+        (in_flags & socket_base::message_out_of_band) == 0, false);
+    p.v = p.p = 0;
+  }
+
+  // Wait until data can be received without blocking.
+  template <typename Handler, typename IoExecutor>
+  void async_receive_with_flags(base_implementation_type& impl,
+      const null_buffers&, socket_base::message_flags in_flags,
+      socket_base::message_flags& out_flags, Handler& handler,
+      const IoExecutor& io_ex)
+  {
+    bool is_continuation =
+      asio_handler_cont_helpers::is_continuation(handler);
+
+    // Allocate and construct an operation to wrap the handler.
+    typedef reactive_null_buffers_op<Handler, IoExecutor> op;
+    typename op::ptr p = { asio::detail::addressof(handler),
+      op::ptr::allocate(handler), 0 };
+    p.p = new (p.v) op(success_ec_, handler, io_ex);
+
+    ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket",
+          &impl, impl.socket_, "async_receive_with_flags(null_buffers)"));
+
+    // Clear out_flags, since we cannot give it any other sensible value when
+    // performing a null_buffers operation.
+    out_flags = 0;
+
+    start_op(impl,
+        (in_flags & socket_base::message_out_of_band)
+          ? reactor::except_op : reactor::read_op,
+        p.p, is_continuation, false, false);
+    p.v = p.p = 0;
+  }
+
+protected:
+  // Open a new socket implementation.
+  ASIO_DECL asio::error_code do_open(
+      base_implementation_type& impl, int af,
+      int type, int protocol, asio::error_code& ec);
+
+  // Assign a native socket to a socket implementation.
+  ASIO_DECL asio::error_code do_assign(
+      base_implementation_type& impl, int type,
+      const native_handle_type& native_socket, asio::error_code& ec);
+
+  // Start the asynchronous read or write operation.
+  ASIO_DECL void start_op(base_implementation_type& impl, int op_type,
+      reactor_op* op, bool is_continuation, bool is_non_blocking, bool noop);
+
+  // Start the asynchronous accept operation.
+  ASIO_DECL void start_accept_op(base_implementation_type& impl,
+      reactor_op* op, bool is_continuation, bool peer_is_open);
+
+  // Start the asynchronous connect operation.
+  ASIO_DECL void start_connect_op(base_implementation_type& impl,
+      reactor_op* op, bool is_continuation,
+      const socket_addr_type* addr, size_t addrlen);
+
+  // The selector that performs event demultiplexing for the service.
+  reactor& reactor_;
+
+  // Cached success value to avoid accessing category singleton.
+  const asio::error_code success_ec_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/reactive_socket_service_base.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // !defined(ASIO_HAS_IOCP)
+       //   && !defined(ASIO_WINDOWS_RUNTIME)
+
+#endif // ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_BASE_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/reactive_wait_op.hpp b/link/modules/asio-standalone/asio/include/asio/detail/reactive_wait_op.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/reactive_wait_op.hpp
@@ -0,0 +1,98 @@
+//
+// detail/reactive_wait_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_REACTIVE_WAIT_OP_HPP
+#define ASIO_DETAIL_REACTIVE_WAIT_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/handler_work.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/detail/reactor_op.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Handler, typename IoExecutor>
+class reactive_wait_op : public reactor_op
+{
+public:
+  ASIO_DEFINE_HANDLER_PTR(reactive_wait_op);
+
+  reactive_wait_op(const asio::error_code& success_ec,
+      Handler& handler, const IoExecutor& io_ex)
+    : reactor_op(success_ec, &reactive_wait_op::do_perform,
+        &reactive_wait_op::do_complete),
+      handler_(ASIO_MOVE_CAST(Handler)(handler)),
+      work_(handler_, io_ex)
+  {
+  }
+
+  static status do_perform(reactor_op*)
+  {
+    return done;
+  }
+
+  static void do_complete(void* owner, operation* base,
+      const asio::error_code& /*ec*/,
+      std::size_t /*bytes_transferred*/)
+  {
+    // Take ownership of the handler object.
+    reactive_wait_op* o(static_cast<reactive_wait_op*>(base));
+    ptr p = { asio::detail::addressof(o->handler_), o, o };
+
+    ASIO_HANDLER_COMPLETION((*o));
+
+    // Take ownership of the operation's outstanding work.
+    handler_work<Handler, IoExecutor> w(
+        ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)(
+          o->work_));
+
+    // Make a copy of the handler so that the memory can be deallocated before
+    // the upcall is made. Even if we're not about to make an upcall, a
+    // sub-object of the handler may be the true owner of the memory associated
+    // with the handler. Consequently, a local copy of the handler is required
+    // to ensure that any owning sub-object remains valid until after we have
+    // deallocated the memory here.
+    detail::binder1<Handler, asio::error_code>
+      handler(o->handler_, o->ec_);
+    p.h = asio::detail::addressof(handler.handler_);
+    p.reset();
+
+    // Make the upcall if required.
+    if (owner)
+    {
+      fenced_block b(fenced_block::half);
+      ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_));
+      w.complete(handler, handler.handler_);
+      ASIO_HANDLER_INVOCATION_END;
+    }
+  }
+
+private:
+  Handler handler_;
+  handler_work<Handler, IoExecutor> work_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_REACTIVE_WAIT_OP_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/reactor.hpp b/link/modules/asio-standalone/asio/include/asio/detail/reactor.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/reactor.hpp
@@ -0,0 +1,32 @@
+//
+// detail/reactor.hpp
+// ~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_REACTOR_HPP
+#define ASIO_DETAIL_REACTOR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/reactor_fwd.hpp"
+
+#if defined(ASIO_HAS_EPOLL)
+# include "asio/detail/epoll_reactor.hpp"
+#elif defined(ASIO_HAS_KQUEUE)
+# include "asio/detail/kqueue_reactor.hpp"
+#elif defined(ASIO_HAS_DEV_POLL)
+# include "asio/detail/dev_poll_reactor.hpp"
+#elif defined(ASIO_HAS_IOCP) || defined(ASIO_WINDOWS_RUNTIME)
+# include "asio/detail/null_reactor.hpp"
+#else
+# include "asio/detail/select_reactor.hpp"
+#endif
+
+#endif // ASIO_DETAIL_REACTOR_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/reactor_fwd.hpp b/link/modules/asio-standalone/asio/include/asio/detail/reactor_fwd.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/reactor_fwd.hpp
@@ -0,0 +1,40 @@
+//
+// detail/reactor_fwd.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_REACTOR_FWD_HPP
+#define ASIO_DETAIL_REACTOR_FWD_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+namespace asio {
+namespace detail {
+
+#if defined(ASIO_HAS_IOCP) || defined(ASIO_WINDOWS_RUNTIME)
+typedef class null_reactor reactor;
+#elif defined(ASIO_HAS_IOCP)
+typedef class select_reactor reactor;
+#elif defined(ASIO_HAS_EPOLL)
+typedef class epoll_reactor reactor;
+#elif defined(ASIO_HAS_KQUEUE)
+typedef class kqueue_reactor reactor;
+#elif defined(ASIO_HAS_DEV_POLL)
+typedef class dev_poll_reactor reactor;
+#else
+typedef class select_reactor reactor;
+#endif
+
+} // namespace detail
+} // namespace asio
+
+#endif // ASIO_DETAIL_REACTOR_FWD_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/reactor_op.hpp b/link/modules/asio-standalone/asio/include/asio/detail/reactor_op.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/reactor_op.hpp
@@ -0,0 +1,67 @@
+//
+// detail/reactor_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_REACTOR_OP_HPP
+#define ASIO_DETAIL_REACTOR_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/operation.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class reactor_op
+  : public operation
+{
+public:
+  // The error code to be passed to the completion handler.
+  asio::error_code ec_;
+
+  // The number of bytes transferred, to be passed to the completion handler.
+  std::size_t bytes_transferred_;
+
+  // Status returned by perform function. May be used to decide whether it is
+  // worth performing more operations on the descriptor immediately.
+  enum status { not_done, done, done_and_exhausted };
+
+  // Perform the operation. Returns true if it is finished.
+  status perform()
+  {
+    return perform_func_(this);
+  }
+
+protected:
+  typedef status (*perform_func_type)(reactor_op*);
+
+  reactor_op(const asio::error_code& success_ec,
+      perform_func_type perform_func, func_type complete_func)
+    : operation(complete_func),
+      ec_(success_ec),
+      bytes_transferred_(0),
+      perform_func_(perform_func)
+  {
+  }
+
+private:
+  perform_func_type perform_func_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_REACTOR_OP_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/reactor_op_queue.hpp b/link/modules/asio-standalone/asio/include/asio/detail/reactor_op_queue.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/reactor_op_queue.hpp
@@ -0,0 +1,168 @@
+//
+// detail/reactor_op_queue.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_REACTOR_OP_QUEUE_HPP
+#define ASIO_DETAIL_REACTOR_OP_QUEUE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/hash_map.hpp"
+#include "asio/detail/noncopyable.hpp"
+#include "asio/detail/op_queue.hpp"
+#include "asio/detail/reactor_op.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Descriptor>
+class reactor_op_queue
+  : private noncopyable
+{
+public:
+  typedef Descriptor key_type;
+
+  struct mapped_type : op_queue<reactor_op>
+  {
+    mapped_type() {}
+    mapped_type(const mapped_type&) {}
+    void operator=(const mapped_type&) {}
+  };
+
+  typedef typename hash_map<key_type, mapped_type>::value_type value_type;
+  typedef typename hash_map<key_type, mapped_type>::iterator iterator;
+
+  // Constructor.
+  reactor_op_queue()
+    : operations_()
+  {
+  }
+
+  // Obtain iterators to all registered descriptors.
+  iterator begin() { return operations_.begin(); }
+  iterator end() { return operations_.end(); }
+
+  // Add a new operation to the queue. Returns true if this is the only
+  // operation for the given descriptor, in which case the reactor's event
+  // demultiplexing function call may need to be interrupted and restarted.
+  bool enqueue_operation(Descriptor descriptor, reactor_op* op)
+  {
+    std::pair<iterator, bool> entry =
+      operations_.insert(value_type(descriptor, mapped_type()));
+    entry.first->second.push(op);
+    return entry.second;
+  }
+
+  // Cancel all operations associated with the descriptor identified by the
+  // supplied iterator. Any operations pending for the descriptor will be
+  // cancelled. Returns true if any operations were cancelled, in which case
+  // the reactor's event demultiplexing function may need to be interrupted and
+  // restarted.
+  bool cancel_operations(iterator i, op_queue<operation>& ops,
+      const asio::error_code& ec =
+        asio::error::operation_aborted)
+  {
+    if (i != operations_.end())
+    {
+      while (reactor_op* op = i->second.front())
+      {
+        op->ec_ = ec;
+        i->second.pop();
+        ops.push(op);
+      }
+      operations_.erase(i);
+      return true;
+    }
+
+    return false;
+  }
+
+  // Cancel all operations associated with the descriptor. Any operations
+  // pending for the descriptor will be cancelled. Returns true if any
+  // operations were cancelled, in which case the reactor's event
+  // demultiplexing function may need to be interrupted and restarted.
+  bool cancel_operations(Descriptor descriptor, op_queue<operation>& ops,
+      const asio::error_code& ec =
+        asio::error::operation_aborted)
+  {
+    return this->cancel_operations(operations_.find(descriptor), ops, ec);
+  }
+
+  // Whether there are no operations in the queue.
+  bool empty() const
+  {
+    return operations_.empty();
+  }
+
+  // Determine whether there are any operations associated with the descriptor.
+  bool has_operation(Descriptor descriptor) const
+  {
+    return operations_.find(descriptor) != operations_.end();
+  }
+
+  // Perform the operations corresponding to the descriptor identified by the
+  // supplied iterator. Returns true if there are still unfinished operations
+  // queued for the descriptor.
+  bool perform_operations(iterator i, op_queue<operation>& ops)
+  {
+    if (i != operations_.end())
+    {
+      while (reactor_op* op = i->second.front())
+      {
+        if (op->perform())
+        {
+          i->second.pop();
+          ops.push(op);
+        }
+        else
+        {
+          return true;
+        }
+      }
+      operations_.erase(i);
+    }
+    return false;
+  }
+
+  // Perform the operations corresponding to the descriptor. Returns true if
+  // there are still unfinished operations queued for the descriptor.
+  bool perform_operations(Descriptor descriptor, op_queue<operation>& ops)
+  {
+    return this->perform_operations(operations_.find(descriptor), ops);
+  }
+
+  // Get all operations owned by the queue.
+  void get_all_operations(op_queue<operation>& ops)
+  {
+    iterator i = operations_.begin();
+    while (i != operations_.end())
+    {
+      iterator op_iter = i++;
+      ops.push(op_iter->second);
+      operations_.erase(op_iter);
+    }
+  }
+
+private:
+  // The operations that are currently executing asynchronously.
+  hash_map<key_type, mapped_type> operations_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_REACTOR_OP_QUEUE_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/recycling_allocator.hpp b/link/modules/asio-standalone/asio/include/asio/detail/recycling_allocator.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/recycling_allocator.hpp
@@ -0,0 +1,106 @@
+//
+// detail/recycling_allocator.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_RECYCLING_ALLOCATOR_HPP
+#define ASIO_DETAIL_RECYCLING_ALLOCATOR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/detail/thread_context.hpp"
+#include "asio/detail/thread_info_base.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename T, typename Purpose = thread_info_base::default_tag>
+class recycling_allocator
+{
+public:
+  typedef T value_type;
+
+  template <typename U>
+  struct rebind
+  {
+    typedef recycling_allocator<U, Purpose> other;
+  };
+
+  recycling_allocator()
+  {
+  }
+
+  template <typename U>
+  recycling_allocator(const recycling_allocator<U, Purpose>&)
+  {
+  }
+
+  T* allocate(std::size_t n)
+  {
+    typedef thread_context::thread_call_stack call_stack;
+    void* p = thread_info_base::allocate(Purpose(),
+        call_stack::top(), sizeof(T) * n);
+    return static_cast<T*>(p);
+  }
+
+  void deallocate(T* p, std::size_t n)
+  {
+    typedef thread_context::thread_call_stack call_stack;
+    thread_info_base::deallocate(Purpose(),
+        call_stack::top(), p, sizeof(T) * n);
+  }
+};
+
+template <typename Purpose>
+class recycling_allocator<void, Purpose>
+{
+public:
+  typedef void value_type;
+
+  template <typename U>
+  struct rebind
+  {
+    typedef recycling_allocator<U, Purpose> other;
+  };
+
+  recycling_allocator()
+  {
+  }
+
+  template <typename U>
+  recycling_allocator(const recycling_allocator<U, Purpose>&)
+  {
+  }
+};
+
+template <typename Allocator, typename Purpose>
+struct get_recycling_allocator
+{
+  typedef Allocator type;
+  static type get(const Allocator& a) { return a; }
+};
+
+template <typename T, typename Purpose>
+struct get_recycling_allocator<std::allocator<T>, Purpose>
+{
+  typedef recycling_allocator<T, Purpose> type;
+  static type get(const std::allocator<T>&) { return type(); }
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_RECYCLING_ALLOCATOR_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/regex_fwd.hpp b/link/modules/asio-standalone/asio/include/asio/detail/regex_fwd.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/regex_fwd.hpp
@@ -0,0 +1,35 @@
+//
+// detail/regex_fwd.hpp
+// ~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_REGEX_FWD_HPP
+#define ASIO_DETAIL_REGEX_FWD_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#if defined(ASIO_HAS_BOOST_REGEX)
+
+#include <boost/regex_fwd.hpp>
+#include <boost/regex/v4/match_flags.hpp>
+
+namespace boost {
+
+template <class BidiIterator>
+struct sub_match;
+
+template <class BidiIterator, class Allocator>
+class match_results;
+
+} // namespace boost
+
+#endif // defined(ASIO_HAS_BOOST_REGEX)
+
+#endif // ASIO_DETAIL_REGEX_FWD_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/resolve_endpoint_op.hpp b/link/modules/asio-standalone/asio/include/asio/detail/resolve_endpoint_op.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/resolve_endpoint_op.hpp
@@ -0,0 +1,140 @@
+//
+// detail/resolve_endpoint_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_RESOLVER_ENDPOINT_OP_HPP
+#define ASIO_DETAIL_RESOLVER_ENDPOINT_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/handler_work.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/detail/resolve_op.hpp"
+#include "asio/detail/socket_ops.hpp"
+#include "asio/error.hpp"
+#include "asio/ip/basic_resolver_results.hpp"
+
+#if defined(ASIO_HAS_IOCP)
+# include "asio/detail/win_iocp_io_context.hpp"
+#else // defined(ASIO_HAS_IOCP)
+# include "asio/detail/scheduler.hpp"
+#endif // defined(ASIO_HAS_IOCP)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Protocol, typename Handler, typename IoExecutor>
+class resolve_endpoint_op : public resolve_op
+{
+public:
+  ASIO_DEFINE_HANDLER_PTR(resolve_endpoint_op);
+
+  typedef typename Protocol::endpoint endpoint_type;
+  typedef asio::ip::basic_resolver_results<Protocol> results_type;
+
+#if defined(ASIO_HAS_IOCP)
+  typedef class win_iocp_io_context scheduler_impl;
+#else
+  typedef class scheduler scheduler_impl;
+#endif
+
+  resolve_endpoint_op(socket_ops::weak_cancel_token_type cancel_token,
+      const endpoint_type& endpoint, scheduler_impl& sched,
+      Handler& handler, const IoExecutor& io_ex)
+    : resolve_op(&resolve_endpoint_op::do_complete),
+      cancel_token_(cancel_token),
+      endpoint_(endpoint),
+      scheduler_(sched),
+      handler_(ASIO_MOVE_CAST(Handler)(handler)),
+      work_(handler_, io_ex)
+  {
+  }
+
+  static void do_complete(void* owner, operation* base,
+      const asio::error_code& /*ec*/,
+      std::size_t /*bytes_transferred*/)
+  {
+    // Take ownership of the operation object.
+    resolve_endpoint_op* o(static_cast<resolve_endpoint_op*>(base));
+    ptr p = { asio::detail::addressof(o->handler_), o, o };
+
+    if (owner && owner != &o->scheduler_)
+    {
+      // The operation is being run on the worker io_context. Time to perform
+      // the resolver operation.
+    
+      // Perform the blocking endpoint resolution operation.
+      char host_name[NI_MAXHOST];
+      char service_name[NI_MAXSERV];
+      socket_ops::background_getnameinfo(o->cancel_token_, o->endpoint_.data(),
+          o->endpoint_.size(), host_name, NI_MAXHOST, service_name, NI_MAXSERV,
+          o->endpoint_.protocol().type(), o->ec_);
+      o->results_ = results_type::create(o->endpoint_, host_name, service_name);
+
+      // Pass operation back to main io_context for completion.
+      o->scheduler_.post_deferred_completion(o);
+      p.v = p.p = 0;
+    }
+    else
+    {
+      // The operation has been returned to the main io_context. The completion
+      // handler is ready to be delivered.
+
+      ASIO_HANDLER_COMPLETION((*o));
+
+      // Take ownership of the operation's outstanding work.
+      handler_work<Handler, IoExecutor> w(
+          ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)(
+            o->work_));
+
+      // Make a copy of the handler so that the memory can be deallocated
+      // before the upcall is made. Even if we're not about to make an upcall,
+      // a sub-object of the handler may be the true owner of the memory
+      // associated with the handler. Consequently, a local copy of the handler
+      // is required to ensure that any owning sub-object remains valid until
+      // after we have deallocated the memory here.
+      detail::binder2<Handler, asio::error_code, results_type>
+        handler(o->handler_, o->ec_, o->results_);
+      p.h = asio::detail::addressof(handler.handler_);
+      p.reset();
+
+      if (owner)
+      {
+        fenced_block b(fenced_block::half);
+        ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, "..."));
+        w.complete(handler, handler.handler_);
+        ASIO_HANDLER_INVOCATION_END;
+      }
+    }
+  }
+
+private:
+  socket_ops::weak_cancel_token_type cancel_token_;
+  endpoint_type endpoint_;
+  scheduler_impl& scheduler_;
+  Handler handler_;
+  handler_work<Handler, IoExecutor> work_;
+  results_type results_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_RESOLVER_ENDPOINT_OP_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/resolve_op.hpp b/link/modules/asio-standalone/asio/include/asio/detail/resolve_op.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/resolve_op.hpp
@@ -0,0 +1,45 @@
+//
+// detail/resolve_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_RESOLVE_OP_HPP
+#define ASIO_DETAIL_RESOLVE_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/error.hpp"
+#include "asio/detail/operation.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class resolve_op : public operation
+{
+public:
+  // The error code to be passed to the completion handler.
+  asio::error_code ec_;
+
+protected:
+  resolve_op(func_type complete_func)
+    : operation(complete_func)
+  {
+  }
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_RESOLVE_OP_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/resolve_query_op.hpp b/link/modules/asio-standalone/asio/include/asio/detail/resolve_query_op.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/resolve_query_op.hpp
@@ -0,0 +1,150 @@
+//
+// detail/resolve_query_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_RESOLVE_QUERY_OP_HPP
+#define ASIO_DETAIL_RESOLVE_QUERY_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/handler_work.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/detail/resolve_op.hpp"
+#include "asio/detail/socket_ops.hpp"
+#include "asio/error.hpp"
+#include "asio/ip/basic_resolver_query.hpp"
+#include "asio/ip/basic_resolver_results.hpp"
+
+#if defined(ASIO_HAS_IOCP)
+# include "asio/detail/win_iocp_io_context.hpp"
+#else // defined(ASIO_HAS_IOCP)
+# include "asio/detail/scheduler.hpp"
+#endif // defined(ASIO_HAS_IOCP)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Protocol, typename Handler, typename IoExecutor>
+class resolve_query_op : public resolve_op
+{
+public:
+  ASIO_DEFINE_HANDLER_PTR(resolve_query_op);
+
+  typedef asio::ip::basic_resolver_query<Protocol> query_type;
+  typedef asio::ip::basic_resolver_results<Protocol> results_type;
+
+#if defined(ASIO_HAS_IOCP)
+  typedef class win_iocp_io_context scheduler_impl;
+#else
+  typedef class scheduler scheduler_impl;
+#endif
+
+  resolve_query_op(socket_ops::weak_cancel_token_type cancel_token,
+      const query_type& query, scheduler_impl& sched,
+      Handler& handler, const IoExecutor& io_ex)
+    : resolve_op(&resolve_query_op::do_complete),
+      cancel_token_(cancel_token),
+      query_(query),
+      scheduler_(sched),
+      handler_(ASIO_MOVE_CAST(Handler)(handler)),
+      work_(handler_, io_ex),
+      addrinfo_(0)
+  {
+  }
+
+  ~resolve_query_op()
+  {
+    if (addrinfo_)
+      socket_ops::freeaddrinfo(addrinfo_);
+  }
+
+  static void do_complete(void* owner, operation* base,
+      const asio::error_code& /*ec*/,
+      std::size_t /*bytes_transferred*/)
+  {
+    // Take ownership of the operation object.
+    resolve_query_op* o(static_cast<resolve_query_op*>(base));
+    ptr p = { asio::detail::addressof(o->handler_), o, o };
+
+    if (owner && owner != &o->scheduler_)
+    {
+      // The operation is being run on the worker io_context. Time to perform
+      // the resolver operation.
+    
+      // Perform the blocking host resolution operation.
+      socket_ops::background_getaddrinfo(o->cancel_token_,
+          o->query_.host_name().c_str(), o->query_.service_name().c_str(),
+          o->query_.hints(), &o->addrinfo_, o->ec_);
+
+      // Pass operation back to main io_context for completion.
+      o->scheduler_.post_deferred_completion(o);
+      p.v = p.p = 0;
+    }
+    else
+    {
+      // The operation has been returned to the main io_context. The completion
+      // handler is ready to be delivered.
+
+      ASIO_HANDLER_COMPLETION((*o));
+
+      // Take ownership of the operation's outstanding work.
+      handler_work<Handler, IoExecutor> w(
+          ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)(
+            o->work_));
+
+      // Make a copy of the handler so that the memory can be deallocated
+      // before the upcall is made. Even if we're not about to make an upcall,
+      // a sub-object of the handler may be the true owner of the memory
+      // associated with the handler. Consequently, a local copy of the handler
+      // is required to ensure that any owning sub-object remains valid until
+      // after we have deallocated the memory here.
+      detail::binder2<Handler, asio::error_code, results_type>
+        handler(o->handler_, o->ec_, results_type());
+      p.h = asio::detail::addressof(handler.handler_);
+      if (o->addrinfo_)
+      {
+        handler.arg2_ = results_type::create(o->addrinfo_,
+            o->query_.host_name(), o->query_.service_name());
+      }
+      p.reset();
+
+      if (owner)
+      {
+        fenced_block b(fenced_block::half);
+        ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, "..."));
+        w.complete(handler, handler.handler_);
+        ASIO_HANDLER_INVOCATION_END;
+      }
+    }
+  }
+
+private:
+  socket_ops::weak_cancel_token_type cancel_token_;
+  query_type query_;
+  scheduler_impl& scheduler_;
+  Handler handler_;
+  handler_work<Handler, IoExecutor> work_;
+  asio::detail::addrinfo_type* addrinfo_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_RESOLVE_QUERY_OP_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/resolver_service.hpp b/link/modules/asio-standalone/asio/include/asio/detail/resolver_service.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/resolver_service.hpp
@@ -0,0 +1,145 @@
+//
+// detail/resolver_service.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_RESOLVER_SERVICE_HPP
+#define ASIO_DETAIL_RESOLVER_SERVICE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if !defined(ASIO_WINDOWS_RUNTIME)
+
+#include "asio/ip/basic_resolver_query.hpp"
+#include "asio/ip/basic_resolver_results.hpp"
+#include "asio/detail/concurrency_hint.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/detail/resolve_endpoint_op.hpp"
+#include "asio/detail/resolve_query_op.hpp"
+#include "asio/detail/resolver_service_base.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Protocol>
+class resolver_service :
+  public execution_context_service_base<resolver_service<Protocol> >,
+  public resolver_service_base
+{
+public:
+  // The implementation type of the resolver. A cancellation token is used to
+  // indicate to the background thread that the operation has been cancelled.
+  typedef socket_ops::shared_cancel_token_type implementation_type;
+
+  // The endpoint type.
+  typedef typename Protocol::endpoint endpoint_type;
+
+  // The query type.
+  typedef asio::ip::basic_resolver_query<Protocol> query_type;
+
+  // The results type.
+  typedef asio::ip::basic_resolver_results<Protocol> results_type;
+
+  // Constructor.
+  resolver_service(execution_context& context)
+    : execution_context_service_base<resolver_service<Protocol> >(context),
+      resolver_service_base(context)
+  {
+  }
+
+  // Destroy all user-defined handler objects owned by the service.
+  void shutdown()
+  {
+    this->base_shutdown();
+  }
+
+  // Perform any fork-related housekeeping.
+  void notify_fork(execution_context::fork_event fork_ev)
+  {
+    this->base_notify_fork(fork_ev);
+  }
+
+  // Resolve a query to a list of entries.
+  results_type resolve(implementation_type&, const query_type& query,
+      asio::error_code& ec)
+  {
+    asio::detail::addrinfo_type* address_info = 0;
+
+    socket_ops::getaddrinfo(query.host_name().c_str(),
+        query.service_name().c_str(), query.hints(), &address_info, ec);
+    auto_addrinfo auto_address_info(address_info);
+
+    return ec ? results_type() : results_type::create(
+        address_info, query.host_name(), query.service_name());
+  }
+
+  // Asynchronously resolve a query to a list of entries.
+  template <typename Handler, typename IoExecutor>
+  void async_resolve(implementation_type& impl, const query_type& query,
+      Handler& handler, const IoExecutor& io_ex)
+  {
+    // Allocate and construct an operation to wrap the handler.
+    typedef resolve_query_op<Protocol, Handler, IoExecutor> op;
+    typename op::ptr p = { asio::detail::addressof(handler),
+      op::ptr::allocate(handler), 0 };
+    p.p = new (p.v) op(impl, query, scheduler_, handler, io_ex);
+
+    ASIO_HANDLER_CREATION((scheduler_.context(),
+          *p.p, "resolver", &impl, 0, "async_resolve"));
+
+    start_resolve_op(p.p);
+    p.v = p.p = 0;
+  }
+
+  // Resolve an endpoint to a list of entries.
+  results_type resolve(implementation_type&,
+      const endpoint_type& endpoint, asio::error_code& ec)
+  {
+    char host_name[NI_MAXHOST];
+    char service_name[NI_MAXSERV];
+    socket_ops::sync_getnameinfo(endpoint.data(), endpoint.size(),
+        host_name, NI_MAXHOST, service_name, NI_MAXSERV,
+        endpoint.protocol().type(), ec);
+
+    return ec ? results_type() : results_type::create(
+        endpoint, host_name, service_name);
+  }
+
+  // Asynchronously resolve an endpoint to a list of entries.
+  template <typename Handler, typename IoExecutor>
+  void async_resolve(implementation_type& impl, const endpoint_type& endpoint,
+      Handler& handler, const IoExecutor& io_ex)
+  {
+    // Allocate and construct an operation to wrap the handler.
+    typedef resolve_endpoint_op<Protocol, Handler, IoExecutor> op;
+    typename op::ptr p = { asio::detail::addressof(handler),
+      op::ptr::allocate(handler), 0 };
+    p.p = new (p.v) op(impl, endpoint, scheduler_, handler, io_ex);
+
+    ASIO_HANDLER_CREATION((scheduler_.context(),
+          *p.p, "resolver", &impl, 0, "async_resolve"));
+
+    start_resolve_op(p.p);
+    p.v = p.p = 0;
+  }
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // !defined(ASIO_WINDOWS_RUNTIME)
+
+#endif // ASIO_DETAIL_RESOLVER_SERVICE_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/resolver_service_base.hpp b/link/modules/asio-standalone/asio/include/asio/detail/resolver_service_base.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/resolver_service_base.hpp
@@ -0,0 +1,143 @@
+//
+// detail/resolver_service_base.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_RESOLVER_SERVICE_BASE_HPP
+#define ASIO_DETAIL_RESOLVER_SERVICE_BASE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/error.hpp"
+#include "asio/execution_context.hpp"
+#include "asio/detail/mutex.hpp"
+#include "asio/detail/noncopyable.hpp"
+#include "asio/detail/resolve_op.hpp"
+#include "asio/detail/socket_ops.hpp"
+#include "asio/detail/socket_types.hpp"
+#include "asio/detail/scoped_ptr.hpp"
+#include "asio/detail/thread.hpp"
+
+#if defined(ASIO_HAS_IOCP)
+# include "asio/detail/win_iocp_io_context.hpp"
+#else // defined(ASIO_HAS_IOCP)
+# include "asio/detail/scheduler.hpp"
+#endif // defined(ASIO_HAS_IOCP)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class resolver_service_base
+{
+public:
+  // The implementation type of the resolver. A cancellation token is used to
+  // indicate to the background thread that the operation has been cancelled.
+  typedef socket_ops::shared_cancel_token_type implementation_type;
+
+  // Constructor.
+  ASIO_DECL resolver_service_base(execution_context& context);
+
+  // Destructor.
+  ASIO_DECL ~resolver_service_base();
+
+  // Destroy all user-defined handler objects owned by the service.
+  ASIO_DECL void base_shutdown();
+
+  // Perform any fork-related housekeeping.
+  ASIO_DECL void base_notify_fork(
+      execution_context::fork_event fork_ev);
+
+  // Construct a new resolver implementation.
+  ASIO_DECL void construct(implementation_type& impl);
+
+  // Destroy a resolver implementation.
+  ASIO_DECL void destroy(implementation_type&);
+
+  // Move-construct a new resolver implementation.
+  ASIO_DECL void move_construct(implementation_type& impl,
+      implementation_type& other_impl);
+
+  // Move-assign from another resolver implementation.
+  ASIO_DECL void move_assign(implementation_type& impl,
+      resolver_service_base& other_service,
+      implementation_type& other_impl);
+
+  // Cancel pending asynchronous operations.
+  ASIO_DECL void cancel(implementation_type& impl);
+
+protected:
+  // Helper function to start an asynchronous resolve operation.
+  ASIO_DECL void start_resolve_op(resolve_op* op);
+
+#if !defined(ASIO_WINDOWS_RUNTIME)
+  // Helper class to perform exception-safe cleanup of addrinfo objects.
+  class auto_addrinfo
+    : private asio::detail::noncopyable
+  {
+  public:
+    explicit auto_addrinfo(asio::detail::addrinfo_type* ai)
+      : ai_(ai)
+    {
+    }
+
+    ~auto_addrinfo()
+    {
+      if (ai_)
+        socket_ops::freeaddrinfo(ai_);
+    }
+
+    operator asio::detail::addrinfo_type*()
+    {
+      return ai_;
+    }
+
+  private:
+    asio::detail::addrinfo_type* ai_;
+  };
+#endif // !defined(ASIO_WINDOWS_RUNTIME)
+
+  // Helper class to run the work scheduler in a thread.
+  class work_scheduler_runner;
+
+  // Start the work scheduler if it's not already running.
+  ASIO_DECL void start_work_thread();
+
+  // The scheduler implementation used to post completions.
+#if defined(ASIO_HAS_IOCP)
+  typedef class win_iocp_io_context scheduler_impl;
+#else
+  typedef class scheduler scheduler_impl;
+#endif
+  scheduler_impl& scheduler_;
+
+private:
+  // Mutex to protect access to internal data.
+  asio::detail::mutex mutex_;
+
+  // Private scheduler used for performing asynchronous host resolution.
+  asio::detail::scoped_ptr<scheduler_impl> work_scheduler_;
+
+  // Thread used for running the work io_context's run loop.
+  asio::detail::scoped_ptr<asio::detail::thread> work_thread_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/resolver_service_base.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // ASIO_DETAIL_RESOLVER_SERVICE_BASE_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/scheduler.hpp b/link/modules/asio-standalone/asio/include/asio/detail/scheduler.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/scheduler.hpp
@@ -0,0 +1,232 @@
+//
+// detail/scheduler.hpp
+// ~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_SCHEDULER_HPP
+#define ASIO_DETAIL_SCHEDULER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#include "asio/error_code.hpp"
+#include "asio/execution_context.hpp"
+#include "asio/detail/atomic_count.hpp"
+#include "asio/detail/conditionally_enabled_event.hpp"
+#include "asio/detail/conditionally_enabled_mutex.hpp"
+#include "asio/detail/op_queue.hpp"
+#include "asio/detail/reactor_fwd.hpp"
+#include "asio/detail/scheduler_operation.hpp"
+#include "asio/detail/thread.hpp"
+#include "asio/detail/thread_context.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+struct scheduler_thread_info;
+
+class scheduler
+  : public execution_context_service_base<scheduler>,
+    public thread_context
+{
+public:
+  typedef scheduler_operation operation;
+
+  // Constructor. Specifies the number of concurrent threads that are likely to
+  // run the scheduler. If set to 1 certain optimisation are performed.
+  ASIO_DECL scheduler(asio::execution_context& ctx,
+      int concurrency_hint = 0, bool own_thread = true);
+
+  // Destructor.
+  ASIO_DECL ~scheduler();
+
+  // Destroy all user-defined handler objects owned by the service.
+  ASIO_DECL void shutdown();
+
+  // Initialise the task, if required.
+  ASIO_DECL void init_task();
+
+  // Run the event loop until interrupted or no more work.
+  ASIO_DECL std::size_t run(asio::error_code& ec);
+
+  // Run until interrupted or one operation is performed.
+  ASIO_DECL std::size_t run_one(asio::error_code& ec);
+
+  // Run until timeout, interrupted, or one operation is performed.
+  ASIO_DECL std::size_t wait_one(
+      long usec, asio::error_code& ec);
+
+  // Poll for operations without blocking.
+  ASIO_DECL std::size_t poll(asio::error_code& ec);
+
+  // Poll for one operation without blocking.
+  ASIO_DECL std::size_t poll_one(asio::error_code& ec);
+
+  // Interrupt the event processing loop.
+  ASIO_DECL void stop();
+
+  // Determine whether the scheduler is stopped.
+  ASIO_DECL bool stopped() const;
+
+  // Restart in preparation for a subsequent run invocation.
+  ASIO_DECL void restart();
+
+  // Notify that some work has started.
+  void work_started()
+  {
+    ++outstanding_work_;
+  }
+
+  // Used to compensate for a forthcoming work_finished call. Must be called
+  // from within a scheduler-owned thread.
+  ASIO_DECL void compensating_work_started();
+
+  // Notify that some work has finished.
+  void work_finished()
+  {
+    if (--outstanding_work_ == 0)
+      stop();
+  }
+
+  // Return whether a handler can be dispatched immediately.
+  bool can_dispatch()
+  {
+    return thread_call_stack::contains(this) != 0;
+  }
+
+  /// Capture the current exception so it can be rethrown from a run function.
+  ASIO_DECL void capture_current_exception();
+
+  // Request invocation of the given operation and return immediately. Assumes
+  // that work_started() has not yet been called for the operation.
+  ASIO_DECL void post_immediate_completion(
+      operation* op, bool is_continuation);
+
+  // Request invocation of the given operations and return immediately. Assumes
+  // that work_started() has not yet been called for the operations.
+  ASIO_DECL void post_immediate_completions(std::size_t n,
+      op_queue<operation>& ops, bool is_continuation);
+
+  // Request invocation of the given operation and return immediately. Assumes
+  // that work_started() was previously called for the operation.
+  ASIO_DECL void post_deferred_completion(operation* op);
+
+  // Request invocation of the given operations and return immediately. Assumes
+  // that work_started() was previously called for each operation.
+  ASIO_DECL void post_deferred_completions(op_queue<operation>& ops);
+
+  // Enqueue the given operation following a failed attempt to dispatch the
+  // operation for immediate invocation.
+  ASIO_DECL void do_dispatch(operation* op);
+
+  // Process unfinished operations as part of a shutdownoperation. Assumes that
+  // work_started() was previously called for the operations.
+  ASIO_DECL void abandon_operations(op_queue<operation>& ops);
+
+  // Get the concurrency hint that was used to initialise the scheduler.
+  int concurrency_hint() const
+  {
+    return concurrency_hint_;
+  }
+
+private:
+  // The mutex type used by this scheduler.
+  typedef conditionally_enabled_mutex mutex;
+
+  // The event type used by this scheduler.
+  typedef conditionally_enabled_event event;
+
+  // Structure containing thread-specific data.
+  typedef scheduler_thread_info thread_info;
+
+  // Run at most one operation. May block.
+  ASIO_DECL std::size_t do_run_one(mutex::scoped_lock& lock,
+      thread_info& this_thread, const asio::error_code& ec);
+
+  // Run at most one operation with a timeout. May block.
+  ASIO_DECL std::size_t do_wait_one(mutex::scoped_lock& lock,
+      thread_info& this_thread, long usec, const asio::error_code& ec);
+
+  // Poll for at most one operation.
+  ASIO_DECL std::size_t do_poll_one(mutex::scoped_lock& lock,
+      thread_info& this_thread, const asio::error_code& ec);
+
+  // Stop the task and all idle threads.
+  ASIO_DECL void stop_all_threads(mutex::scoped_lock& lock);
+
+  // Wake a single idle thread, or the task, and always unlock the mutex.
+  ASIO_DECL void wake_one_thread_and_unlock(
+      mutex::scoped_lock& lock);
+
+  // Helper class to run the scheduler in its own thread.
+  class thread_function;
+  friend class thread_function;
+
+  // Helper class to perform task-related operations on block exit.
+  struct task_cleanup;
+  friend struct task_cleanup;
+
+  // Helper class to call work-related operations on block exit.
+  struct work_cleanup;
+  friend struct work_cleanup;
+
+  // Whether to optimise for single-threaded use cases.
+  const bool one_thread_;
+
+  // Mutex to protect access to internal data.
+  mutable mutex mutex_;
+
+  // Event to wake up blocked threads.
+  event wakeup_event_;
+
+  // The task to be run by this service.
+  reactor* task_;
+
+  // Operation object to represent the position of the task in the queue.
+  struct task_operation : operation
+  {
+    task_operation() : operation(0) {}
+  } task_operation_;
+
+  // Whether the task has been interrupted.
+  bool task_interrupted_;
+
+  // The count of unfinished work.
+  atomic_count outstanding_work_;
+
+  // The queue of handlers that are ready to be delivered.
+  op_queue<operation> op_queue_;
+
+  // Flag to indicate that the dispatcher has been stopped.
+  bool stopped_;
+
+  // Flag to indicate that the dispatcher has been shut down.
+  bool shutdown_;
+
+  // The concurrency hint used to initialise the scheduler.
+  const int concurrency_hint_;
+
+  // The thread that is running the scheduler.
+  asio::detail::thread* thread_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/scheduler.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // ASIO_DETAIL_SCHEDULER_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/scheduler_operation.hpp b/link/modules/asio-standalone/asio/include/asio/detail/scheduler_operation.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/scheduler_operation.hpp
@@ -0,0 +1,78 @@
+//
+// detail/scheduler_operation.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_SCHEDULER_OPERATION_HPP
+#define ASIO_DETAIL_SCHEDULER_OPERATION_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/error_code.hpp"
+#include "asio/detail/handler_tracking.hpp"
+#include "asio/detail/op_queue.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class scheduler;
+
+// Base class for all operations. A function pointer is used instead of virtual
+// functions to avoid the associated overhead.
+class scheduler_operation ASIO_INHERIT_TRACKED_HANDLER
+{
+public:
+  typedef scheduler_operation operation_type;
+
+  void complete(void* owner, const asio::error_code& ec,
+      std::size_t bytes_transferred)
+  {
+    func_(owner, this, ec, bytes_transferred);
+  }
+
+  void destroy()
+  {
+    func_(0, this, asio::error_code(), 0);
+  }
+
+protected:
+  typedef void (*func_type)(void*,
+      scheduler_operation*,
+      const asio::error_code&, std::size_t);
+
+  scheduler_operation(func_type func)
+    : next_(0),
+      func_(func),
+      task_result_(0)
+  {
+  }
+
+  // Prevents deletion through this type.
+  ~scheduler_operation()
+  {
+  }
+
+private:
+  friend class op_queue_access;
+  scheduler_operation* next_;
+  func_type func_;
+protected:
+  friend class scheduler;
+  unsigned int task_result_; // Passed into bytes transferred.
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_SCHEDULER_OPERATION_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/scheduler_thread_info.hpp b/link/modules/asio-standalone/asio/include/asio/detail/scheduler_thread_info.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/scheduler_thread_info.hpp
@@ -0,0 +1,40 @@
+//
+// detail/scheduler_thread_info.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_SCHEDULER_THREAD_INFO_HPP
+#define ASIO_DETAIL_SCHEDULER_THREAD_INFO_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/op_queue.hpp"
+#include "asio/detail/thread_info_base.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class scheduler;
+class scheduler_operation;
+
+struct scheduler_thread_info : public thread_info_base
+{
+  op_queue<scheduler_operation> private_op_queue;
+  long private_outstanding_work;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_SCHEDULER_THREAD_INFO_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/scoped_lock.hpp b/link/modules/asio-standalone/asio/include/asio/detail/scoped_lock.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/scoped_lock.hpp
@@ -0,0 +1,101 @@
+//
+// detail/scoped_lock.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_SCOPED_LOCK_HPP
+#define ASIO_DETAIL_SCOPED_LOCK_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/noncopyable.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+// Helper class to lock and unlock a mutex automatically.
+template <typename Mutex>
+class scoped_lock
+  : private noncopyable
+{
+public:
+  // Tag type used to distinguish constructors.
+  enum adopt_lock_t { adopt_lock };
+
+  // Constructor adopts a lock that is already held.
+  scoped_lock(Mutex& m, adopt_lock_t)
+    : mutex_(m),
+      locked_(true)
+  {
+  }
+
+  // Constructor acquires the lock.
+  explicit scoped_lock(Mutex& m)
+    : mutex_(m)
+  {
+    mutex_.lock();
+    locked_ = true;
+  }
+
+  // Destructor releases the lock.
+  ~scoped_lock()
+  {
+    if (locked_)
+      mutex_.unlock();
+  }
+
+  // Explicitly acquire the lock.
+  void lock()
+  {
+    if (!locked_)
+    {
+      mutex_.lock();
+      locked_ = true;
+    }
+  }
+
+  // Explicitly release the lock.
+  void unlock()
+  {
+    if (locked_)
+    {
+      mutex_.unlock();
+      locked_ = false;
+    }
+  }
+
+  // Test whether the lock is held.
+  bool locked() const
+  {
+    return locked_;
+  }
+
+  // Get the underlying mutex.
+  Mutex& mutex()
+  {
+    return mutex_;
+  }
+
+private:
+  // The underlying mutex.
+  Mutex& mutex_;
+
+  // Whether the mutex is currently locked or unlocked.
+  bool locked_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_SCOPED_LOCK_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/scoped_ptr.hpp b/link/modules/asio-standalone/asio/include/asio/detail/scoped_ptr.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/scoped_ptr.hpp
@@ -0,0 +1,87 @@
+//
+// detail/scoped_ptr.hpp
+// ~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_SCOPED_PTR_HPP
+#define ASIO_DETAIL_SCOPED_PTR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename T>
+class scoped_ptr
+{
+public:
+  // Constructor.
+  explicit scoped_ptr(T* p = 0)
+    : p_(p)
+  {
+  }
+
+  // Destructor.
+  ~scoped_ptr()
+  {
+    delete p_;
+  }
+
+  // Access.
+  T* get()
+  {
+    return p_;
+  }
+
+  // Access.
+  T* operator->()
+  {
+    return p_;
+  }
+
+  // Dereference.
+  T& operator*()
+  {
+    return *p_;
+  }
+
+  // Reset pointer.
+  void reset(T* p = 0)
+  {
+    delete p_;
+    p_ = p;
+  }
+
+  // Release ownership of the pointer.
+  T* release()
+  {
+    T* tmp = p_;
+    p_ = 0;
+    return tmp;
+  }
+
+private:
+  // Disallow copying and assignment.
+  scoped_ptr(const scoped_ptr&);
+  scoped_ptr& operator=(const scoped_ptr&);
+
+  T* p_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_SCOPED_PTR_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/select_interrupter.hpp b/link/modules/asio-standalone/asio/include/asio/detail/select_interrupter.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/select_interrupter.hpp
@@ -0,0 +1,46 @@
+//
+// detail/select_interrupter.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_SELECT_INTERRUPTER_HPP
+#define ASIO_DETAIL_SELECT_INTERRUPTER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if !defined(ASIO_WINDOWS_RUNTIME)
+
+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) || defined(__SYMBIAN32__)
+# include "asio/detail/socket_select_interrupter.hpp"
+#elif defined(ASIO_HAS_EVENTFD)
+# include "asio/detail/eventfd_select_interrupter.hpp"
+#else
+# include "asio/detail/pipe_select_interrupter.hpp"
+#endif
+
+namespace asio {
+namespace detail {
+
+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) || defined(__SYMBIAN32__)
+typedef socket_select_interrupter select_interrupter;
+#elif defined(ASIO_HAS_EVENTFD)
+typedef eventfd_select_interrupter select_interrupter;
+#else
+typedef pipe_select_interrupter select_interrupter;
+#endif
+
+} // namespace detail
+} // namespace asio
+
+#endif // !defined(ASIO_WINDOWS_RUNTIME)
+
+#endif // ASIO_DETAIL_SELECT_INTERRUPTER_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/select_reactor.hpp b/link/modules/asio-standalone/asio/include/asio/detail/select_reactor.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/select_reactor.hpp
@@ -0,0 +1,238 @@
+//
+// detail/select_reactor.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_SELECT_REACTOR_HPP
+#define ASIO_DETAIL_SELECT_REACTOR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_IOCP) \
+  || (!defined(ASIO_HAS_DEV_POLL) \
+      && !defined(ASIO_HAS_EPOLL) \
+      && !defined(ASIO_HAS_KQUEUE) \
+      && !defined(ASIO_WINDOWS_RUNTIME))
+
+#include <cstddef>
+#include "asio/detail/fd_set_adapter.hpp"
+#include "asio/detail/limits.hpp"
+#include "asio/detail/mutex.hpp"
+#include "asio/detail/op_queue.hpp"
+#include "asio/detail/reactor_op.hpp"
+#include "asio/detail/reactor_op_queue.hpp"
+#include "asio/detail/select_interrupter.hpp"
+#include "asio/detail/socket_types.hpp"
+#include "asio/detail/timer_queue_base.hpp"
+#include "asio/detail/timer_queue_set.hpp"
+#include "asio/detail/wait_op.hpp"
+#include "asio/execution_context.hpp"
+
+#if defined(ASIO_HAS_IOCP)
+# include "asio/detail/thread.hpp"
+#endif // defined(ASIO_HAS_IOCP)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class select_reactor
+  : public execution_context_service_base<select_reactor>
+{
+public:
+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+  enum op_types { read_op = 0, write_op = 1, except_op = 2,
+    max_select_ops = 3, connect_op = 3, max_ops = 4 };
+#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+  enum op_types { read_op = 0, write_op = 1, except_op = 2,
+    max_select_ops = 3, connect_op = 1, max_ops = 3 };
+#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+
+  // Per-descriptor data.
+  struct per_descriptor_data
+  {
+  };
+
+  // Constructor.
+  ASIO_DECL select_reactor(asio::execution_context& ctx);
+
+  // Destructor.
+  ASIO_DECL ~select_reactor();
+
+  // Destroy all user-defined handler objects owned by the service.
+  ASIO_DECL void shutdown();
+
+  // Recreate internal descriptors following a fork.
+  ASIO_DECL void notify_fork(
+      asio::execution_context::fork_event fork_ev);
+
+  // Initialise the task, but only if the reactor is not in its own thread.
+  ASIO_DECL void init_task();
+
+  // Register a socket with the reactor. Returns 0 on success, system error
+  // code on failure.
+  ASIO_DECL int register_descriptor(socket_type, per_descriptor_data&);
+
+  // Register a descriptor with an associated single operation. Returns 0 on
+  // success, system error code on failure.
+  ASIO_DECL int register_internal_descriptor(
+      int op_type, socket_type descriptor,
+      per_descriptor_data& descriptor_data, reactor_op* op);
+
+  // Post a reactor operation for immediate completion.
+  void post_immediate_completion(reactor_op* op, bool is_continuation)
+  {
+    scheduler_.post_immediate_completion(op, is_continuation);
+  }
+
+  // Start a new operation. The reactor operation will be performed when the
+  // given descriptor is flagged as ready, or an error has occurred.
+  ASIO_DECL void start_op(int op_type, socket_type descriptor,
+      per_descriptor_data&, reactor_op* op, bool is_continuation, bool);
+
+  // Cancel all operations associated with the given descriptor. The
+  // handlers associated with the descriptor will be invoked with the
+  // operation_aborted error.
+  ASIO_DECL void cancel_ops(socket_type descriptor, per_descriptor_data&);
+
+  // Cancel any operations that are running against the descriptor and remove
+  // its registration from the reactor. The reactor resources associated with
+  // the descriptor must be released by calling cleanup_descriptor_data.
+  ASIO_DECL void deregister_descriptor(socket_type descriptor,
+      per_descriptor_data&, bool closing);
+
+  // Remove the descriptor's registration from the reactor. The reactor
+  // resources associated with the descriptor must be released by calling
+  // cleanup_descriptor_data.
+  ASIO_DECL void deregister_internal_descriptor(
+      socket_type descriptor, per_descriptor_data&);
+
+  // Perform any post-deregistration cleanup tasks associated with the
+  // descriptor data.
+  ASIO_DECL void cleanup_descriptor_data(per_descriptor_data&);
+
+  // Move descriptor registration from one descriptor_data object to another.
+  ASIO_DECL void move_descriptor(socket_type descriptor,
+      per_descriptor_data& target_descriptor_data,
+      per_descriptor_data& source_descriptor_data);
+
+  // Add a new timer queue to the reactor.
+  template <typename Time_Traits>
+  void add_timer_queue(timer_queue<Time_Traits>& queue);
+
+  // Remove a timer queue from the reactor.
+  template <typename Time_Traits>
+  void remove_timer_queue(timer_queue<Time_Traits>& queue);
+
+  // Schedule a new operation in the given timer queue to expire at the
+  // specified absolute time.
+  template <typename Time_Traits>
+  void schedule_timer(timer_queue<Time_Traits>& queue,
+      const typename Time_Traits::time_type& time,
+      typename timer_queue<Time_Traits>::per_timer_data& timer, wait_op* op);
+
+  // Cancel the timer operations associated with the given token. Returns the
+  // number of operations that have been posted or dispatched.
+  template <typename Time_Traits>
+  std::size_t cancel_timer(timer_queue<Time_Traits>& queue,
+      typename timer_queue<Time_Traits>::per_timer_data& timer,
+      std::size_t max_cancelled = (std::numeric_limits<std::size_t>::max)());
+
+  // Move the timer operations associated with the given timer.
+  template <typename Time_Traits>
+  void move_timer(timer_queue<Time_Traits>& queue,
+      typename timer_queue<Time_Traits>::per_timer_data& target,
+      typename timer_queue<Time_Traits>::per_timer_data& source);
+
+  // Run select once until interrupted or events are ready to be dispatched.
+  ASIO_DECL void run(long usec, op_queue<operation>& ops);
+
+  // Interrupt the select loop.
+  ASIO_DECL void interrupt();
+
+private:
+#if defined(ASIO_HAS_IOCP)
+  // Run the select loop in the thread.
+  ASIO_DECL void run_thread();
+#endif // defined(ASIO_HAS_IOCP)
+
+  // Helper function to add a new timer queue.
+  ASIO_DECL void do_add_timer_queue(timer_queue_base& queue);
+
+  // Helper function to remove a timer queue.
+  ASIO_DECL void do_remove_timer_queue(timer_queue_base& queue);
+
+  // Get the timeout value for the select call.
+  ASIO_DECL timeval* get_timeout(long usec, timeval& tv);
+
+  // Cancel all operations associated with the given descriptor. This function
+  // does not acquire the select_reactor's mutex.
+  ASIO_DECL void cancel_ops_unlocked(socket_type descriptor,
+      const asio::error_code& ec);
+
+  // The scheduler implementation used to post completions.
+# if defined(ASIO_HAS_IOCP)
+  typedef class win_iocp_io_context scheduler_type;
+# else // defined(ASIO_HAS_IOCP)
+  typedef class scheduler scheduler_type;
+# endif // defined(ASIO_HAS_IOCP)
+  scheduler_type& scheduler_;
+
+  // Mutex to protect access to internal data.
+  asio::detail::mutex mutex_;
+
+  // The interrupter is used to break a blocking select call.
+  select_interrupter interrupter_;
+
+  // The queues of read, write and except operations.
+  reactor_op_queue<socket_type> op_queue_[max_ops];
+
+  // The file descriptor sets to be passed to the select system call.
+  fd_set_adapter fd_sets_[max_select_ops];
+
+  // The timer queues.
+  timer_queue_set timer_queues_;
+
+#if defined(ASIO_HAS_IOCP)
+  // Helper class to run the reactor loop in a thread.
+  class thread_function;
+  friend class thread_function;
+
+  // Does the reactor loop thread need to stop.
+  bool stop_thread_;
+
+  // The thread that is running the reactor loop.
+  asio::detail::thread* thread_;
+#endif // defined(ASIO_HAS_IOCP)
+
+  // Whether the service has been shut down.
+  bool shutdown_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/detail/impl/select_reactor.hpp"
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/select_reactor.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // defined(ASIO_HAS_IOCP)
+       //   || (!defined(ASIO_HAS_DEV_POLL)
+       //       && !defined(ASIO_HAS_EPOLL)
+       //       && !defined(ASIO_HAS_KQUEUE)
+       //       && !defined(ASIO_WINDOWS_RUNTIME))
+
+#endif // ASIO_DETAIL_SELECT_REACTOR_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/service_registry.hpp b/link/modules/asio-standalone/asio/include/asio/detail/service_registry.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/service_registry.hpp
@@ -0,0 +1,164 @@
+//
+// detail/service_registry.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_SERVICE_REGISTRY_HPP
+#define ASIO_DETAIL_SERVICE_REGISTRY_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <typeinfo>
+#include "asio/detail/mutex.hpp"
+#include "asio/detail/noncopyable.hpp"
+#include "asio/detail/type_traits.hpp"
+#include "asio/execution_context.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+class io_context;
+
+namespace detail {
+
+template <typename T>
+class typeid_wrapper {};
+
+class service_registry
+  : private noncopyable
+{
+public:
+  // Constructor.
+  ASIO_DECL service_registry(execution_context& owner);
+
+  // Destructor.
+  ASIO_DECL ~service_registry();
+
+  // Shutdown all services.
+  ASIO_DECL void shutdown_services();
+
+  // Destroy all services.
+  ASIO_DECL void destroy_services();
+
+  // Notify all services of a fork event.
+  ASIO_DECL void notify_fork(execution_context::fork_event fork_ev);
+
+  // Get the service object corresponding to the specified service type. Will
+  // create a new service object automatically if no such object already
+  // exists. Ownership of the service object is not transferred to the caller.
+  template <typename Service>
+  Service& use_service();
+
+  // Get the service object corresponding to the specified service type. Will
+  // create a new service object automatically if no such object already
+  // exists. Ownership of the service object is not transferred to the caller.
+  // This overload is used for backwards compatibility with services that
+  // inherit from io_context::service.
+  template <typename Service>
+  Service& use_service(io_context& owner);
+
+  // Add a service object. Throws on error, in which case ownership of the
+  // object is retained by the caller.
+  template <typename Service>
+  void add_service(Service* new_service);
+
+  // Check whether a service object of the specified type already exists.
+  template <typename Service>
+  bool has_service() const;
+
+private:
+  // Initalise a service's key when the key_type typedef is not available.
+  template <typename Service>
+  static void init_key(execution_context::service::key& key, ...);
+
+#if !defined(ASIO_NO_TYPEID)
+  // Initalise a service's key when the key_type typedef is available.
+  template <typename Service>
+  static void init_key(execution_context::service::key& key,
+      typename enable_if<
+        is_base_of<typename Service::key_type, Service>::value>::type*);
+#endif // !defined(ASIO_NO_TYPEID)
+
+  // Initialise a service's key based on its id.
+  ASIO_DECL static void init_key_from_id(
+      execution_context::service::key& key,
+      const execution_context::id& id);
+
+#if !defined(ASIO_NO_TYPEID)
+  // Initialise a service's key based on its id.
+  template <typename Service>
+  static void init_key_from_id(execution_context::service::key& key,
+      const service_id<Service>& /*id*/);
+#endif // !defined(ASIO_NO_TYPEID)
+
+  // Check if a service matches the given id.
+  ASIO_DECL static bool keys_match(
+      const execution_context::service::key& key1,
+      const execution_context::service::key& key2);
+
+  // The type of a factory function used for creating a service instance.
+  typedef execution_context::service*(*factory_type)(void*);
+
+  // Factory function for creating a service instance.
+  template <typename Service, typename Owner>
+  static execution_context::service* create(void* owner);
+
+  // Destroy a service instance.
+  ASIO_DECL static void destroy(execution_context::service* service);
+
+  // Helper class to manage service pointers.
+  struct auto_service_ptr;
+  friend struct auto_service_ptr;
+  struct auto_service_ptr
+  {
+    execution_context::service* ptr_;
+    ~auto_service_ptr() { destroy(ptr_); }
+  };
+
+  // Get the service object corresponding to the specified service key. Will
+  // create a new service object automatically if no such object already
+  // exists. Ownership of the service object is not transferred to the caller.
+  ASIO_DECL execution_context::service* do_use_service(
+      const execution_context::service::key& key,
+      factory_type factory, void* owner);
+
+  // Add a service object. Throws on error, in which case ownership of the
+  // object is retained by the caller.
+  ASIO_DECL void do_add_service(
+      const execution_context::service::key& key,
+      execution_context::service* new_service);
+
+  // Check whether a service object with the specified key already exists.
+  ASIO_DECL bool do_has_service(
+      const execution_context::service::key& key) const;
+
+  // Mutex to protect access to internal data.
+  mutable asio::detail::mutex mutex_;
+
+  // The owner of this service registry and the services it contains.
+  execution_context& owner_;
+
+  // The first service in the list of contained services.
+  execution_context::service* first_service_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/detail/impl/service_registry.hpp"
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/service_registry.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // ASIO_DETAIL_SERVICE_REGISTRY_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/signal_blocker.hpp b/link/modules/asio-standalone/asio/include/asio/detail/signal_blocker.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/signal_blocker.hpp
@@ -0,0 +1,44 @@
+//
+// detail/signal_blocker.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_SIGNAL_BLOCKER_HPP
+#define ASIO_DETAIL_SIGNAL_BLOCKER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if !defined(ASIO_HAS_THREADS) || defined(ASIO_WINDOWS) \
+  || defined(ASIO_WINDOWS_RUNTIME) \
+  || defined(__CYGWIN__) || defined(__SYMBIAN32__)
+# include "asio/detail/null_signal_blocker.hpp"
+#elif defined(ASIO_HAS_PTHREADS)
+# include "asio/detail/posix_signal_blocker.hpp"
+#else
+# error Only Windows and POSIX are supported!
+#endif
+
+namespace asio {
+namespace detail {
+
+#if !defined(ASIO_HAS_THREADS) || defined(ASIO_WINDOWS) \
+  || defined(ASIO_WINDOWS_RUNTIME) \
+  || defined(__CYGWIN__) || defined(__SYMBIAN32__)
+typedef null_signal_blocker signal_blocker;
+#elif defined(ASIO_HAS_PTHREADS)
+typedef posix_signal_blocker signal_blocker;
+#endif
+
+} // namespace detail
+} // namespace asio
+
+#endif // ASIO_DETAIL_SIGNAL_BLOCKER_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/signal_handler.hpp b/link/modules/asio-standalone/asio/include/asio/detail/signal_handler.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/signal_handler.hpp
@@ -0,0 +1,90 @@
+//
+// detail/signal_handler.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_SIGNAL_HANDLER_HPP
+#define ASIO_DETAIL_SIGNAL_HANDLER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_work.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/detail/signal_op.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Handler, typename IoExecutor>
+class signal_handler : public signal_op
+{
+public:
+  ASIO_DEFINE_HANDLER_PTR(signal_handler);
+
+  signal_handler(Handler& h, const IoExecutor& io_ex)
+    : signal_op(&signal_handler::do_complete),
+      handler_(ASIO_MOVE_CAST(Handler)(h)),
+      work_(handler_, io_ex)
+  {
+  }
+
+  static void do_complete(void* owner, operation* base,
+      const asio::error_code& /*ec*/,
+      std::size_t /*bytes_transferred*/)
+  {
+    // Take ownership of the handler object.
+    signal_handler* h(static_cast<signal_handler*>(base));
+    ptr p = { asio::detail::addressof(h->handler_), h, h };
+
+    ASIO_HANDLER_COMPLETION((*h));
+
+    // Take ownership of the operation's outstanding work.
+    handler_work<Handler, IoExecutor> w(
+        ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)(
+          h->work_));
+
+    // Make a copy of the handler so that the memory can be deallocated before
+    // the upcall is made. Even if we're not about to make an upcall, a
+    // sub-object of the handler may be the true owner of the memory associated
+    // with the handler. Consequently, a local copy of the handler is required
+    // to ensure that any owning sub-object remains valid until after we have
+    // deallocated the memory here.
+    detail::binder2<Handler, asio::error_code, int>
+      handler(h->handler_, h->ec_, h->signal_number_);
+    p.h = asio::detail::addressof(handler.handler_);
+    p.reset();
+
+    // Make the upcall if required.
+    if (owner)
+    {
+      fenced_block b(fenced_block::half);
+      ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_));
+      w.complete(handler, handler.handler_);
+      ASIO_HANDLER_INVOCATION_END;
+    }
+  }
+
+private:
+  Handler handler_;
+  handler_work<Handler, IoExecutor> work_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_SIGNAL_HANDLER_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/signal_init.hpp b/link/modules/asio-standalone/asio/include/asio/detail/signal_init.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/signal_init.hpp
@@ -0,0 +1,47 @@
+//
+// detail/signal_init.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_SIGNAL_INIT_HPP
+#define ASIO_DETAIL_SIGNAL_INIT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if !defined(ASIO_WINDOWS) && !defined(__CYGWIN__)
+
+#include <csignal>
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <int Signal = SIGPIPE>
+class signal_init
+{
+public:
+  // Constructor.
+  signal_init()
+  {
+    std::signal(Signal, SIG_IGN);
+  }
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // !defined(ASIO_WINDOWS) && !defined(__CYGWIN__)
+
+#endif // ASIO_DETAIL_SIGNAL_INIT_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/signal_op.hpp b/link/modules/asio-standalone/asio/include/asio/detail/signal_op.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/signal_op.hpp
@@ -0,0 +1,49 @@
+//
+// detail/signal_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_SIGNAL_OP_HPP
+#define ASIO_DETAIL_SIGNAL_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/operation.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class signal_op
+  : public operation
+{
+public:
+  // The error code to be passed to the completion handler.
+  asio::error_code ec_;
+
+  // The signal number to be passed to the completion handler.
+  int signal_number_;
+
+protected:
+  signal_op(func_type func)
+    : operation(func),
+      signal_number_(0)
+  {
+  }
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_SIGNAL_OP_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/signal_set_service.hpp b/link/modules/asio-standalone/asio/include/asio/detail/signal_set_service.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/signal_set_service.hpp
@@ -0,0 +1,229 @@
+//
+// detail/signal_set_service.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_SIGNAL_SET_SERVICE_HPP
+#define ASIO_DETAIL_SIGNAL_SET_SERVICE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#include <cstddef>
+#include <signal.h>
+#include "asio/error.hpp"
+#include "asio/execution_context.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/detail/op_queue.hpp"
+#include "asio/detail/signal_handler.hpp"
+#include "asio/detail/signal_op.hpp"
+#include "asio/detail/socket_types.hpp"
+
+#if defined(ASIO_HAS_IOCP)
+# include "asio/detail/win_iocp_io_context.hpp"
+#else // defined(ASIO_HAS_IOCP)
+# include "asio/detail/scheduler.hpp"
+#endif // defined(ASIO_HAS_IOCP)
+
+#if !defined(ASIO_WINDOWS) && !defined(__CYGWIN__)
+# include "asio/detail/reactor.hpp"
+#endif // !defined(ASIO_WINDOWS) && !defined(__CYGWIN__)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+#if defined(NSIG) && (NSIG > 0)
+enum { max_signal_number = NSIG };
+#else
+enum { max_signal_number = 128 };
+#endif
+
+extern ASIO_DECL struct signal_state* get_signal_state();
+
+extern "C" ASIO_DECL void asio_signal_handler(int signal_number);
+
+class signal_set_service :
+  public execution_context_service_base<signal_set_service>
+{
+public:
+  // Type used for tracking an individual signal registration.
+  class registration
+  {
+  public:
+    // Default constructor.
+    registration()
+      : signal_number_(0),
+        queue_(0),
+        undelivered_(0),
+        next_in_table_(0),
+        prev_in_table_(0),
+        next_in_set_(0)
+    {
+    }
+
+  private:
+    // Only this service will have access to the internal values.
+    friend class signal_set_service;
+
+    // The signal number that is registered.
+    int signal_number_;
+
+    // The waiting signal handlers.
+    op_queue<signal_op>* queue_;
+
+    // The number of undelivered signals.
+    std::size_t undelivered_;
+
+    // Pointers to adjacent registrations in the registrations_ table.
+    registration* next_in_table_;
+    registration* prev_in_table_;
+
+    // Link to next registration in the signal set.
+    registration* next_in_set_;
+  };
+
+  // The implementation type of the signal_set.
+  class implementation_type
+  {
+  public:
+    // Default constructor.
+    implementation_type()
+      : signals_(0)
+    {
+    }
+
+  private:
+    // Only this service will have access to the internal values.
+    friend class signal_set_service;
+
+    // The pending signal handlers.
+    op_queue<signal_op> queue_;
+
+    // Linked list of registered signals.
+    registration* signals_;
+  };
+
+  // Constructor.
+  ASIO_DECL signal_set_service(execution_context& context);
+
+  // Destructor.
+  ASIO_DECL ~signal_set_service();
+
+  // Destroy all user-defined handler objects owned by the service.
+  ASIO_DECL void shutdown();
+
+  // Perform fork-related housekeeping.
+  ASIO_DECL void notify_fork(
+      asio::execution_context::fork_event fork_ev);
+
+  // Construct a new signal_set implementation.
+  ASIO_DECL void construct(implementation_type& impl);
+
+  // Destroy a signal_set implementation.
+  ASIO_DECL void destroy(implementation_type& impl);
+
+  // Add a signal to a signal_set.
+  ASIO_DECL asio::error_code add(implementation_type& impl,
+      int signal_number, asio::error_code& ec);
+
+  // Remove a signal to a signal_set.
+  ASIO_DECL asio::error_code remove(implementation_type& impl,
+      int signal_number, asio::error_code& ec);
+
+  // Remove all signals from a signal_set.
+  ASIO_DECL asio::error_code clear(implementation_type& impl,
+      asio::error_code& ec);
+
+  // Cancel all operations associated with the signal set.
+  ASIO_DECL asio::error_code cancel(implementation_type& impl,
+      asio::error_code& ec);
+
+  // Start an asynchronous operation to wait for a signal to be delivered.
+  template <typename Handler, typename IoExecutor>
+  void async_wait(implementation_type& impl,
+      Handler& handler, const IoExecutor& io_ex)
+  {
+    // Allocate and construct an operation to wrap the handler.
+    typedef signal_handler<Handler, IoExecutor> op;
+    typename op::ptr p = { asio::detail::addressof(handler),
+      op::ptr::allocate(handler), 0 };
+    p.p = new (p.v) op(handler, io_ex);
+
+    ASIO_HANDLER_CREATION((scheduler_.context(),
+          *p.p, "signal_set", &impl, 0, "async_wait"));
+
+    start_wait_op(impl, p.p);
+    p.v = p.p = 0;
+  }
+
+  // Deliver notification that a particular signal occurred.
+  ASIO_DECL static void deliver_signal(int signal_number);
+
+private:
+  // Helper function to add a service to the global signal state.
+  ASIO_DECL static void add_service(signal_set_service* service);
+
+  // Helper function to remove a service from the global signal state.
+  ASIO_DECL static void remove_service(signal_set_service* service);
+
+  // Helper function to create the pipe descriptors.
+  ASIO_DECL static void open_descriptors();
+
+  // Helper function to close the pipe descriptors.
+  ASIO_DECL static void close_descriptors();
+
+  // Helper function to start a wait operation.
+  ASIO_DECL void start_wait_op(implementation_type& impl, signal_op* op);
+
+  // The scheduler used for dispatching handlers.
+#if defined(ASIO_HAS_IOCP)
+  typedef class win_iocp_io_context scheduler_impl;
+#else
+  typedef class scheduler scheduler_impl;
+#endif
+  scheduler_impl& scheduler_;
+
+#if !defined(ASIO_WINDOWS) \
+  && !defined(ASIO_WINDOWS_RUNTIME) \
+  && !defined(__CYGWIN__)
+  // The type used for registering for pipe reactor notifications.
+  class pipe_read_op;
+
+  // The reactor used for waiting for pipe readiness.
+  reactor& reactor_;
+
+  // The per-descriptor reactor data used for the pipe.
+  reactor::per_descriptor_data reactor_data_;
+#endif // !defined(ASIO_WINDOWS)
+       //   && !defined(ASIO_WINDOWS_RUNTIME)
+       //   && !defined(__CYGWIN__)
+
+  // A mapping from signal number to the registered signal sets.
+  registration* registrations_[max_signal_number];
+
+  // Pointers to adjacent services in linked list.
+  signal_set_service* next_;
+  signal_set_service* prev_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/signal_set_service.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // ASIO_DETAIL_SIGNAL_SET_SERVICE_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/socket_holder.hpp b/link/modules/asio-standalone/asio/include/asio/detail/socket_holder.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/socket_holder.hpp
@@ -0,0 +1,98 @@
+//
+// detail/socket_holder.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_SOCKET_HOLDER_HPP
+#define ASIO_DETAIL_SOCKET_HOLDER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/noncopyable.hpp"
+#include "asio/detail/socket_ops.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+// Implement the resource acquisition is initialisation idiom for sockets.
+class socket_holder
+  : private noncopyable
+{
+public:
+  // Construct as an uninitialised socket.
+  socket_holder()
+    : socket_(invalid_socket)
+  {
+  }
+
+  // Construct to take ownership of the specified socket.
+  explicit socket_holder(socket_type s)
+    : socket_(s)
+  {
+  }
+
+  // Destructor.
+  ~socket_holder()
+  {
+    if (socket_ != invalid_socket)
+    {
+      asio::error_code ec;
+      socket_ops::state_type state = 0;
+      socket_ops::close(socket_, state, true, ec);
+    }
+  }
+
+  // Get the underlying socket.
+  socket_type get() const
+  {
+    return socket_;
+  }
+
+  // Reset to an uninitialised socket.
+  void reset()
+  {
+    if (socket_ != invalid_socket)
+    {
+      asio::error_code ec;
+      socket_ops::state_type state = 0;
+      socket_ops::close(socket_, state, true, ec);
+      socket_ = invalid_socket;
+    }
+  }
+
+  // Reset to take ownership of the specified socket.
+  void reset(socket_type s)
+  {
+    reset();
+    socket_ = s;
+  }
+
+  // Release ownership of the socket.
+  socket_type release()
+  {
+    socket_type tmp = socket_;
+    socket_ = invalid_socket;
+    return tmp;
+  }
+
+private:
+  // The underlying socket.
+  socket_type socket_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_SOCKET_HOLDER_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/socket_ops.hpp b/link/modules/asio-standalone/asio/include/asio/detail/socket_ops.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/socket_ops.hpp
@@ -0,0 +1,383 @@
+//
+// detail/socket_ops.hpp
+// ~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_SOCKET_OPS_HPP
+#define ASIO_DETAIL_SOCKET_OPS_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#include "asio/error_code.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/detail/socket_types.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+namespace socket_ops {
+
+// Socket state bits.
+enum
+{
+  // The user wants a non-blocking socket.
+  user_set_non_blocking = 1,
+
+  // The socket has been set non-blocking.
+  internal_non_blocking = 2,
+
+  // Helper "state" used to determine whether the socket is non-blocking.
+  non_blocking = user_set_non_blocking | internal_non_blocking,
+
+  // User wants connection_aborted errors, which are disabled by default.
+  enable_connection_aborted = 4,
+
+  // The user set the linger option. Needs to be checked when closing.
+  user_set_linger = 8,
+
+  // The socket is stream-oriented.
+  stream_oriented = 16,
+
+  // The socket is datagram-oriented.
+  datagram_oriented = 32,
+
+  // The socket may have been dup()-ed.
+  possible_dup = 64
+};
+
+typedef unsigned char state_type;
+
+struct noop_deleter { void operator()(void*) {} };
+typedef shared_ptr<void> shared_cancel_token_type;
+typedef weak_ptr<void> weak_cancel_token_type;
+
+#if !defined(ASIO_WINDOWS_RUNTIME)
+
+ASIO_DECL socket_type accept(socket_type s, socket_addr_type* addr,
+    std::size_t* addrlen, asio::error_code& ec);
+
+ASIO_DECL socket_type sync_accept(socket_type s,
+    state_type state, socket_addr_type* addr,
+    std::size_t* addrlen, asio::error_code& ec);
+
+#if defined(ASIO_HAS_IOCP)
+
+ASIO_DECL void complete_iocp_accept(socket_type s,
+    void* output_buffer, DWORD address_length,
+    socket_addr_type* addr, std::size_t* addrlen,
+    socket_type new_socket, asio::error_code& ec);
+
+#else // defined(ASIO_HAS_IOCP)
+
+ASIO_DECL bool non_blocking_accept(socket_type s,
+    state_type state, socket_addr_type* addr, std::size_t* addrlen,
+    asio::error_code& ec, socket_type& new_socket);
+
+#endif // defined(ASIO_HAS_IOCP)
+
+ASIO_DECL int bind(socket_type s, const socket_addr_type* addr,
+    std::size_t addrlen, asio::error_code& ec);
+
+ASIO_DECL int close(socket_type s, state_type& state,
+    bool destruction, asio::error_code& ec);
+
+ASIO_DECL bool set_user_non_blocking(socket_type s,
+    state_type& state, bool value, asio::error_code& ec);
+
+ASIO_DECL bool set_internal_non_blocking(socket_type s,
+    state_type& state, bool value, asio::error_code& ec);
+
+ASIO_DECL int shutdown(socket_type s,
+    int what, asio::error_code& ec);
+
+ASIO_DECL int connect(socket_type s, const socket_addr_type* addr,
+    std::size_t addrlen, asio::error_code& ec);
+
+ASIO_DECL void sync_connect(socket_type s, const socket_addr_type* addr,
+    std::size_t addrlen, asio::error_code& ec);
+
+#if defined(ASIO_HAS_IOCP)
+
+ASIO_DECL void complete_iocp_connect(socket_type s,
+    asio::error_code& ec);
+
+#endif // defined(ASIO_HAS_IOCP)
+
+ASIO_DECL bool non_blocking_connect(socket_type s,
+    asio::error_code& ec);
+
+ASIO_DECL int socketpair(int af, int type, int protocol,
+    socket_type sv[2], asio::error_code& ec);
+
+ASIO_DECL bool sockatmark(socket_type s, asio::error_code& ec);
+
+ASIO_DECL size_t available(socket_type s, asio::error_code& ec);
+
+ASIO_DECL int listen(socket_type s,
+    int backlog, asio::error_code& ec);
+
+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+typedef WSABUF buf;
+#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+typedef iovec buf;
+#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+
+ASIO_DECL void init_buf(buf& b, void* data, size_t size);
+
+ASIO_DECL void init_buf(buf& b, const void* data, size_t size);
+
+ASIO_DECL signed_size_type recv(socket_type s, buf* bufs,
+    size_t count, int flags, asio::error_code& ec);
+
+ASIO_DECL signed_size_type recv1(socket_type s,
+    void* data, size_t size, int flags, asio::error_code& ec);
+
+ASIO_DECL size_t sync_recv(socket_type s, state_type state, buf* bufs,
+    size_t count, int flags, bool all_empty, asio::error_code& ec);
+
+ASIO_DECL size_t sync_recv1(socket_type s, state_type state,
+    void* data, size_t size, int flags, asio::error_code& ec);
+
+#if defined(ASIO_HAS_IOCP)
+
+ASIO_DECL void complete_iocp_recv(state_type state,
+    const weak_cancel_token_type& cancel_token, bool all_empty,
+    asio::error_code& ec, size_t bytes_transferred);
+
+#else // defined(ASIO_HAS_IOCP)
+
+ASIO_DECL bool non_blocking_recv(socket_type s,
+    buf* bufs, size_t count, int flags, bool is_stream,
+    asio::error_code& ec, size_t& bytes_transferred);
+
+ASIO_DECL bool non_blocking_recv1(socket_type s,
+    void* data, size_t size, int flags, bool is_stream,
+    asio::error_code& ec, size_t& bytes_transferred);
+
+#endif // defined(ASIO_HAS_IOCP)
+
+ASIO_DECL signed_size_type recvfrom(socket_type s, buf* bufs,
+    size_t count, int flags, socket_addr_type* addr,
+    std::size_t* addrlen, asio::error_code& ec);
+
+ASIO_DECL signed_size_type recvfrom1(socket_type s, void* data,
+    size_t size, int flags, socket_addr_type* addr,
+    std::size_t* addrlen, asio::error_code& ec);
+
+ASIO_DECL size_t sync_recvfrom(socket_type s, state_type state,
+    buf* bufs, size_t count, int flags, socket_addr_type* addr,
+    std::size_t* addrlen, asio::error_code& ec);
+
+ASIO_DECL size_t sync_recvfrom1(socket_type s, state_type state,
+    void* data, size_t size, int flags, socket_addr_type* addr,
+    std::size_t* addrlen, asio::error_code& ec);
+
+#if defined(ASIO_HAS_IOCP)
+
+ASIO_DECL void complete_iocp_recvfrom(
+    const weak_cancel_token_type& cancel_token,
+    asio::error_code& ec);
+
+#else // defined(ASIO_HAS_IOCP)
+
+ASIO_DECL bool non_blocking_recvfrom(socket_type s,
+    buf* bufs, size_t count, int flags,
+    socket_addr_type* addr, std::size_t* addrlen,
+    asio::error_code& ec, size_t& bytes_transferred);
+
+ASIO_DECL bool non_blocking_recvfrom1(socket_type s,
+    void* data, size_t size, int flags,
+    socket_addr_type* addr, std::size_t* addrlen,
+    asio::error_code& ec, size_t& bytes_transferred);
+
+#endif // defined(ASIO_HAS_IOCP)
+
+ASIO_DECL signed_size_type recvmsg(socket_type s, buf* bufs,
+    size_t count, int in_flags, int& out_flags,
+    asio::error_code& ec);
+
+ASIO_DECL size_t sync_recvmsg(socket_type s, state_type state,
+    buf* bufs, size_t count, int in_flags, int& out_flags,
+    asio::error_code& ec);
+
+#if defined(ASIO_HAS_IOCP)
+
+ASIO_DECL void complete_iocp_recvmsg(
+    const weak_cancel_token_type& cancel_token,
+    asio::error_code& ec);
+
+#else // defined(ASIO_HAS_IOCP)
+
+ASIO_DECL bool non_blocking_recvmsg(socket_type s,
+    buf* bufs, size_t count, int in_flags, int& out_flags,
+    asio::error_code& ec, size_t& bytes_transferred);
+
+#endif // defined(ASIO_HAS_IOCP)
+
+ASIO_DECL signed_size_type send(socket_type s, const buf* bufs,
+    size_t count, int flags, asio::error_code& ec);
+
+ASIO_DECL signed_size_type send1(socket_type s,
+    const void* data, size_t size, int flags, asio::error_code& ec);
+
+ASIO_DECL size_t sync_send(socket_type s, state_type state,
+    const buf* bufs, size_t count, int flags,
+    bool all_empty, asio::error_code& ec);
+
+ASIO_DECL size_t sync_send1(socket_type s, state_type state,
+    const void* data, size_t size, int flags, asio::error_code& ec);
+
+#if defined(ASIO_HAS_IOCP)
+
+ASIO_DECL void complete_iocp_send(
+    const weak_cancel_token_type& cancel_token,
+    asio::error_code& ec);
+
+#else // defined(ASIO_HAS_IOCP)
+
+ASIO_DECL bool non_blocking_send(socket_type s,
+    const buf* bufs, size_t count, int flags,
+    asio::error_code& ec, size_t& bytes_transferred);
+
+ASIO_DECL bool non_blocking_send1(socket_type s,
+    const void* data, size_t size, int flags,
+    asio::error_code& ec, size_t& bytes_transferred);
+
+#endif // defined(ASIO_HAS_IOCP)
+
+ASIO_DECL signed_size_type sendto(socket_type s, const buf* bufs,
+    size_t count, int flags, const socket_addr_type* addr,
+    std::size_t addrlen, asio::error_code& ec);
+
+ASIO_DECL signed_size_type sendto1(socket_type s, const void* data,
+    size_t size, int flags, const socket_addr_type* addr,
+    std::size_t addrlen, asio::error_code& ec);
+
+ASIO_DECL size_t sync_sendto(socket_type s, state_type state,
+    const buf* bufs, size_t count, int flags, const socket_addr_type* addr,
+    std::size_t addrlen, asio::error_code& ec);
+
+ASIO_DECL size_t sync_sendto1(socket_type s, state_type state,
+    const void* data, size_t size, int flags, const socket_addr_type* addr,
+    std::size_t addrlen, asio::error_code& ec);
+
+#if !defined(ASIO_HAS_IOCP)
+
+ASIO_DECL bool non_blocking_sendto(socket_type s,
+    const buf* bufs, size_t count, int flags,
+    const socket_addr_type* addr, std::size_t addrlen,
+    asio::error_code& ec, size_t& bytes_transferred);
+
+ASIO_DECL bool non_blocking_sendto1(socket_type s,
+    const void* data, size_t size, int flags,
+    const socket_addr_type* addr, std::size_t addrlen,
+    asio::error_code& ec, size_t& bytes_transferred);
+
+#endif // !defined(ASIO_HAS_IOCP)
+
+ASIO_DECL socket_type socket(int af, int type, int protocol,
+    asio::error_code& ec);
+
+ASIO_DECL int setsockopt(socket_type s, state_type& state,
+    int level, int optname, const void* optval,
+    std::size_t optlen, asio::error_code& ec);
+
+ASIO_DECL int getsockopt(socket_type s, state_type state,
+    int level, int optname, void* optval,
+    size_t* optlen, asio::error_code& ec);
+
+ASIO_DECL int getpeername(socket_type s, socket_addr_type* addr,
+    std::size_t* addrlen, bool cached, asio::error_code& ec);
+
+ASIO_DECL int getsockname(socket_type s, socket_addr_type* addr,
+    std::size_t* addrlen, asio::error_code& ec);
+
+ASIO_DECL int ioctl(socket_type s, state_type& state,
+    int cmd, ioctl_arg_type* arg, asio::error_code& ec);
+
+ASIO_DECL int select(int nfds, fd_set* readfds, fd_set* writefds,
+    fd_set* exceptfds, timeval* timeout, asio::error_code& ec);
+
+ASIO_DECL int poll_read(socket_type s,
+    state_type state, int msec, asio::error_code& ec);
+
+ASIO_DECL int poll_write(socket_type s,
+    state_type state, int msec, asio::error_code& ec);
+
+ASIO_DECL int poll_error(socket_type s,
+    state_type state, int msec, asio::error_code& ec);
+
+ASIO_DECL int poll_connect(socket_type s,
+    int msec, asio::error_code& ec);
+
+#endif // !defined(ASIO_WINDOWS_RUNTIME)
+
+ASIO_DECL const char* inet_ntop(int af, const void* src, char* dest,
+    size_t length, unsigned long scope_id, asio::error_code& ec);
+
+ASIO_DECL int inet_pton(int af, const char* src, void* dest,
+    unsigned long* scope_id, asio::error_code& ec);
+
+ASIO_DECL int gethostname(char* name,
+    int namelen, asio::error_code& ec);
+
+#if !defined(ASIO_WINDOWS_RUNTIME)
+
+ASIO_DECL asio::error_code getaddrinfo(const char* host,
+    const char* service, const addrinfo_type& hints,
+    addrinfo_type** result, asio::error_code& ec);
+
+ASIO_DECL asio::error_code background_getaddrinfo(
+    const weak_cancel_token_type& cancel_token, const char* host,
+    const char* service, const addrinfo_type& hints,
+    addrinfo_type** result, asio::error_code& ec);
+
+ASIO_DECL void freeaddrinfo(addrinfo_type* ai);
+
+ASIO_DECL asio::error_code getnameinfo(
+    const socket_addr_type* addr, std::size_t addrlen,
+    char* host, std::size_t hostlen, char* serv,
+    std::size_t servlen, int flags, asio::error_code& ec);
+
+ASIO_DECL asio::error_code sync_getnameinfo(
+    const socket_addr_type* addr, std::size_t addrlen,
+    char* host, std::size_t hostlen, char* serv,
+    std::size_t servlen, int sock_type, asio::error_code& ec);
+
+ASIO_DECL asio::error_code background_getnameinfo(
+    const weak_cancel_token_type& cancel_token,
+    const socket_addr_type* addr, std::size_t addrlen,
+    char* host, std::size_t hostlen, char* serv,
+    std::size_t servlen, int sock_type, asio::error_code& ec);
+
+#endif // !defined(ASIO_WINDOWS_RUNTIME)
+
+ASIO_DECL u_long_type network_to_host_long(u_long_type value);
+
+ASIO_DECL u_long_type host_to_network_long(u_long_type value);
+
+ASIO_DECL u_short_type network_to_host_short(u_short_type value);
+
+ASIO_DECL u_short_type host_to_network_short(u_short_type value);
+
+} // namespace socket_ops
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/socket_ops.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // ASIO_DETAIL_SOCKET_OPS_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/socket_option.hpp b/link/modules/asio-standalone/asio/include/asio/detail/socket_option.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/socket_option.hpp
@@ -0,0 +1,316 @@
+//
+// detail/socket_option.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_SOCKET_OPTION_HPP
+#define ASIO_DETAIL_SOCKET_OPTION_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <cstddef>
+#include <stdexcept>
+#include "asio/detail/socket_types.hpp"
+#include "asio/detail/throw_exception.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+namespace socket_option {
+
+// Helper template for implementing boolean-based options.
+template <int Level, int Name>
+class boolean
+{
+public:
+  // Default constructor.
+  boolean()
+    : value_(0)
+  {
+  }
+
+  // Construct with a specific option value.
+  explicit boolean(bool v)
+    : value_(v ? 1 : 0)
+  {
+  }
+
+  // Set the current value of the boolean.
+  boolean& operator=(bool v)
+  {
+    value_ = v ? 1 : 0;
+    return *this;
+  }
+
+  // Get the current value of the boolean.
+  bool value() const
+  {
+    return !!value_;
+  }
+
+  // Convert to bool.
+  operator bool() const
+  {
+    return !!value_;
+  }
+
+  // Test for false.
+  bool operator!() const
+  {
+    return !value_;
+  }
+
+  // Get the level of the socket option.
+  template <typename Protocol>
+  int level(const Protocol&) const
+  {
+    return Level;
+  }
+
+  // Get the name of the socket option.
+  template <typename Protocol>
+  int name(const Protocol&) const
+  {
+    return Name;
+  }
+
+  // Get the address of the boolean data.
+  template <typename Protocol>
+  int* data(const Protocol&)
+  {
+    return &value_;
+  }
+
+  // Get the address of the boolean data.
+  template <typename Protocol>
+  const int* data(const Protocol&) const
+  {
+    return &value_;
+  }
+
+  // Get the size of the boolean data.
+  template <typename Protocol>
+  std::size_t size(const Protocol&) const
+  {
+    return sizeof(value_);
+  }
+
+  // Set the size of the boolean data.
+  template <typename Protocol>
+  void resize(const Protocol&, std::size_t s)
+  {
+    // On some platforms (e.g. Windows Vista), the getsockopt function will
+    // return the size of a boolean socket option as one byte, even though a
+    // four byte integer was passed in.
+    switch (s)
+    {
+    case sizeof(char):
+      value_ = *reinterpret_cast<char*>(&value_) ? 1 : 0;
+      break;
+    case sizeof(value_):
+      break;
+    default:
+      {
+        std::length_error ex("boolean socket option resize");
+        asio::detail::throw_exception(ex);
+      }
+    }
+  }
+
+private:
+  int value_;
+};
+
+// Helper template for implementing integer options.
+template <int Level, int Name>
+class integer
+{
+public:
+  // Default constructor.
+  integer()
+    : value_(0)
+  {
+  }
+
+  // Construct with a specific option value.
+  explicit integer(int v)
+    : value_(v)
+  {
+  }
+
+  // Set the value of the int option.
+  integer& operator=(int v)
+  {
+    value_ = v;
+    return *this;
+  }
+
+  // Get the current value of the int option.
+  int value() const
+  {
+    return value_;
+  }
+
+  // Get the level of the socket option.
+  template <typename Protocol>
+  int level(const Protocol&) const
+  {
+    return Level;
+  }
+
+  // Get the name of the socket option.
+  template <typename Protocol>
+  int name(const Protocol&) const
+  {
+    return Name;
+  }
+
+  // Get the address of the int data.
+  template <typename Protocol>
+  int* data(const Protocol&)
+  {
+    return &value_;
+  }
+
+  // Get the address of the int data.
+  template <typename Protocol>
+  const int* data(const Protocol&) const
+  {
+    return &value_;
+  }
+
+  // Get the size of the int data.
+  template <typename Protocol>
+  std::size_t size(const Protocol&) const
+  {
+    return sizeof(value_);
+  }
+
+  // Set the size of the int data.
+  template <typename Protocol>
+  void resize(const Protocol&, std::size_t s)
+  {
+    if (s != sizeof(value_))
+    {
+      std::length_error ex("integer socket option resize");
+      asio::detail::throw_exception(ex);
+    }
+  }
+
+private:
+  int value_;
+};
+
+// Helper template for implementing linger options.
+template <int Level, int Name>
+class linger
+{
+public:
+  // Default constructor.
+  linger()
+  {
+    value_.l_onoff = 0;
+    value_.l_linger = 0;
+  }
+
+  // Construct with specific option values.
+  linger(bool e, int t)
+  {
+    enabled(e);
+    timeout ASIO_PREVENT_MACRO_SUBSTITUTION(t);
+  }
+
+  // Set the value for whether linger is enabled.
+  void enabled(bool value)
+  {
+    value_.l_onoff = value ? 1 : 0;
+  }
+
+  // Get the value for whether linger is enabled.
+  bool enabled() const
+  {
+    return value_.l_onoff != 0;
+  }
+
+  // Set the value for the linger timeout.
+  void timeout ASIO_PREVENT_MACRO_SUBSTITUTION(int value)
+  {
+#if defined(WIN32)
+    value_.l_linger = static_cast<u_short>(value);
+#else
+    value_.l_linger = value;
+#endif
+  }
+
+  // Get the value for the linger timeout.
+  int timeout ASIO_PREVENT_MACRO_SUBSTITUTION() const
+  {
+    return static_cast<int>(value_.l_linger);
+  }
+
+  // Get the level of the socket option.
+  template <typename Protocol>
+  int level(const Protocol&) const
+  {
+    return Level;
+  }
+
+  // Get the name of the socket option.
+  template <typename Protocol>
+  int name(const Protocol&) const
+  {
+    return Name;
+  }
+
+  // Get the address of the linger data.
+  template <typename Protocol>
+  detail::linger_type* data(const Protocol&)
+  {
+    return &value_;
+  }
+
+  // Get the address of the linger data.
+  template <typename Protocol>
+  const detail::linger_type* data(const Protocol&) const
+  {
+    return &value_;
+  }
+
+  // Get the size of the linger data.
+  template <typename Protocol>
+  std::size_t size(const Protocol&) const
+  {
+    return sizeof(value_);
+  }
+
+  // Set the size of the int data.
+  template <typename Protocol>
+  void resize(const Protocol&, std::size_t s)
+  {
+    if (s != sizeof(value_))
+    {
+      std::length_error ex("linger socket option resize");
+      asio::detail::throw_exception(ex);
+    }
+  }
+
+private:
+  detail::linger_type value_;
+};
+
+} // namespace socket_option
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_SOCKET_OPTION_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/socket_select_interrupter.hpp b/link/modules/asio-standalone/asio/include/asio/detail/socket_select_interrupter.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/socket_select_interrupter.hpp
@@ -0,0 +1,91 @@
+//
+// detail/socket_select_interrupter.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_SOCKET_SELECT_INTERRUPTER_HPP
+#define ASIO_DETAIL_SOCKET_SELECT_INTERRUPTER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if !defined(ASIO_WINDOWS_RUNTIME)
+
+#if defined(ASIO_WINDOWS) \
+  || defined(__CYGWIN__) \
+  || defined(__SYMBIAN32__)
+
+#include "asio/detail/socket_types.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class socket_select_interrupter
+{
+public:
+  // Constructor.
+  ASIO_DECL socket_select_interrupter();
+
+  // Destructor.
+  ASIO_DECL ~socket_select_interrupter();
+
+  // Recreate the interrupter's descriptors. Used after a fork.
+  ASIO_DECL void recreate();
+
+  // Interrupt the select call.
+  ASIO_DECL void interrupt();
+
+  // Reset the select interrupter. Returns true if the reset was successful.
+  ASIO_DECL bool reset();
+
+  // Get the read descriptor to be passed to select.
+  socket_type read_descriptor() const
+  {
+    return read_descriptor_;
+  }
+
+private:
+  // Open the descriptors. Throws on error.
+  ASIO_DECL void open_descriptors();
+
+  // Close the descriptors.
+  ASIO_DECL void close_descriptors();
+
+  // The read end of a connection used to interrupt the select call. This file
+  // descriptor is passed to select such that when it is time to stop, a single
+  // byte will be written on the other end of the connection and this
+  // descriptor will become readable.
+  socket_type read_descriptor_;
+
+  // The write end of a connection used to interrupt the select call. A single
+  // byte may be written to this to wake up the select which is waiting for the
+  // other end to become readable.
+  socket_type write_descriptor_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/socket_select_interrupter.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // defined(ASIO_WINDOWS)
+       // || defined(__CYGWIN__)
+       // || defined(__SYMBIAN32__)
+
+#endif // !defined(ASIO_WINDOWS_RUNTIME)
+
+#endif // ASIO_DETAIL_SOCKET_SELECT_INTERRUPTER_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/socket_types.hpp b/link/modules/asio-standalone/asio/include/asio/detail/socket_types.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/socket_types.hpp
@@ -0,0 +1,416 @@
+//
+// detail/socket_types.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_SOCKET_TYPES_HPP
+#define ASIO_DETAIL_SOCKET_TYPES_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_WINDOWS_RUNTIME)
+// Empty.
+#elif defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+# if defined(_WINSOCKAPI_) && !defined(_WINSOCK2API_)
+#  error WinSock.h has already been included
+# endif // defined(_WINSOCKAPI_) && !defined(_WINSOCK2API_)
+# if defined(__BORLANDC__)
+#  include <stdlib.h> // Needed for __errno
+#  if !defined(_WSPIAPI_H_)
+#   define _WSPIAPI_H_
+#   define ASIO_WSPIAPI_H_DEFINED
+#  endif // !defined(_WSPIAPI_H_)
+# endif // defined(__BORLANDC__)
+# include <winsock2.h>
+# include <ws2tcpip.h>
+# if defined(WINAPI_FAMILY)
+#  if ((WINAPI_FAMILY & WINAPI_PARTITION_DESKTOP) != 0)
+#   include <windows.h>
+#  endif // ((WINAPI_FAMILY & WINAPI_PARTITION_DESKTOP) != 0)
+# endif // defined(WINAPI_FAMILY)
+# if !defined(ASIO_WINDOWS_APP)
+#  include <mswsock.h>
+# endif // !defined(ASIO_WINDOWS_APP)
+# if defined(ASIO_WSPIAPI_H_DEFINED)
+#  undef _WSPIAPI_H_
+#  undef ASIO_WSPIAPI_H_DEFINED
+# endif // defined(ASIO_WSPIAPI_H_DEFINED)
+# if !defined(ASIO_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")
+#   if !defined(ASIO_WINDOWS_APP)
+#    pragma comment(lib, "mswsock.lib")
+#   endif // !defined(ASIO_WINDOWS_APP)
+#  endif // defined(_MSC_VER) || defined(__BORLANDC__)
+# endif // !defined(ASIO_NO_DEFAULT_LINKED_LIBS)
+# include "asio/detail/old_win_sdk_compat.hpp"
+#else
+# include <sys/ioctl.h>
+# if (defined(__MACH__) && defined(__APPLE__)) \
+   || defined(__FreeBSD__) || defined(__NetBSD__) \
+   || defined(__OpenBSD__) || defined(__linux__) \
+   || defined(__EMSCRIPTEN__)
+#  include <poll.h>
+# elif !defined(__SYMBIAN32__)
+#  include <sys/poll.h>
+# endif
+# include <sys/types.h>
+# include <sys/stat.h>
+# include <fcntl.h>
+# if defined(__hpux)
+#  include <sys/time.h>
+# endif
+# if !defined(__hpux) || defined(__SELECT)
+#  include <sys/select.h>
+# endif
+# include <sys/socket.h>
+# include <sys/uio.h>
+# include <sys/un.h>
+# include <netinet/in.h>
+# if !defined(__SYMBIAN32__)
+#  include <netinet/tcp.h>
+# endif
+# include <arpa/inet.h>
+# include <netdb.h>
+# include <net/if.h>
+# include <limits.h>
+# if defined(__sun)
+#  include <sys/filio.h>
+#  include <sys/sockio.h>
+# endif
+#endif
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+#if defined(ASIO_WINDOWS_RUNTIME)
+const int max_addr_v4_str_len = 256;
+const int max_addr_v6_str_len = 256;
+typedef unsigned __int32 u_long_type;
+typedef unsigned __int16 u_short_type;
+struct in4_addr_type { u_long_type s_addr; };
+struct in4_mreq_type { in4_addr_type imr_multiaddr, imr_interface; };
+struct in6_addr_type { unsigned char s6_addr[16]; };
+struct in6_mreq_type { in6_addr_type ipv6mr_multiaddr;
+  unsigned long ipv6mr_interface; };
+struct socket_addr_type { int sa_family; };
+struct sockaddr_in4_type { int sin_family;
+  in4_addr_type sin_addr; u_short_type sin_port; };
+struct sockaddr_in6_type { int sin6_family;
+  in6_addr_type sin6_addr; u_short_type sin6_port;
+  u_long_type sin6_flowinfo; u_long_type sin6_scope_id; };
+struct sockaddr_storage_type { int ss_family;
+  unsigned char ss_bytes[128 - sizeof(int)]; };
+struct addrinfo_type { int ai_flags;
+  int ai_family, ai_socktype, ai_protocol;
+  int ai_addrlen; const void* ai_addr;
+  const char* ai_canonname; addrinfo_type* ai_next; };
+struct linger_type { u_short_type l_onoff, l_linger; };
+typedef u_long_type ioctl_arg_type;
+typedef int signed_size_type;
+# define ASIO_OS_DEF(c) ASIO_OS_DEF_##c
+# define ASIO_OS_DEF_AF_UNSPEC 0
+# define ASIO_OS_DEF_AF_INET 2
+# define ASIO_OS_DEF_AF_INET6 23
+# define ASIO_OS_DEF_SOCK_STREAM 1
+# define ASIO_OS_DEF_SOCK_DGRAM 2
+# define ASIO_OS_DEF_SOCK_RAW 3
+# define ASIO_OS_DEF_SOCK_SEQPACKET 5
+# define ASIO_OS_DEF_IPPROTO_IP 0
+# define ASIO_OS_DEF_IPPROTO_IPV6 41
+# define ASIO_OS_DEF_IPPROTO_TCP 6
+# define ASIO_OS_DEF_IPPROTO_UDP 17
+# define ASIO_OS_DEF_IPPROTO_ICMP 1
+# define ASIO_OS_DEF_IPPROTO_ICMPV6 58
+# define ASIO_OS_DEF_FIONBIO 1
+# define ASIO_OS_DEF_FIONREAD 2
+# define ASIO_OS_DEF_INADDR_ANY 0
+# define ASIO_OS_DEF_MSG_OOB 0x1
+# define ASIO_OS_DEF_MSG_PEEK 0x2
+# define ASIO_OS_DEF_MSG_DONTROUTE 0x4
+# define ASIO_OS_DEF_MSG_EOR 0 // Not supported.
+# define ASIO_OS_DEF_SHUT_RD 0x0
+# define ASIO_OS_DEF_SHUT_WR 0x1
+# define ASIO_OS_DEF_SHUT_RDWR 0x2
+# define ASIO_OS_DEF_SOMAXCONN 0x7fffffff
+# define ASIO_OS_DEF_SOL_SOCKET 0xffff
+# define ASIO_OS_DEF_SO_BROADCAST 0x20
+# define ASIO_OS_DEF_SO_DEBUG 0x1
+# define ASIO_OS_DEF_SO_DONTROUTE 0x10
+# define ASIO_OS_DEF_SO_KEEPALIVE 0x8
+# define ASIO_OS_DEF_SO_LINGER 0x80
+# define ASIO_OS_DEF_SO_OOBINLINE 0x100
+# define ASIO_OS_DEF_SO_SNDBUF 0x1001
+# define ASIO_OS_DEF_SO_RCVBUF 0x1002
+# define ASIO_OS_DEF_SO_SNDLOWAT 0x1003
+# define ASIO_OS_DEF_SO_RCVLOWAT 0x1004
+# define ASIO_OS_DEF_SO_REUSEADDR 0x4
+# define ASIO_OS_DEF_TCP_NODELAY 0x1
+# define ASIO_OS_DEF_IP_MULTICAST_IF 2
+# define ASIO_OS_DEF_IP_MULTICAST_TTL 3
+# define ASIO_OS_DEF_IP_MULTICAST_LOOP 4
+# define ASIO_OS_DEF_IP_ADD_MEMBERSHIP 5
+# define ASIO_OS_DEF_IP_DROP_MEMBERSHIP 6
+# define ASIO_OS_DEF_IP_TTL 7
+# define ASIO_OS_DEF_IPV6_UNICAST_HOPS 4
+# define ASIO_OS_DEF_IPV6_MULTICAST_IF 9
+# define ASIO_OS_DEF_IPV6_MULTICAST_HOPS 10
+# define ASIO_OS_DEF_IPV6_MULTICAST_LOOP 11
+# define ASIO_OS_DEF_IPV6_JOIN_GROUP 12
+# define ASIO_OS_DEF_IPV6_LEAVE_GROUP 13
+# define ASIO_OS_DEF_AI_CANONNAME 0x2
+# define ASIO_OS_DEF_AI_PASSIVE 0x1
+# define ASIO_OS_DEF_AI_NUMERICHOST 0x4
+# define ASIO_OS_DEF_AI_NUMERICSERV 0x8
+# define ASIO_OS_DEF_AI_V4MAPPED 0x800
+# define ASIO_OS_DEF_AI_ALL 0x100
+# define ASIO_OS_DEF_AI_ADDRCONFIG 0x400
+#elif defined(ASIO_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(ASIO_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 ::linger linger_type;
+typedef unsigned long ioctl_arg_type;
+typedef u_long u_long_type;
+typedef u_short u_short_type;
+typedef int signed_size_type;
+# define ASIO_OS_DEF(c) ASIO_OS_DEF_##c
+# define ASIO_OS_DEF_AF_UNSPEC AF_UNSPEC
+# define ASIO_OS_DEF_AF_INET AF_INET
+# define ASIO_OS_DEF_AF_INET6 AF_INET6
+# define ASIO_OS_DEF_SOCK_STREAM SOCK_STREAM
+# define ASIO_OS_DEF_SOCK_DGRAM SOCK_DGRAM
+# define ASIO_OS_DEF_SOCK_RAW SOCK_RAW
+# define ASIO_OS_DEF_SOCK_SEQPACKET SOCK_SEQPACKET
+# define ASIO_OS_DEF_IPPROTO_IP IPPROTO_IP
+# define ASIO_OS_DEF_IPPROTO_IPV6 IPPROTO_IPV6
+# define ASIO_OS_DEF_IPPROTO_TCP IPPROTO_TCP
+# define ASIO_OS_DEF_IPPROTO_UDP IPPROTO_UDP
+# define ASIO_OS_DEF_IPPROTO_ICMP IPPROTO_ICMP
+# define ASIO_OS_DEF_IPPROTO_ICMPV6 IPPROTO_ICMPV6
+# define ASIO_OS_DEF_FIONBIO FIONBIO
+# define ASIO_OS_DEF_FIONREAD FIONREAD
+# define ASIO_OS_DEF_INADDR_ANY INADDR_ANY
+# define ASIO_OS_DEF_MSG_OOB MSG_OOB
+# define ASIO_OS_DEF_MSG_PEEK MSG_PEEK
+# define ASIO_OS_DEF_MSG_DONTROUTE MSG_DONTROUTE
+# define ASIO_OS_DEF_MSG_EOR 0 // Not supported on Windows.
+# define ASIO_OS_DEF_SHUT_RD SD_RECEIVE
+# define ASIO_OS_DEF_SHUT_WR SD_SEND
+# define ASIO_OS_DEF_SHUT_RDWR SD_BOTH
+# define ASIO_OS_DEF_SOMAXCONN SOMAXCONN
+# define ASIO_OS_DEF_SOL_SOCKET SOL_SOCKET
+# define ASIO_OS_DEF_SO_BROADCAST SO_BROADCAST
+# define ASIO_OS_DEF_SO_DEBUG SO_DEBUG
+# define ASIO_OS_DEF_SO_DONTROUTE SO_DONTROUTE
+# define ASIO_OS_DEF_SO_KEEPALIVE SO_KEEPALIVE
+# define ASIO_OS_DEF_SO_LINGER SO_LINGER
+# define ASIO_OS_DEF_SO_OOBINLINE SO_OOBINLINE
+# define ASIO_OS_DEF_SO_SNDBUF SO_SNDBUF
+# define ASIO_OS_DEF_SO_RCVBUF SO_RCVBUF
+# define ASIO_OS_DEF_SO_SNDLOWAT SO_SNDLOWAT
+# define ASIO_OS_DEF_SO_RCVLOWAT SO_RCVLOWAT
+# define ASIO_OS_DEF_SO_REUSEADDR SO_REUSEADDR
+# define ASIO_OS_DEF_TCP_NODELAY TCP_NODELAY
+# define ASIO_OS_DEF_IP_MULTICAST_IF IP_MULTICAST_IF
+# define ASIO_OS_DEF_IP_MULTICAST_TTL IP_MULTICAST_TTL
+# define ASIO_OS_DEF_IP_MULTICAST_LOOP IP_MULTICAST_LOOP
+# define ASIO_OS_DEF_IP_ADD_MEMBERSHIP IP_ADD_MEMBERSHIP
+# define ASIO_OS_DEF_IP_DROP_MEMBERSHIP IP_DROP_MEMBERSHIP
+# define ASIO_OS_DEF_IP_TTL IP_TTL
+# define ASIO_OS_DEF_IPV6_UNICAST_HOPS IPV6_UNICAST_HOPS
+# define ASIO_OS_DEF_IPV6_MULTICAST_IF IPV6_MULTICAST_IF
+# define ASIO_OS_DEF_IPV6_MULTICAST_HOPS IPV6_MULTICAST_HOPS
+# define ASIO_OS_DEF_IPV6_MULTICAST_LOOP IPV6_MULTICAST_LOOP
+# define ASIO_OS_DEF_IPV6_JOIN_GROUP IPV6_JOIN_GROUP
+# define ASIO_OS_DEF_IPV6_LEAVE_GROUP IPV6_LEAVE_GROUP
+# define ASIO_OS_DEF_AI_CANONNAME AI_CANONNAME
+# define ASIO_OS_DEF_AI_PASSIVE AI_PASSIVE
+# define ASIO_OS_DEF_AI_NUMERICHOST AI_NUMERICHOST
+# if defined(AI_NUMERICSERV)
+#  define ASIO_OS_DEF_AI_NUMERICSERV AI_NUMERICSERV
+# else
+#  define ASIO_OS_DEF_AI_NUMERICSERV 0
+# endif
+# if defined(AI_V4MAPPED)
+#  define ASIO_OS_DEF_AI_V4MAPPED AI_V4MAPPED
+# else
+#  define ASIO_OS_DEF_AI_V4MAPPED 0
+# endif
+# if defined(AI_ALL)
+#  define ASIO_OS_DEF_AI_ALL AI_ALL
+# else
+#  define ASIO_OS_DEF_AI_ALL 0
+# endif
+# if defined(AI_ADDRCONFIG)
+#  define ASIO_OS_DEF_AI_ADDRCONFIG AI_ADDRCONFIG
+# else
+#  define ASIO_OS_DEF_AI_ADDRCONFIG 0
+# endif
+# 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 ::linger linger_type;
+typedef int ioctl_arg_type;
+typedef uint32_t u_long_type;
+typedef uint16_t u_short_type;
+#if defined(ASIO_HAS_SSIZE_T)
+typedef ssize_t signed_size_type;
+#else // defined(ASIO_HAS_SSIZE_T)
+typedef int signed_size_type;
+#endif // defined(ASIO_HAS_SSIZE_T)
+# define ASIO_OS_DEF(c) ASIO_OS_DEF_##c
+# define ASIO_OS_DEF_AF_UNSPEC AF_UNSPEC
+# define ASIO_OS_DEF_AF_INET AF_INET
+# define ASIO_OS_DEF_AF_INET6 AF_INET6
+# define ASIO_OS_DEF_SOCK_STREAM SOCK_STREAM
+# define ASIO_OS_DEF_SOCK_DGRAM SOCK_DGRAM
+# define ASIO_OS_DEF_SOCK_RAW SOCK_RAW
+# define ASIO_OS_DEF_SOCK_SEQPACKET SOCK_SEQPACKET
+# define ASIO_OS_DEF_IPPROTO_IP IPPROTO_IP
+# define ASIO_OS_DEF_IPPROTO_IPV6 IPPROTO_IPV6
+# define ASIO_OS_DEF_IPPROTO_TCP IPPROTO_TCP
+# define ASIO_OS_DEF_IPPROTO_UDP IPPROTO_UDP
+# define ASIO_OS_DEF_IPPROTO_ICMP IPPROTO_ICMP
+# define ASIO_OS_DEF_IPPROTO_ICMPV6 IPPROTO_ICMPV6
+# define ASIO_OS_DEF_FIONBIO FIONBIO
+# define ASIO_OS_DEF_FIONREAD FIONREAD
+# define ASIO_OS_DEF_INADDR_ANY INADDR_ANY
+# define ASIO_OS_DEF_MSG_OOB MSG_OOB
+# define ASIO_OS_DEF_MSG_PEEK MSG_PEEK
+# define ASIO_OS_DEF_MSG_DONTROUTE MSG_DONTROUTE
+# define ASIO_OS_DEF_MSG_EOR MSG_EOR
+# define ASIO_OS_DEF_SHUT_RD SHUT_RD
+# define ASIO_OS_DEF_SHUT_WR SHUT_WR
+# define ASIO_OS_DEF_SHUT_RDWR SHUT_RDWR
+# define ASIO_OS_DEF_SOMAXCONN SOMAXCONN
+# define ASIO_OS_DEF_SOL_SOCKET SOL_SOCKET
+# define ASIO_OS_DEF_SO_BROADCAST SO_BROADCAST
+# define ASIO_OS_DEF_SO_DEBUG SO_DEBUG
+# define ASIO_OS_DEF_SO_DONTROUTE SO_DONTROUTE
+# define ASIO_OS_DEF_SO_KEEPALIVE SO_KEEPALIVE
+# define ASIO_OS_DEF_SO_LINGER SO_LINGER
+# define ASIO_OS_DEF_SO_OOBINLINE SO_OOBINLINE
+# define ASIO_OS_DEF_SO_SNDBUF SO_SNDBUF
+# define ASIO_OS_DEF_SO_RCVBUF SO_RCVBUF
+# define ASIO_OS_DEF_SO_SNDLOWAT SO_SNDLOWAT
+# define ASIO_OS_DEF_SO_RCVLOWAT SO_RCVLOWAT
+# define ASIO_OS_DEF_SO_REUSEADDR SO_REUSEADDR
+# define ASIO_OS_DEF_TCP_NODELAY TCP_NODELAY
+# define ASIO_OS_DEF_IP_MULTICAST_IF IP_MULTICAST_IF
+# define ASIO_OS_DEF_IP_MULTICAST_TTL IP_MULTICAST_TTL
+# define ASIO_OS_DEF_IP_MULTICAST_LOOP IP_MULTICAST_LOOP
+# define ASIO_OS_DEF_IP_ADD_MEMBERSHIP IP_ADD_MEMBERSHIP
+# define ASIO_OS_DEF_IP_DROP_MEMBERSHIP IP_DROP_MEMBERSHIP
+# define ASIO_OS_DEF_IP_TTL IP_TTL
+# define ASIO_OS_DEF_IPV6_UNICAST_HOPS IPV6_UNICAST_HOPS
+# define ASIO_OS_DEF_IPV6_MULTICAST_IF IPV6_MULTICAST_IF
+# define ASIO_OS_DEF_IPV6_MULTICAST_HOPS IPV6_MULTICAST_HOPS
+# define ASIO_OS_DEF_IPV6_MULTICAST_LOOP IPV6_MULTICAST_LOOP
+# define ASIO_OS_DEF_IPV6_JOIN_GROUP IPV6_JOIN_GROUP
+# define ASIO_OS_DEF_IPV6_LEAVE_GROUP IPV6_LEAVE_GROUP
+# define ASIO_OS_DEF_AI_CANONNAME AI_CANONNAME
+# define ASIO_OS_DEF_AI_PASSIVE AI_PASSIVE
+# define ASIO_OS_DEF_AI_NUMERICHOST AI_NUMERICHOST
+# if defined(AI_NUMERICSERV)
+#  define ASIO_OS_DEF_AI_NUMERICSERV AI_NUMERICSERV
+# else
+#  define ASIO_OS_DEF_AI_NUMERICSERV 0
+# endif
+// Note: QNX Neutrino 6.3 defines AI_V4MAPPED, AI_ALL and AI_ADDRCONFIG but
+// does not implement them. Therefore they are specifically excluded here.
+# if defined(AI_V4MAPPED) && !defined(__QNXNTO__)
+#  define ASIO_OS_DEF_AI_V4MAPPED AI_V4MAPPED
+# else
+#  define ASIO_OS_DEF_AI_V4MAPPED 0
+# endif
+# if defined(AI_ALL) && !defined(__QNXNTO__)
+#  define ASIO_OS_DEF_AI_ALL AI_ALL
+# else
+#  define ASIO_OS_DEF_AI_ALL 0
+# endif
+# if defined(AI_ADDRCONFIG) && !defined(__QNXNTO__)
+#  define ASIO_OS_DEF_AI_ADDRCONFIG AI_ADDRCONFIG
+# else
+#  define ASIO_OS_DEF_AI_ADDRCONFIG 0
+# endif
+# 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 asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_SOCKET_TYPES_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/solaris_fenced_block.hpp b/link/modules/asio-standalone/asio/include/asio/detail/solaris_fenced_block.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/solaris_fenced_block.hpp
@@ -0,0 +1,62 @@
+//
+// detail/solaris_fenced_block.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_SOLARIS_FENCED_BLOCK_HPP
+#define ASIO_DETAIL_SOLARIS_FENCED_BLOCK_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(__sun)
+
+#include <atomic.h>
+#include "asio/detail/noncopyable.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class solaris_fenced_block
+  : private noncopyable
+{
+public:
+  enum half_t { half };
+  enum full_t { full };
+
+  // Constructor for a half fenced block.
+  explicit solaris_fenced_block(half_t)
+  {
+  }
+
+  // Constructor for a full fenced block.
+  explicit solaris_fenced_block(full_t)
+  {
+    membar_consumer();
+  }
+
+  // Destructor.
+  ~solaris_fenced_block()
+  {
+    membar_producer();
+  }
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(__sun)
+
+#endif // ASIO_DETAIL_SOLARIS_FENCED_BLOCK_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/source_location.hpp b/link/modules/asio-standalone/asio/include/asio/detail/source_location.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/source_location.hpp
@@ -0,0 +1,45 @@
+//
+// detail/source_location.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_SOURCE_LOCATION_HPP
+#define ASIO_DETAIL_SOURCE_LOCATION_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_SOURCE_LOCATION)
+
+#if defined(ASIO_HAS_STD_SOURCE_LOCATION)
+# include <source_location>
+#elif defined(ASIO_HAS_STD_EXPERIMENTAL_SOURCE_LOCATION)
+# include <experimental/source_location>
+#else // defined(ASIO_HAS_STD_EXPERIMENTAL_SOURCE_LOCATION)
+# error ASIO_HAS_SOURCE_LOCATION is set \
+  but no source_location is available
+#endif // defined(ASIO_HAS_STD_EXPERIMENTAL_SOURCE_LOCATION)
+
+namespace asio {
+namespace detail {
+
+#if defined(ASIO_HAS_STD_SOURCE_LOCATION)
+using std::source_location;
+#elif defined(ASIO_HAS_STD_EXPERIMENTAL_SOURCE_LOCATION)
+using std::experimental::source_location;
+#endif // defined(ASIO_HAS_STD_EXPERIMENTAL_SOURCE_LOCATION)
+
+} // namespace detail
+} // namespace asio
+
+#endif // defined(ASIO_HAS_SOURCE_LOCATION)
+
+#endif // ASIO_DETAIL_SOURCE_LOCATION_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/static_mutex.hpp b/link/modules/asio-standalone/asio/include/asio/detail/static_mutex.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/static_mutex.hpp
@@ -0,0 +1,52 @@
+//
+// detail/static_mutex.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_STATIC_MUTEX_HPP
+#define ASIO_DETAIL_STATIC_MUTEX_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if !defined(ASIO_HAS_THREADS)
+# include "asio/detail/null_static_mutex.hpp"
+#elif defined(ASIO_WINDOWS)
+# include "asio/detail/win_static_mutex.hpp"
+#elif defined(ASIO_HAS_PTHREADS)
+# include "asio/detail/posix_static_mutex.hpp"
+#elif defined(ASIO_HAS_STD_MUTEX_AND_CONDVAR)
+# include "asio/detail/std_static_mutex.hpp"
+#else
+# error Only Windows and POSIX are supported!
+#endif
+
+namespace asio {
+namespace detail {
+
+#if !defined(ASIO_HAS_THREADS)
+typedef null_static_mutex static_mutex;
+# define ASIO_STATIC_MUTEX_INIT ASIO_NULL_STATIC_MUTEX_INIT
+#elif defined(ASIO_WINDOWS)
+typedef win_static_mutex static_mutex;
+# define ASIO_STATIC_MUTEX_INIT ASIO_WIN_STATIC_MUTEX_INIT
+#elif defined(ASIO_HAS_PTHREADS)
+typedef posix_static_mutex static_mutex;
+# define ASIO_STATIC_MUTEX_INIT ASIO_POSIX_STATIC_MUTEX_INIT
+#elif defined(ASIO_HAS_STD_MUTEX_AND_CONDVAR)
+typedef std_static_mutex static_mutex;
+# define ASIO_STATIC_MUTEX_INIT ASIO_STD_STATIC_MUTEX_INIT
+#endif
+
+} // namespace detail
+} // namespace asio
+
+#endif // ASIO_DETAIL_STATIC_MUTEX_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/std_event.hpp b/link/modules/asio-standalone/asio/include/asio/detail/std_event.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/std_event.hpp
@@ -0,0 +1,188 @@
+//
+// detail/std_event.hpp
+// ~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_STD_EVENT_HPP
+#define ASIO_DETAIL_STD_EVENT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_STD_MUTEX_AND_CONDVAR)
+
+#include <chrono>
+#include <condition_variable>
+#include "asio/detail/assert.hpp"
+#include "asio/detail/noncopyable.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class std_event
+  : private noncopyable
+{
+public:
+  // Constructor.
+  std_event()
+    : state_(0)
+  {
+  }
+
+  // Destructor.
+  ~std_event()
+  {
+  }
+
+  // Signal the event. (Retained for backward compatibility.)
+  template <typename Lock>
+  void signal(Lock& lock)
+  {
+    this->signal_all(lock);
+  }
+
+  // Signal all waiters.
+  template <typename Lock>
+  void signal_all(Lock& lock)
+  {
+    ASIO_ASSERT(lock.locked());
+    (void)lock;
+    state_ |= 1;
+    cond_.notify_all();
+  }
+
+  // Unlock the mutex and signal one waiter.
+  template <typename Lock>
+  void unlock_and_signal_one(Lock& lock)
+  {
+    ASIO_ASSERT(lock.locked());
+    state_ |= 1;
+    bool have_waiters = (state_ > 1);
+    lock.unlock();
+    if (have_waiters)
+      cond_.notify_one();
+  }
+
+  // Unlock the mutex and signal one waiter who may destroy us.
+  template <typename Lock>
+  void unlock_and_signal_one(Lock& lock)
+  {
+    ASIO_ASSERT(lock.locked());
+    state_ |= 1;
+    bool have_waiters = (state_ > 1);
+    if (have_waiters)
+      cond_.notify_one();
+    lock.unlock();
+  }
+
+  // If there's a waiter, unlock the mutex and signal it.
+  template <typename Lock>
+  bool maybe_unlock_and_signal_one(Lock& lock)
+  {
+    ASIO_ASSERT(lock.locked());
+    state_ |= 1;
+    if (state_ > 1)
+    {
+      lock.unlock();
+      cond_.notify_one();
+      return true;
+    }
+    return false;
+  }
+
+  // Reset the event.
+  template <typename Lock>
+  void clear(Lock& lock)
+  {
+    ASIO_ASSERT(lock.locked());
+    (void)lock;
+    state_ &= ~std::size_t(1);
+  }
+
+  // Wait for the event to become signalled.
+  template <typename Lock>
+  void wait(Lock& lock)
+  {
+    ASIO_ASSERT(lock.locked());
+    unique_lock_adapter u_lock(lock);
+    while ((state_ & 1) == 0)
+    {
+      waiter w(state_);
+      cond_.wait(u_lock.unique_lock_);
+    }
+  }
+
+  // Timed wait for the event to become signalled.
+  template <typename Lock>
+  bool wait_for_usec(Lock& lock, long usec)
+  {
+    ASIO_ASSERT(lock.locked());
+    unique_lock_adapter u_lock(lock);
+    if ((state_ & 1) == 0)
+    {
+      waiter w(state_);
+      cond_.wait_for(u_lock.unique_lock_, std::chrono::microseconds(usec));
+    }
+    return (state_ & 1) != 0;
+  }
+
+private:
+  // Helper class to temporarily adapt a scoped_lock into a unique_lock so that
+  // it can be passed to std::condition_variable::wait().
+  struct unique_lock_adapter
+  {
+    template <typename Lock>
+    explicit unique_lock_adapter(Lock& lock)
+      : unique_lock_(lock.mutex().mutex_, std::adopt_lock)
+    {
+    }
+
+    ~unique_lock_adapter()
+    {
+      unique_lock_.release();
+    }
+
+    std::unique_lock<std::mutex> unique_lock_;
+  };
+
+  // Helper to increment and decrement the state to track outstanding waiters.
+  class waiter
+  {
+  public:
+    explicit waiter(std::size_t& state)
+      : state_(state)
+    {
+      state_ += 2;
+    }
+
+    ~waiter()
+    {
+      state_ -= 2;
+    }
+
+  private:
+    std::size_t& state_;
+  };
+
+  std::condition_variable cond_;
+  std::size_t state_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_STD_MUTEX_AND_CONDVAR)
+
+#endif // ASIO_DETAIL_STD_EVENT_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/std_fenced_block.hpp b/link/modules/asio-standalone/asio/include/asio/detail/std_fenced_block.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/std_fenced_block.hpp
@@ -0,0 +1,62 @@
+//
+// detail/std_fenced_block.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_STD_FENCED_BLOCK_HPP
+#define ASIO_DETAIL_STD_FENCED_BLOCK_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_STD_ATOMIC)
+
+#include <atomic>
+#include "asio/detail/noncopyable.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class std_fenced_block
+  : private noncopyable
+{
+public:
+  enum half_t { half };
+  enum full_t { full };
+
+  // Constructor for a half fenced block.
+  explicit std_fenced_block(half_t)
+  {
+  }
+
+  // Constructor for a full fenced block.
+  explicit std_fenced_block(full_t)
+  {
+    std::atomic_thread_fence(std::memory_order_acquire);
+  }
+
+  // Destructor.
+  ~std_fenced_block()
+  {
+    std::atomic_thread_fence(std::memory_order_release);
+  }
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_STD_ATOMIC)
+
+#endif // ASIO_DETAIL_STD_FENCED_BLOCK_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/std_global.hpp b/link/modules/asio-standalone/asio/include/asio/detail/std_global.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/std_global.hpp
@@ -0,0 +1,70 @@
+//
+// detail/std_global.hpp
+// ~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_STD_GLOBAL_HPP
+#define ASIO_DETAIL_STD_GLOBAL_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_STD_CALL_ONCE)
+
+#include <exception>
+#include <mutex>
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename T>
+struct std_global_impl
+{
+  // Helper function to perform initialisation.
+  static void do_init()
+  {
+    instance_.ptr_ = new T;
+  }
+
+  // Destructor automatically cleans up the global.
+  ~std_global_impl()
+  {
+    delete ptr_;
+  }
+
+  static std::once_flag init_once_;
+  static std_global_impl instance_;
+  T* ptr_;
+};
+
+template <typename T>
+std::once_flag std_global_impl<T>::init_once_;
+
+template <typename T>
+std_global_impl<T> std_global_impl<T>::instance_;
+
+template <typename T>
+T& std_global()
+{
+  std::call_once(std_global_impl<T>::init_once_, &std_global_impl<T>::do_init);
+  return *std_global_impl<T>::instance_.ptr_;
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_STD_CALL_ONCE)
+
+#endif // ASIO_DETAIL_STD_GLOBAL_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/std_mutex.hpp b/link/modules/asio-standalone/asio/include/asio/detail/std_mutex.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/std_mutex.hpp
@@ -0,0 +1,73 @@
+//
+// detail/std_mutex.hpp
+// ~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_STD_MUTEX_HPP
+#define ASIO_DETAIL_STD_MUTEX_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_STD_MUTEX_AND_CONDVAR)
+
+#include <mutex>
+#include "asio/detail/noncopyable.hpp"
+#include "asio/detail/scoped_lock.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class std_event;
+
+class std_mutex
+  : private noncopyable
+{
+public:
+  typedef asio::detail::scoped_lock<std_mutex> scoped_lock;
+
+  // Constructor.
+  std_mutex()
+  {
+  }
+
+  // Destructor.
+  ~std_mutex()
+  {
+  }
+
+  // Lock the mutex.
+  void lock()
+  {
+    mutex_.lock();
+  }
+
+  // Unlock the mutex.
+  void unlock()
+  {
+    mutex_.unlock();
+  }
+
+private:
+  friend class std_event;
+  std::mutex mutex_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_STD_MUTEX_AND_CONDVAR)
+
+#endif // ASIO_DETAIL_STD_MUTEX_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/std_static_mutex.hpp b/link/modules/asio-standalone/asio/include/asio/detail/std_static_mutex.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/std_static_mutex.hpp
@@ -0,0 +1,81 @@
+//
+// detail/std_static_mutex.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_STD_STATIC_MUTEX_HPP
+#define ASIO_DETAIL_STD_STATIC_MUTEX_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_STD_MUTEX_AND_CONDVAR)
+
+#include <mutex>
+#include "asio/detail/noncopyable.hpp"
+#include "asio/detail/scoped_lock.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class std_event;
+
+class std_static_mutex
+  : private noncopyable
+{
+public:
+  typedef asio::detail::scoped_lock<std_static_mutex> scoped_lock;
+
+  // Constructor.
+  std_static_mutex(int)
+  {
+  }
+
+  // Destructor.
+  ~std_static_mutex()
+  {
+  }
+
+  // Initialise the mutex.
+  void init()
+  {
+    // Nothing to do.
+  }
+
+  // Lock the mutex.
+  void lock()
+  {
+    mutex_.lock();
+  }
+
+  // Unlock the mutex.
+  void unlock()
+  {
+    mutex_.unlock();
+  }
+
+private:
+  friend class std_event;
+  std::mutex mutex_;
+};
+
+#define ASIO_STD_STATIC_MUTEX_INIT 0
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_STD_MUTEX_AND_CONDVAR)
+
+#endif // ASIO_DETAIL_STD_STATIC_MUTEX_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/std_thread.hpp b/link/modules/asio-standalone/asio/include/asio/detail/std_thread.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/std_thread.hpp
@@ -0,0 +1,71 @@
+//
+// detail/std_thread.hpp
+// ~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_STD_THREAD_HPP
+#define ASIO_DETAIL_STD_THREAD_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_STD_THREAD)
+
+#include <thread>
+#include "asio/detail/noncopyable.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class std_thread
+  : private noncopyable
+{
+public:
+  // Constructor.
+  template <typename Function>
+  std_thread(Function f, unsigned int = 0)
+    : thread_(f)
+  {
+  }
+
+  // Destructor.
+  ~std_thread()
+  {
+    join();
+  }
+
+  // Wait for the thread to exit.
+  void join()
+  {
+    if (thread_.joinable())
+      thread_.join();
+  }
+
+  // Get number of CPUs.
+  static std::size_t hardware_concurrency()
+  {
+    return std::thread::hardware_concurrency();
+  }
+
+private:
+  std::thread thread_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_STD_THREAD)
+
+#endif // ASIO_DETAIL_STD_THREAD_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/strand_executor_service.hpp b/link/modules/asio-standalone/asio/include/asio/detail/strand_executor_service.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/strand_executor_service.hpp
@@ -0,0 +1,166 @@
+//
+// detail/strand_executor_service.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_STRAND_EXECUTOR_SERVICE_HPP
+#define ASIO_DETAIL_STRAND_EXECUTOR_SERVICE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/atomic_count.hpp"
+#include "asio/detail/executor_op.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/detail/mutex.hpp"
+#include "asio/detail/op_queue.hpp"
+#include "asio/detail/scheduler_operation.hpp"
+#include "asio/detail/scoped_ptr.hpp"
+#include "asio/detail/type_traits.hpp"
+#include "asio/execution.hpp"
+#include "asio/execution_context.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+// Default service implementation for a strand.
+class strand_executor_service
+  : public execution_context_service_base<strand_executor_service>
+{
+public:
+  // The underlying implementation of a strand.
+  class strand_impl
+  {
+  public:
+    ASIO_DECL ~strand_impl();
+
+  private:
+    friend class strand_executor_service;
+
+    // Mutex to protect access to internal data.
+    mutex* mutex_;
+
+    // Indicates whether the strand is currently "locked" by a handler. This
+    // means that there is a handler upcall in progress, or that the strand
+    // itself has been scheduled in order to invoke some pending handlers.
+    bool locked_;
+
+    // Indicates that the strand has been shut down and will accept no further
+    // handlers.
+    bool shutdown_;
+
+    // The handlers that are waiting on the strand but should not be run until
+    // after the next time the strand is scheduled. This queue must only be
+    // modified while the mutex is locked.
+    op_queue<scheduler_operation> waiting_queue_;
+
+    // The handlers that are ready to be run. Logically speaking, these are the
+    // handlers that hold the strand's lock. The ready queue is only modified
+    // from within the strand and so may be accessed without locking the mutex.
+    op_queue<scheduler_operation> ready_queue_;
+
+    // Pointers to adjacent handle implementations in linked list.
+    strand_impl* next_;
+    strand_impl* prev_;
+
+    // The strand service in where the implementation is held.
+    strand_executor_service* service_;
+  };
+
+  typedef shared_ptr<strand_impl> implementation_type;
+
+  // Construct a new strand service for the specified context.
+  ASIO_DECL explicit strand_executor_service(execution_context& context);
+
+  // Destroy all user-defined handler objects owned by the service.
+  ASIO_DECL void shutdown();
+
+  // Create a new strand_executor implementation.
+  ASIO_DECL implementation_type create_implementation();
+
+  // Request invocation of the given function.
+  template <typename Executor, typename Function>
+  static void execute(const implementation_type& impl, Executor& ex,
+      ASIO_MOVE_ARG(Function) function,
+      typename enable_if<
+        can_query<Executor, execution::allocator_t<void> >::value
+      >::type* = 0);
+
+  // Request invocation of the given function.
+  template <typename Executor, typename Function>
+  static void execute(const implementation_type& impl, Executor& ex,
+      ASIO_MOVE_ARG(Function) function,
+      typename enable_if<
+        !can_query<Executor, execution::allocator_t<void> >::value
+      >::type* = 0);
+
+  // Request invocation of the given function.
+  template <typename Executor, typename Function, typename Allocator>
+  static void dispatch(const implementation_type& impl, Executor& ex,
+      ASIO_MOVE_ARG(Function) function, const Allocator& a);
+
+  // Request invocation of the given function and return immediately.
+  template <typename Executor, typename Function, typename Allocator>
+  static void post(const implementation_type& impl, Executor& ex,
+      ASIO_MOVE_ARG(Function) function, const Allocator& a);
+
+  // Request invocation of the given function and return immediately.
+  template <typename Executor, typename Function, typename Allocator>
+  static void defer(const implementation_type& impl, Executor& ex,
+      ASIO_MOVE_ARG(Function) function, const Allocator& a);
+
+  // Determine whether the strand is running in the current thread.
+  ASIO_DECL static bool running_in_this_thread(
+      const implementation_type& impl);
+
+private:
+  friend class strand_impl;
+  template <typename F, typename Allocator> class allocator_binder;
+  template <typename Executor, typename = void> class invoker;
+
+  // Adds a function to the strand. Returns true if it acquires the lock.
+  ASIO_DECL static bool enqueue(const implementation_type& impl,
+      scheduler_operation* op);
+
+  // Helper function to request invocation of the given function.
+  template <typename Executor, typename Function, typename Allocator>
+  static void do_execute(const implementation_type& impl, Executor& ex,
+      ASIO_MOVE_ARG(Function) function, const Allocator& a);
+
+  // Mutex to protect access to the service-wide state.
+  mutex mutex_;
+
+  // Number of mutexes shared between all strand objects.
+  enum { num_mutexes = 193 };
+
+  // Pool of mutexes.
+  scoped_ptr<mutex> mutexes_[num_mutexes];
+
+  // Extra value used when hashing to prevent recycled memory locations from
+  // getting the same mutex.
+  std::size_t salt_;
+
+  // The head of a linked list of all implementations.
+  strand_impl* impl_list_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/detail/impl/strand_executor_service.hpp"
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/strand_executor_service.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // ASIO_DETAIL_STRAND_EXECUTOR_SERVICE_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/strand_service.hpp b/link/modules/asio-standalone/asio/include/asio/detail/strand_service.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/strand_service.hpp
@@ -0,0 +1,145 @@
+//
+// detail/strand_service.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_STRAND_SERVICE_HPP
+#define ASIO_DETAIL_STRAND_SERVICE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/io_context.hpp"
+#include "asio/detail/mutex.hpp"
+#include "asio/detail/op_queue.hpp"
+#include "asio/detail/operation.hpp"
+#include "asio/detail/scoped_ptr.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+// Default service implementation for a strand.
+class strand_service
+  : public asio::detail::service_base<strand_service>
+{
+private:
+  // Helper class to re-post the strand on exit.
+  struct on_do_complete_exit;
+
+  // Helper class to re-post the strand on exit.
+  struct on_dispatch_exit;
+
+public:
+
+  // The underlying implementation of a strand.
+  class strand_impl
+    : public operation
+  {
+  public:
+    strand_impl();
+
+  private:
+    // Only this service will have access to the internal values.
+    friend class strand_service;
+    friend struct on_do_complete_exit;
+    friend struct on_dispatch_exit;
+
+    // Mutex to protect access to internal data.
+    asio::detail::mutex mutex_;
+
+    // Indicates whether the strand is currently "locked" by a handler. This
+    // means that there is a handler upcall in progress, or that the strand
+    // itself has been scheduled in order to invoke some pending handlers.
+    bool locked_;
+
+    // The handlers that are waiting on the strand but should not be run until
+    // after the next time the strand is scheduled. This queue must only be
+    // modified while the mutex is locked.
+    op_queue<operation> waiting_queue_;
+
+    // The handlers that are ready to be run. Logically speaking, these are the
+    // handlers that hold the strand's lock. The ready queue is only modified
+    // from within the strand and so may be accessed without locking the mutex.
+    op_queue<operation> ready_queue_;
+  };
+
+  typedef strand_impl* implementation_type;
+
+  // Construct a new strand service for the specified io_context.
+  ASIO_DECL explicit strand_service(asio::io_context& io_context);
+
+  // Destroy all user-defined handler objects owned by the service.
+  ASIO_DECL void shutdown();
+
+  // Construct a new strand implementation.
+  ASIO_DECL void construct(implementation_type& impl);
+
+  // Request the io_context to invoke the given handler.
+  template <typename Handler>
+  void dispatch(implementation_type& impl, Handler& handler);
+
+  // Request the io_context to invoke the given handler and return immediately.
+  template <typename Handler>
+  void post(implementation_type& impl, Handler& handler);
+
+  // Determine whether the strand is running in the current thread.
+  ASIO_DECL bool running_in_this_thread(
+      const implementation_type& impl) const;
+
+private:
+  // Helper function to dispatch a handler. Returns true if the handler should
+  // be dispatched immediately.
+  ASIO_DECL bool do_dispatch(implementation_type& impl, operation* op);
+
+  // Helper fiunction to post a handler.
+  ASIO_DECL void do_post(implementation_type& impl,
+      operation* op, bool is_continuation);
+
+  ASIO_DECL static void do_complete(void* owner,
+      operation* base, const asio::error_code& ec,
+      std::size_t bytes_transferred);
+
+  // The io_context used to obtain an I/O executor.
+  io_context& io_context_;
+
+  // The io_context implementation used to post completions.
+  io_context_impl& io_context_impl_;
+
+  // Mutex to protect access to the array of implementations.
+  asio::detail::mutex mutex_;
+
+  // Number of implementations shared between all strand objects.
+#if defined(ASIO_STRAND_IMPLEMENTATIONS)
+  enum { num_implementations = ASIO_STRAND_IMPLEMENTATIONS };
+#else // defined(ASIO_STRAND_IMPLEMENTATIONS)
+  enum { num_implementations = 193 };
+#endif // defined(ASIO_STRAND_IMPLEMENTATIONS)
+
+  // Pool of implementations.
+  scoped_ptr<strand_impl> implementations_[num_implementations];
+
+  // Extra value used when hashing to prevent recycled memory locations from
+  // getting the same strand implementation.
+  std::size_t salt_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/detail/impl/strand_service.hpp"
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/strand_service.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // ASIO_DETAIL_STRAND_SERVICE_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/string_view.hpp b/link/modules/asio-standalone/asio/include/asio/detail/string_view.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/string_view.hpp
@@ -0,0 +1,47 @@
+//
+// detail/string_view.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_STRING_VIEW_HPP
+#define ASIO_DETAIL_STRING_VIEW_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_STRING_VIEW)
+
+#if defined(ASIO_HAS_STD_STRING_VIEW)
+# include <string_view>
+#elif defined(ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW)
+# include <experimental/string_view>
+#else // defined(ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW)
+# error ASIO_HAS_STRING_VIEW is set but no string_view is available
+#endif // defined(ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW)
+
+namespace asio {
+
+#if defined(ASIO_HAS_STD_STRING_VIEW)
+using std::basic_string_view;
+using std::string_view;
+#elif defined(ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW)
+using std::experimental::basic_string_view;
+using std::experimental::string_view;
+#endif // defined(ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW)
+
+} // namespace asio
+
+# define ASIO_STRING_VIEW_PARAM asio::string_view
+#else // defined(ASIO_HAS_STRING_VIEW)
+# define ASIO_STRING_VIEW_PARAM const std::string&
+#endif // defined(ASIO_HAS_STRING_VIEW)
+
+#endif // ASIO_DETAIL_STRING_VIEW_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/thread.hpp b/link/modules/asio-standalone/asio/include/asio/detail/thread.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/thread.hpp
@@ -0,0 +1,60 @@
+//
+// detail/thread.hpp
+// ~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_THREAD_HPP
+#define ASIO_DETAIL_THREAD_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if !defined(ASIO_HAS_THREADS)
+# include "asio/detail/null_thread.hpp"
+#elif defined(ASIO_WINDOWS)
+# if defined(UNDER_CE)
+#  include "asio/detail/wince_thread.hpp"
+# elif defined(ASIO_WINDOWS_APP)
+#  include "asio/detail/winapp_thread.hpp"
+# else
+#  include "asio/detail/win_thread.hpp"
+# endif
+#elif defined(ASIO_HAS_PTHREADS)
+# include "asio/detail/posix_thread.hpp"
+#elif defined(ASIO_HAS_STD_THREAD)
+# include "asio/detail/std_thread.hpp"
+#else
+# error Only Windows, POSIX and std::thread are supported!
+#endif
+
+namespace asio {
+namespace detail {
+
+#if !defined(ASIO_HAS_THREADS)
+typedef null_thread thread;
+#elif defined(ASIO_WINDOWS)
+# if defined(UNDER_CE)
+typedef wince_thread thread;
+# elif defined(ASIO_WINDOWS_APP)
+typedef winapp_thread thread;
+# else
+typedef win_thread thread;
+# endif
+#elif defined(ASIO_HAS_PTHREADS)
+typedef posix_thread thread;
+#elif defined(ASIO_HAS_STD_THREAD)
+typedef std_thread thread;
+#endif
+
+} // namespace detail
+} // namespace asio
+
+#endif // ASIO_DETAIL_THREAD_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/thread_context.hpp b/link/modules/asio-standalone/asio/include/asio/detail/thread_context.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/thread_context.hpp
@@ -0,0 +1,42 @@
+//
+// detail/thread_context.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_THREAD_CONTEXT_HPP
+#define ASIO_DETAIL_THREAD_CONTEXT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <climits>
+#include <cstddef>
+#include "asio/detail/call_stack.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class thread_info_base;
+
+// Base class for things that manage threads (scheduler, win_iocp_io_context).
+class thread_context
+{
+public:
+  // Per-thread call stack to track the state of each thread in the context.
+  typedef call_stack<thread_context, thread_info_base> thread_call_stack;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_THREAD_CONTEXT_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/thread_group.hpp b/link/modules/asio-standalone/asio/include/asio/detail/thread_group.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/thread_group.hpp
@@ -0,0 +1,95 @@
+//
+// detail/thread_group.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_THREAD_GROUP_HPP
+#define ASIO_DETAIL_THREAD_GROUP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/scoped_ptr.hpp"
+#include "asio/detail/thread.hpp"
+
+namespace asio {
+namespace detail {
+
+class thread_group
+{
+public:
+  // Constructor initialises an empty thread group.
+  thread_group()
+    : first_(0)
+  {
+  }
+
+  // Destructor joins any remaining threads in the group.
+  ~thread_group()
+  {
+    join();
+  }
+
+  // Create a new thread in the group.
+  template <typename Function>
+  void create_thread(Function f)
+  {
+    first_ = new item(f, first_);
+  }
+
+  // Create new threads in the group.
+  template <typename Function>
+  void create_threads(Function f, std::size_t num_threads)
+  {
+    for (std::size_t i = 0; i < num_threads; ++i)
+      create_thread(f);
+  }
+
+  // Wait for all threads in the group to exit.
+  void join()
+  {
+    while (first_)
+    {
+      first_->thread_.join();
+      item* tmp = first_;
+      first_ = first_->next_;
+      delete tmp;
+    }
+  }
+
+  // Test whether the group is empty.
+  bool empty() const
+  {
+    return first_ == 0;
+  }
+
+private:
+  // Structure used to track a single thread in the group.
+  struct item
+  {
+    template <typename Function>
+    explicit item(Function f, item* next)
+      : thread_(f),
+        next_(next)
+    {
+    }
+
+    asio::detail::thread thread_;
+    item* next_;
+  };
+
+  // The first thread in the group.
+  item* first_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#endif // ASIO_DETAIL_THREAD_GROUP_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/thread_info_base.hpp b/link/modules/asio-standalone/asio/include/asio/detail/thread_info_base.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/thread_info_base.hpp
@@ -0,0 +1,189 @@
+//
+// detail/thread_info_base.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_THREAD_INFO_BASE_HPP
+#define ASIO_DETAIL_THREAD_INFO_BASE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <climits>
+#include <cstddef>
+#include "asio/detail/noncopyable.hpp"
+
+#if defined(ASIO_HAS_STD_EXCEPTION_PTR) \
+  && !defined(ASIO_NO_EXCEPTIONS)
+# include <exception>
+# include "asio/multiple_exceptions.hpp"
+#endif // defined(ASIO_HAS_STD_EXCEPTION_PTR)
+       // && !defined(ASIO_NO_EXCEPTIONS)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class thread_info_base
+  : private noncopyable
+{
+public:
+  struct default_tag
+  {
+    enum { mem_index = 0 };
+  };
+
+  struct awaitable_frame_tag
+  {
+    enum { mem_index = 1 };
+  };
+
+  struct executor_function_tag
+  {
+    enum { mem_index = 2 };
+  };
+
+  thread_info_base()
+#if defined(ASIO_HAS_STD_EXCEPTION_PTR) \
+  && !defined(ASIO_NO_EXCEPTIONS)
+    : has_pending_exception_(0)
+#endif // defined(ASIO_HAS_STD_EXCEPTION_PTR)
+       // && !defined(ASIO_NO_EXCEPTIONS)
+  {
+    for (int i = 0; i < max_mem_index; ++i)
+    {
+      // The following test for non-null pointers is technically redundant, but
+      // it is significantly faster when using a tight io_context::poll() loop
+      // in latency sensitive applications.
+      if (reusable_memory_[i])
+        reusable_memory_[i] = 0;
+    }
+  }
+
+  ~thread_info_base()
+  {
+    for (int i = 0; i < max_mem_index; ++i)
+      ::operator delete(reusable_memory_[i]);
+  }
+
+  static void* allocate(thread_info_base* this_thread, std::size_t size)
+  {
+    return allocate(default_tag(), this_thread, size);
+  }
+
+  static void deallocate(thread_info_base* this_thread,
+      void* pointer, std::size_t size)
+  {
+    deallocate(default_tag(), this_thread, pointer, size);
+  }
+
+  template <typename Purpose>
+  static void* allocate(Purpose, thread_info_base* this_thread,
+      std::size_t size)
+  {
+    std::size_t chunks = (size + chunk_size - 1) / chunk_size;
+
+    if (this_thread && this_thread->reusable_memory_[Purpose::mem_index])
+    {
+      void* const pointer = this_thread->reusable_memory_[Purpose::mem_index];
+      this_thread->reusable_memory_[Purpose::mem_index] = 0;
+
+      unsigned char* const mem = static_cast<unsigned char*>(pointer);
+      if (static_cast<std::size_t>(mem[0]) >= chunks)
+      {
+        mem[size] = mem[0];
+        return pointer;
+      }
+
+      ::operator delete(pointer);
+    }
+
+    void* const pointer = ::operator new(chunks * chunk_size + 1);
+    unsigned char* const mem = static_cast<unsigned char*>(pointer);
+    mem[size] = (chunks <= UCHAR_MAX) ? static_cast<unsigned char>(chunks) : 0;
+    return pointer;
+  }
+
+  template <typename Purpose>
+  static void deallocate(Purpose, thread_info_base* this_thread,
+      void* pointer, std::size_t size)
+  {
+    if (size <= chunk_size * UCHAR_MAX)
+    {
+      if (this_thread && this_thread->reusable_memory_[Purpose::mem_index] == 0)
+      {
+        unsigned char* const mem = static_cast<unsigned char*>(pointer);
+        mem[0] = mem[size];
+        this_thread->reusable_memory_[Purpose::mem_index] = pointer;
+        return;
+      }
+    }
+
+    ::operator delete(pointer);
+  }
+
+  void capture_current_exception()
+  {
+#if defined(ASIO_HAS_STD_EXCEPTION_PTR) \
+  && !defined(ASIO_NO_EXCEPTIONS)
+    switch (has_pending_exception_)
+    {
+    case 0:
+      has_pending_exception_ = 1;
+      pending_exception_ = std::current_exception();
+      break;
+    case 1:
+      has_pending_exception_ = 2;
+      pending_exception_ =
+        std::make_exception_ptr<multiple_exceptions>(
+            multiple_exceptions(pending_exception_));
+    default:
+      break;
+    }
+#endif // defined(ASIO_HAS_STD_EXCEPTION_PTR)
+       // && !defined(ASIO_NO_EXCEPTIONS)
+  }
+
+  void rethrow_pending_exception()
+  {
+#if defined(ASIO_HAS_STD_EXCEPTION_PTR) \
+  && !defined(ASIO_NO_EXCEPTIONS)
+    if (has_pending_exception_ > 0)
+    {
+      has_pending_exception_ = 0;
+      std::exception_ptr ex(
+          ASIO_MOVE_CAST(std::exception_ptr)(
+            pending_exception_));
+      std::rethrow_exception(ex);
+    }
+#endif // defined(ASIO_HAS_STD_EXCEPTION_PTR)
+       // && !defined(ASIO_NO_EXCEPTIONS)
+  }
+
+private:
+  enum { chunk_size = 4 };
+  enum { max_mem_index = 3 };
+  void* reusable_memory_[max_mem_index];
+
+#if defined(ASIO_HAS_STD_EXCEPTION_PTR) \
+  && !defined(ASIO_NO_EXCEPTIONS)
+  int has_pending_exception_;
+  std::exception_ptr pending_exception_;
+#endif // defined(ASIO_HAS_STD_EXCEPTION_PTR)
+       // && !defined(ASIO_NO_EXCEPTIONS)
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_THREAD_INFO_BASE_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/throw_error.hpp b/link/modules/asio-standalone/asio/include/asio/detail/throw_error.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/throw_error.hpp
@@ -0,0 +1,53 @@
+//
+// detail/throw_error.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_THROW_ERROR_HPP
+#define ASIO_DETAIL_THROW_ERROR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/error_code.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+ASIO_DECL void do_throw_error(const asio::error_code& err);
+
+ASIO_DECL void do_throw_error(const asio::error_code& err,
+    const char* location);
+
+inline void throw_error(const asio::error_code& err)
+{
+  if (err)
+    do_throw_error(err);
+}
+
+inline void throw_error(const asio::error_code& err,
+    const char* location)
+{
+  if (err)
+    do_throw_error(err, location);
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/throw_error.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // ASIO_DETAIL_THROW_ERROR_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/throw_exception.hpp b/link/modules/asio-standalone/asio/include/asio/detail/throw_exception.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/throw_exception.hpp
@@ -0,0 +1,51 @@
+//
+// detail/throw_exception.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_THROW_EXCEPTION_HPP
+#define ASIO_DETAIL_THROW_EXCEPTION_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_BOOST_THROW_EXCEPTION)
+# include <boost/throw_exception.hpp>
+#endif // defined(ASIO_BOOST_THROW_EXCEPTION)
+
+namespace asio {
+namespace detail {
+
+#if defined(ASIO_HAS_BOOST_THROW_EXCEPTION)
+using boost::throw_exception;
+#else // defined(ASIO_HAS_BOOST_THROW_EXCEPTION)
+
+// Declare the throw_exception function for all targets.
+template <typename Exception>
+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(ASIO_NO_EXCEPTIONS)
+template <typename Exception>
+void throw_exception(const Exception& e)
+{
+  throw e;
+}
+# endif // !defined(ASIO_NO_EXCEPTIONS)
+
+#endif // defined(ASIO_HAS_BOOST_THROW_EXCEPTION)
+
+} // namespace detail
+} // namespace asio
+
+#endif // ASIO_DETAIL_THROW_EXCEPTION_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/timer_queue.hpp b/link/modules/asio-standalone/asio/include/asio/detail/timer_queue.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/timer_queue.hpp
@@ -0,0 +1,360 @@
+//
+// detail/timer_queue.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_TIMER_QUEUE_HPP
+#define ASIO_DETAIL_TIMER_QUEUE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <cstddef>
+#include <vector>
+#include "asio/detail/cstdint.hpp"
+#include "asio/detail/date_time_fwd.hpp"
+#include "asio/detail/limits.hpp"
+#include "asio/detail/op_queue.hpp"
+#include "asio/detail/timer_queue_base.hpp"
+#include "asio/detail/wait_op.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Time_Traits>
+class timer_queue
+  : public timer_queue_base
+{
+public:
+  // The time type.
+  typedef typename Time_Traits::time_type time_type;
+
+  // The duration type.
+  typedef typename Time_Traits::duration_type duration_type;
+
+  // Per-timer data.
+  class per_timer_data
+  {
+  public:
+    per_timer_data() :
+      heap_index_((std::numeric_limits<std::size_t>::max)()),
+      next_(0), prev_(0)
+    {
+    }
+
+  private:
+    friend class timer_queue;
+
+    // The operations waiting on the timer.
+    op_queue<wait_op> op_queue_;
+
+    // The index of the timer in the heap.
+    std::size_t heap_index_;
+
+    // Pointers to adjacent timers in a linked list.
+    per_timer_data* next_;
+    per_timer_data* prev_;
+  };
+
+  // Constructor.
+  timer_queue()
+    : timers_(),
+      heap_()
+  {
+  }
+
+  // Add a new timer to the queue. Returns true if this is the timer that is
+  // earliest in the queue, in which case the reactor's event demultiplexing
+  // function call may need to be interrupted and restarted.
+  bool enqueue_timer(const time_type& time, per_timer_data& timer, wait_op* op)
+  {
+    // Enqueue the timer object.
+    if (timer.prev_ == 0 && &timer != timers_)
+    {
+      if (this->is_positive_infinity(time))
+      {
+        // No heap entry is required for timers that never expire.
+        timer.heap_index_ = (std::numeric_limits<std::size_t>::max)();
+      }
+      else
+      {
+        // Put the new timer at the correct position in the heap. This is done
+        // first since push_back() can throw due to allocation failure.
+        timer.heap_index_ = heap_.size();
+        heap_entry entry = { time, &timer };
+        heap_.push_back(entry);
+        up_heap(heap_.size() - 1);
+      }
+
+      // Insert the new timer into the linked list of active timers.
+      timer.next_ = timers_;
+      timer.prev_ = 0;
+      if (timers_)
+        timers_->prev_ = &timer;
+      timers_ = &timer;
+    }
+
+    // Enqueue the individual timer operation.
+    timer.op_queue_.push(op);
+
+    // Interrupt reactor only if newly added timer is first to expire.
+    return timer.heap_index_ == 0 && timer.op_queue_.front() == op;
+  }
+
+  // Whether there are no timers in the queue.
+  virtual bool empty() const
+  {
+    return timers_ == 0;
+  }
+
+  // Get the time for the timer that is earliest in the queue.
+  virtual long wait_duration_msec(long max_duration) const
+  {
+    if (heap_.empty())
+      return max_duration;
+
+    return this->to_msec(
+        Time_Traits::to_posix_duration(
+          Time_Traits::subtract(heap_[0].time_, Time_Traits::now())),
+        max_duration);
+  }
+
+  // Get the time for the timer that is earliest in the queue.
+  virtual long wait_duration_usec(long max_duration) const
+  {
+    if (heap_.empty())
+      return max_duration;
+
+    return this->to_usec(
+        Time_Traits::to_posix_duration(
+          Time_Traits::subtract(heap_[0].time_, Time_Traits::now())),
+        max_duration);
+  }
+
+  // Dequeue all timers not later than the current time.
+  virtual void get_ready_timers(op_queue<operation>& ops)
+  {
+    if (!heap_.empty())
+    {
+      const time_type now = Time_Traits::now();
+      while (!heap_.empty() && !Time_Traits::less_than(now, heap_[0].time_))
+      {
+        per_timer_data* timer = heap_[0].timer_;
+        ops.push(timer->op_queue_);
+        remove_timer(*timer);
+      }
+    }
+  }
+
+  // Dequeue all timers.
+  virtual void get_all_timers(op_queue<operation>& ops)
+  {
+    while (timers_)
+    {
+      per_timer_data* timer = timers_;
+      timers_ = timers_->next_;
+      ops.push(timer->op_queue_);
+      timer->next_ = 0;
+      timer->prev_ = 0;
+    }
+
+    heap_.clear();
+  }
+
+  // Cancel and dequeue operations for the given timer.
+  std::size_t cancel_timer(per_timer_data& timer, op_queue<operation>& ops,
+      std::size_t max_cancelled = (std::numeric_limits<std::size_t>::max)())
+  {
+    std::size_t num_cancelled = 0;
+    if (timer.prev_ != 0 || &timer == timers_)
+    {
+      while (wait_op* op = (num_cancelled != max_cancelled)
+          ? timer.op_queue_.front() : 0)
+      {
+        op->ec_ = asio::error::operation_aborted;
+        timer.op_queue_.pop();
+        ops.push(op);
+        ++num_cancelled;
+      }
+      if (timer.op_queue_.empty())
+        remove_timer(timer);
+    }
+    return num_cancelled;
+  }
+
+  // Move operations from one timer to another, empty timer.
+  void move_timer(per_timer_data& target, per_timer_data& source)
+  {
+    target.op_queue_.push(source.op_queue_);
+
+    target.heap_index_ = source.heap_index_;
+    source.heap_index_ = (std::numeric_limits<std::size_t>::max)();
+
+    if (target.heap_index_ < heap_.size())
+      heap_[target.heap_index_].timer_ = &target;
+
+    if (timers_ == &source)
+      timers_ = &target;
+    if (source.prev_)
+      source.prev_->next_ = &target;
+    if (source.next_)
+      source.next_->prev_= &target;
+    target.next_ = source.next_;
+    target.prev_ = source.prev_;
+    source.next_ = 0;
+    source.prev_ = 0;
+  }
+
+private:
+  // Move the item at the given index up the heap to its correct position.
+  void up_heap(std::size_t index)
+  {
+    while (index > 0)
+    {
+      std::size_t parent = (index - 1) / 2;
+      if (!Time_Traits::less_than(heap_[index].time_, heap_[parent].time_))
+        break;
+      swap_heap(index, parent);
+      index = parent;
+    }
+  }
+
+  // Move the item at the given index down the heap to its correct position.
+  void down_heap(std::size_t index)
+  {
+    std::size_t child = index * 2 + 1;
+    while (child < heap_.size())
+    {
+      std::size_t min_child = (child + 1 == heap_.size()
+          || Time_Traits::less_than(
+            heap_[child].time_, heap_[child + 1].time_))
+        ? child : child + 1;
+      if (Time_Traits::less_than(heap_[index].time_, heap_[min_child].time_))
+        break;
+      swap_heap(index, min_child);
+      index = min_child;
+      child = index * 2 + 1;
+    }
+  }
+
+  // Swap two entries in the heap.
+  void swap_heap(std::size_t index1, std::size_t index2)
+  {
+    heap_entry tmp = heap_[index1];
+    heap_[index1] = heap_[index2];
+    heap_[index2] = tmp;
+    heap_[index1].timer_->heap_index_ = index1;
+    heap_[index2].timer_->heap_index_ = index2;
+  }
+
+  // Remove a timer from the heap and list of timers.
+  void remove_timer(per_timer_data& timer)
+  {
+    // Remove the timer from the heap.
+    std::size_t index = timer.heap_index_;
+    if (!heap_.empty() && index < heap_.size())
+    {
+      if (index == heap_.size() - 1)
+      {
+        timer.heap_index_ = (std::numeric_limits<std::size_t>::max)();
+        heap_.pop_back();
+      }
+      else
+      {
+        swap_heap(index, heap_.size() - 1);
+        timer.heap_index_ = (std::numeric_limits<std::size_t>::max)();
+        heap_.pop_back();
+        if (index > 0 && Time_Traits::less_than(
+              heap_[index].time_, heap_[(index - 1) / 2].time_))
+          up_heap(index);
+        else
+          down_heap(index);
+      }
+    }
+
+    // Remove the timer from the linked list of active timers.
+    if (timers_ == &timer)
+      timers_ = timer.next_;
+    if (timer.prev_)
+      timer.prev_->next_ = timer.next_;
+    if (timer.next_)
+      timer.next_->prev_= timer.prev_;
+    timer.next_ = 0;
+    timer.prev_ = 0;
+  }
+
+  // Determine if the specified absolute time is positive infinity.
+  template <typename Time_Type>
+  static bool is_positive_infinity(const Time_Type&)
+  {
+    return false;
+  }
+
+  // Determine if the specified absolute time is positive infinity.
+  template <typename T, typename TimeSystem>
+  static bool is_positive_infinity(
+      const boost::date_time::base_time<T, TimeSystem>& time)
+  {
+    return time.is_pos_infinity();
+  }
+
+  // Helper function to convert a duration into milliseconds.
+  template <typename Duration>
+  long to_msec(const Duration& d, long max_duration) const
+  {
+    if (d.ticks() <= 0)
+      return 0;
+    int64_t msec = d.total_milliseconds();
+    if (msec == 0)
+      return 1;
+    if (msec > max_duration)
+      return max_duration;
+    return static_cast<long>(msec);
+  }
+
+  // Helper function to convert a duration into microseconds.
+  template <typename Duration>
+  long to_usec(const Duration& d, long max_duration) const
+  {
+    if (d.ticks() <= 0)
+      return 0;
+    int64_t usec = d.total_microseconds();
+    if (usec == 0)
+      return 1;
+    if (usec > max_duration)
+      return max_duration;
+    return static_cast<long>(usec);
+  }
+
+  // The head of a linked list of all active timers.
+  per_timer_data* timers_;
+
+  struct heap_entry
+  {
+    // The time when the timer should fire.
+    time_type time_;
+
+    // The associated timer with enqueued operations.
+    per_timer_data* timer_;
+  };
+
+  // The heap of timers, with the earliest timer at the front.
+  std::vector<heap_entry> heap_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_TIMER_QUEUE_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/timer_queue_base.hpp b/link/modules/asio-standalone/asio/include/asio/detail/timer_queue_base.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/timer_queue_base.hpp
@@ -0,0 +1,68 @@
+//
+// detail/timer_queue_base.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_TIMER_QUEUE_BASE_HPP
+#define ASIO_DETAIL_TIMER_QUEUE_BASE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/noncopyable.hpp"
+#include "asio/detail/op_queue.hpp"
+#include "asio/detail/operation.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class timer_queue_base
+  : private noncopyable
+{
+public:
+  // Constructor.
+  timer_queue_base() : next_(0) {}
+
+  // Destructor.
+  virtual ~timer_queue_base() {}
+
+  // Whether there are no timers in the queue.
+  virtual bool empty() const = 0;
+
+  // Get the time to wait until the next timer.
+  virtual long wait_duration_msec(long max_duration) const = 0;
+
+  // Get the time to wait until the next timer.
+  virtual long wait_duration_usec(long max_duration) const = 0;
+
+  // Dequeue all ready timers.
+  virtual void get_ready_timers(op_queue<operation>& ops) = 0;
+
+  // Dequeue all timers.
+  virtual void get_all_timers(op_queue<operation>& ops) = 0;
+
+private:
+  friend class timer_queue_set;
+
+  // Next timer queue in the set.
+  timer_queue_base* next_;
+};
+
+template <typename Time_Traits>
+class timer_queue;
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_TIMER_QUEUE_BASE_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/timer_queue_ptime.hpp b/link/modules/asio-standalone/asio/include/asio/detail/timer_queue_ptime.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/timer_queue_ptime.hpp
@@ -0,0 +1,99 @@
+//
+// detail/timer_queue_ptime.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_TIMER_QUEUE_PTIME_HPP
+#define ASIO_DETAIL_TIMER_QUEUE_PTIME_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_BOOST_DATE_TIME)
+
+#include "asio/time_traits.hpp"
+#include "asio/detail/timer_queue.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+struct forwarding_posix_time_traits : time_traits<boost::posix_time::ptime> {};
+
+// Template specialisation for the commonly used instantation.
+template <>
+class timer_queue<time_traits<boost::posix_time::ptime> >
+  : public timer_queue_base
+{
+public:
+  // The time type.
+  typedef boost::posix_time::ptime time_type;
+
+  // The duration type.
+  typedef boost::posix_time::time_duration duration_type;
+
+  // Per-timer data.
+  typedef timer_queue<forwarding_posix_time_traits>::per_timer_data
+    per_timer_data;
+
+  // Constructor.
+  ASIO_DECL timer_queue();
+
+  // Destructor.
+  ASIO_DECL virtual ~timer_queue();
+
+  // Add a new timer to the queue. Returns true if this is the timer that is
+  // earliest in the queue, in which case the reactor's event demultiplexing
+  // function call may need to be interrupted and restarted.
+  ASIO_DECL bool enqueue_timer(const time_type& time,
+      per_timer_data& timer, wait_op* op);
+
+  // Whether there are no timers in the queue.
+  ASIO_DECL virtual bool empty() const;
+
+  // Get the time for the timer that is earliest in the queue.
+  ASIO_DECL virtual long wait_duration_msec(long max_duration) const;
+
+  // Get the time for the timer that is earliest in the queue.
+  ASIO_DECL virtual long wait_duration_usec(long max_duration) const;
+
+  // Dequeue all timers not later than the current time.
+  ASIO_DECL virtual void get_ready_timers(op_queue<operation>& ops);
+
+  // Dequeue all timers.
+  ASIO_DECL virtual void get_all_timers(op_queue<operation>& ops);
+
+  // Cancel and dequeue operations for the given timer.
+  ASIO_DECL std::size_t cancel_timer(
+      per_timer_data& timer, op_queue<operation>& ops,
+      std::size_t max_cancelled = (std::numeric_limits<std::size_t>::max)());
+
+  // Move operations from one timer to another, empty timer.
+  ASIO_DECL void move_timer(per_timer_data& target,
+      per_timer_data& source);
+
+private:
+  timer_queue<forwarding_posix_time_traits> impl_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/timer_queue_ptime.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // defined(ASIO_HAS_BOOST_DATE_TIME)
+
+#endif // ASIO_DETAIL_TIMER_QUEUE_PTIME_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/timer_queue_set.hpp b/link/modules/asio-standalone/asio/include/asio/detail/timer_queue_set.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/timer_queue_set.hpp
@@ -0,0 +1,66 @@
+//
+// detail/timer_queue_set.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_TIMER_QUEUE_SET_HPP
+#define ASIO_DETAIL_TIMER_QUEUE_SET_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/timer_queue_base.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class timer_queue_set
+{
+public:
+  // Constructor.
+  ASIO_DECL timer_queue_set();
+
+  // Add a timer queue to the set.
+  ASIO_DECL void insert(timer_queue_base* q);
+
+  // Remove a timer queue from the set.
+  ASIO_DECL void erase(timer_queue_base* q);
+
+  // Determine whether all queues are empty.
+  ASIO_DECL bool all_empty() const;
+
+  // Get the wait duration in milliseconds.
+  ASIO_DECL long wait_duration_msec(long max_duration) const;
+
+  // Get the wait duration in microseconds.
+  ASIO_DECL long wait_duration_usec(long max_duration) const;
+
+  // Dequeue all ready timers.
+  ASIO_DECL void get_ready_timers(op_queue<operation>& ops);
+
+  // Dequeue all timers.
+  ASIO_DECL void get_all_timers(op_queue<operation>& ops);
+
+private:
+  timer_queue_base* first_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/timer_queue_set.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // ASIO_DETAIL_TIMER_QUEUE_SET_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/timer_scheduler.hpp b/link/modules/asio-standalone/asio/include/asio/detail/timer_scheduler.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/timer_scheduler.hpp
@@ -0,0 +1,35 @@
+//
+// detail/timer_scheduler.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_TIMER_SCHEDULER_HPP
+#define ASIO_DETAIL_TIMER_SCHEDULER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/timer_scheduler_fwd.hpp"
+
+#if defined(ASIO_WINDOWS_RUNTIME)
+# include "asio/detail/winrt_timer_scheduler.hpp"
+#elif defined(ASIO_HAS_IOCP)
+# include "asio/detail/win_iocp_io_context.hpp"
+#elif defined(ASIO_HAS_EPOLL)
+# include "asio/detail/epoll_reactor.hpp"
+#elif defined(ASIO_HAS_KQUEUE)
+# include "asio/detail/kqueue_reactor.hpp"
+#elif defined(ASIO_HAS_DEV_POLL)
+# include "asio/detail/dev_poll_reactor.hpp"
+#else
+# include "asio/detail/select_reactor.hpp"
+#endif
+
+#endif // ASIO_DETAIL_TIMER_SCHEDULER_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/timer_scheduler_fwd.hpp b/link/modules/asio-standalone/asio/include/asio/detail/timer_scheduler_fwd.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/timer_scheduler_fwd.hpp
@@ -0,0 +1,40 @@
+//
+// detail/timer_scheduler_fwd.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_TIMER_SCHEDULER_FWD_HPP
+#define ASIO_DETAIL_TIMER_SCHEDULER_FWD_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+namespace asio {
+namespace detail {
+
+#if defined(ASIO_WINDOWS_RUNTIME)
+typedef class winrt_timer_scheduler timer_scheduler;
+#elif defined(ASIO_HAS_IOCP)
+typedef class win_iocp_io_context timer_scheduler;
+#elif defined(ASIO_HAS_EPOLL)
+typedef class epoll_reactor timer_scheduler;
+#elif defined(ASIO_HAS_KQUEUE)
+typedef class kqueue_reactor timer_scheduler;
+#elif defined(ASIO_HAS_DEV_POLL)
+typedef class dev_poll_reactor timer_scheduler;
+#else
+typedef class select_reactor timer_scheduler;
+#endif
+
+} // namespace detail
+} // namespace asio
+
+#endif // ASIO_DETAIL_TIMER_SCHEDULER_FWD_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/tss_ptr.hpp b/link/modules/asio-standalone/asio/include/asio/detail/tss_ptr.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/tss_ptr.hpp
@@ -0,0 +1,69 @@
+//
+// detail/tss_ptr.hpp
+// ~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_TSS_PTR_HPP
+#define ASIO_DETAIL_TSS_PTR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if !defined(ASIO_HAS_THREADS)
+# include "asio/detail/null_tss_ptr.hpp"
+#elif defined(ASIO_HAS_THREAD_KEYWORD_EXTENSION)
+# include "asio/detail/keyword_tss_ptr.hpp"
+#elif defined(ASIO_WINDOWS)
+# include "asio/detail/win_tss_ptr.hpp"
+#elif defined(ASIO_HAS_PTHREADS)
+# include "asio/detail/posix_tss_ptr.hpp"
+#else
+# error Only Windows and POSIX are supported!
+#endif
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename T>
+class tss_ptr
+#if !defined(ASIO_HAS_THREADS)
+  : public null_tss_ptr<T>
+#elif defined(ASIO_HAS_THREAD_KEYWORD_EXTENSION)
+  : public keyword_tss_ptr<T>
+#elif defined(ASIO_WINDOWS)
+  : public win_tss_ptr<T>
+#elif defined(ASIO_HAS_PTHREADS)
+  : public posix_tss_ptr<T>
+#endif
+{
+public:
+  void operator=(T* value)
+  {
+#if !defined(ASIO_HAS_THREADS)
+    null_tss_ptr<T>::operator=(value);
+#elif defined(ASIO_HAS_THREAD_KEYWORD_EXTENSION)
+    keyword_tss_ptr<T>::operator=(value);
+#elif defined(ASIO_WINDOWS)
+    win_tss_ptr<T>::operator=(value);
+#elif defined(ASIO_HAS_PTHREADS)
+    posix_tss_ptr<T>::operator=(value);
+#endif
+  }
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_TSS_PTR_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/type_traits.hpp b/link/modules/asio-standalone/asio/include/asio/detail/type_traits.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/type_traits.hpp
@@ -0,0 +1,148 @@
+//
+// detail/type_traits.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_TYPE_TRAITS_HPP
+#define ASIO_DETAIL_TYPE_TRAITS_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_STD_TYPE_TRAITS)
+# include <type_traits>
+#else // defined(ASIO_HAS_STD_TYPE_TRAITS)
+# include <boost/type_traits/add_const.hpp>
+# include <boost/type_traits/add_lvalue_reference.hpp>
+# include <boost/type_traits/aligned_storage.hpp>
+# include <boost/type_traits/alignment_of.hpp>
+# include <boost/type_traits/conditional.hpp>
+# include <boost/type_traits/decay.hpp>
+# include <boost/type_traits/has_nothrow_copy.hpp>
+# include <boost/type_traits/has_nothrow_destructor.hpp>
+# include <boost/type_traits/integral_constant.hpp>
+# include <boost/type_traits/is_base_of.hpp>
+# include <boost/type_traits/is_class.hpp>
+# include <boost/type_traits/is_const.hpp>
+# include <boost/type_traits/is_convertible.hpp>
+# include <boost/type_traits/is_constructible.hpp>
+# include <boost/type_traits/is_copy_constructible.hpp>
+# include <boost/type_traits/is_destructible.hpp>
+# include <boost/type_traits/is_function.hpp>
+# include <boost/type_traits/is_object.hpp>
+# include <boost/type_traits/is_same.hpp>
+# include <boost/type_traits/remove_cv.hpp>
+# include <boost/type_traits/remove_pointer.hpp>
+# include <boost/type_traits/remove_reference.hpp>
+# include <boost/utility/declval.hpp>
+# include <boost/utility/enable_if.hpp>
+# include <boost/utility/result_of.hpp>
+#endif // defined(ASIO_HAS_STD_TYPE_TRAITS)
+
+namespace asio {
+
+#if defined(ASIO_HAS_STD_TYPE_TRAITS)
+using std::add_const;
+using std::add_lvalue_reference;
+using std::aligned_storage;
+using std::alignment_of;
+using std::conditional;
+using std::decay;
+using std::declval;
+using std::enable_if;
+using std::false_type;
+using std::integral_constant;
+using std::is_base_of;
+using std::is_class;
+using std::is_const;
+using std::is_constructible;
+using std::is_convertible;
+using std::is_copy_constructible;
+using std::is_destructible;
+using std::is_function;
+using std::is_move_constructible;
+using std::is_nothrow_copy_constructible;
+using std::is_nothrow_destructible;
+using std::is_object;
+using std::is_reference;
+using std::is_same;
+using std::is_scalar;
+using std::remove_cv;
+template <typename T>
+struct remove_cvref : remove_cv<typename std::remove_reference<T>::type> {};
+using std::remove_pointer;
+using std::remove_reference;
+#if defined(ASIO_HAS_STD_INVOKE_RESULT)
+template <typename> struct result_of;
+template <typename F, typename... Args>
+struct result_of<F(Args...)> : std::invoke_result<F, Args...> {};
+#else // defined(ASIO_HAS_STD_INVOKE_RESULT)
+using std::result_of;
+#endif // defined(ASIO_HAS_STD_INVOKE_RESULT)
+using std::true_type;
+#else // defined(ASIO_HAS_STD_TYPE_TRAITS)
+using boost::add_const;
+using boost::add_lvalue_reference;
+using boost::aligned_storage;
+using boost::alignment_of;
+template <bool Condition, typename Type = void>
+struct enable_if : boost::enable_if_c<Condition, Type> {};
+using boost::conditional;
+using boost::decay;
+using boost::declval;
+using boost::false_type;
+using boost::integral_constant;
+using boost::is_base_of;
+using boost::is_class;
+using boost::is_const;
+using boost::is_constructible;
+using boost::is_convertible;
+using boost::is_copy_constructible;
+using boost::is_destructible;
+using boost::is_function;
+#if defined(ASIO_HAS_MOVE)
+template <typename T>
+struct is_move_constructible : false_type {};
+#else // defined(ASIO_HAS_MOVE)
+template <typename T>
+struct is_move_constructible : is_copy_constructible<T> {};
+#endif // defined(ASIO_HAS_MOVE)
+template <typename T>
+struct is_nothrow_copy_constructible : boost::has_nothrow_copy<T> {};
+template <typename T>
+struct is_nothrow_destructible : boost::has_nothrow_destructor<T> {};
+using boost::is_object;
+using boost::is_reference;
+using boost::is_same;
+using boost::is_scalar;
+using boost::remove_cv;
+template <typename T>
+struct remove_cvref : remove_cv<typename boost::remove_reference<T>::type> {};
+using boost::remove_pointer;
+using boost::remove_reference;
+using boost::result_of;
+using boost::true_type;
+#endif // defined(ASIO_HAS_STD_TYPE_TRAITS)
+
+template <typename> struct void_type { typedef void type; };
+
+#if defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+template <typename...> struct conjunction : true_type {};
+template <typename T> struct conjunction<T> : T {};
+template <typename Head, typename... Tail> struct conjunction<Head, Tail...> :
+  conditional<Head::value, conjunction<Tail...>, Head>::type {};
+
+#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+} // namespace asio
+
+#endif // ASIO_DETAIL_TYPE_TRAITS_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/variadic_templates.hpp b/link/modules/asio-standalone/asio/include/asio/detail/variadic_templates.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/variadic_templates.hpp
@@ -0,0 +1,294 @@
+//
+// detail/variadic_templates.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_VARIADIC_TEMPLATES_HPP
+#define ASIO_DETAIL_VARIADIC_TEMPLATES_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if !defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+# define ASIO_VARIADIC_TPARAMS(n) ASIO_VARIADIC_TPARAMS_##n
+
+# define ASIO_VARIADIC_TPARAMS_1 \
+  typename T1
+# define ASIO_VARIADIC_TPARAMS_2 \
+  typename T1, typename T2
+# define ASIO_VARIADIC_TPARAMS_3 \
+  typename T1, typename T2, typename T3
+# define ASIO_VARIADIC_TPARAMS_4 \
+  typename T1, typename T2, typename T3, typename T4
+# define ASIO_VARIADIC_TPARAMS_5 \
+  typename T1, typename T2, typename T3, typename T4, typename T5
+# define ASIO_VARIADIC_TPARAMS_6 \
+  typename T1, typename T2, typename T3, typename T4, typename T5, \
+  typename T6
+# define ASIO_VARIADIC_TPARAMS_7 \
+  typename T1, typename T2, typename T3, typename T4, typename T5, \
+  typename T6, typename T7
+# define ASIO_VARIADIC_TPARAMS_8 \
+  typename T1, typename T2, typename T3, typename T4, typename T5, \
+  typename T6, typename T7, typename T8
+
+# define ASIO_VARIADIC_TARGS(n) ASIO_VARIADIC_TARGS_##n
+
+# define ASIO_VARIADIC_TARGS_1 T1
+# define ASIO_VARIADIC_TARGS_2 T1, T2
+# define ASIO_VARIADIC_TARGS_3 T1, T2, T3
+# define ASIO_VARIADIC_TARGS_4 T1, T2, T3, T4
+# define ASIO_VARIADIC_TARGS_5 T1, T2, T3, T4, T5
+# define ASIO_VARIADIC_TARGS_6 T1, T2, T3, T4, T5, T6
+# define ASIO_VARIADIC_TARGS_7 T1, T2, T3, T4, T5, T6, T7
+# define ASIO_VARIADIC_TARGS_8 T1, T2, T3, T4, T5, T6, T7, T8
+
+# define ASIO_VARIADIC_BYVAL_PARAMS(n) \
+  ASIO_VARIADIC_BYVAL_PARAMS_##n
+
+# define ASIO_VARIADIC_BYVAL_PARAMS_1 T1 x1
+# define ASIO_VARIADIC_BYVAL_PARAMS_2 T1 x1, T2 x2
+# define ASIO_VARIADIC_BYVAL_PARAMS_3 T1 x1, T2 x2, T3 x3
+# define ASIO_VARIADIC_BYVAL_PARAMS_4 T1 x1, T2 x2, T3 x3, T4 x4
+# define ASIO_VARIADIC_BYVAL_PARAMS_5 T1 x1, T2 x2, T3 x3, T4 x4, T5 x5
+# define ASIO_VARIADIC_BYVAL_PARAMS_6 T1 x1, T2 x2, T3 x3, T4 x4, T5 x5, \
+  T6 x6
+# define ASIO_VARIADIC_BYVAL_PARAMS_7 T1 x1, T2 x2, T3 x3, T4 x4, T5 x5, \
+  T6 x6, T7 x7
+# define ASIO_VARIADIC_BYVAL_PARAMS_8 T1 x1, T2 x2, T3 x3, T4 x4, T5 x5, \
+  T6 x6, T7 x7, T8 x8
+
+# define ASIO_VARIADIC_BYVAL_ARGS(n) \
+  ASIO_VARIADIC_BYVAL_ARGS_##n
+
+# define ASIO_VARIADIC_BYVAL_ARGS_1 x1
+# define ASIO_VARIADIC_BYVAL_ARGS_2 x1, x2
+# define ASIO_VARIADIC_BYVAL_ARGS_3 x1, x2, x3
+# define ASIO_VARIADIC_BYVAL_ARGS_4 x1, x2, x3, x4
+# define ASIO_VARIADIC_BYVAL_ARGS_5 x1, x2, x3, x4, x5
+# define ASIO_VARIADIC_BYVAL_ARGS_6 x1, x2, x3, x4, x5, x6
+# define ASIO_VARIADIC_BYVAL_ARGS_7 x1, x2, x3, x4, x5, x6, x7
+# define ASIO_VARIADIC_BYVAL_ARGS_8 x1, x2, x3, x4, x5, x6, x7, x8
+
+# define ASIO_VARIADIC_CONSTREF_PARAMS(n) \
+  ASIO_VARIADIC_CONSTREF_PARAMS_##n
+
+# define ASIO_VARIADIC_CONSTREF_PARAMS_1 \
+  const T1& x1
+# define ASIO_VARIADIC_CONSTREF_PARAMS_2 \
+  const T1& x1, const T2& x2
+# define ASIO_VARIADIC_CONSTREF_PARAMS_3 \
+  const T1& x1, const T2& x2, const T3& x3
+# define ASIO_VARIADIC_CONSTREF_PARAMS_4 \
+  const T1& x1, const T2& x2, const T3& x3, const T4& x4
+# define ASIO_VARIADIC_CONSTREF_PARAMS_5 \
+  const T1& x1, const T2& x2, const T3& x3, const T4& x4, const T5& x5
+# define ASIO_VARIADIC_CONSTREF_PARAMS_6 \
+  const T1& x1, const T2& x2, const T3& x3, const T4& x4, const T5& x5, \
+  const T6& x6
+# define ASIO_VARIADIC_CONSTREF_PARAMS_7 \
+  const T1& x1, const T2& x2, const T3& x3, const T4& x4, const T5& x5, \
+  const T6& x6, const T7& x7
+# define ASIO_VARIADIC_CONSTREF_PARAMS_8 \
+  const T1& x1, const T2& x2, const T3& x3, const T4& x4, const T5& x5, \
+  const T6& x6, const T7& x7, const T8& x8
+
+# define ASIO_VARIADIC_MOVE_PARAMS(n) \
+  ASIO_VARIADIC_MOVE_PARAMS_##n
+
+# define ASIO_VARIADIC_MOVE_PARAMS_1 \
+  ASIO_MOVE_ARG(T1) x1
+# define ASIO_VARIADIC_MOVE_PARAMS_2 \
+  ASIO_MOVE_ARG(T1) x1, ASIO_MOVE_ARG(T2) x2
+# define ASIO_VARIADIC_MOVE_PARAMS_3 \
+  ASIO_MOVE_ARG(T1) x1, ASIO_MOVE_ARG(T2) x2, \
+  ASIO_MOVE_ARG(T3) x3
+# define ASIO_VARIADIC_MOVE_PARAMS_4 \
+  ASIO_MOVE_ARG(T1) x1, ASIO_MOVE_ARG(T2) x2, \
+  ASIO_MOVE_ARG(T3) x3, ASIO_MOVE_ARG(T4) x4
+# define ASIO_VARIADIC_MOVE_PARAMS_5 \
+  ASIO_MOVE_ARG(T1) x1, ASIO_MOVE_ARG(T2) x2, \
+  ASIO_MOVE_ARG(T3) x3, ASIO_MOVE_ARG(T4) x4, \
+  ASIO_MOVE_ARG(T5) x5
+# define ASIO_VARIADIC_MOVE_PARAMS_6 \
+  ASIO_MOVE_ARG(T1) x1, ASIO_MOVE_ARG(T2) x2, \
+  ASIO_MOVE_ARG(T3) x3, ASIO_MOVE_ARG(T4) x4, \
+  ASIO_MOVE_ARG(T5) x5, ASIO_MOVE_ARG(T6) x6
+# define ASIO_VARIADIC_MOVE_PARAMS_7 \
+  ASIO_MOVE_ARG(T1) x1, ASIO_MOVE_ARG(T2) x2, \
+  ASIO_MOVE_ARG(T3) x3, ASIO_MOVE_ARG(T4) x4, \
+  ASIO_MOVE_ARG(T5) x5, ASIO_MOVE_ARG(T6) x6, \
+  ASIO_MOVE_ARG(T7) x7
+# define ASIO_VARIADIC_MOVE_PARAMS_8 \
+  ASIO_MOVE_ARG(T1) x1, ASIO_MOVE_ARG(T2) x2, \
+  ASIO_MOVE_ARG(T3) x3, ASIO_MOVE_ARG(T4) x4, \
+  ASIO_MOVE_ARG(T5) x5, ASIO_MOVE_ARG(T6) x6, \
+  ASIO_MOVE_ARG(T7) x7, ASIO_MOVE_ARG(T8) x8
+
+# define ASIO_VARIADIC_UNNAMED_MOVE_PARAMS(n) \
+  ASIO_VARIADIC_UNNAMED_MOVE_PARAMS_##n
+
+# define ASIO_VARIADIC_UNNAMED_MOVE_PARAMS_1 \
+  ASIO_MOVE_ARG(T1)
+# define ASIO_VARIADIC_UNNAMED_MOVE_PARAMS_2 \
+  ASIO_MOVE_ARG(T1), ASIO_MOVE_ARG(T2)
+# define ASIO_VARIADIC_UNNAMED_MOVE_PARAMS_3 \
+  ASIO_MOVE_ARG(T1), ASIO_MOVE_ARG(T2), \
+  ASIO_MOVE_ARG(T3)
+# define ASIO_VARIADIC_UNNAMED_MOVE_PARAMS_4 \
+  ASIO_MOVE_ARG(T1), ASIO_MOVE_ARG(T2), \
+  ASIO_MOVE_ARG(T3), ASIO_MOVE_ARG(T4)
+# define ASIO_VARIADIC_UNNAMED_MOVE_PARAMS_5 \
+  ASIO_MOVE_ARG(T1), ASIO_MOVE_ARG(T2), \
+  ASIO_MOVE_ARG(T3), ASIO_MOVE_ARG(T4), \
+  ASIO_MOVE_ARG(T5)
+# define ASIO_VARIADIC_UNNAMED_MOVE_PARAMS_6 \
+  ASIO_MOVE_ARG(T1), ASIO_MOVE_ARG(T2), \
+  ASIO_MOVE_ARG(T3), ASIO_MOVE_ARG(T4), \
+  ASIO_MOVE_ARG(T5), ASIO_MOVE_ARG(T6)
+# define ASIO_VARIADIC_UNNAMED_MOVE_PARAMS_7 \
+  ASIO_MOVE_ARG(T1), ASIO_MOVE_ARG(T2), \
+  ASIO_MOVE_ARG(T3), ASIO_MOVE_ARG(T4), \
+  ASIO_MOVE_ARG(T5), ASIO_MOVE_ARG(T6), \
+  ASIO_MOVE_ARG(T7)
+# define ASIO_VARIADIC_UNNAMED_MOVE_PARAMS_8 \
+  ASIO_MOVE_ARG(T1), ASIO_MOVE_ARG(T2), \
+  ASIO_MOVE_ARG(T3), ASIO_MOVE_ARG(T4), \
+  ASIO_MOVE_ARG(T5), ASIO_MOVE_ARG(T6), \
+  ASIO_MOVE_ARG(T7), ASIO_MOVE_ARG(T8)
+
+# define ASIO_VARIADIC_MOVE_ARGS(n) \
+  ASIO_VARIADIC_MOVE_ARGS_##n
+
+# define ASIO_VARIADIC_MOVE_ARGS_1 \
+  ASIO_MOVE_CAST(T1)(x1)
+# define ASIO_VARIADIC_MOVE_ARGS_2 \
+  ASIO_MOVE_CAST(T1)(x1), ASIO_MOVE_CAST(T2)(x2)
+# define ASIO_VARIADIC_MOVE_ARGS_3 \
+  ASIO_MOVE_CAST(T1)(x1), ASIO_MOVE_CAST(T2)(x2), \
+  ASIO_MOVE_CAST(T3)(x3)
+# define ASIO_VARIADIC_MOVE_ARGS_4 \
+  ASIO_MOVE_CAST(T1)(x1), ASIO_MOVE_CAST(T2)(x2), \
+  ASIO_MOVE_CAST(T3)(x3), ASIO_MOVE_CAST(T4)(x4)
+# define ASIO_VARIADIC_MOVE_ARGS_5 \
+  ASIO_MOVE_CAST(T1)(x1), ASIO_MOVE_CAST(T2)(x2), \
+  ASIO_MOVE_CAST(T3)(x3), ASIO_MOVE_CAST(T4)(x4), \
+  ASIO_MOVE_CAST(T5)(x5)
+# define ASIO_VARIADIC_MOVE_ARGS_6 \
+  ASIO_MOVE_CAST(T1)(x1), ASIO_MOVE_CAST(T2)(x2), \
+  ASIO_MOVE_CAST(T3)(x3), ASIO_MOVE_CAST(T4)(x4), \
+  ASIO_MOVE_CAST(T5)(x5), ASIO_MOVE_CAST(T6)(x6)
+# define ASIO_VARIADIC_MOVE_ARGS_7 \
+  ASIO_MOVE_CAST(T1)(x1), ASIO_MOVE_CAST(T2)(x2), \
+  ASIO_MOVE_CAST(T3)(x3), ASIO_MOVE_CAST(T4)(x4), \
+  ASIO_MOVE_CAST(T5)(x5), ASIO_MOVE_CAST(T6)(x6), \
+  ASIO_MOVE_CAST(T7)(x7)
+# define ASIO_VARIADIC_MOVE_ARGS_8 \
+  ASIO_MOVE_CAST(T1)(x1), ASIO_MOVE_CAST(T2)(x2), \
+  ASIO_MOVE_CAST(T3)(x3), ASIO_MOVE_CAST(T4)(x4), \
+  ASIO_MOVE_CAST(T5)(x5), ASIO_MOVE_CAST(T6)(x6), \
+  ASIO_MOVE_CAST(T7)(x7), ASIO_MOVE_CAST(T8)(x8)
+
+# define ASIO_VARIADIC_DECLVAL(n) \
+  ASIO_VARIADIC_DECLVAL_##n
+
+# define ASIO_VARIADIC_DECLVAL_1 \
+  declval<T1>()
+# define ASIO_VARIADIC_DECLVAL_2 \
+  declval<T1>(), declval<T2>()
+# define ASIO_VARIADIC_DECLVAL_3 \
+  declval<T1>(), declval<T2>(), declval<T3>()
+# define ASIO_VARIADIC_DECLVAL_4 \
+  declval<T1>(), declval<T2>(), declval<T3>(), declval<T4>()
+# define ASIO_VARIADIC_DECLVAL_5 \
+  declval<T1>(), declval<T2>(), declval<T3>(), declval<T4>(), \
+  declval<T5>()
+# define ASIO_VARIADIC_DECLVAL_6 \
+  declval<T1>(), declval<T2>(), declval<T3>(), declval<T4>(), \
+  declval<T5>(), declval<T6>()
+# define ASIO_VARIADIC_DECLVAL_7 \
+  declval<T1>(), declval<T2>(), declval<T3>(), declval<T4>(), \
+  declval<T5>(), declval<T6>(), declval<T7>()
+# define ASIO_VARIADIC_DECLVAL_8 \
+  declval<T1>(), declval<T2>(), declval<T3>(), declval<T4>(), \
+  declval<T5>(), declval<T6>(), declval<T7>(), declval<T8>()
+
+# define ASIO_VARIADIC_MOVE_DECLVAL(n) \
+  ASIO_VARIADIC_MOVE_DECLVAL_##n
+
+# define ASIO_VARIADIC_MOVE_DECLVAL_1 \
+  declval<ASIO_MOVE_ARG(T1)>()
+# define ASIO_VARIADIC_MOVE_DECLVAL_2 \
+  declval<ASIO_MOVE_ARG(T1)>(), declval<ASIO_MOVE_ARG(T2)>()
+# define ASIO_VARIADIC_MOVE_DECLVAL_3 \
+  declval<ASIO_MOVE_ARG(T1)>(), declval<ASIO_MOVE_ARG(T2)>(), \
+  declval<ASIO_MOVE_ARG(T3)>()
+# define ASIO_VARIADIC_MOVE_DECLVAL_4 \
+  declval<ASIO_MOVE_ARG(T1)>(), declval<ASIO_MOVE_ARG(T2)>(), \
+  declval<ASIO_MOVE_ARG(T3)>(), declval<ASIO_MOVE_ARG(T4)>()
+# define ASIO_VARIADIC_MOVE_DECLVAL_5 \
+  declval<ASIO_MOVE_ARG(T1)>(), declval<ASIO_MOVE_ARG(T2)>(), \
+  declval<ASIO_MOVE_ARG(T3)>(), declval<ASIO_MOVE_ARG(T4)>(), \
+  declval<ASIO_MOVE_ARG(T5)>()
+# define ASIO_VARIADIC_MOVE_DECLVAL_6 \
+  declval<ASIO_MOVE_ARG(T1)>(), declval<ASIO_MOVE_ARG(T2)>(), \
+  declval<ASIO_MOVE_ARG(T3)>(), declval<ASIO_MOVE_ARG(T4)>(), \
+  declval<ASIO_MOVE_ARG(T5)>(), declval<ASIO_MOVE_ARG(T6)>()
+# define ASIO_VARIADIC_MOVE_DECLVAL_7 \
+  declval<ASIO_MOVE_ARG(T1)>(), declval<ASIO_MOVE_ARG(T2)>(), \
+  declval<ASIO_MOVE_ARG(T3)>(), declval<ASIO_MOVE_ARG(T4)>(), \
+  declval<ASIO_MOVE_ARG(T5)>(), declval<ASIO_MOVE_ARG(T6)>(), \
+  declval<ASIO_MOVE_ARG(T7)>()
+# define ASIO_VARIADIC_MOVE_DECLVAL_8 \
+  declval<ASIO_MOVE_ARG(T1)>(), declval<ASIO_MOVE_ARG(T2)>(), \
+  declval<ASIO_MOVE_ARG(T3)>(), declval<ASIO_MOVE_ARG(T4)>(), \
+  declval<ASIO_MOVE_ARG(T5)>(), declval<ASIO_MOVE_ARG(T6)>(), \
+  declval<ASIO_MOVE_ARG(T7)>(), declval<ASIO_MOVE_ARG(T8)>()
+
+# define ASIO_VARIADIC_DECAY(n) \
+  ASIO_VARIADIC_DECAY_##n
+
+# define ASIO_VARIADIC_DECAY_1 \
+  typename decay<T1>::type
+# define ASIO_VARIADIC_DECAY_2 \
+  typename decay<T1>::type, typename decay<T2>::type
+# define ASIO_VARIADIC_DECAY_3 \
+  typename decay<T1>::type, typename decay<T2>::type, \
+  typename decay<T3>::type
+# define ASIO_VARIADIC_DECAY_4 \
+  typename decay<T1>::type, typename decay<T2>::type, \
+  typename decay<T3>::type, typename decay<T4>::type
+# define ASIO_VARIADIC_DECAY_5 \
+  typename decay<T1>::type, typename decay<T2>::type, \
+  typename decay<T3>::type, typename decay<T4>::type, \
+  typename decay<T5>::type
+# define ASIO_VARIADIC_DECAY_6 \
+  typename decay<T1>::type, typename decay<T2>::type, \
+  typename decay<T3>::type, typename decay<T4>::type, \
+  typename decay<T5>::type, typename decay<T6>::type
+# define ASIO_VARIADIC_DECAY_7 \
+  typename decay<T1>::type, typename decay<T2>::type, \
+  typename decay<T3>::type, typename decay<T4>::type, \
+  typename decay<T5>::type, typename decay<T6>::type, \
+  typename decay<T7>::type
+# define ASIO_VARIADIC_DECAY_8 \
+  typename decay<T1>::type, typename decay<T2>::type, \
+  typename decay<T3>::type, typename decay<T4>::type, \
+  typename decay<T5>::type, typename decay<T6>::type, \
+  typename decay<T7>::type, typename decay<T8>::type
+
+# define ASIO_VARIADIC_GENERATE(m) m(1) m(2) m(3) m(4) m(5) m(6) m(7) m(8)
+# define ASIO_VARIADIC_GENERATE_5(m) m(1) m(2) m(3) m(4) m(5)
+
+#endif // !defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+#endif // ASIO_DETAIL_VARIADIC_TEMPLATES_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/wait_handler.hpp b/link/modules/asio-standalone/asio/include/asio/detail/wait_handler.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/wait_handler.hpp
@@ -0,0 +1,90 @@
+//
+// detail/wait_handler.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_WAIT_HANDLER_HPP
+#define ASIO_DETAIL_WAIT_HANDLER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_work.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/detail/wait_op.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Handler, typename IoExecutor>
+class wait_handler : public wait_op
+{
+public:
+  ASIO_DEFINE_HANDLER_PTR(wait_handler);
+
+  wait_handler(Handler& h, const IoExecutor& io_ex)
+    : wait_op(&wait_handler::do_complete),
+      handler_(ASIO_MOVE_CAST(Handler)(h)),
+      work_(handler_, io_ex)
+  {
+  }
+
+  static void do_complete(void* owner, operation* base,
+      const asio::error_code& /*ec*/,
+      std::size_t /*bytes_transferred*/)
+  {
+    // Take ownership of the handler object.
+    wait_handler* h(static_cast<wait_handler*>(base));
+    ptr p = { asio::detail::addressof(h->handler_), h, h };
+
+    ASIO_HANDLER_COMPLETION((*h));
+
+    // Take ownership of the operation's outstanding work.
+    handler_work<Handler, IoExecutor> w(
+        ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)(
+          h->work_));
+
+    // Make a copy of the handler so that the memory can be deallocated before
+    // the upcall is made. Even if we're not about to make an upcall, a
+    // sub-object of the handler may be the true owner of the memory associated
+    // with the handler. Consequently, a local copy of the handler is required
+    // to ensure that any owning sub-object remains valid until after we have
+    // deallocated the memory here.
+    detail::binder1<Handler, asio::error_code>
+      handler(h->handler_, h->ec_);
+    p.h = asio::detail::addressof(handler.handler_);
+    p.reset();
+
+    // Make the upcall if required.
+    if (owner)
+    {
+      fenced_block b(fenced_block::half);
+      ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_));
+      w.complete(handler, handler.handler_);
+      ASIO_HANDLER_INVOCATION_END;
+    }
+  }
+
+private:
+  Handler handler_;
+  handler_work<Handler, IoExecutor> work_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_WAIT_HANDLER_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/wait_op.hpp b/link/modules/asio-standalone/asio/include/asio/detail/wait_op.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/wait_op.hpp
@@ -0,0 +1,45 @@
+//
+// detail/wait_op.hpp
+// ~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_WAIT_OP_HPP
+#define ASIO_DETAIL_WAIT_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/operation.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class wait_op
+  : public operation
+{
+public:
+  // The error code to be passed to the completion handler.
+  asio::error_code ec_;
+
+protected:
+  wait_op(func_type func)
+    : operation(func)
+  {
+  }
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_WAIT_OP_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/win_event.hpp b/link/modules/asio-standalone/asio/include/asio/detail/win_event.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/win_event.hpp
@@ -0,0 +1,164 @@
+//
+// detail/win_event.hpp
+// ~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_WIN_EVENT_HPP
+#define ASIO_DETAIL_WIN_EVENT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_WINDOWS)
+
+#include <cstddef>
+#include "asio/detail/assert.hpp"
+#include "asio/detail/noncopyable.hpp"
+#include "asio/detail/socket_types.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class win_event
+  : private noncopyable
+{
+public:
+  // Constructor.
+  ASIO_DECL win_event();
+
+  // Destructor.
+  ASIO_DECL ~win_event();
+
+  // Signal the event. (Retained for backward compatibility.)
+  template <typename Lock>
+  void signal(Lock& lock)
+  {
+    this->signal_all(lock);
+  }
+
+  // Signal all waiters.
+  template <typename Lock>
+  void signal_all(Lock& lock)
+  {
+    ASIO_ASSERT(lock.locked());
+    (void)lock;
+    state_ |= 1;
+    ::SetEvent(events_[0]);
+  }
+
+  // Unlock the mutex and signal one waiter.
+  template <typename Lock>
+  void unlock_and_signal_one(Lock& lock)
+  {
+    ASIO_ASSERT(lock.locked());
+    state_ |= 1;
+    bool have_waiters = (state_ > 1);
+    lock.unlock();
+    if (have_waiters)
+      ::SetEvent(events_[1]);
+  }
+
+  // Unlock the mutex and signal one waiter who may destroy us.
+  template <typename Lock>
+  void unlock_and_signal_one_for_destruction(Lock& lock)
+  {
+    ASIO_ASSERT(lock.locked());
+    state_ |= 1;
+    bool have_waiters = (state_ > 1);
+    if (have_waiters)
+      ::SetEvent(events_[1]);
+    lock.unlock();
+  }
+
+  // If there's a waiter, unlock the mutex and signal it.
+  template <typename Lock>
+  bool maybe_unlock_and_signal_one(Lock& lock)
+  {
+    ASIO_ASSERT(lock.locked());
+    state_ |= 1;
+    if (state_ > 1)
+    {
+      lock.unlock();
+      ::SetEvent(events_[1]);
+      return true;
+    }
+    return false;
+  }
+
+  // Reset the event.
+  template <typename Lock>
+  void clear(Lock& lock)
+  {
+    ASIO_ASSERT(lock.locked());
+    (void)lock;
+    ::ResetEvent(events_[0]);
+    state_ &= ~std::size_t(1);
+  }
+
+  // Wait for the event to become signalled.
+  template <typename Lock>
+  void wait(Lock& lock)
+  {
+    ASIO_ASSERT(lock.locked());
+    while ((state_ & 1) == 0)
+    {
+      state_ += 2;
+      lock.unlock();
+#if defined(ASIO_WINDOWS_APP)
+      ::WaitForMultipleObjectsEx(2, events_, false, INFINITE, false);
+#else // defined(ASIO_WINDOWS_APP)
+      ::WaitForMultipleObjects(2, events_, false, INFINITE);
+#endif // defined(ASIO_WINDOWS_APP)
+      lock.lock();
+      state_ -= 2;
+    }
+  }
+
+  // Timed wait for the event to become signalled.
+  template <typename Lock>
+  bool wait_for_usec(Lock& lock, long usec)
+  {
+    ASIO_ASSERT(lock.locked());
+    if ((state_ & 1) == 0)
+    {
+      state_ += 2;
+      lock.unlock();
+      DWORD msec = usec > 0 ? (usec < 1000 ? 1 : usec / 1000) : 0;
+#if defined(ASIO_WINDOWS_APP)
+      ::WaitForMultipleObjectsEx(2, events_, false, msec, false);
+#else // defined(ASIO_WINDOWS_APP)
+      ::WaitForMultipleObjects(2, events_, false, msec);
+#endif // defined(ASIO_WINDOWS_APP)
+      lock.lock();
+      state_ -= 2;
+    }
+    return (state_ & 1) != 0;
+  }
+
+private:
+  HANDLE events_[2];
+  std::size_t state_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/win_event.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // defined(ASIO_WINDOWS)
+
+#endif // ASIO_DETAIL_WIN_EVENT_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/win_fd_set_adapter.hpp b/link/modules/asio-standalone/asio/include/asio/detail/win_fd_set_adapter.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/win_fd_set_adapter.hpp
@@ -0,0 +1,149 @@
+//
+// detail/win_fd_set_adapter.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_WIN_FD_SET_ADAPTER_HPP
+#define ASIO_DETAIL_WIN_FD_SET_ADAPTER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+
+#include "asio/detail/noncopyable.hpp"
+#include "asio/detail/reactor_op_queue.hpp"
+#include "asio/detail/socket_types.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+// Adapts the FD_SET type to meet the Descriptor_Set concept's requirements.
+class win_fd_set_adapter : noncopyable
+{
+public:
+  enum { default_fd_set_size = 1024 };
+
+  win_fd_set_adapter()
+    : capacity_(default_fd_set_size),
+      max_descriptor_(invalid_socket)
+  {
+    fd_set_ = static_cast<win_fd_set*>(::operator new(
+          sizeof(win_fd_set) - sizeof(SOCKET)
+          + sizeof(SOCKET) * (capacity_)));
+    fd_set_->fd_count = 0;
+  }
+
+  ~win_fd_set_adapter()
+  {
+    ::operator delete(fd_set_);
+  }
+
+  void reset()
+  {
+    fd_set_->fd_count = 0;
+    max_descriptor_ = invalid_socket;
+  }
+
+  bool set(socket_type descriptor)
+  {
+    for (u_int i = 0; i < fd_set_->fd_count; ++i)
+      if (fd_set_->fd_array[i] == descriptor)
+        return true;
+
+    reserve(fd_set_->fd_count + 1);
+    fd_set_->fd_array[fd_set_->fd_count++] = descriptor;
+    return true;
+  }
+
+  void set(reactor_op_queue<socket_type>& operations, op_queue<operation>&)
+  {
+    reactor_op_queue<socket_type>::iterator i = operations.begin();
+    while (i != operations.end())
+    {
+      reactor_op_queue<socket_type>::iterator op_iter = i++;
+      reserve(fd_set_->fd_count + 1);
+      fd_set_->fd_array[fd_set_->fd_count++] = op_iter->first;
+    }
+  }
+
+  bool is_set(socket_type descriptor) const
+  {
+    return !!__WSAFDIsSet(descriptor,
+        const_cast<fd_set*>(reinterpret_cast<const fd_set*>(fd_set_)));
+  }
+
+  operator fd_set*()
+  {
+    return reinterpret_cast<fd_set*>(fd_set_);
+  }
+
+  socket_type max_descriptor() const
+  {
+    return max_descriptor_;
+  }
+
+  void perform(reactor_op_queue<socket_type>& operations,
+      op_queue<operation>& ops) const
+  {
+    for (u_int i = 0; i < fd_set_->fd_count; ++i)
+      operations.perform_operations(fd_set_->fd_array[i], ops);
+  }
+
+private:
+  // This structure is defined to be compatible with the Windows API fd_set
+  // structure, but without being dependent on the value of FD_SETSIZE. We use
+  // the "struct hack" to allow the number of descriptors to be varied at
+  // runtime.
+  struct win_fd_set
+  {
+    u_int fd_count;
+    SOCKET fd_array[1];
+  };
+
+  // Increase the fd_set_ capacity to at least the specified number of elements.
+  void reserve(u_int n)
+  {
+    if (n <= capacity_)
+      return;
+
+    u_int new_capacity = capacity_ + capacity_ / 2;
+    if (new_capacity < n)
+      new_capacity = n;
+
+    win_fd_set* new_fd_set = static_cast<win_fd_set*>(::operator new(
+          sizeof(win_fd_set) - sizeof(SOCKET)
+          + sizeof(SOCKET) * (new_capacity)));
+
+    new_fd_set->fd_count = fd_set_->fd_count;
+    for (u_int i = 0; i < fd_set_->fd_count; ++i)
+      new_fd_set->fd_array[i] = fd_set_->fd_array[i];
+
+    ::operator delete(fd_set_);
+    fd_set_ = new_fd_set;
+    capacity_ = new_capacity;
+  }
+
+  win_fd_set* fd_set_;
+  u_int capacity_;
+  socket_type max_descriptor_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+
+#endif // ASIO_DETAIL_WIN_FD_SET_ADAPTER_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/win_fenced_block.hpp b/link/modules/asio-standalone/asio/include/asio/detail/win_fenced_block.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/win_fenced_block.hpp
@@ -0,0 +1,90 @@
+//
+// detail/win_fenced_block.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_WIN_FENCED_BLOCK_HPP
+#define ASIO_DETAIL_WIN_FENCED_BLOCK_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_WINDOWS) && !defined(UNDER_CE)
+
+#include "asio/detail/socket_types.hpp"
+#include "asio/detail/noncopyable.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class win_fenced_block
+  : private noncopyable
+{
+public:
+  enum half_t { half };
+  enum full_t { full };
+
+  // Constructor for a half fenced block.
+  explicit win_fenced_block(half_t)
+  {
+  }
+
+  // Constructor for a full fenced block.
+  explicit win_fenced_block(full_t)
+  {
+#if defined(__BORLANDC__)
+    LONG barrier = 0;
+    ::InterlockedExchange(&barrier, 1);
+#elif defined(ASIO_MSVC) \
+  && ((ASIO_MSVC < 1400) || !defined(MemoryBarrier))
+# if defined(_M_IX86)
+#  pragma warning(push)
+#  pragma warning(disable:4793)
+    LONG barrier;
+    __asm { xchg barrier, eax }
+#  pragma warning(pop)
+# endif // defined(_M_IX86)
+#else
+    MemoryBarrier();
+#endif
+  }
+
+  // Destructor.
+  ~win_fenced_block()
+  {
+#if defined(__BORLANDC__)
+    LONG barrier = 0;
+    ::InterlockedExchange(&barrier, 1);
+#elif defined(ASIO_MSVC) \
+  && ((ASIO_MSVC < 1400) || !defined(MemoryBarrier))
+# if defined(_M_IX86)
+#  pragma warning(push)
+#  pragma warning(disable:4793)
+    LONG barrier;
+    __asm { xchg barrier, eax }
+#  pragma warning(pop)
+# endif // defined(_M_IX86)
+#else
+    MemoryBarrier();
+#endif
+  }
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_WINDOWS) && !defined(UNDER_CE)
+
+#endif // ASIO_DETAIL_WIN_FENCED_BLOCK_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/win_global.hpp b/link/modules/asio-standalone/asio/include/asio/detail/win_global.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/win_global.hpp
@@ -0,0 +1,71 @@
+//
+// detail/win_global.hpp
+// ~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_WIN_GLOBAL_HPP
+#define ASIO_DETAIL_WIN_GLOBAL_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/static_mutex.hpp"
+#include "asio/detail/tss_ptr.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename T>
+struct win_global_impl
+{
+  // Destructor automatically cleans up the global.
+  ~win_global_impl()
+  {
+    delete ptr_;
+  }
+
+  static win_global_impl instance_;
+  static static_mutex mutex_;
+  T* ptr_;
+  static tss_ptr<T> tss_ptr_;
+};
+
+template <typename T>
+win_global_impl<T> win_global_impl<T>::instance_ = { 0 };
+
+template <typename T>
+static_mutex win_global_impl<T>::mutex_ = ASIO_STATIC_MUTEX_INIT;
+
+template <typename T>
+tss_ptr<T> win_global_impl<T>::tss_ptr_;
+
+template <typename T>
+T& win_global()
+{
+  if (static_cast<T*>(win_global_impl<T>::tss_ptr_) == 0)
+  {
+    win_global_impl<T>::mutex_.init();
+    static_mutex::scoped_lock lock(win_global_impl<T>::mutex_);
+    if (win_global_impl<T>::instance_.ptr_ == 0)
+      win_global_impl<T>::instance_.ptr_ = new T;
+    win_global_impl<T>::tss_ptr_ = win_global_impl<T>::instance_.ptr_;
+  }
+
+  return *win_global_impl<T>::tss_ptr_;
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_WIN_GLOBAL_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/win_iocp_handle_read_op.hpp b/link/modules/asio-standalone/asio/include/asio/detail/win_iocp_handle_read_op.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/win_iocp_handle_read_op.hpp
@@ -0,0 +1,117 @@
+//
+// detail/win_iocp_handle_read_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.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 ASIO_DETAIL_WIN_IOCP_HANDLE_READ_OP_HPP
+#define ASIO_DETAIL_WIN_IOCP_HANDLE_READ_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_IOCP)
+
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/buffer_sequence_adapter.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/handler_work.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/detail/operation.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename MutableBufferSequence, typename Handler, typename IoExecutor>
+class win_iocp_handle_read_op : public operation
+{
+public:
+  ASIO_DEFINE_HANDLER_PTR(win_iocp_handle_read_op);
+
+  win_iocp_handle_read_op(const MutableBufferSequence& buffers,
+      Handler& handler, const IoExecutor& io_ex)
+    : operation(&win_iocp_handle_read_op::do_complete),
+      buffers_(buffers),
+      handler_(ASIO_MOVE_CAST(Handler)(handler)),
+      work_(handler_, io_ex)
+  {
+  }
+
+  static void do_complete(void* owner, operation* base,
+      const asio::error_code& result_ec,
+      std::size_t bytes_transferred)
+  {
+    asio::error_code ec(result_ec);
+
+    // Take ownership of the operation object.
+    win_iocp_handle_read_op* o(static_cast<win_iocp_handle_read_op*>(base));
+    ptr p = { asio::detail::addressof(o->handler_), o, o };
+
+    ASIO_HANDLER_COMPLETION((*o));
+
+    // Take ownership of the operation's outstanding work.
+    handler_work<Handler, IoExecutor> w(
+        ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)(
+          o->work_));
+
+#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
+    if (owner)
+    {
+      // Check whether buffers are still valid.
+      buffer_sequence_adapter<asio::mutable_buffer,
+          MutableBufferSequence>::validate(o->buffers_);
+    }
+#endif // defined(ASIO_ENABLE_BUFFER_DEBUGGING)
+
+    // Map non-portable errors to their portable counterparts.
+    if (ec.value() == ERROR_HANDLE_EOF)
+      ec = asio::error::eof;
+
+    // Make a copy of the handler so that the memory can be deallocated before
+    // the upcall is made. Even if we're not about to make an upcall, a
+    // sub-object of the handler may be the true owner of the memory associated
+    // with the handler. Consequently, a local copy of the handler is required
+    // to ensure that any owning sub-object remains valid until after we have
+    // deallocated the memory here.
+    detail::binder2<Handler, asio::error_code, std::size_t>
+      handler(o->handler_, ec, bytes_transferred);
+    p.h = asio::detail::addressof(handler.handler_);
+    p.reset();
+
+    // Make the upcall if required.
+    if (owner)
+    {
+      fenced_block b(fenced_block::half);
+      ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_));
+      w.complete(handler, handler.handler_);
+      ASIO_HANDLER_INVOCATION_END;
+    }
+  }
+
+private:
+  MutableBufferSequence buffers_;
+  Handler handler_;
+  handler_work<Handler, IoExecutor> work_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_IOCP)
+
+#endif // ASIO_DETAIL_WIN_IOCP_HANDLE_READ_OP_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/win_iocp_handle_service.hpp b/link/modules/asio-standalone/asio/include/asio/detail/win_iocp_handle_service.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/win_iocp_handle_service.hpp
@@ -0,0 +1,335 @@
+//
+// detail/win_iocp_handle_service.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.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 ASIO_DETAIL_WIN_IOCP_HANDLE_SERVICE_HPP
+#define ASIO_DETAIL_WIN_IOCP_HANDLE_SERVICE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_IOCP)
+
+#include "asio/error.hpp"
+#include "asio/execution_context.hpp"
+#include "asio/detail/buffer_sequence_adapter.hpp"
+#include "asio/detail/cstdint.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/detail/mutex.hpp"
+#include "asio/detail/operation.hpp"
+#include "asio/detail/win_iocp_handle_read_op.hpp"
+#include "asio/detail/win_iocp_handle_write_op.hpp"
+#include "asio/detail/win_iocp_io_context.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class win_iocp_handle_service :
+  public execution_context_service_base<win_iocp_handle_service>
+{
+public:
+  // The native type of a stream handle.
+  typedef HANDLE native_handle_type;
+
+  // The implementation type of the stream handle.
+  class implementation_type
+  {
+  public:
+    // Default constructor.
+    implementation_type()
+      : handle_(INVALID_HANDLE_VALUE),
+        safe_cancellation_thread_id_(0),
+        next_(0),
+        prev_(0)
+    {
+    }
+
+  private:
+    // Only this service will have access to the internal values.
+    friend class win_iocp_handle_service;
+
+    // The native stream handle representation.
+    native_handle_type handle_;
+
+    // The ID of the thread from which it is safe to cancel asynchronous
+    // operations. 0 means no asynchronous operations have been started yet.
+    // ~0 means asynchronous operations have been started from more than one
+    // thread, and cancellation is not supported for the handle.
+    DWORD safe_cancellation_thread_id_;
+
+    // Pointers to adjacent handle implementations in linked list.
+    implementation_type* next_;
+    implementation_type* prev_;
+  };
+
+  ASIO_DECL win_iocp_handle_service(execution_context& context);
+
+  // Destroy all user-defined handler objects owned by the service.
+  ASIO_DECL void shutdown();
+
+  // Construct a new handle implementation.
+  ASIO_DECL void construct(implementation_type& impl);
+
+  // Move-construct a new handle implementation.
+  ASIO_DECL void move_construct(implementation_type& impl,
+      implementation_type& other_impl);
+
+  // Move-assign from another handle implementation.
+  ASIO_DECL void move_assign(implementation_type& impl,
+      win_iocp_handle_service& other_service,
+      implementation_type& other_impl);
+
+  // Destroy a handle implementation.
+  ASIO_DECL void destroy(implementation_type& impl);
+
+  // Assign a native handle to a handle implementation.
+  ASIO_DECL asio::error_code assign(implementation_type& impl,
+      const native_handle_type& handle, asio::error_code& ec);
+
+  // Determine whether the handle is open.
+  bool is_open(const implementation_type& impl) const
+  {
+    return impl.handle_ != INVALID_HANDLE_VALUE;
+  }
+
+  // Destroy a handle implementation.
+  ASIO_DECL asio::error_code close(implementation_type& impl,
+      asio::error_code& ec);
+
+  // Get the native handle representation.
+  native_handle_type native_handle(const implementation_type& impl) const
+  {
+    return impl.handle_;
+  }
+
+  // Cancel all operations associated with the handle.
+  ASIO_DECL asio::error_code cancel(implementation_type& impl,
+      asio::error_code& ec);
+
+  // Write the given data. Returns the number of bytes written.
+  template <typename ConstBufferSequence>
+  size_t write_some(implementation_type& impl,
+      const ConstBufferSequence& buffers, asio::error_code& ec)
+  {
+    return write_some_at(impl, 0, buffers, ec);
+  }
+
+  // Write the given data at the specified offset. Returns the number of bytes
+  // written.
+  template <typename ConstBufferSequence>
+  size_t write_some_at(implementation_type& impl, uint64_t offset,
+      const ConstBufferSequence& buffers, asio::error_code& ec)
+  {
+    asio::const_buffer buffer =
+      buffer_sequence_adapter<asio::const_buffer,
+        ConstBufferSequence>::first(buffers);
+
+    return do_write(impl, offset, buffer, ec);
+  }
+
+  // Start an asynchronous write. The data being written must be valid for the
+  // lifetime of the asynchronous operation.
+  template <typename ConstBufferSequence, typename Handler, typename IoExecutor>
+  void async_write_some(implementation_type& impl,
+      const ConstBufferSequence& buffers,
+      Handler& handler, const IoExecutor& io_ex)
+  {
+    // Allocate and construct an operation to wrap the handler.
+    typedef win_iocp_handle_write_op<
+        ConstBufferSequence, Handler, IoExecutor> op;
+    typename op::ptr p = { asio::detail::addressof(handler),
+      op::ptr::allocate(handler), 0 };
+    p.p = new (p.v) op(buffers, handler, io_ex);
+
+    ASIO_HANDLER_CREATION((iocp_service_.context(), *p.p, "handle", &impl,
+          reinterpret_cast<uintmax_t>(impl.handle_), "async_write_some"));
+
+    start_write_op(impl, 0,
+        buffer_sequence_adapter<asio::const_buffer,
+          ConstBufferSequence>::first(buffers), p.p);
+    p.v = p.p = 0;
+  }
+
+  // Start an asynchronous write at a specified offset. The data being written
+  // must be valid for the lifetime of the asynchronous operation.
+  template <typename ConstBufferSequence, typename Handler, typename IoExecutor>
+  void async_write_some_at(implementation_type& impl,
+      uint64_t offset, const ConstBufferSequence& buffers,
+      Handler& handler, const IoExecutor& io_ex)
+  {
+    // Allocate and construct an operation to wrap the handler.
+    typedef win_iocp_handle_write_op<
+        ConstBufferSequence, Handler, IoExecutor> op;
+    typename op::ptr p = { asio::detail::addressof(handler),
+      op::ptr::allocate(handler), 0 };
+    p.p = new (p.v) op(buffers, handler, io_ex);
+
+    ASIO_HANDLER_CREATION((iocp_service_.context(), *p.p, "handle", &impl,
+          reinterpret_cast<uintmax_t>(impl.handle_), "async_write_some_at"));
+
+    start_write_op(impl, offset,
+        buffer_sequence_adapter<asio::const_buffer,
+          ConstBufferSequence>::first(buffers), p.p);
+    p.v = p.p = 0;
+  }
+
+  // Read some data. Returns the number of bytes received.
+  template <typename MutableBufferSequence>
+  size_t read_some(implementation_type& impl,
+      const MutableBufferSequence& buffers, asio::error_code& ec)
+  {
+    return read_some_at(impl, 0, buffers, ec);
+  }
+
+  // Read some data at a specified offset. Returns the number of bytes received.
+  template <typename MutableBufferSequence>
+  size_t read_some_at(implementation_type& impl, uint64_t offset,
+      const MutableBufferSequence& buffers, asio::error_code& ec)
+  {
+    asio::mutable_buffer buffer =
+      buffer_sequence_adapter<asio::mutable_buffer,
+        MutableBufferSequence>::first(buffers);
+
+    return do_read(impl, offset, buffer, ec);
+  }
+
+  // Start an asynchronous read. The buffer for the data being received must be
+  // valid for the lifetime of the asynchronous operation.
+  template <typename MutableBufferSequence,
+      typename Handler, typename IoExecutor>
+  void async_read_some(implementation_type& impl,
+      const MutableBufferSequence& buffers,
+      Handler& handler, const IoExecutor& io_ex)
+  {
+    // Allocate and construct an operation to wrap the handler.
+    typedef win_iocp_handle_read_op<
+        MutableBufferSequence, Handler, IoExecutor> op;
+    typename op::ptr p = { asio::detail::addressof(handler),
+      op::ptr::allocate(handler), 0 };
+    p.p = new (p.v) op(buffers, handler, io_ex);
+
+    ASIO_HANDLER_CREATION((iocp_service_.context(), *p.p, "handle", &impl,
+          reinterpret_cast<uintmax_t>(impl.handle_), "async_read_some"));
+
+    start_read_op(impl, 0,
+        buffer_sequence_adapter<asio::mutable_buffer,
+          MutableBufferSequence>::first(buffers), p.p);
+    p.v = p.p = 0;
+  }
+
+  // Start an asynchronous read at a specified offset. The buffer for the data
+  // being received must be valid for the lifetime of the asynchronous
+  // operation.
+  template <typename MutableBufferSequence,
+      typename Handler, typename IoExecutor>
+  void async_read_some_at(implementation_type& impl,
+      uint64_t offset, const MutableBufferSequence& buffers,
+      Handler& handler, const IoExecutor& io_ex)
+  {
+    // Allocate and construct an operation to wrap the handler.
+    typedef win_iocp_handle_read_op<
+        MutableBufferSequence, Handler, IoExecutor> op;
+    typename op::ptr p = { asio::detail::addressof(handler),
+      op::ptr::allocate(handler), 0 };
+    p.p = new (p.v) op(buffers, handler, io_ex);
+
+    ASIO_HANDLER_CREATION((iocp_service_.context(), *p.p, "handle", &impl,
+          reinterpret_cast<uintmax_t>(impl.handle_), "async_read_some_at"));
+
+    start_read_op(impl, offset,
+        buffer_sequence_adapter<asio::mutable_buffer,
+          MutableBufferSequence>::first(buffers), p.p);
+    p.v = p.p = 0;
+  }
+
+private:
+  // Prevent the use of the null_buffers type with this service.
+  size_t write_some(implementation_type& impl,
+      const null_buffers& buffers, asio::error_code& ec);
+  size_t write_some_at(implementation_type& impl, uint64_t offset,
+      const null_buffers& buffers, asio::error_code& ec);
+  template <typename Handler, typename IoExecutor>
+  void async_write_some(implementation_type& impl,
+      const null_buffers& buffers, Handler& handler,
+      const IoExecutor& io_ex);
+  template <typename Handler, typename IoExecutor>
+  void async_write_some_at(implementation_type& impl, uint64_t offset,
+      const null_buffers& buffers, Handler& handler, const IoExecutor& io_ex);
+  size_t read_some(implementation_type& impl,
+      const null_buffers& buffers, asio::error_code& ec);
+  size_t read_some_at(implementation_type& impl, uint64_t offset,
+      const null_buffers& buffers, asio::error_code& ec);
+  template <typename Handler, typename IoExecutor>
+  void async_read_some(implementation_type& impl,
+      const null_buffers& buffers, Handler& handler,
+      const IoExecutor& io_ex);
+  template <typename Handler, typename IoExecutor>
+  void async_read_some_at(implementation_type& impl, uint64_t offset,
+      const null_buffers& buffers, Handler& handler, const IoExecutor& io_ex);
+
+  // Helper class for waiting for synchronous operations to complete.
+  class overlapped_wrapper;
+
+  // Helper function to perform a synchronous write operation.
+  ASIO_DECL size_t do_write(implementation_type& impl,
+      uint64_t offset, const asio::const_buffer& buffer,
+      asio::error_code& ec);
+
+  // Helper function to start a write operation.
+  ASIO_DECL void start_write_op(implementation_type& impl,
+      uint64_t offset, const asio::const_buffer& buffer,
+      operation* op);
+
+  // Helper function to perform a synchronous write operation.
+  ASIO_DECL size_t do_read(implementation_type& impl,
+      uint64_t offset, const asio::mutable_buffer& buffer,
+      asio::error_code& ec);
+
+  // Helper function to start a read operation.
+  ASIO_DECL void start_read_op(implementation_type& impl,
+      uint64_t offset, const asio::mutable_buffer& buffer,
+      operation* op);
+
+  // Update the ID of the thread from which cancellation is safe.
+  ASIO_DECL void update_cancellation_thread_id(implementation_type& impl);
+
+  // Helper function to close a handle when the associated object is being
+  // destroyed.
+  ASIO_DECL void close_for_destruction(implementation_type& impl);
+
+  // The IOCP service used for running asynchronous operations and dispatching
+  // handlers.
+  win_iocp_io_context& iocp_service_;
+
+  // Mutex to protect access to the linked list of implementations.
+  mutex mutex_;
+
+  // The head of a linked list of all implementations.
+  implementation_type* impl_list_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/win_iocp_handle_service.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // defined(ASIO_HAS_IOCP)
+
+#endif // ASIO_DETAIL_WIN_IOCP_HANDLE_SERVICE_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/win_iocp_handle_write_op.hpp b/link/modules/asio-standalone/asio/include/asio/detail/win_iocp_handle_write_op.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/win_iocp_handle_write_op.hpp
@@ -0,0 +1,110 @@
+//
+// detail/win_iocp_handle_write_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.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 ASIO_DETAIL_WIN_IOCP_HANDLE_WRITE_OP_HPP
+#define ASIO_DETAIL_WIN_IOCP_HANDLE_WRITE_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_IOCP)
+
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/buffer_sequence_adapter.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/handler_work.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/detail/operation.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename ConstBufferSequence, typename Handler, typename IoExecutor>
+class win_iocp_handle_write_op : public operation
+{
+public:
+  ASIO_DEFINE_HANDLER_PTR(win_iocp_handle_write_op);
+
+  win_iocp_handle_write_op(const ConstBufferSequence& buffers,
+      Handler& handler, const IoExecutor& io_ex)
+    : operation(&win_iocp_handle_write_op::do_complete),
+      buffers_(buffers),
+      handler_(ASIO_MOVE_CAST(Handler)(handler)),
+      work_(handler_, io_ex)
+  {
+  }
+
+  static void do_complete(void* owner, operation* base,
+      const asio::error_code& ec, std::size_t bytes_transferred)
+  {
+    // Take ownership of the operation object.
+    win_iocp_handle_write_op* o(static_cast<win_iocp_handle_write_op*>(base));
+    ptr p = { asio::detail::addressof(o->handler_), o, o };
+
+    ASIO_HANDLER_COMPLETION((*o));
+
+    // Take ownership of the operation's outstanding work.
+    handler_work<Handler, IoExecutor> w(
+        ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)(
+          o->work_));
+
+#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
+    if (owner)
+    {
+      // Check whether buffers are still valid.
+      buffer_sequence_adapter<asio::const_buffer,
+          ConstBufferSequence>::validate(o->buffers_);
+    }
+#endif // defined(ASIO_ENABLE_BUFFER_DEBUGGING)
+
+    // Make a copy of the handler so that the memory can be deallocated before
+    // the upcall is made. Even if we're not about to make an upcall, a
+    // sub-object of the handler may be the true owner of the memory associated
+    // with the handler. Consequently, a local copy of the handler is required
+    // to ensure that any owning sub-object remains valid until after we have
+    // deallocated the memory here.
+    detail::binder2<Handler, asio::error_code, std::size_t>
+      handler(o->handler_, ec, bytes_transferred);
+    p.h = asio::detail::addressof(handler.handler_);
+    p.reset();
+
+    // Make the upcall if required.
+    if (owner)
+    {
+      fenced_block b(fenced_block::half);
+      ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_));
+      w.complete(handler, handler.handler_);
+      ASIO_HANDLER_INVOCATION_END;
+    }
+  }
+
+private:
+  ConstBufferSequence buffers_;
+  Handler handler_;
+  handler_work<Handler, IoExecutor> work_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_IOCP)
+
+#endif // ASIO_DETAIL_WIN_IOCP_HANDLE_WRITE_OP_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/win_iocp_io_context.hpp b/link/modules/asio-standalone/asio/include/asio/detail/win_iocp_io_context.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/win_iocp_io_context.hpp
@@ -0,0 +1,342 @@
+//
+// detail/win_iocp_io_context.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_WIN_IOCP_IO_CONTEXT_HPP
+#define ASIO_DETAIL_WIN_IOCP_IO_CONTEXT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_IOCP)
+
+#include "asio/detail/limits.hpp"
+#include "asio/detail/mutex.hpp"
+#include "asio/detail/op_queue.hpp"
+#include "asio/detail/scoped_ptr.hpp"
+#include "asio/detail/socket_types.hpp"
+#include "asio/detail/thread.hpp"
+#include "asio/detail/thread_context.hpp"
+#include "asio/detail/timer_queue_base.hpp"
+#include "asio/detail/timer_queue_set.hpp"
+#include "asio/detail/wait_op.hpp"
+#include "asio/detail/win_iocp_operation.hpp"
+#include "asio/detail/win_iocp_thread_info.hpp"
+#include "asio/execution_context.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class wait_op;
+
+class win_iocp_io_context
+  : public execution_context_service_base<win_iocp_io_context>,
+    public thread_context
+{
+public:
+  // Constructor. Specifies a concurrency hint that is passed through to the
+  // underlying I/O completion port.
+  ASIO_DECL win_iocp_io_context(asio::execution_context& ctx,
+      int concurrency_hint = -1, bool own_thread = true);
+
+  // Destructor.
+  ASIO_DECL ~win_iocp_io_context();
+
+  // Destroy all user-defined handler objects owned by the service.
+  ASIO_DECL void shutdown();
+
+  // Initialise the task. Nothing to do here.
+  void init_task()
+  {
+  }
+
+  // Register a handle with the IO completion port.
+  ASIO_DECL asio::error_code register_handle(
+      HANDLE handle, asio::error_code& ec);
+
+  // Run the event loop until stopped or no more work.
+  ASIO_DECL size_t run(asio::error_code& ec);
+
+  // Run until stopped or one operation is performed.
+  ASIO_DECL size_t run_one(asio::error_code& ec);
+
+  // Run until timeout, interrupted, or one operation is performed.
+  ASIO_DECL size_t wait_one(long usec, asio::error_code& ec);
+
+  // Poll for operations without blocking.
+  ASIO_DECL size_t poll(asio::error_code& ec);
+
+  // Poll for one operation without blocking.
+  ASIO_DECL size_t poll_one(asio::error_code& ec);
+
+  // Stop the event processing loop.
+  ASIO_DECL void stop();
+
+  // Determine whether the io_context is stopped.
+  bool stopped() const
+  {
+    return ::InterlockedExchangeAdd(&stopped_, 0) != 0;
+  }
+
+  // Restart in preparation for a subsequent run invocation.
+  void restart()
+  {
+    ::InterlockedExchange(&stopped_, 0);
+  }
+
+  // Notify that some work has started.
+  void work_started()
+  {
+    ::InterlockedIncrement(&outstanding_work_);
+  }
+
+  // Notify that some work has finished.
+  void work_finished()
+  {
+    if (::InterlockedDecrement(&outstanding_work_) == 0)
+      stop();
+  }
+
+  // Return whether a handler can be dispatched immediately.
+  bool can_dispatch()
+  {
+    return thread_call_stack::contains(this) != 0;
+  }
+
+  /// Capture the current exception so it can be rethrown from a run function.
+  ASIO_DECL void capture_current_exception();
+
+  // Request invocation of the given operation and return immediately. Assumes
+  // that work_started() has not yet been called for the operation.
+  void post_immediate_completion(win_iocp_operation* op, bool)
+  {
+    work_started();
+    post_deferred_completion(op);
+  }
+
+  // Request invocation of the given operation and return immediately. Assumes
+  // that work_started() was previously called for the operation.
+  ASIO_DECL void post_deferred_completion(win_iocp_operation* op);
+
+  // Request invocation of the given operation and return immediately. Assumes
+  // that work_started() was previously called for the operations.
+  ASIO_DECL void post_deferred_completions(
+      op_queue<win_iocp_operation>& ops);
+
+  // Request invocation of the given operation using the thread-private queue
+  // and return immediately. Assumes that work_started() has not yet been
+  // called for the operation.
+  void post_private_immediate_completion(win_iocp_operation* op)
+  {
+    post_immediate_completion(op, false);
+  }
+
+  // Request invocation of the given operation using the thread-private queue
+  // and return immediately. Assumes that work_started() was previously called
+  // for the operation.
+  void post_private_deferred_completion(win_iocp_operation* op)
+  {
+    post_deferred_completion(op);
+  }
+
+  // Enqueue the given operation following a failed attempt to dispatch the
+  // operation for immediate invocation.
+  void do_dispatch(operation* op)
+  {
+    post_immediate_completion(op, false);
+  }
+
+  // Process unfinished operations as part of a shutdown operation. Assumes
+  // that work_started() was previously called for the operations.
+  ASIO_DECL void abandon_operations(op_queue<operation>& ops);
+
+  // Called after starting an overlapped I/O operation that did not complete
+  // immediately. The caller must have already called work_started() prior to
+  // starting the operation.
+  ASIO_DECL void on_pending(win_iocp_operation* op);
+
+  // Called after starting an overlapped I/O operation that completed
+  // immediately. The caller must have already called work_started() prior to
+  // starting the operation.
+  ASIO_DECL void on_completion(win_iocp_operation* op,
+      DWORD last_error = 0, DWORD bytes_transferred = 0);
+
+  // Called after starting an overlapped I/O operation that completed
+  // immediately. The caller must have already called work_started() prior to
+  // starting the operation.
+  ASIO_DECL void on_completion(win_iocp_operation* op,
+      const asio::error_code& ec, DWORD bytes_transferred = 0);
+
+  // Add a new timer queue to the service.
+  template <typename Time_Traits>
+  void add_timer_queue(timer_queue<Time_Traits>& timer_queue);
+
+  // Remove a timer queue from the service.
+  template <typename Time_Traits>
+  void remove_timer_queue(timer_queue<Time_Traits>& timer_queue);
+
+  // Schedule a new operation in the given timer queue to expire at the
+  // specified absolute time.
+  template <typename Time_Traits>
+  void schedule_timer(timer_queue<Time_Traits>& queue,
+      const typename Time_Traits::time_type& time,
+      typename timer_queue<Time_Traits>::per_timer_data& timer, wait_op* op);
+
+  // Cancel the timer associated with the given token. Returns the number of
+  // handlers that have been posted or dispatched.
+  template <typename Time_Traits>
+  std::size_t cancel_timer(timer_queue<Time_Traits>& queue,
+      typename timer_queue<Time_Traits>::per_timer_data& timer,
+      std::size_t max_cancelled = (std::numeric_limits<std::size_t>::max)());
+
+  // Move the timer operations associated with the given timer.
+  template <typename Time_Traits>
+  void move_timer(timer_queue<Time_Traits>& queue,
+      typename timer_queue<Time_Traits>::per_timer_data& to,
+      typename timer_queue<Time_Traits>::per_timer_data& from);
+
+  // Get the concurrency hint that was used to initialise the io_context.
+  int concurrency_hint() const
+  {
+    return concurrency_hint_;
+  }
+
+private:
+#if defined(WINVER) && (WINVER < 0x0500)
+  typedef DWORD dword_ptr_t;
+  typedef ULONG ulong_ptr_t;
+#else // defined(WINVER) && (WINVER < 0x0500)
+  typedef DWORD_PTR dword_ptr_t;
+  typedef ULONG_PTR ulong_ptr_t;
+#endif // defined(WINVER) && (WINVER < 0x0500)
+
+  // Dequeues at most one operation from the I/O completion port, and then
+  // executes it. Returns the number of operations that were dequeued (i.e.
+  // either 0 or 1).
+  ASIO_DECL size_t do_one(DWORD msec,
+      win_iocp_thread_info& this_thread, asio::error_code& ec);
+
+  // Helper to calculate the GetQueuedCompletionStatus timeout.
+  ASIO_DECL static DWORD get_gqcs_timeout();
+
+  // Helper function to add a new timer queue.
+  ASIO_DECL void do_add_timer_queue(timer_queue_base& queue);
+
+  // Helper function to remove a timer queue.
+  ASIO_DECL void do_remove_timer_queue(timer_queue_base& queue);
+
+  // Called to recalculate and update the timeout.
+  ASIO_DECL void update_timeout();
+
+  // Helper class to call work_finished() on block exit.
+  struct work_finished_on_block_exit;
+
+  // Helper class for managing a HANDLE.
+  struct auto_handle
+  {
+    HANDLE handle;
+    auto_handle() : handle(0) {}
+    ~auto_handle() { if (handle) ::CloseHandle(handle); }
+  };
+
+  // The IO completion port used for queueing operations.
+  auto_handle iocp_;
+
+  // The count of unfinished work.
+  long outstanding_work_;
+
+  // Flag to indicate whether the event loop has been stopped.
+  mutable long stopped_;
+
+  // Flag to indicate whether there is an in-flight stop event. Every event
+  // posted using PostQueuedCompletionStatus consumes non-paged pool, so to
+  // avoid exhausting this resouce we limit the number of outstanding events.
+  long stop_event_posted_;
+
+  // Flag to indicate whether the service has been shut down.
+  long shutdown_;
+
+  enum
+  {
+    // Timeout to use with GetQueuedCompletionStatus on older versions of
+    // Windows. Some versions of windows have a "bug" where a call to
+    // GetQueuedCompletionStatus can appear stuck even though there are events
+    // waiting on the queue. Using a timeout helps to work around the issue.
+    default_gqcs_timeout = 500,
+
+    // Maximum waitable timer timeout, in milliseconds.
+    max_timeout_msec = 5 * 60 * 1000,
+
+    // Maximum waitable timer timeout, in microseconds.
+    max_timeout_usec = max_timeout_msec * 1000,
+
+    // Completion key value used to wake up a thread to dispatch timers or
+    // completed operations.
+    wake_for_dispatch = 1,
+
+    // Completion key value to indicate that an operation has posted with the
+    // original last_error and bytes_transferred values stored in the fields of
+    // the OVERLAPPED structure.
+    overlapped_contains_result = 2
+  };
+
+  // Timeout to use with GetQueuedCompletionStatus.
+  const DWORD gqcs_timeout_;
+
+  // Helper class to run the scheduler in its own thread.
+  struct thread_function;
+  friend struct thread_function;
+
+  // Function object for processing timeouts in a background thread.
+  struct timer_thread_function;
+  friend struct timer_thread_function;
+
+  // Background thread used for processing timeouts.
+  scoped_ptr<thread> timer_thread_;
+
+  // A waitable timer object used for waiting for timeouts.
+  auto_handle waitable_timer_;
+
+  // Non-zero if timers or completed operations need to be dispatched.
+  long dispatch_required_;
+
+  // Mutex for protecting access to the timer queues and completed operations.
+  mutex dispatch_mutex_;
+
+  // The timer queues.
+  timer_queue_set timer_queues_;
+
+  // The operations that are ready to dispatch.
+  op_queue<win_iocp_operation> completed_ops_;
+
+  // The concurrency hint used to initialise the io_context.
+  const int concurrency_hint_;
+
+  // The thread that is running the io_context.
+  scoped_ptr<thread> thread_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/detail/impl/win_iocp_io_context.hpp"
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/win_iocp_io_context.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // defined(ASIO_HAS_IOCP)
+
+#endif // ASIO_DETAIL_WIN_IOCP_IO_CONTEXT_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/win_iocp_null_buffers_op.hpp b/link/modules/asio-standalone/asio/include/asio/detail/win_iocp_null_buffers_op.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/win_iocp_null_buffers_op.hpp
@@ -0,0 +1,127 @@
+//
+// detail/win_iocp_null_buffers_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_WIN_IOCP_NULL_BUFFERS_OP_HPP
+#define ASIO_DETAIL_WIN_IOCP_NULL_BUFFERS_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_IOCP)
+
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/handler_work.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/detail/reactor_op.hpp"
+#include "asio/detail/socket_ops.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Handler, typename IoExecutor>
+class win_iocp_null_buffers_op : public reactor_op
+{
+public:
+  ASIO_DEFINE_HANDLER_PTR(win_iocp_null_buffers_op);
+
+  win_iocp_null_buffers_op(socket_ops::weak_cancel_token_type cancel_token,
+      Handler& handler, const IoExecutor& io_ex)
+    : reactor_op(asio::error_code(),
+        &win_iocp_null_buffers_op::do_perform,
+        &win_iocp_null_buffers_op::do_complete),
+      cancel_token_(cancel_token),
+      handler_(ASIO_MOVE_CAST(Handler)(handler)),
+      work_(handler_, io_ex)
+  {
+  }
+
+  static status do_perform(reactor_op*)
+  {
+    return done;
+  }
+
+  static void do_complete(void* owner, operation* base,
+      const asio::error_code& result_ec,
+      std::size_t bytes_transferred)
+  {
+    asio::error_code ec(result_ec);
+
+    // Take ownership of the operation object.
+    win_iocp_null_buffers_op* o(static_cast<win_iocp_null_buffers_op*>(base));
+    ptr p = { asio::detail::addressof(o->handler_), o, o };
+
+    ASIO_HANDLER_COMPLETION((*o));
+
+    // Take ownership of the operation's outstanding work.
+    handler_work<Handler, IoExecutor> w(
+        ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)(
+          o->work_));
+
+    // The reactor may have stored a result in the operation object.
+    if (o->ec_)
+      ec = o->ec_;
+
+    // Map non-portable errors to their portable counterparts.
+    if (ec.value() == ERROR_NETNAME_DELETED)
+    {
+      if (o->cancel_token_.expired())
+        ec = asio::error::operation_aborted;
+      else
+        ec = asio::error::connection_reset;
+    }
+    else if (ec.value() == ERROR_PORT_UNREACHABLE)
+    {
+      ec = asio::error::connection_refused;
+    }
+
+    // Make a copy of the handler so that the memory can be deallocated before
+    // the upcall is made. Even if we're not about to make an upcall, a
+    // sub-object of the handler may be the true owner of the memory associated
+    // with the handler. Consequently, a local copy of the handler is required
+    // to ensure that any owning sub-object remains valid until after we have
+    // deallocated the memory here.
+    detail::binder2<Handler, asio::error_code, std::size_t>
+      handler(o->handler_, ec, bytes_transferred);
+    p.h = asio::detail::addressof(handler.handler_);
+    p.reset();
+
+    // Make the upcall if required.
+    if (owner)
+    {
+      fenced_block b(fenced_block::half);
+      ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_));
+      w.complete(handler, handler.handler_);
+      ASIO_HANDLER_INVOCATION_END;
+    }
+  }
+
+private:
+  socket_ops::weak_cancel_token_type cancel_token_;
+  Handler handler_;
+  handler_work<Handler, IoExecutor> work_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_IOCP)
+
+#endif // ASIO_DETAIL_WIN_IOCP_NULL_BUFFERS_OP_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/win_iocp_operation.hpp b/link/modules/asio-standalone/asio/include/asio/detail/win_iocp_operation.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/win_iocp_operation.hpp
@@ -0,0 +1,96 @@
+//
+// detail/win_iocp_operation.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_WIN_IOCP_OPERATION_HPP
+#define ASIO_DETAIL_WIN_IOCP_OPERATION_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_IOCP)
+
+#include "asio/detail/handler_tracking.hpp"
+#include "asio/detail/op_queue.hpp"
+#include "asio/detail/socket_types.hpp"
+#include "asio/error_code.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class win_iocp_io_context;
+
+// Base class for all operations. A function pointer is used instead of virtual
+// functions to avoid the associated overhead.
+class win_iocp_operation
+  : public OVERLAPPED
+    ASIO_ALSO_INHERIT_TRACKED_HANDLER
+{
+public:
+  typedef win_iocp_operation operation_type;
+
+  void complete(void* owner, const asio::error_code& ec,
+      std::size_t bytes_transferred)
+  {
+    func_(owner, this, ec, bytes_transferred);
+  }
+
+  void destroy()
+  {
+    func_(0, this, asio::error_code(), 0);
+  }
+
+protected:
+  typedef void (*func_type)(
+      void*, win_iocp_operation*,
+      const asio::error_code&, std::size_t);
+
+  win_iocp_operation(func_type func)
+    : next_(0),
+      func_(func)
+  {
+    reset();
+  }
+
+  // Prevents deletion through this type.
+  ~win_iocp_operation()
+  {
+  }
+
+  void reset()
+  {
+    Internal = 0;
+    InternalHigh = 0;
+    Offset = 0;
+    OffsetHigh = 0;
+    hEvent = 0;
+    ready_ = 0;
+  }
+
+private:
+  friend class op_queue_access;
+  friend class win_iocp_io_context;
+  win_iocp_operation* next_;
+  func_type func_;
+  long ready_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_IOCP)
+
+#endif // ASIO_DETAIL_WIN_IOCP_OPERATION_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/win_iocp_overlapped_op.hpp b/link/modules/asio-standalone/asio/include/asio/detail/win_iocp_overlapped_op.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/win_iocp_overlapped_op.hpp
@@ -0,0 +1,96 @@
+//
+// detail/win_iocp_overlapped_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_WIN_IOCP_OVERLAPPED_OP_HPP
+#define ASIO_DETAIL_WIN_IOCP_OVERLAPPED_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_IOCP)
+
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/handler_work.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/detail/operation.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Handler, typename IoExecutor>
+class win_iocp_overlapped_op : public operation
+{
+public:
+  ASIO_DEFINE_HANDLER_PTR(win_iocp_overlapped_op);
+
+  win_iocp_overlapped_op(Handler& handler, const IoExecutor& io_ex)
+    : operation(&win_iocp_overlapped_op::do_complete),
+      handler_(ASIO_MOVE_CAST(Handler)(handler)),
+      work_(handler_, io_ex)
+  {
+  }
+
+  static void do_complete(void* owner, operation* base,
+      const asio::error_code& ec, std::size_t bytes_transferred)
+  {
+    // Take ownership of the operation object.
+    win_iocp_overlapped_op* o(static_cast<win_iocp_overlapped_op*>(base));
+    ptr p = { asio::detail::addressof(o->handler_), o, o };
+
+    ASIO_HANDLER_COMPLETION((*o));
+
+    // Take ownership of the operation's outstanding work.
+    handler_work<Handler, IoExecutor> w(
+        ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)(
+          o->work_));
+
+    // Make a copy of the handler so that the memory can be deallocated before
+    // the upcall is made. Even if we're not about to make an upcall, a
+    // sub-object of the handler may be the true owner of the memory associated
+    // with the handler. Consequently, a local copy of the handler is required
+    // to ensure that any owning sub-object remains valid until after we have
+    // deallocated the memory here.
+    detail::binder2<Handler, asio::error_code, std::size_t>
+      handler(o->handler_, ec, bytes_transferred);
+    p.h = asio::detail::addressof(handler.handler_);
+    p.reset();
+
+    // Make the upcall if required.
+    if (owner)
+    {
+      fenced_block b(fenced_block::half);
+      ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_));
+      w.complete(handler, handler.handler_);
+      ASIO_HANDLER_INVOCATION_END;
+    }
+  }
+
+private:
+  Handler handler_;
+  handler_work<Handler, IoExecutor> work_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_IOCP)
+
+#endif // ASIO_DETAIL_WIN_IOCP_OVERLAPPED_OP_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/win_iocp_overlapped_ptr.hpp b/link/modules/asio-standalone/asio/include/asio/detail/win_iocp_overlapped_ptr.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/win_iocp_overlapped_ptr.hpp
@@ -0,0 +1,171 @@
+//
+// detail/win_iocp_overlapped_ptr.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_WIN_IOCP_OVERLAPPED_PTR_HPP
+#define ASIO_DETAIL_WIN_IOCP_OVERLAPPED_PTR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_IOCP)
+
+#include "asio/io_context.hpp"
+#include "asio/query.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/detail/noncopyable.hpp"
+#include "asio/detail/win_iocp_overlapped_op.hpp"
+#include "asio/detail/win_iocp_io_context.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+// Wraps a handler to create an OVERLAPPED object for use with overlapped I/O.
+class win_iocp_overlapped_ptr
+  : private noncopyable
+{
+public:
+  // Construct an empty win_iocp_overlapped_ptr.
+  win_iocp_overlapped_ptr()
+    : ptr_(0),
+      iocp_service_(0)
+  {
+  }
+
+  // Construct an win_iocp_overlapped_ptr to contain the specified handler.
+  template <typename Executor, typename Handler>
+  explicit win_iocp_overlapped_ptr(const Executor& ex,
+      ASIO_MOVE_ARG(Handler) handler)
+    : ptr_(0),
+      iocp_service_(0)
+  {
+    this->reset(ex, ASIO_MOVE_CAST(Handler)(handler));
+  }
+
+  // Destructor automatically frees the OVERLAPPED object unless released.
+  ~win_iocp_overlapped_ptr()
+  {
+    reset();
+  }
+
+  // Reset to empty.
+  void reset()
+  {
+    if (ptr_)
+    {
+      ptr_->destroy();
+      ptr_ = 0;
+      iocp_service_->work_finished();
+      iocp_service_ = 0;
+    }
+  }
+
+  // Reset to contain the specified handler, freeing any current OVERLAPPED
+  // object.
+  template <typename Executor, typename Handler>
+  void reset(const Executor& ex, Handler handler)
+  {
+    win_iocp_io_context* iocp_service = this->get_iocp_service(ex);
+
+    typedef win_iocp_overlapped_op<Handler, Executor> op;
+    typename op::ptr p = { asio::detail::addressof(handler),
+      op::ptr::allocate(handler), 0 };
+    p.p = new (p.v) op(handler, ex);
+
+    ASIO_HANDLER_CREATION((ex.context(), *p.p,
+          "iocp_service", iocp_service, 0, "overlapped"));
+
+    iocp_service->work_started();
+    reset();
+    ptr_ = p.p;
+    p.v = p.p = 0;
+    iocp_service_ = iocp_service;
+  }
+
+  // Get the contained OVERLAPPED object.
+  OVERLAPPED* get()
+  {
+    return ptr_;
+  }
+
+  // Get the contained OVERLAPPED object.
+  const OVERLAPPED* get() const
+  {
+    return ptr_;
+  }
+
+  // Release ownership of the OVERLAPPED object.
+  OVERLAPPED* release()
+  {
+    if (ptr_)
+      iocp_service_->on_pending(ptr_);
+
+    OVERLAPPED* tmp = ptr_;
+    ptr_ = 0;
+    iocp_service_ = 0;
+    return tmp;
+  }
+
+  // Post completion notification for overlapped operation. Releases ownership.
+  void complete(const asio::error_code& ec,
+      std::size_t bytes_transferred)
+  {
+    if (ptr_)
+    {
+      iocp_service_->on_completion(ptr_, ec,
+          static_cast<DWORD>(bytes_transferred));
+      ptr_ = 0;
+      iocp_service_ = 0;
+    }
+  }
+
+private:
+  template <typename Executor>
+  static win_iocp_io_context* get_iocp_service(const Executor& ex,
+      typename enable_if<
+        can_query<const Executor&, execution::context_t>::value
+      >::type* = 0)
+  {
+    return &use_service<win_iocp_io_context>(
+        asio::query(ex, execution::context));
+  }
+
+  template <typename Executor>
+  static win_iocp_io_context* get_iocp_service(const Executor& ex,
+      typename enable_if<
+        !can_query<const Executor&, execution::context_t>::value
+      >::type* = 0)
+  {
+    return &use_service<win_iocp_io_context>(ex.context());
+  }
+
+  static win_iocp_io_context* get_iocp_service(
+      const io_context::executor_type& ex)
+  {
+    return &asio::query(ex, execution::context).impl_;
+  }
+
+  win_iocp_operation* ptr_;
+  win_iocp_io_context* iocp_service_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_IOCP)
+
+#endif // ASIO_DETAIL_WIN_IOCP_OVERLAPPED_PTR_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/win_iocp_serial_port_service.hpp b/link/modules/asio-standalone/asio/include/asio/detail/win_iocp_serial_port_service.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/win_iocp_serial_port_service.hpp
@@ -0,0 +1,232 @@
+//
+// detail/win_iocp_serial_port_service.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.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 ASIO_DETAIL_WIN_IOCP_SERIAL_PORT_SERVICE_HPP
+#define ASIO_DETAIL_WIN_IOCP_SERIAL_PORT_SERVICE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_IOCP) && defined(ASIO_HAS_SERIAL_PORT)
+
+#include <string>
+#include "asio/error.hpp"
+#include "asio/execution_context.hpp"
+#include "asio/detail/win_iocp_handle_service.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+// Extend win_iocp_handle_service to provide serial port support.
+class win_iocp_serial_port_service :
+  public execution_context_service_base<win_iocp_serial_port_service>
+{
+public:
+  // The native type of a serial port.
+  typedef win_iocp_handle_service::native_handle_type native_handle_type;
+
+  // The implementation type of the serial port.
+  typedef win_iocp_handle_service::implementation_type implementation_type;
+
+  // Constructor.
+  ASIO_DECL win_iocp_serial_port_service(execution_context& context);
+
+  // Destroy all user-defined handler objects owned by the service.
+  ASIO_DECL void shutdown();
+
+  // Construct a new serial port implementation.
+  void construct(implementation_type& impl)
+  {
+    handle_service_.construct(impl);
+  }
+
+  // Move-construct a new serial port implementation.
+  void move_construct(implementation_type& impl,
+      implementation_type& other_impl)
+  {
+    handle_service_.move_construct(impl, other_impl);
+  }
+
+  // Move-assign from another serial port implementation.
+  void move_assign(implementation_type& impl,
+      win_iocp_serial_port_service& other_service,
+      implementation_type& other_impl)
+  {
+    handle_service_.move_assign(impl,
+        other_service.handle_service_, other_impl);
+  }
+
+  // Destroy a serial port implementation.
+  void destroy(implementation_type& impl)
+  {
+    handle_service_.destroy(impl);
+  }
+
+  // Open the serial port using the specified device name.
+  ASIO_DECL asio::error_code open(implementation_type& impl,
+      const std::string& device, asio::error_code& ec);
+
+  // Assign a native handle to a serial port implementation.
+  asio::error_code assign(implementation_type& impl,
+      const native_handle_type& handle, asio::error_code& ec)
+  {
+    return handle_service_.assign(impl, handle, ec);
+  }
+
+  // Determine whether the serial port is open.
+  bool is_open(const implementation_type& impl) const
+  {
+    return handle_service_.is_open(impl);
+  }
+
+  // Destroy a serial port implementation.
+  asio::error_code close(implementation_type& impl,
+      asio::error_code& ec)
+  {
+    return handle_service_.close(impl, ec);
+  }
+
+  // Get the native serial port representation.
+  native_handle_type native_handle(implementation_type& impl)
+  {
+    return handle_service_.native_handle(impl);
+  }
+
+  // Cancel all operations associated with the handle.
+  asio::error_code cancel(implementation_type& impl,
+      asio::error_code& ec)
+  {
+    return handle_service_.cancel(impl, ec);
+  }
+
+  // Set an option on the serial port.
+  template <typename SettableSerialPortOption>
+  asio::error_code set_option(implementation_type& impl,
+      const SettableSerialPortOption& option, asio::error_code& ec)
+  {
+    return do_set_option(impl,
+        &win_iocp_serial_port_service::store_option<SettableSerialPortOption>,
+        &option, ec);
+  }
+
+  // Get an option from the serial port.
+  template <typename GettableSerialPortOption>
+  asio::error_code get_option(const implementation_type& impl,
+      GettableSerialPortOption& option, asio::error_code& ec) const
+  {
+    return do_get_option(impl,
+        &win_iocp_serial_port_service::load_option<GettableSerialPortOption>,
+        &option, ec);
+  }
+
+  // Send a break sequence to the serial port.
+  asio::error_code send_break(implementation_type&,
+      asio::error_code& ec)
+  {
+    ec = asio::error::operation_not_supported;
+    return ec;
+  }
+
+  // Write the given data. Returns the number of bytes sent.
+  template <typename ConstBufferSequence>
+  size_t write_some(implementation_type& impl,
+      const ConstBufferSequence& buffers, asio::error_code& ec)
+  {
+    return handle_service_.write_some(impl, buffers, ec);
+  }
+
+  // Start an asynchronous write. The data being written must be valid for the
+  // lifetime of the asynchronous operation.
+  template <typename ConstBufferSequence, typename Handler, typename IoExecutor>
+  void async_write_some(implementation_type& impl,
+      const ConstBufferSequence& buffers,
+      Handler& handler, const IoExecutor& io_ex)
+  {
+    handle_service_.async_write_some(impl, buffers, handler, io_ex);
+  }
+
+  // Read some data. Returns the number of bytes received.
+  template <typename MutableBufferSequence>
+  size_t read_some(implementation_type& impl,
+      const MutableBufferSequence& buffers, asio::error_code& ec)
+  {
+    return handle_service_.read_some(impl, buffers, ec);
+  }
+
+  // Start an asynchronous read. The buffer for the data being received must be
+  // valid for the lifetime of the asynchronous operation.
+  template <typename MutableBufferSequence,
+      typename Handler, typename IoExecutor>
+  void async_read_some(implementation_type& impl,
+      const MutableBufferSequence& buffers,
+      Handler& handler, const IoExecutor& io_ex)
+  {
+    handle_service_.async_read_some(impl, buffers, handler, io_ex);
+  }
+
+private:
+  // Function pointer type for storing a serial port option.
+  typedef asio::error_code (*store_function_type)(
+      const void*, ::DCB&, asio::error_code&);
+
+  // Helper function template to store a serial port option.
+  template <typename SettableSerialPortOption>
+  static asio::error_code store_option(const void* option,
+      ::DCB& storage, asio::error_code& ec)
+  {
+    static_cast<const SettableSerialPortOption*>(option)->store(storage, ec);
+    return ec;
+  }
+
+  // Helper function to set a serial port option.
+  ASIO_DECL asio::error_code do_set_option(
+      implementation_type& impl, store_function_type store,
+      const void* option, asio::error_code& ec);
+
+  // Function pointer type for loading a serial port option.
+  typedef asio::error_code (*load_function_type)(
+      void*, const ::DCB&, asio::error_code&);
+
+  // Helper function template to load a serial port option.
+  template <typename GettableSerialPortOption>
+  static asio::error_code load_option(void* option,
+      const ::DCB& storage, asio::error_code& ec)
+  {
+    static_cast<GettableSerialPortOption*>(option)->load(storage, ec);
+    return ec;
+  }
+
+  // Helper function to get a serial port option.
+  ASIO_DECL asio::error_code do_get_option(
+      const implementation_type& impl, load_function_type load,
+      void* option, asio::error_code& ec) const;
+
+  // The implementation used for initiating asynchronous operations.
+  win_iocp_handle_service handle_service_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/win_iocp_serial_port_service.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // defined(ASIO_HAS_IOCP) && defined(ASIO_HAS_SERIAL_PORT)
+
+#endif // ASIO_DETAIL_WIN_IOCP_SERIAL_PORT_SERVICE_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/win_iocp_socket_accept_op.hpp b/link/modules/asio-standalone/asio/include/asio/detail/win_iocp_socket_accept_op.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/win_iocp_socket_accept_op.hpp
@@ -0,0 +1,312 @@
+//
+// detail/win_iocp_socket_accept_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_WIN_IOCP_SOCKET_ACCEPT_OP_HPP
+#define ASIO_DETAIL_WIN_IOCP_SOCKET_ACCEPT_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_IOCP)
+
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/handler_work.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/detail/operation.hpp"
+#include "asio/detail/socket_ops.hpp"
+#include "asio/detail/win_iocp_socket_service_base.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Socket, typename Protocol,
+    typename Handler, typename IoExecutor>
+class win_iocp_socket_accept_op : public operation
+{
+public:
+  ASIO_DEFINE_HANDLER_PTR(win_iocp_socket_accept_op);
+
+  win_iocp_socket_accept_op(win_iocp_socket_service_base& socket_service,
+      socket_type socket, Socket& peer, const Protocol& protocol,
+      typename Protocol::endpoint* peer_endpoint,
+      bool enable_connection_aborted, Handler& handler, const IoExecutor& io_ex)
+    : operation(&win_iocp_socket_accept_op::do_complete),
+      socket_service_(socket_service),
+      socket_(socket),
+      peer_(peer),
+      protocol_(protocol),
+      peer_endpoint_(peer_endpoint),
+      enable_connection_aborted_(enable_connection_aborted),
+      handler_(ASIO_MOVE_CAST(Handler)(handler)),
+      work_(handler_, io_ex)
+  {
+  }
+
+  socket_holder& new_socket()
+  {
+    return new_socket_;
+  }
+
+  void* output_buffer()
+  {
+    return output_buffer_;
+  }
+
+  DWORD address_length()
+  {
+    return sizeof(sockaddr_storage_type) + 16;
+  }
+
+  static void do_complete(void* owner, operation* base,
+      const asio::error_code& result_ec,
+      std::size_t /*bytes_transferred*/)
+  {
+    asio::error_code ec(result_ec);
+
+    // Take ownership of the operation object.
+    win_iocp_socket_accept_op* o(static_cast<win_iocp_socket_accept_op*>(base));
+    ptr p = { asio::detail::addressof(o->handler_), o, o };
+
+    if (owner)
+    {
+      typename Protocol::endpoint peer_endpoint;
+      std::size_t addr_len = peer_endpoint.capacity();
+      socket_ops::complete_iocp_accept(o->socket_,
+          o->output_buffer(), o->address_length(),
+          peer_endpoint.data(), &addr_len,
+          o->new_socket_.get(), ec);
+
+      // Restart the accept operation if we got the connection_aborted error
+      // and the enable_connection_aborted socket option is not set.
+      if (ec == asio::error::connection_aborted
+          && !o->enable_connection_aborted_)
+      {
+        o->reset();
+        o->socket_service_.restart_accept_op(o->socket_,
+            o->new_socket_, o->protocol_.family(),
+            o->protocol_.type(), o->protocol_.protocol(),
+            o->output_buffer(), o->address_length(), o);
+        p.v = p.p = 0;
+        return;
+      }
+
+      // If the socket was successfully accepted, transfer ownership of the
+      // socket to the peer object.
+      if (!ec)
+      {
+        o->peer_.assign(o->protocol_,
+            typename Socket::native_handle_type(
+              o->new_socket_.get(), peer_endpoint), ec);
+        if (!ec)
+          o->new_socket_.release();
+      }
+
+      // Pass endpoint back to caller.
+      if (o->peer_endpoint_)
+        *o->peer_endpoint_ = peer_endpoint;
+    }
+
+    ASIO_HANDLER_COMPLETION((*o));
+
+    // Take ownership of the operation's outstanding work.
+    handler_work<Handler, IoExecutor> w(
+        ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)(
+          o->work_));
+
+    // Make a copy of the handler so that the memory can be deallocated before
+    // the upcall is made. Even if we're not about to make an upcall, a
+    // sub-object of the handler may be the true owner of the memory associated
+    // with the handler. Consequently, a local copy of the handler is required
+    // to ensure that any owning sub-object remains valid until after we have
+    // deallocated the memory here.
+    detail::binder1<Handler, asio::error_code>
+      handler(o->handler_, ec);
+    p.h = asio::detail::addressof(handler.handler_);
+    p.reset();
+
+    // Make the upcall if required.
+    if (owner)
+    {
+      fenced_block b(fenced_block::half);
+      ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_));
+      w.complete(handler, handler.handler_);
+      ASIO_HANDLER_INVOCATION_END;
+    }
+  }
+
+private:
+  win_iocp_socket_service_base& socket_service_;
+  socket_type socket_;
+  socket_holder new_socket_;
+  Socket& peer_;
+  Protocol protocol_;
+  typename Protocol::endpoint* peer_endpoint_;
+  unsigned char output_buffer_[(sizeof(sockaddr_storage_type) + 16) * 2];
+  bool enable_connection_aborted_;
+  Handler handler_;
+  handler_work<Handler, IoExecutor> work_;
+};
+
+#if defined(ASIO_HAS_MOVE)
+
+template <typename Protocol, typename PeerIoExecutor,
+    typename Handler, typename IoExecutor>
+class win_iocp_socket_move_accept_op : public operation
+{
+public:
+  ASIO_DEFINE_HANDLER_PTR(win_iocp_socket_move_accept_op);
+
+  win_iocp_socket_move_accept_op(
+      win_iocp_socket_service_base& socket_service, socket_type socket,
+      const Protocol& protocol, const PeerIoExecutor& peer_io_ex,
+      typename Protocol::endpoint* peer_endpoint,
+      bool enable_connection_aborted, Handler& handler, const IoExecutor& io_ex)
+    : operation(&win_iocp_socket_move_accept_op::do_complete),
+      socket_service_(socket_service),
+      socket_(socket),
+      peer_(peer_io_ex),
+      protocol_(protocol),
+      peer_endpoint_(peer_endpoint),
+      enable_connection_aborted_(enable_connection_aborted),
+      handler_(ASIO_MOVE_CAST(Handler)(handler)),
+      work_(handler_, io_ex)
+  {
+  }
+
+  socket_holder& new_socket()
+  {
+    return new_socket_;
+  }
+
+  void* output_buffer()
+  {
+    return output_buffer_;
+  }
+
+  DWORD address_length()
+  {
+    return sizeof(sockaddr_storage_type) + 16;
+  }
+
+  static void do_complete(void* owner, operation* base,
+      const asio::error_code& result_ec,
+      std::size_t /*bytes_transferred*/)
+  {
+    asio::error_code ec(result_ec);
+
+    // Take ownership of the operation object.
+    win_iocp_socket_move_accept_op* o(
+        static_cast<win_iocp_socket_move_accept_op*>(base));
+    ptr p = { asio::detail::addressof(o->handler_), o, o };
+
+    if (owner)
+    {
+      typename Protocol::endpoint peer_endpoint;
+      std::size_t addr_len = peer_endpoint.capacity();
+      socket_ops::complete_iocp_accept(o->socket_,
+          o->output_buffer(), o->address_length(),
+          peer_endpoint.data(), &addr_len,
+          o->new_socket_.get(), ec);
+
+      // Restart the accept operation if we got the connection_aborted error
+      // and the enable_connection_aborted socket option is not set.
+      if (ec == asio::error::connection_aborted
+          && !o->enable_connection_aborted_)
+      {
+        o->reset();
+        o->socket_service_.restart_accept_op(o->socket_,
+            o->new_socket_, o->protocol_.family(),
+            o->protocol_.type(), o->protocol_.protocol(),
+            o->output_buffer(), o->address_length(), o);
+        p.v = p.p = 0;
+        return;
+      }
+
+      // If the socket was successfully accepted, transfer ownership of the
+      // socket to the peer object.
+      if (!ec)
+      {
+        o->peer_.assign(o->protocol_,
+            typename Protocol::socket::native_handle_type(
+              o->new_socket_.get(), peer_endpoint), ec);
+        if (!ec)
+          o->new_socket_.release();
+      }
+
+      // Pass endpoint back to caller.
+      if (o->peer_endpoint_)
+        *o->peer_endpoint_ = peer_endpoint;
+    }
+
+    ASIO_HANDLER_COMPLETION((*o));
+
+    // Take ownership of the operation's outstanding work.
+    handler_work<Handler, IoExecutor> w(
+        ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)(
+          o->work_));
+
+    // Make a copy of the handler so that the memory can be deallocated before
+    // the upcall is made. Even if we're not about to make an upcall, a
+    // sub-object of the handler may be the true owner of the memory associated
+    // with the handler. Consequently, a local copy of the handler is required
+    // to ensure that any owning sub-object remains valid until after we have
+    // deallocated the memory here.
+    detail::move_binder2<Handler,
+      asio::error_code, peer_socket_type>
+        handler(0, ASIO_MOVE_CAST(Handler)(o->handler_), ec,
+          ASIO_MOVE_CAST(peer_socket_type)(o->peer_));
+    p.h = asio::detail::addressof(handler.handler_);
+    p.reset();
+
+    // Make the upcall if required.
+    if (owner)
+    {
+      fenced_block b(fenced_block::half);
+      ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, "..."));
+      w.complete(handler, handler.handler_);
+      ASIO_HANDLER_INVOCATION_END;
+    }
+  }
+
+private:
+  typedef typename Protocol::socket::template
+    rebind_executor<PeerIoExecutor>::other peer_socket_type;
+
+  win_iocp_socket_service_base& socket_service_;
+  socket_type socket_;
+  socket_holder new_socket_;
+  peer_socket_type peer_;
+  Protocol protocol_;
+  typename Protocol::endpoint* peer_endpoint_;
+  unsigned char output_buffer_[(sizeof(sockaddr_storage_type) + 16) * 2];
+  bool enable_connection_aborted_;
+  Handler handler_;
+  handler_work<Handler, IoExecutor> work_;
+};
+
+#endif // defined(ASIO_HAS_MOVE)
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_IOCP)
+
+#endif // ASIO_DETAIL_WIN_IOCP_SOCKET_ACCEPT_OP_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/win_iocp_socket_connect_op.hpp b/link/modules/asio-standalone/asio/include/asio/detail/win_iocp_socket_connect_op.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/win_iocp_socket_connect_op.hpp
@@ -0,0 +1,135 @@
+//
+// detail/win_iocp_socket_connect_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_WIN_IOCP_SOCKET_CONNECT_OP_HPP
+#define ASIO_DETAIL_WIN_IOCP_SOCKET_CONNECT_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_IOCP)
+
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/handler_work.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/detail/reactor_op.hpp"
+#include "asio/detail/socket_ops.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class win_iocp_socket_connect_op_base : public reactor_op
+{
+public:
+  win_iocp_socket_connect_op_base(socket_type socket, func_type complete_func)
+    : reactor_op(asio::error_code(),
+        &win_iocp_socket_connect_op_base::do_perform, complete_func),
+      socket_(socket),
+      connect_ex_(false)
+  {
+  }
+
+  static status do_perform(reactor_op* base)
+  {
+    win_iocp_socket_connect_op_base* o(
+        static_cast<win_iocp_socket_connect_op_base*>(base));
+
+    return socket_ops::non_blocking_connect(
+        o->socket_, o->ec_) ? done : not_done;
+  }
+
+  socket_type socket_;
+  bool connect_ex_;
+};
+
+template <typename Handler, typename IoExecutor>
+class win_iocp_socket_connect_op : public win_iocp_socket_connect_op_base
+{
+public:
+  ASIO_DEFINE_HANDLER_PTR(win_iocp_socket_connect_op);
+
+  win_iocp_socket_connect_op(socket_type socket,
+      Handler& handler, const IoExecutor& io_ex)
+    : win_iocp_socket_connect_op_base(socket,
+        &win_iocp_socket_connect_op::do_complete),
+      handler_(ASIO_MOVE_CAST(Handler)(handler)),
+      work_(handler_, io_ex)
+  {
+  }
+
+  static void do_complete(void* owner, operation* base,
+      const asio::error_code& result_ec,
+      std::size_t /*bytes_transferred*/)
+  {
+    asio::error_code ec(result_ec);
+
+    // Take ownership of the operation object.
+    win_iocp_socket_connect_op* o(
+        static_cast<win_iocp_socket_connect_op*>(base));
+    ptr p = { asio::detail::addressof(o->handler_), o, o };
+
+    if (owner)
+    {
+      if (o->connect_ex_)
+        socket_ops::complete_iocp_connect(o->socket_, ec);
+      else
+        ec = o->ec_;
+    }
+
+    ASIO_HANDLER_COMPLETION((*o));
+
+    // Take ownership of the operation's outstanding work.
+    handler_work<Handler, IoExecutor> w(
+        ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)(
+          o->work_));
+
+    // Make a copy of the handler so that the memory can be deallocated before
+    // the upcall is made. Even if we're not about to make an upcall, a
+    // sub-object of the handler may be the true owner of the memory associated
+    // with the handler. Consequently, a local copy of the handler is required
+    // to ensure that any owning sub-object remains valid until after we have
+    // deallocated the memory here.
+    detail::binder1<Handler, asio::error_code>
+      handler(o->handler_, ec);
+    p.h = asio::detail::addressof(handler.handler_);
+    p.reset();
+
+    // Make the upcall if required.
+    if (owner)
+    {
+      fenced_block b(fenced_block::half);
+      ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_));
+      w.complete(handler, handler.handler_);
+      ASIO_HANDLER_INVOCATION_END;
+    }
+  }
+
+private:
+  Handler handler_;
+  handler_work<Handler, IoExecutor> work_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_IOCP)
+
+#endif // ASIO_DETAIL_WIN_IOCP_SOCKET_CONNECT_OP_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/win_iocp_socket_recv_op.hpp b/link/modules/asio-standalone/asio/include/asio/detail/win_iocp_socket_recv_op.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/win_iocp_socket_recv_op.hpp
@@ -0,0 +1,124 @@
+//
+// detail/win_iocp_socket_recv_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_WIN_IOCP_SOCKET_RECV_OP_HPP
+#define ASIO_DETAIL_WIN_IOCP_SOCKET_RECV_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_IOCP)
+
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/buffer_sequence_adapter.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/handler_work.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/detail/operation.hpp"
+#include "asio/detail/socket_ops.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename MutableBufferSequence, typename Handler, typename IoExecutor>
+class win_iocp_socket_recv_op : public operation
+{
+public:
+  ASIO_DEFINE_HANDLER_PTR(win_iocp_socket_recv_op);
+
+  win_iocp_socket_recv_op(socket_ops::state_type state,
+      socket_ops::weak_cancel_token_type cancel_token,
+      const MutableBufferSequence& buffers, Handler& handler,
+      const IoExecutor& io_ex)
+    : operation(&win_iocp_socket_recv_op::do_complete),
+      state_(state),
+      cancel_token_(cancel_token),
+      buffers_(buffers),
+      handler_(ASIO_MOVE_CAST(Handler)(handler)),
+      work_(handler_, io_ex)
+  {
+  }
+
+  static void do_complete(void* owner, operation* base,
+      const asio::error_code& result_ec,
+      std::size_t bytes_transferred)
+  {
+    asio::error_code ec(result_ec);
+
+    // Take ownership of the operation object.
+    win_iocp_socket_recv_op* o(static_cast<win_iocp_socket_recv_op*>(base));
+    ptr p = { asio::detail::addressof(o->handler_), o, o };
+
+    ASIO_HANDLER_COMPLETION((*o));
+
+    // Take ownership of the operation's outstanding work.
+    handler_work<Handler, IoExecutor> w(
+        ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)(
+          o->work_));
+
+#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
+    // Check whether buffers are still valid.
+    if (owner)
+    {
+      buffer_sequence_adapter<asio::mutable_buffer,
+          MutableBufferSequence>::validate(o->buffers_);
+    }
+#endif // defined(ASIO_ENABLE_BUFFER_DEBUGGING)
+
+    socket_ops::complete_iocp_recv(o->state_, o->cancel_token_,
+        buffer_sequence_adapter<asio::mutable_buffer,
+          MutableBufferSequence>::all_empty(o->buffers_),
+        ec, bytes_transferred);
+
+    // Make a copy of the handler so that the memory can be deallocated before
+    // the upcall is made. Even if we're not about to make an upcall, a
+    // sub-object of the handler may be the true owner of the memory associated
+    // with the handler. Consequently, a local copy of the handler is required
+    // to ensure that any owning sub-object remains valid until after we have
+    // deallocated the memory here.
+    detail::binder2<Handler, asio::error_code, std::size_t>
+      handler(o->handler_, ec, bytes_transferred);
+    p.h = asio::detail::addressof(handler.handler_);
+    p.reset();
+
+    // Make the upcall if required.
+    if (owner)
+    {
+      fenced_block b(fenced_block::half);
+      ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_));
+      w.complete(handler, handler.handler_);
+      ASIO_HANDLER_INVOCATION_END;
+    }
+  }
+
+private:
+  socket_ops::state_type state_;
+  socket_ops::weak_cancel_token_type cancel_token_;
+  MutableBufferSequence buffers_;
+  Handler handler_;
+  handler_work<Handler, IoExecutor> work_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_IOCP)
+
+#endif // ASIO_DETAIL_WIN_IOCP_SOCKET_RECV_OP_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/win_iocp_socket_recvfrom_op.hpp b/link/modules/asio-standalone/asio/include/asio/detail/win_iocp_socket_recvfrom_op.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/win_iocp_socket_recvfrom_op.hpp
@@ -0,0 +1,133 @@
+//
+// detail/win_iocp_socket_recvfrom_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_WIN_IOCP_SOCKET_RECVFROM_OP_HPP
+#define ASIO_DETAIL_WIN_IOCP_SOCKET_RECVFROM_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_IOCP)
+
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/buffer_sequence_adapter.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/handler_work.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/detail/operation.hpp"
+#include "asio/detail/socket_ops.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename MutableBufferSequence, typename Endpoint,
+    typename Handler, typename IoExecutor>
+class win_iocp_socket_recvfrom_op : public operation
+{
+public:
+  ASIO_DEFINE_HANDLER_PTR(win_iocp_socket_recvfrom_op);
+
+  win_iocp_socket_recvfrom_op(Endpoint& endpoint,
+      socket_ops::weak_cancel_token_type cancel_token,
+      const MutableBufferSequence& buffers, Handler& handler,
+      const IoExecutor& io_ex)
+    : operation(&win_iocp_socket_recvfrom_op::do_complete),
+      endpoint_(endpoint),
+      endpoint_size_(static_cast<int>(endpoint.capacity())),
+      cancel_token_(cancel_token),
+      buffers_(buffers),
+      handler_(ASIO_MOVE_CAST(Handler)(handler)),
+      work_(handler_, io_ex)
+  {
+  }
+
+  int& endpoint_size()
+  {
+    return endpoint_size_;
+  }
+
+  static void do_complete(void* owner, operation* base,
+      const asio::error_code& result_ec,
+      std::size_t bytes_transferred)
+  {
+    asio::error_code ec(result_ec);
+
+    // Take ownership of the operation object.
+    win_iocp_socket_recvfrom_op* o(
+        static_cast<win_iocp_socket_recvfrom_op*>(base));
+    ptr p = { asio::detail::addressof(o->handler_), o, o };
+
+    ASIO_HANDLER_COMPLETION((*o));
+
+    // Take ownership of the operation's outstanding work.
+    handler_work<Handler, IoExecutor> w(
+        ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)(
+          o->work_));
+
+#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
+    // Check whether buffers are still valid.
+    if (owner)
+    {
+      buffer_sequence_adapter<asio::mutable_buffer,
+          MutableBufferSequence>::validate(o->buffers_);
+    }
+#endif // defined(ASIO_ENABLE_BUFFER_DEBUGGING)
+
+    socket_ops::complete_iocp_recvfrom(o->cancel_token_, ec);
+
+    // Record the size of the endpoint returned by the operation.
+    o->endpoint_.resize(o->endpoint_size_);
+
+    // Make a copy of the handler so that the memory can be deallocated before
+    // the upcall is made. Even if we're not about to make an upcall, a
+    // sub-object of the handler may be the true owner of the memory associated
+    // with the handler. Consequently, a local copy of the handler is required
+    // to ensure that any owning sub-object remains valid until after we have
+    // deallocated the memory here.
+    detail::binder2<Handler, asio::error_code, std::size_t>
+      handler(o->handler_, ec, bytes_transferred);
+    p.h = asio::detail::addressof(handler.handler_);
+    p.reset();
+
+    // Make the upcall if required.
+    if (owner)
+    {
+      fenced_block b(fenced_block::half);
+      ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_));
+      w.complete(handler, handler.handler_);
+      ASIO_HANDLER_INVOCATION_END;
+    }
+  }
+
+private:
+  Endpoint& endpoint_;
+  int endpoint_size_;
+  socket_ops::weak_cancel_token_type cancel_token_;
+  MutableBufferSequence buffers_;
+  Handler handler_;
+  handler_work<Handler, IoExecutor> work_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_IOCP)
+
+#endif // ASIO_DETAIL_WIN_IOCP_SOCKET_RECVFROM_OP_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/win_iocp_socket_recvmsg_op.hpp b/link/modules/asio-standalone/asio/include/asio/detail/win_iocp_socket_recvmsg_op.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/win_iocp_socket_recvmsg_op.hpp
@@ -0,0 +1,125 @@
+//
+// detail/win_iocp_socket_recvmsg_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_WIN_IOCP_SOCKET_RECVMSG_OP_HPP
+#define ASIO_DETAIL_WIN_IOCP_SOCKET_RECVMSG_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_IOCP)
+
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/buffer_sequence_adapter.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/handler_work.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/detail/operation.hpp"
+#include "asio/detail/socket_ops.hpp"
+#include "asio/error.hpp"
+#include "asio/socket_base.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename MutableBufferSequence, typename Handler, typename IoExecutor>
+class win_iocp_socket_recvmsg_op : public operation
+{
+public:
+  ASIO_DEFINE_HANDLER_PTR(win_iocp_socket_recvmsg_op);
+
+  win_iocp_socket_recvmsg_op(
+      socket_ops::weak_cancel_token_type cancel_token,
+      const MutableBufferSequence& buffers,
+      socket_base::message_flags& out_flags,
+      Handler& handler, const IoExecutor& io_ex)
+    : operation(&win_iocp_socket_recvmsg_op::do_complete),
+      cancel_token_(cancel_token),
+      buffers_(buffers),
+      out_flags_(out_flags),
+      handler_(ASIO_MOVE_CAST(Handler)(handler)),
+      work_(handler_, io_ex)
+  {
+  }
+
+  static void do_complete(void* owner, operation* base,
+      const asio::error_code& result_ec,
+      std::size_t bytes_transferred)
+  {
+    asio::error_code ec(result_ec);
+
+    // Take ownership of the operation object.
+    win_iocp_socket_recvmsg_op* o(
+        static_cast<win_iocp_socket_recvmsg_op*>(base));
+    ptr p = { asio::detail::addressof(o->handler_), o, o };
+
+    ASIO_HANDLER_COMPLETION((*o));
+
+    // Take ownership of the operation's outstanding work.
+    handler_work<Handler, IoExecutor> w(
+        ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)(
+          o->work_));
+
+#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
+    // Check whether buffers are still valid.
+    if (owner)
+    {
+      buffer_sequence_adapter<asio::mutable_buffer,
+          MutableBufferSequence>::validate(o->buffers_);
+    }
+#endif // defined(ASIO_ENABLE_BUFFER_DEBUGGING)
+
+    socket_ops::complete_iocp_recvmsg(o->cancel_token_, ec);
+    o->out_flags_ = 0;
+
+    // Make a copy of the handler so that the memory can be deallocated before
+    // the upcall is made. Even if we're not about to make an upcall, a
+    // sub-object of the handler may be the true owner of the memory associated
+    // with the handler. Consequently, a local copy of the handler is required
+    // to ensure that any owning sub-object remains valid until after we have
+    // deallocated the memory here.
+    detail::binder2<Handler, asio::error_code, std::size_t>
+      handler(o->handler_, ec, bytes_transferred);
+    p.h = asio::detail::addressof(handler.handler_);
+    p.reset();
+
+    // Make the upcall if required.
+    if (owner)
+    {
+      fenced_block b(fenced_block::half);
+      ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_));
+      w.complete(handler, handler.handler_);
+      ASIO_HANDLER_INVOCATION_END;
+    }
+  }
+
+private:
+  socket_ops::weak_cancel_token_type cancel_token_;
+  MutableBufferSequence buffers_;
+  socket_base::message_flags& out_flags_;
+  Handler handler_;
+  handler_work<Handler, IoExecutor> work_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_IOCP)
+
+#endif // ASIO_DETAIL_WIN_IOCP_SOCKET_RECVMSG_OP_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/win_iocp_socket_send_op.hpp b/link/modules/asio-standalone/asio/include/asio/detail/win_iocp_socket_send_op.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/win_iocp_socket_send_op.hpp
@@ -0,0 +1,118 @@
+//
+// detail/win_iocp_socket_send_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_WIN_IOCP_SOCKET_SEND_OP_HPP
+#define ASIO_DETAIL_WIN_IOCP_SOCKET_SEND_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_IOCP)
+
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/buffer_sequence_adapter.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/handler_work.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/detail/operation.hpp"
+#include "asio/detail/socket_ops.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename ConstBufferSequence, typename Handler, typename IoExecutor>
+class win_iocp_socket_send_op : public operation
+{
+public:
+  ASIO_DEFINE_HANDLER_PTR(win_iocp_socket_send_op);
+
+  win_iocp_socket_send_op(socket_ops::weak_cancel_token_type cancel_token,
+      const ConstBufferSequence& buffers, Handler& handler,
+      const IoExecutor& io_ex)
+    : operation(&win_iocp_socket_send_op::do_complete),
+      cancel_token_(cancel_token),
+      buffers_(buffers),
+      handler_(ASIO_MOVE_CAST(Handler)(handler)),
+      work_(handler_, io_ex)
+  {
+  }
+
+  static void do_complete(void* owner, operation* base,
+      const asio::error_code& result_ec,
+      std::size_t bytes_transferred)
+  {
+    asio::error_code ec(result_ec);
+
+    // Take ownership of the operation object.
+    win_iocp_socket_send_op* o(static_cast<win_iocp_socket_send_op*>(base));
+    ptr p = { asio::detail::addressof(o->handler_), o, o };
+
+    ASIO_HANDLER_COMPLETION((*o));
+
+    // Take ownership of the operation's outstanding work.
+    handler_work<Handler, IoExecutor> w(
+        ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)(
+          o->work_));
+
+#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
+    // Check whether buffers are still valid.
+    if (owner)
+    {
+      buffer_sequence_adapter<asio::const_buffer,
+          ConstBufferSequence>::validate(o->buffers_);
+    }
+#endif // defined(ASIO_ENABLE_BUFFER_DEBUGGING)
+
+    socket_ops::complete_iocp_send(o->cancel_token_, ec);
+
+    // Make a copy of the handler so that the memory can be deallocated before
+    // the upcall is made. Even if we're not about to make an upcall, a
+    // sub-object of the handler may be the true owner of the memory associated
+    // with the handler. Consequently, a local copy of the handler is required
+    // to ensure that any owning sub-object remains valid until after we have
+    // deallocated the memory here.
+    detail::binder2<Handler, asio::error_code, std::size_t>
+      handler(o->handler_, ec, bytes_transferred);
+    p.h = asio::detail::addressof(handler.handler_);
+    p.reset();
+
+    // Make the upcall if required.
+    if (owner)
+    {
+      fenced_block b(fenced_block::half);
+      ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_));
+      w.complete(handler, handler.handler_);
+      ASIO_HANDLER_INVOCATION_END;
+    }
+  }
+
+private:
+  socket_ops::weak_cancel_token_type cancel_token_;
+  ConstBufferSequence buffers_;
+  Handler handler_;
+  handler_work<Handler, IoExecutor> work_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_IOCP)
+
+#endif // ASIO_DETAIL_WIN_IOCP_SOCKET_SEND_OP_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/win_iocp_socket_service.hpp b/link/modules/asio-standalone/asio/include/asio/detail/win_iocp_socket_service.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/win_iocp_socket_service.hpp
@@ -0,0 +1,581 @@
+//
+// detail/win_iocp_socket_service.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_WIN_IOCP_SOCKET_SERVICE_HPP
+#define ASIO_DETAIL_WIN_IOCP_SOCKET_SERVICE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_IOCP)
+
+#include <cstring>
+#include "asio/error.hpp"
+#include "asio/execution_context.hpp"
+#include "asio/socket_base.hpp"
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/buffer_sequence_adapter.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/detail/mutex.hpp"
+#include "asio/detail/operation.hpp"
+#include "asio/detail/reactor_op.hpp"
+#include "asio/detail/select_reactor.hpp"
+#include "asio/detail/socket_holder.hpp"
+#include "asio/detail/socket_ops.hpp"
+#include "asio/detail/socket_types.hpp"
+#include "asio/detail/win_iocp_io_context.hpp"
+#include "asio/detail/win_iocp_null_buffers_op.hpp"
+#include "asio/detail/win_iocp_socket_accept_op.hpp"
+#include "asio/detail/win_iocp_socket_connect_op.hpp"
+#include "asio/detail/win_iocp_socket_recvfrom_op.hpp"
+#include "asio/detail/win_iocp_socket_send_op.hpp"
+#include "asio/detail/win_iocp_socket_service_base.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Protocol>
+class win_iocp_socket_service :
+  public execution_context_service_base<win_iocp_socket_service<Protocol> >,
+  public win_iocp_socket_service_base
+{
+public:
+  // The protocol type.
+  typedef Protocol protocol_type;
+
+  // The endpoint type.
+  typedef typename Protocol::endpoint endpoint_type;
+
+  // The native type of a socket.
+  class native_handle_type
+  {
+  public:
+    native_handle_type(socket_type s)
+      : socket_(s),
+        have_remote_endpoint_(false)
+    {
+    }
+
+    native_handle_type(socket_type s, const endpoint_type& ep)
+      : socket_(s),
+        have_remote_endpoint_(true),
+        remote_endpoint_(ep)
+    {
+    }
+
+    void operator=(socket_type s)
+    {
+      socket_ = s;
+      have_remote_endpoint_ = false;
+      remote_endpoint_ = endpoint_type();
+    }
+
+    operator socket_type() const
+    {
+      return socket_;
+    }
+
+    bool have_remote_endpoint() const
+    {
+      return have_remote_endpoint_;
+    }
+
+    endpoint_type remote_endpoint() const
+    {
+      return remote_endpoint_;
+    }
+
+  private:
+    socket_type socket_;
+    bool have_remote_endpoint_;
+    endpoint_type remote_endpoint_;
+  };
+
+  // The implementation type of the socket.
+  struct implementation_type :
+    win_iocp_socket_service_base::base_implementation_type
+  {
+    // Default constructor.
+    implementation_type()
+      : protocol_(endpoint_type().protocol()),
+        have_remote_endpoint_(false),
+        remote_endpoint_()
+    {
+    }
+
+    // The protocol associated with the socket.
+    protocol_type protocol_;
+
+    // Whether we have a cached remote endpoint.
+    bool have_remote_endpoint_;
+
+    // A cached remote endpoint.
+    endpoint_type remote_endpoint_;
+  };
+
+  // Constructor.
+  win_iocp_socket_service(execution_context& context)
+    : execution_context_service_base<
+        win_iocp_socket_service<Protocol> >(context),
+      win_iocp_socket_service_base(context)
+  {
+  }
+
+  // Destroy all user-defined handler objects owned by the service.
+  void shutdown()
+  {
+    this->base_shutdown();
+  }
+
+  // Move-construct a new socket implementation.
+  void move_construct(implementation_type& impl,
+      implementation_type& other_impl) ASIO_NOEXCEPT
+  {
+    this->base_move_construct(impl, other_impl);
+
+    impl.protocol_ = other_impl.protocol_;
+    other_impl.protocol_ = endpoint_type().protocol();
+
+    impl.have_remote_endpoint_ = other_impl.have_remote_endpoint_;
+    other_impl.have_remote_endpoint_ = false;
+
+    impl.remote_endpoint_ = other_impl.remote_endpoint_;
+    other_impl.remote_endpoint_ = endpoint_type();
+  }
+
+  // Move-assign from another socket implementation.
+  void move_assign(implementation_type& impl,
+      win_iocp_socket_service_base& other_service,
+      implementation_type& other_impl)
+  {
+    this->base_move_assign(impl, other_service, other_impl);
+
+    impl.protocol_ = other_impl.protocol_;
+    other_impl.protocol_ = endpoint_type().protocol();
+
+    impl.have_remote_endpoint_ = other_impl.have_remote_endpoint_;
+    other_impl.have_remote_endpoint_ = false;
+
+    impl.remote_endpoint_ = other_impl.remote_endpoint_;
+    other_impl.remote_endpoint_ = endpoint_type();
+  }
+
+  // Move-construct a new socket implementation from another protocol type.
+  template <typename Protocol1>
+  void converting_move_construct(implementation_type& impl,
+      win_iocp_socket_service<Protocol1>&,
+      typename win_iocp_socket_service<
+        Protocol1>::implementation_type& other_impl)
+  {
+    this->base_move_construct(impl, other_impl);
+
+    impl.protocol_ = protocol_type(other_impl.protocol_);
+    other_impl.protocol_ = typename Protocol1::endpoint().protocol();
+
+    impl.have_remote_endpoint_ = other_impl.have_remote_endpoint_;
+    other_impl.have_remote_endpoint_ = false;
+
+    impl.remote_endpoint_ = other_impl.remote_endpoint_;
+    other_impl.remote_endpoint_ = typename Protocol1::endpoint();
+  }
+
+  // Open a new socket implementation.
+  asio::error_code open(implementation_type& impl,
+      const protocol_type& protocol, asio::error_code& ec)
+  {
+    if (!do_open(impl, protocol.family(),
+          protocol.type(), protocol.protocol(), ec))
+    {
+      impl.protocol_ = protocol;
+      impl.have_remote_endpoint_ = false;
+      impl.remote_endpoint_ = endpoint_type();
+    }
+    return ec;
+  }
+
+  // Assign a native socket to a socket implementation.
+  asio::error_code assign(implementation_type& impl,
+      const protocol_type& protocol, const native_handle_type& native_socket,
+      asio::error_code& ec)
+  {
+    if (!do_assign(impl, protocol.type(), native_socket, ec))
+    {
+      impl.protocol_ = protocol;
+      impl.have_remote_endpoint_ = native_socket.have_remote_endpoint();
+      impl.remote_endpoint_ = native_socket.remote_endpoint();
+    }
+    return ec;
+  }
+
+  // Get the native socket representation.
+  native_handle_type native_handle(implementation_type& impl)
+  {
+    if (impl.have_remote_endpoint_)
+      return native_handle_type(impl.socket_, impl.remote_endpoint_);
+    return native_handle_type(impl.socket_);
+  }
+
+  // Bind the socket to the specified local endpoint.
+  asio::error_code bind(implementation_type& impl,
+      const endpoint_type& endpoint, asio::error_code& ec)
+  {
+    socket_ops::bind(impl.socket_, endpoint.data(), endpoint.size(), ec);
+    return ec;
+  }
+
+  // Set a socket option.
+  template <typename Option>
+  asio::error_code set_option(implementation_type& impl,
+      const Option& option, asio::error_code& ec)
+  {
+    socket_ops::setsockopt(impl.socket_, impl.state_,
+        option.level(impl.protocol_), option.name(impl.protocol_),
+        option.data(impl.protocol_), option.size(impl.protocol_), ec);
+    return ec;
+  }
+
+  // Set a socket option.
+  template <typename Option>
+  asio::error_code get_option(const implementation_type& impl,
+      Option& option, asio::error_code& ec) const
+  {
+    std::size_t size = option.size(impl.protocol_);
+    socket_ops::getsockopt(impl.socket_, impl.state_,
+        option.level(impl.protocol_), option.name(impl.protocol_),
+        option.data(impl.protocol_), &size, ec);
+    if (!ec)
+      option.resize(impl.protocol_, size);
+    return ec;
+  }
+
+  // Get the local endpoint.
+  endpoint_type local_endpoint(const implementation_type& impl,
+      asio::error_code& ec) const
+  {
+    endpoint_type endpoint;
+    std::size_t addr_len = endpoint.capacity();
+    if (socket_ops::getsockname(impl.socket_, endpoint.data(), &addr_len, ec))
+      return endpoint_type();
+    endpoint.resize(addr_len);
+    return endpoint;
+  }
+
+  // Get the remote endpoint.
+  endpoint_type remote_endpoint(const implementation_type& impl,
+      asio::error_code& ec) const
+  {
+    endpoint_type endpoint = impl.remote_endpoint_;
+    std::size_t addr_len = endpoint.capacity();
+    if (socket_ops::getpeername(impl.socket_, endpoint.data(),
+          &addr_len, impl.have_remote_endpoint_, ec))
+      return endpoint_type();
+    endpoint.resize(addr_len);
+    return endpoint;
+  }
+
+  // Disable sends or receives on the socket.
+  asio::error_code shutdown(base_implementation_type& impl,
+      socket_base::shutdown_type what, asio::error_code& ec)
+  {
+    socket_ops::shutdown(impl.socket_, what, ec);
+    return ec;
+  }
+
+  // Send a datagram to the specified endpoint. Returns the number of bytes
+  // sent.
+  template <typename ConstBufferSequence>
+  size_t send_to(implementation_type& impl, const ConstBufferSequence& buffers,
+      const endpoint_type& destination, socket_base::message_flags flags,
+      asio::error_code& ec)
+  {
+    buffer_sequence_adapter<asio::const_buffer,
+        ConstBufferSequence> bufs(buffers);
+
+    return socket_ops::sync_sendto(impl.socket_, impl.state_,
+        bufs.buffers(), bufs.count(), flags,
+        destination.data(), destination.size(), ec);
+  }
+
+  // Wait until data can be sent without blocking.
+  size_t send_to(implementation_type& impl, const null_buffers&,
+      const endpoint_type&, socket_base::message_flags,
+      asio::error_code& ec)
+  {
+    // Wait for socket to become ready.
+    socket_ops::poll_write(impl.socket_, impl.state_, -1, ec);
+
+    return 0;
+  }
+
+  // Start an asynchronous send. The data being sent must be valid for the
+  // lifetime of the asynchronous operation.
+  template <typename ConstBufferSequence, typename Handler, typename IoExecutor>
+  void async_send_to(implementation_type& impl,
+      const ConstBufferSequence& buffers, const endpoint_type& destination,
+      socket_base::message_flags flags, Handler& handler,
+      const IoExecutor& io_ex)
+  {
+    // Allocate and construct an operation to wrap the handler.
+    typedef win_iocp_socket_send_op<
+        ConstBufferSequence, Handler, IoExecutor> op;
+    typename op::ptr p = { asio::detail::addressof(handler),
+      op::ptr::allocate(handler), 0 };
+    p.p = new (p.v) op(impl.cancel_token_, buffers, handler, io_ex);
+
+    ASIO_HANDLER_CREATION((context_, *p.p, "socket",
+          &impl, impl.socket_, "async_send_to"));
+
+    buffer_sequence_adapter<asio::const_buffer,
+        ConstBufferSequence> bufs(buffers);
+
+    start_send_to_op(impl, bufs.buffers(), bufs.count(),
+        destination.data(), static_cast<int>(destination.size()),
+        flags, p.p);
+    p.v = p.p = 0;
+  }
+
+  // Start an asynchronous wait until data can be sent without blocking.
+  template <typename Handler, typename IoExecutor>
+  void async_send_to(implementation_type& impl, const null_buffers&,
+      const endpoint_type&, socket_base::message_flags, Handler& handler,
+      const IoExecutor& io_ex)
+  {
+    // Allocate and construct an operation to wrap the handler.
+    typedef win_iocp_null_buffers_op<Handler, IoExecutor> op;
+    typename op::ptr p = { asio::detail::addressof(handler),
+      op::ptr::allocate(handler), 0 };
+    p.p = new (p.v) op(impl.cancel_token_, handler, io_ex);
+
+    ASIO_HANDLER_CREATION((context_, *p.p, "socket",
+          &impl, impl.socket_, "async_send_to(null_buffers)"));
+
+    start_reactor_op(impl, select_reactor::write_op, p.p);
+    p.v = p.p = 0;
+  }
+
+  // Receive a datagram with the endpoint of the sender. Returns the number of
+  // bytes received.
+  template <typename MutableBufferSequence>
+  size_t receive_from(implementation_type& impl,
+      const MutableBufferSequence& buffers,
+      endpoint_type& sender_endpoint, socket_base::message_flags flags,
+      asio::error_code& ec)
+  {
+    buffer_sequence_adapter<asio::mutable_buffer,
+        MutableBufferSequence> bufs(buffers);
+
+    std::size_t addr_len = sender_endpoint.capacity();
+    std::size_t bytes_recvd = socket_ops::sync_recvfrom(
+        impl.socket_, impl.state_, bufs.buffers(), bufs.count(),
+        flags, sender_endpoint.data(), &addr_len, ec);
+
+    if (!ec)
+      sender_endpoint.resize(addr_len);
+
+    return bytes_recvd;
+  }
+
+  // Wait until data can be received without blocking.
+  size_t receive_from(implementation_type& impl,
+      const null_buffers&, endpoint_type& sender_endpoint,
+      socket_base::message_flags, asio::error_code& ec)
+  {
+    // Wait for socket to become ready.
+    socket_ops::poll_read(impl.socket_, impl.state_, -1, ec);
+
+    // Reset endpoint since it can be given no sensible value at this time.
+    sender_endpoint = endpoint_type();
+
+    return 0;
+  }
+
+  // Start an asynchronous receive. The buffer for the data being received and
+  // the sender_endpoint object must both be valid for the lifetime of the
+  // asynchronous operation.
+  template <typename MutableBufferSequence,
+      typename Handler, typename IoExecutor>
+  void async_receive_from(implementation_type& impl,
+      const MutableBufferSequence& buffers, endpoint_type& sender_endp,
+      socket_base::message_flags flags, Handler& handler,
+      const IoExecutor& io_ex)
+  {
+    // Allocate and construct an operation to wrap the handler.
+    typedef win_iocp_socket_recvfrom_op<MutableBufferSequence,
+        endpoint_type, Handler, IoExecutor> op;
+    typename op::ptr p = { asio::detail::addressof(handler),
+      op::ptr::allocate(handler), 0 };
+    p.p = new (p.v) op(sender_endp, impl.cancel_token_,
+        buffers, handler, io_ex);
+
+    ASIO_HANDLER_CREATION((context_, *p.p, "socket",
+          &impl, impl.socket_, "async_receive_from"));
+
+    buffer_sequence_adapter<asio::mutable_buffer,
+        MutableBufferSequence> bufs(buffers);
+
+    start_receive_from_op(impl, bufs.buffers(), bufs.count(),
+        sender_endp.data(), flags, &p.p->endpoint_size(), p.p);
+    p.v = p.p = 0;
+  }
+
+  // Wait until data can be received without blocking.
+  template <typename Handler, typename IoExecutor>
+  void async_receive_from(implementation_type& impl, const null_buffers&,
+      endpoint_type& sender_endpoint, socket_base::message_flags flags,
+      Handler& handler, const IoExecutor& io_ex)
+  {
+    // Allocate and construct an operation to wrap the handler.
+    typedef win_iocp_null_buffers_op<Handler, IoExecutor> op;
+    typename op::ptr p = { asio::detail::addressof(handler),
+      op::ptr::allocate(handler), 0 };
+    p.p = new (p.v) op(impl.cancel_token_, handler, io_ex);
+
+    ASIO_HANDLER_CREATION((context_, *p.p, "socket",
+          &impl, impl.socket_, "async_receive_from(null_buffers)"));
+
+    // Reset endpoint since it can be given no sensible value at this time.
+    sender_endpoint = endpoint_type();
+
+    start_null_buffers_receive_op(impl, flags, p.p);
+    p.v = p.p = 0;
+  }
+
+  // Accept a new connection.
+  template <typename Socket>
+  asio::error_code accept(implementation_type& impl, Socket& peer,
+      endpoint_type* peer_endpoint, asio::error_code& ec)
+  {
+    // We cannot accept a socket that is already open.
+    if (peer.is_open())
+    {
+      ec = asio::error::already_open;
+      return ec;
+    }
+
+    std::size_t addr_len = peer_endpoint ? peer_endpoint->capacity() : 0;
+    socket_holder new_socket(socket_ops::sync_accept(impl.socket_,
+          impl.state_, peer_endpoint ? peer_endpoint->data() : 0,
+          peer_endpoint ? &addr_len : 0, ec));
+
+    // On success, assign new connection to peer socket object.
+    if (new_socket.get() != invalid_socket)
+    {
+      if (peer_endpoint)
+        peer_endpoint->resize(addr_len);
+      peer.assign(impl.protocol_, new_socket.get(), ec);
+      if (!ec)
+        new_socket.release();
+    }
+
+    return ec;
+  }
+
+  // Start an asynchronous accept. The peer and peer_endpoint objects
+  // must be valid until the accept's handler is invoked.
+  template <typename Socket, typename Handler, typename IoExecutor>
+  void async_accept(implementation_type& impl, Socket& peer,
+      endpoint_type* peer_endpoint, Handler& handler, const IoExecutor& io_ex)
+  {
+    // Allocate and construct an operation to wrap the handler.
+    typedef win_iocp_socket_accept_op<Socket,
+        protocol_type, Handler, IoExecutor> op;
+    typename op::ptr p = { asio::detail::addressof(handler),
+      op::ptr::allocate(handler), 0 };
+    bool enable_connection_aborted =
+      (impl.state_ & socket_ops::enable_connection_aborted) != 0;
+    p.p = new (p.v) op(*this, impl.socket_, peer, impl.protocol_,
+        peer_endpoint, enable_connection_aborted, handler, io_ex);
+
+    ASIO_HANDLER_CREATION((context_, *p.p, "socket",
+          &impl, impl.socket_, "async_accept"));
+
+    start_accept_op(impl, peer.is_open(), p.p->new_socket(),
+        impl.protocol_.family(), impl.protocol_.type(),
+        impl.protocol_.protocol(), p.p->output_buffer(),
+        p.p->address_length(), p.p);
+    p.v = p.p = 0;
+  }
+
+#if defined(ASIO_HAS_MOVE)
+  // Start an asynchronous accept. The peer and peer_endpoint objects
+  // must be valid until the accept's handler is invoked.
+  template <typename PeerIoExecutor, typename Handler, typename IoExecutor>
+  void async_move_accept(implementation_type& impl,
+      const PeerIoExecutor& peer_io_ex, endpoint_type* peer_endpoint,
+      Handler& handler, const IoExecutor& io_ex)
+  {
+    // Allocate and construct an operation to wrap the handler.
+    typedef win_iocp_socket_move_accept_op<
+        protocol_type, PeerIoExecutor, Handler, IoExecutor> op;
+    typename op::ptr p = { asio::detail::addressof(handler),
+      op::ptr::allocate(handler), 0 };
+    bool enable_connection_aborted =
+      (impl.state_ & socket_ops::enable_connection_aborted) != 0;
+    p.p = new (p.v) op(*this, impl.socket_, impl.protocol_,
+        peer_io_ex, peer_endpoint, enable_connection_aborted,
+        handler, io_ex);
+
+    ASIO_HANDLER_CREATION((context_, *p.p, "socket",
+          &impl, impl.socket_, "async_accept"));
+
+    start_accept_op(impl, false, p.p->new_socket(),
+        impl.protocol_.family(), impl.protocol_.type(),
+        impl.protocol_.protocol(), p.p->output_buffer(),
+        p.p->address_length(), p.p);
+    p.v = p.p = 0;
+  }
+#endif // defined(ASIO_HAS_MOVE)
+
+  // Connect the socket to the specified endpoint.
+  asio::error_code connect(implementation_type& impl,
+      const endpoint_type& peer_endpoint, asio::error_code& ec)
+  {
+    socket_ops::sync_connect(impl.socket_,
+        peer_endpoint.data(), peer_endpoint.size(), ec);
+    return ec;
+  }
+
+  // Start an asynchronous connect.
+  template <typename Handler, typename IoExecutor>
+  void async_connect(implementation_type& impl,
+      const endpoint_type& peer_endpoint, Handler& handler,
+      const IoExecutor& io_ex)
+  {
+    // Allocate and construct an operation to wrap the handler.
+    typedef win_iocp_socket_connect_op<Handler, IoExecutor> op;
+    typename op::ptr p = { asio::detail::addressof(handler),
+      op::ptr::allocate(handler), 0 };
+    p.p = new (p.v) op(impl.socket_, handler, io_ex);
+
+    ASIO_HANDLER_CREATION((context_, *p.p, "socket",
+          &impl, impl.socket_, "async_connect"));
+
+    start_connect_op(impl, impl.protocol_.family(), impl.protocol_.type(),
+        peer_endpoint.data(), static_cast<int>(peer_endpoint.size()), p.p);
+    p.v = p.p = 0;
+  }
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_IOCP)
+
+#endif // ASIO_DETAIL_WIN_IOCP_SOCKET_SERVICE_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/win_iocp_socket_service_base.hpp b/link/modules/asio-standalone/asio/include/asio/detail/win_iocp_socket_service_base.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/win_iocp_socket_service_base.hpp
@@ -0,0 +1,600 @@
+//
+// detail/win_iocp_socket_service_base.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_WIN_IOCP_SOCKET_SERVICE_BASE_HPP
+#define ASIO_DETAIL_WIN_IOCP_SOCKET_SERVICE_BASE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_IOCP)
+
+#include "asio/error.hpp"
+#include "asio/execution_context.hpp"
+#include "asio/socket_base.hpp"
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/buffer_sequence_adapter.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/detail/mutex.hpp"
+#include "asio/detail/operation.hpp"
+#include "asio/detail/reactor_op.hpp"
+#include "asio/detail/select_reactor.hpp"
+#include "asio/detail/socket_holder.hpp"
+#include "asio/detail/socket_ops.hpp"
+#include "asio/detail/socket_types.hpp"
+#include "asio/detail/win_iocp_io_context.hpp"
+#include "asio/detail/win_iocp_null_buffers_op.hpp"
+#include "asio/detail/win_iocp_socket_connect_op.hpp"
+#include "asio/detail/win_iocp_socket_send_op.hpp"
+#include "asio/detail/win_iocp_socket_recv_op.hpp"
+#include "asio/detail/win_iocp_socket_recvmsg_op.hpp"
+#include "asio/detail/win_iocp_wait_op.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class win_iocp_socket_service_base
+{
+public:
+  // The implementation type of the socket.
+  struct base_implementation_type
+  {
+    // The native socket representation.
+    socket_type socket_;
+
+    // The current state of the socket.
+    socket_ops::state_type state_;
+
+    // We use a shared pointer as a cancellation token here to work around the
+    // broken Windows support for cancellation. MSDN says that when you call
+    // closesocket any outstanding WSARecv or WSASend operations will complete
+    // with the error ERROR_OPERATION_ABORTED. In practice they complete with
+    // ERROR_NETNAME_DELETED, which means you can't tell the difference between
+    // a local cancellation and the socket being hard-closed by the peer.
+    socket_ops::shared_cancel_token_type cancel_token_;
+
+    // Per-descriptor data used by the reactor.
+    select_reactor::per_descriptor_data reactor_data_;
+
+#if defined(ASIO_ENABLE_CANCELIO)
+    // The ID of the thread from which it is safe to cancel asynchronous
+    // operations. 0 means no asynchronous operations have been started yet.
+    // ~0 means asynchronous operations have been started from more than one
+    // thread, and cancellation is not supported for the socket.
+    DWORD safe_cancellation_thread_id_;
+#endif // defined(ASIO_ENABLE_CANCELIO)
+
+    // Pointers to adjacent socket implementations in linked list.
+    base_implementation_type* next_;
+    base_implementation_type* prev_;
+  };
+
+  // Constructor.
+  ASIO_DECL win_iocp_socket_service_base(execution_context& context);
+
+  // Destroy all user-defined handler objects owned by the service.
+  ASIO_DECL void base_shutdown();
+
+  // Construct a new socket implementation.
+  ASIO_DECL void construct(base_implementation_type& impl);
+
+  // Move-construct a new socket implementation.
+  ASIO_DECL void base_move_construct(base_implementation_type& impl,
+      base_implementation_type& other_impl) ASIO_NOEXCEPT;
+
+  // Move-assign from another socket implementation.
+  ASIO_DECL void base_move_assign(base_implementation_type& impl,
+      win_iocp_socket_service_base& other_service,
+      base_implementation_type& other_impl);
+
+  // Destroy a socket implementation.
+  ASIO_DECL void destroy(base_implementation_type& impl);
+
+  // Determine whether the socket is open.
+  bool is_open(const base_implementation_type& impl) const
+  {
+    return impl.socket_ != invalid_socket;
+  }
+
+  // Destroy a socket implementation.
+  ASIO_DECL asio::error_code close(
+      base_implementation_type& impl, asio::error_code& ec);
+
+  // Release ownership of the socket.
+  ASIO_DECL socket_type release(
+      base_implementation_type& impl, asio::error_code& ec);
+
+  // Cancel all operations associated with the socket.
+  ASIO_DECL asio::error_code cancel(
+      base_implementation_type& impl, asio::error_code& ec);
+
+  // Determine whether the socket is at the out-of-band data mark.
+  bool at_mark(const base_implementation_type& impl,
+      asio::error_code& ec) const
+  {
+    return socket_ops::sockatmark(impl.socket_, ec);
+  }
+
+  // Determine the number of bytes available for reading.
+  std::size_t available(const base_implementation_type& impl,
+      asio::error_code& ec) const
+  {
+    return socket_ops::available(impl.socket_, ec);
+  }
+
+  // Place the socket into the state where it will listen for new connections.
+  asio::error_code listen(base_implementation_type& impl,
+      int backlog, asio::error_code& ec)
+  {
+    socket_ops::listen(impl.socket_, backlog, ec);
+    return ec;
+  }
+
+  // Perform an IO control command on the socket.
+  template <typename IO_Control_Command>
+  asio::error_code io_control(base_implementation_type& impl,
+      IO_Control_Command& command, asio::error_code& ec)
+  {
+    socket_ops::ioctl(impl.socket_, impl.state_, command.name(),
+        static_cast<ioctl_arg_type*>(command.data()), ec);
+    return ec;
+  }
+
+  // Gets the non-blocking mode of the socket.
+  bool non_blocking(const base_implementation_type& impl) const
+  {
+    return (impl.state_ & socket_ops::user_set_non_blocking) != 0;
+  }
+
+  // Sets the non-blocking mode of the socket.
+  asio::error_code non_blocking(base_implementation_type& impl,
+      bool mode, asio::error_code& ec)
+  {
+    socket_ops::set_user_non_blocking(impl.socket_, impl.state_, mode, ec);
+    return ec;
+  }
+
+  // Gets the non-blocking mode of the native socket implementation.
+  bool native_non_blocking(const base_implementation_type& impl) const
+  {
+    return (impl.state_ & socket_ops::internal_non_blocking) != 0;
+  }
+
+  // Sets the non-blocking mode of the native socket implementation.
+  asio::error_code native_non_blocking(base_implementation_type& impl,
+      bool mode, asio::error_code& ec)
+  {
+    socket_ops::set_internal_non_blocking(impl.socket_, impl.state_, mode, ec);
+    return ec;
+  }
+
+  // Wait for the socket to become ready to read, ready to write, or to have
+  // pending error conditions.
+  asio::error_code wait(base_implementation_type& impl,
+      socket_base::wait_type w, asio::error_code& ec)
+  {
+    switch (w)
+    {
+    case socket_base::wait_read:
+      socket_ops::poll_read(impl.socket_, impl.state_, -1, ec);
+      break;
+    case socket_base::wait_write:
+      socket_ops::poll_write(impl.socket_, impl.state_, -1, ec);
+      break;
+    case socket_base::wait_error:
+      socket_ops::poll_error(impl.socket_, impl.state_, -1, ec);
+      break;
+    default:
+      ec = asio::error::invalid_argument;
+      break;
+    }
+
+    return ec;
+  }
+
+  // Asynchronously wait for the socket to become ready to read, ready to
+  // write, or to have pending error conditions.
+  template <typename Handler, typename IoExecutor>
+  void async_wait(base_implementation_type& impl,
+      socket_base::wait_type w, Handler& handler, const IoExecutor& io_ex)
+  {
+    bool is_continuation =
+      asio_handler_cont_helpers::is_continuation(handler);
+
+    // Allocate and construct an operation to wrap the handler.
+    typedef win_iocp_wait_op<Handler, IoExecutor> op;
+    typename op::ptr p = { asio::detail::addressof(handler),
+      op::ptr::allocate(handler), 0 };
+    p.p = new (p.v) op(impl.cancel_token_, handler, io_ex);
+
+    ASIO_HANDLER_CREATION((context_, *p.p, "socket",
+          &impl, impl.socket_, "async_wait"));
+
+    switch (w)
+    {
+      case socket_base::wait_read:
+        start_null_buffers_receive_op(impl, 0, p.p);
+        break;
+      case socket_base::wait_write:
+        start_reactor_op(impl, select_reactor::write_op, p.p);
+        break;
+      case socket_base::wait_error:
+        start_reactor_op(impl, select_reactor::except_op, p.p);
+        break;
+      default:
+        p.p->ec_ = asio::error::invalid_argument;
+        iocp_service_.post_immediate_completion(p.p, is_continuation);
+        break;
+    }
+
+    p.v = p.p = 0;
+  }
+
+  // Send the given data to the peer. Returns the number of bytes sent.
+  template <typename ConstBufferSequence>
+  size_t send(base_implementation_type& impl,
+      const ConstBufferSequence& buffers,
+      socket_base::message_flags flags, asio::error_code& ec)
+  {
+    buffer_sequence_adapter<asio::const_buffer,
+        ConstBufferSequence> bufs(buffers);
+
+    return socket_ops::sync_send(impl.socket_, impl.state_,
+        bufs.buffers(), bufs.count(), flags, bufs.all_empty(), ec);
+  }
+
+  // Wait until data can be sent without blocking.
+  size_t send(base_implementation_type& impl, const null_buffers&,
+      socket_base::message_flags, asio::error_code& ec)
+  {
+    // Wait for socket to become ready.
+    socket_ops::poll_write(impl.socket_, impl.state_, -1, ec);
+
+    return 0;
+  }
+
+  // Start an asynchronous send. The data being sent must be valid for the
+  // lifetime of the asynchronous operation.
+  template <typename ConstBufferSequence, typename Handler, typename IoExecutor>
+  void async_send(base_implementation_type& impl,
+      const ConstBufferSequence& buffers, socket_base::message_flags flags,
+      Handler& handler, const IoExecutor& io_ex)
+  {
+    // Allocate and construct an operation to wrap the handler.
+    typedef win_iocp_socket_send_op<
+        ConstBufferSequence, Handler, IoExecutor> op;
+    typename op::ptr p = { asio::detail::addressof(handler),
+      op::ptr::allocate(handler), 0 };
+    p.p = new (p.v) op(impl.cancel_token_, buffers, handler, io_ex);
+
+    ASIO_HANDLER_CREATION((context_, *p.p, "socket",
+          &impl, impl.socket_, "async_send"));
+
+    buffer_sequence_adapter<asio::const_buffer,
+        ConstBufferSequence> bufs(buffers);
+
+    start_send_op(impl, bufs.buffers(), bufs.count(), flags,
+        (impl.state_ & socket_ops::stream_oriented) != 0 && bufs.all_empty(),
+        p.p);
+    p.v = p.p = 0;
+  }
+
+  // Start an asynchronous wait until data can be sent without blocking.
+  template <typename Handler, typename IoExecutor>
+  void async_send(base_implementation_type& impl, const null_buffers&,
+      socket_base::message_flags, Handler& handler, const IoExecutor& io_ex)
+  {
+    // Allocate and construct an operation to wrap the handler.
+    typedef win_iocp_null_buffers_op<Handler, IoExecutor> op;
+    typename op::ptr p = { asio::detail::addressof(handler),
+      op::ptr::allocate(handler), 0 };
+    p.p = new (p.v) op(impl.cancel_token_, handler, io_ex);
+
+    ASIO_HANDLER_CREATION((context_, *p.p, "socket",
+          &impl, impl.socket_, "async_send(null_buffers)"));
+
+    start_reactor_op(impl, select_reactor::write_op, p.p);
+    p.v = p.p = 0;
+  }
+
+  // Receive some data from the peer. Returns the number of bytes received.
+  template <typename MutableBufferSequence>
+  size_t receive(base_implementation_type& impl,
+      const MutableBufferSequence& buffers,
+      socket_base::message_flags flags, asio::error_code& ec)
+  {
+    buffer_sequence_adapter<asio::mutable_buffer,
+        MutableBufferSequence> bufs(buffers);
+
+    return socket_ops::sync_recv(impl.socket_, impl.state_,
+        bufs.buffers(), bufs.count(), flags, bufs.all_empty(), ec);
+  }
+
+  // Wait until data can be received without blocking.
+  size_t receive(base_implementation_type& impl, const null_buffers&,
+      socket_base::message_flags, asio::error_code& ec)
+  {
+    // Wait for socket to become ready.
+    socket_ops::poll_read(impl.socket_, impl.state_, -1, ec);
+
+    return 0;
+  }
+
+  // Start an asynchronous receive. The buffer for the data being received
+  // must be valid for the lifetime of the asynchronous operation.
+  template <typename MutableBufferSequence,
+      typename Handler, typename IoExecutor>
+  void async_receive(base_implementation_type& impl,
+      const MutableBufferSequence& buffers, socket_base::message_flags flags,
+      Handler& handler, const IoExecutor& io_ex)
+  {
+    // Allocate and construct an operation to wrap the handler.
+    typedef win_iocp_socket_recv_op<
+        MutableBufferSequence, Handler, IoExecutor> op;
+    typename op::ptr p = { asio::detail::addressof(handler),
+      op::ptr::allocate(handler), 0 };
+    p.p = new (p.v) op(impl.state_, impl.cancel_token_,
+        buffers, handler, io_ex);
+
+    ASIO_HANDLER_CREATION((context_, *p.p, "socket",
+          &impl, impl.socket_, "async_receive"));
+
+    buffer_sequence_adapter<asio::mutable_buffer,
+        MutableBufferSequence> bufs(buffers);
+
+    start_receive_op(impl, bufs.buffers(), bufs.count(), flags,
+        (impl.state_ & socket_ops::stream_oriented) != 0 && bufs.all_empty(),
+        p.p);
+    p.v = p.p = 0;
+  }
+
+  // Wait until data can be received without blocking.
+  template <typename Handler, typename IoExecutor>
+  void async_receive(base_implementation_type& impl,
+      const null_buffers&, socket_base::message_flags flags,
+      Handler& handler, const IoExecutor& io_ex)
+  {
+    // Allocate and construct an operation to wrap the handler.
+    typedef win_iocp_null_buffers_op<Handler, IoExecutor> op;
+    typename op::ptr p = { asio::detail::addressof(handler),
+      op::ptr::allocate(handler), 0 };
+    p.p = new (p.v) op(impl.cancel_token_, handler, io_ex);
+
+    ASIO_HANDLER_CREATION((context_, *p.p, "socket",
+          &impl, impl.socket_, "async_receive(null_buffers)"));
+
+    start_null_buffers_receive_op(impl, flags, p.p);
+    p.v = p.p = 0;
+  }
+
+  // Receive some data with associated flags. Returns the number of bytes
+  // received.
+  template <typename MutableBufferSequence>
+  size_t receive_with_flags(base_implementation_type& impl,
+      const MutableBufferSequence& buffers,
+      socket_base::message_flags in_flags,
+      socket_base::message_flags& out_flags, asio::error_code& ec)
+  {
+    buffer_sequence_adapter<asio::mutable_buffer,
+        MutableBufferSequence> bufs(buffers);
+
+    return socket_ops::sync_recvmsg(impl.socket_, impl.state_,
+        bufs.buffers(), bufs.count(), in_flags, out_flags, ec);
+  }
+
+  // Wait until data can be received without blocking.
+  size_t receive_with_flags(base_implementation_type& impl,
+      const null_buffers&, socket_base::message_flags,
+      socket_base::message_flags& out_flags, asio::error_code& ec)
+  {
+    // Wait for socket to become ready.
+    socket_ops::poll_read(impl.socket_, impl.state_, -1, ec);
+
+    // Clear out_flags, since we cannot give it any other sensible value when
+    // performing a null_buffers operation.
+    out_flags = 0;
+
+    return 0;
+  }
+
+  // Start an asynchronous receive. The buffer for the data being received
+  // must be valid for the lifetime of the asynchronous operation.
+  template <typename MutableBufferSequence,
+      typename Handler, typename IoExecutor>
+  void async_receive_with_flags(base_implementation_type& impl,
+      const MutableBufferSequence& buffers, socket_base::message_flags in_flags,
+      socket_base::message_flags& out_flags, Handler& handler,
+      const IoExecutor& io_ex)
+  {
+    // Allocate and construct an operation to wrap the handler.
+    typedef win_iocp_socket_recvmsg_op<
+        MutableBufferSequence, Handler, IoExecutor> op;
+    typename op::ptr p = { asio::detail::addressof(handler),
+      op::ptr::allocate(handler), 0 };
+    p.p = new (p.v) op(impl.cancel_token_,
+        buffers, out_flags, handler, io_ex);
+
+    ASIO_HANDLER_CREATION((context_, *p.p, "socket",
+          &impl, impl.socket_, "async_receive_with_flags"));
+
+    buffer_sequence_adapter<asio::mutable_buffer,
+        MutableBufferSequence> bufs(buffers);
+
+    start_receive_op(impl, bufs.buffers(), bufs.count(), in_flags, false, p.p);
+    p.v = p.p = 0;
+  }
+
+  // Wait until data can be received without blocking.
+  template <typename Handler, typename IoExecutor>
+  void async_receive_with_flags(base_implementation_type& impl,
+      const null_buffers&, socket_base::message_flags in_flags,
+      socket_base::message_flags& out_flags, Handler& handler,
+      const IoExecutor& io_ex)
+  {
+    // Allocate and construct an operation to wrap the handler.
+    typedef win_iocp_null_buffers_op<Handler, IoExecutor> op;
+    typename op::ptr p = { asio::detail::addressof(handler),
+      op::ptr::allocate(handler), 0 };
+    p.p = new (p.v) op(impl.cancel_token_, handler, io_ex);
+
+    ASIO_HANDLER_CREATION((context_, *p.p, "socket",
+          &impl, impl.socket_, "async_receive_with_flags(null_buffers)"));
+
+    // Reset out_flags since it can be given no sensible value at this time.
+    out_flags = 0;
+
+    start_null_buffers_receive_op(impl, in_flags, p.p);
+    p.v = p.p = 0;
+  }
+
+  // Helper function to restart an asynchronous accept operation.
+  ASIO_DECL void restart_accept_op(socket_type s,
+      socket_holder& new_socket, int family, int type, int protocol,
+      void* output_buffer, DWORD address_length, operation* op);
+
+protected:
+  // Open a new socket implementation.
+  ASIO_DECL asio::error_code do_open(
+      base_implementation_type& impl, int family, int type,
+      int protocol, asio::error_code& ec);
+
+  // Assign a native socket to a socket implementation.
+  ASIO_DECL asio::error_code do_assign(
+      base_implementation_type& impl, int type,
+      socket_type native_socket, asio::error_code& ec);
+
+  // Helper function to start an asynchronous send operation.
+  ASIO_DECL void start_send_op(base_implementation_type& impl,
+      WSABUF* buffers, std::size_t buffer_count,
+      socket_base::message_flags flags, bool noop, operation* op);
+
+  // Helper function to start an asynchronous send_to operation.
+  ASIO_DECL void start_send_to_op(base_implementation_type& impl,
+      WSABUF* buffers, std::size_t buffer_count,
+      const socket_addr_type* addr, int addrlen,
+      socket_base::message_flags flags, operation* op);
+
+  // Helper function to start an asynchronous receive operation.
+  ASIO_DECL void start_receive_op(base_implementation_type& impl,
+      WSABUF* buffers, std::size_t buffer_count,
+      socket_base::message_flags flags, bool noop, operation* op);
+
+  // Helper function to start an asynchronous null_buffers receive operation.
+  ASIO_DECL void start_null_buffers_receive_op(
+      base_implementation_type& impl,
+      socket_base::message_flags flags, reactor_op* op);
+
+  // Helper function to start an asynchronous receive_from operation.
+  ASIO_DECL void start_receive_from_op(base_implementation_type& impl,
+      WSABUF* buffers, std::size_t buffer_count, socket_addr_type* addr,
+      socket_base::message_flags flags, int* addrlen, operation* op);
+
+  // Helper function to start an asynchronous accept operation.
+  ASIO_DECL void start_accept_op(base_implementation_type& impl,
+      bool peer_is_open, socket_holder& new_socket, int family, int type,
+      int protocol, void* output_buffer, DWORD address_length, operation* op);
+
+  // Start an asynchronous read or write operation using the reactor.
+  ASIO_DECL void start_reactor_op(base_implementation_type& impl,
+      int op_type, reactor_op* op);
+
+  // Start the asynchronous connect operation using the reactor.
+  ASIO_DECL void start_connect_op(base_implementation_type& impl,
+      int family, int type, const socket_addr_type* remote_addr,
+      std::size_t remote_addrlen, win_iocp_socket_connect_op_base* op);
+
+  // Helper function to close a socket when the associated object is being
+  // destroyed.
+  ASIO_DECL void close_for_destruction(base_implementation_type& impl);
+
+  // Update the ID of the thread from which cancellation is safe.
+  ASIO_DECL void update_cancellation_thread_id(
+      base_implementation_type& impl);
+
+  // Helper function to get the reactor. If no reactor has been created yet, a
+  // new one is obtained from the execution context and a pointer to it is
+  // cached in this service.
+  ASIO_DECL select_reactor& get_reactor();
+
+  // The type of a ConnectEx function pointer, as old SDKs may not provide it.
+  typedef BOOL (PASCAL *connect_ex_fn)(SOCKET,
+      const socket_addr_type*, int, void*, DWORD, DWORD*, OVERLAPPED*);
+
+  // Helper function to get the ConnectEx pointer. If no ConnectEx pointer has
+  // been obtained yet, one is obtained using WSAIoctl and the pointer is
+  // cached. Returns a null pointer if ConnectEx is not available.
+  ASIO_DECL connect_ex_fn get_connect_ex(
+      base_implementation_type& impl, int type);
+
+  // The type of a NtSetInformationFile function pointer.
+  typedef LONG (NTAPI *nt_set_info_fn)(HANDLE, ULONG_PTR*, void*, ULONG, ULONG);
+
+  // Helper function to get the NtSetInformationFile function pointer. If no
+  // NtSetInformationFile pointer has been obtained yet, one is obtained using
+  // GetProcAddress and the pointer is cached. Returns a null pointer if
+  // NtSetInformationFile is not available.
+  ASIO_DECL nt_set_info_fn get_nt_set_info();
+
+  // Helper function to emulate InterlockedCompareExchangePointer functionality
+  // for:
+  // - very old Platform SDKs; and
+  // - platform SDKs where MSVC's /Wp64 option causes spurious warnings.
+  ASIO_DECL void* interlocked_compare_exchange_pointer(
+      void** dest, void* exch, void* cmp);
+
+  // Helper function to emulate InterlockedExchangePointer functionality for:
+  // - very old Platform SDKs; and
+  // - platform SDKs where MSVC's /Wp64 option causes spurious warnings.
+  ASIO_DECL void* interlocked_exchange_pointer(void** dest, void* val);
+
+  // The execution context used to obtain the reactor, if required.
+  execution_context& context_;
+
+  // The IOCP service used for running asynchronous operations and dispatching
+  // handlers.
+  win_iocp_io_context& iocp_service_;
+
+  // The reactor used for performing connect operations. This object is created
+  // only if needed.
+  select_reactor* reactor_;
+
+  // Pointer to ConnectEx implementation.
+  void* connect_ex_;
+
+  // Pointer to NtSetInformationFile implementation.
+  void* nt_set_info_;
+
+  // Mutex to protect access to the linked list of implementations. 
+  asio::detail::mutex mutex_;
+
+  // The head of a linked list of all implementations.
+  base_implementation_type* impl_list_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/win_iocp_socket_service_base.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // defined(ASIO_HAS_IOCP)
+
+#endif // ASIO_DETAIL_WIN_IOCP_SOCKET_SERVICE_BASE_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/win_iocp_thread_info.hpp b/link/modules/asio-standalone/asio/include/asio/detail/win_iocp_thread_info.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/win_iocp_thread_info.hpp
@@ -0,0 +1,34 @@
+//
+// detail/win_iocp_thread_info.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_WIN_IOCP_THREAD_INFO_HPP
+#define ASIO_DETAIL_WIN_IOCP_THREAD_INFO_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/thread_info_base.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+struct win_iocp_thread_info : public thread_info_base
+{
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_WIN_IOCP_THREAD_INFO_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/win_iocp_wait_op.hpp b/link/modules/asio-standalone/asio/include/asio/detail/win_iocp_wait_op.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/win_iocp_wait_op.hpp
@@ -0,0 +1,128 @@
+//
+// detail/win_iocp_wait_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_WIN_IOCP_WAIT_OP_HPP
+#define ASIO_DETAIL_WIN_IOCP_WAIT_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_IOCP)
+
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/buffer_sequence_adapter.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/handler_work.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/detail/reactor_op.hpp"
+#include "asio/detail/socket_ops.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Handler, typename IoExecutor>
+class win_iocp_wait_op : public reactor_op
+{
+public:
+  ASIO_DEFINE_HANDLER_PTR(win_iocp_wait_op);
+
+  win_iocp_wait_op(socket_ops::weak_cancel_token_type cancel_token,
+      Handler& handler, const IoExecutor& io_ex)
+    : reactor_op(asio::error_code(),
+        &win_iocp_wait_op::do_perform,
+        &win_iocp_wait_op::do_complete),
+      cancel_token_(cancel_token),
+      handler_(ASIO_MOVE_CAST(Handler)(handler)),
+      work_(handler_, io_ex)
+  {
+  }
+
+  static status do_perform(reactor_op*)
+  {
+    return done;
+  }
+
+  static void do_complete(void* owner, operation* base,
+      const asio::error_code& result_ec,
+      std::size_t /*bytes_transferred*/)
+  {
+    asio::error_code ec(result_ec);
+
+    // Take ownership of the operation object.
+    win_iocp_wait_op* o(static_cast<win_iocp_wait_op*>(base));
+    ptr p = { asio::detail::addressof(o->handler_), o, o };
+
+    ASIO_HANDLER_COMPLETION((*o));
+
+    // Take ownership of the operation's outstanding work.
+    handler_work<Handler, IoExecutor> w(
+        ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)(
+          o->work_));
+
+    // The reactor may have stored a result in the operation object.
+    if (o->ec_)
+      ec = o->ec_;
+
+    // Map non-portable errors to their portable counterparts.
+    if (ec.value() == ERROR_NETNAME_DELETED)
+    {
+      if (o->cancel_token_.expired())
+        ec = asio::error::operation_aborted;
+      else
+        ec = asio::error::connection_reset;
+    }
+    else if (ec.value() == ERROR_PORT_UNREACHABLE)
+    {
+      ec = asio::error::connection_refused;
+    }
+
+    // Make a copy of the handler so that the memory can be deallocated before
+    // the upcall is made. Even if we're not about to make an upcall, a
+    // sub-object of the handler may be the true owner of the memory associated
+    // with the handler. Consequently, a local copy of the handler is required
+    // to ensure that any owning sub-object remains valid until after we have
+    // deallocated the memory here.
+    detail::binder1<Handler, asio::error_code>
+      handler(o->handler_, ec);
+    p.h = asio::detail::addressof(handler.handler_);
+    p.reset();
+
+    // Make the upcall if required.
+    if (owner)
+    {
+      fenced_block b(fenced_block::half);
+      ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_));
+      w.complete(handler, handler.handler_);
+      ASIO_HANDLER_INVOCATION_END;
+    }
+  }
+
+private:
+  socket_ops::weak_cancel_token_type cancel_token_;
+  Handler handler_;
+  handler_work<Handler, IoExecutor> work_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_IOCP)
+
+#endif // ASIO_DETAIL_WIN_IOCP_WAIT_OP_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/win_mutex.hpp b/link/modules/asio-standalone/asio/include/asio/detail/win_mutex.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/win_mutex.hpp
@@ -0,0 +1,78 @@
+//
+// detail/win_mutex.hpp
+// ~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_WIN_MUTEX_HPP
+#define ASIO_DETAIL_WIN_MUTEX_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_WINDOWS)
+
+#include "asio/detail/noncopyable.hpp"
+#include "asio/detail/scoped_lock.hpp"
+#include "asio/detail/socket_types.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class win_mutex
+  : private noncopyable
+{
+public:
+  typedef asio::detail::scoped_lock<win_mutex> scoped_lock;
+
+  // Constructor.
+  ASIO_DECL win_mutex();
+
+  // Destructor.
+  ~win_mutex()
+  {
+    ::DeleteCriticalSection(&crit_section_);
+  }
+
+  // Lock the mutex.
+  void lock()
+  {
+    ::EnterCriticalSection(&crit_section_);
+  }
+
+  // Unlock the mutex.
+  void unlock()
+  {
+    ::LeaveCriticalSection(&crit_section_);
+  }
+
+private:
+  // Initialisation must be performed in a separate function to the constructor
+  // since the compiler does not support the use of structured exceptions and
+  // C++ exceptions in the same function.
+  ASIO_DECL int do_init();
+
+  ::CRITICAL_SECTION crit_section_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/win_mutex.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // defined(ASIO_WINDOWS)
+
+#endif // ASIO_DETAIL_WIN_MUTEX_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/win_object_handle_service.hpp b/link/modules/asio-standalone/asio/include/asio/detail/win_object_handle_service.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/win_object_handle_service.hpp
@@ -0,0 +1,195 @@
+//
+// detail/win_object_handle_service.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2011 Boris Schaeling (boris@highscore.de)
+//
+// 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 ASIO_DETAIL_WIN_OBJECT_HANDLE_SERVICE_HPP
+#define ASIO_DETAIL_WIN_OBJECT_HANDLE_SERVICE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_WINDOWS_OBJECT_HANDLE)
+
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/detail/wait_handler.hpp"
+#include "asio/error.hpp"
+#include "asio/execution_context.hpp"
+
+#if defined(ASIO_HAS_IOCP)
+# include "asio/detail/win_iocp_io_context.hpp"
+#else // defined(ASIO_HAS_IOCP)
+# include "asio/detail/scheduler.hpp"
+#endif // defined(ASIO_HAS_IOCP)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class win_object_handle_service :
+  public execution_context_service_base<win_object_handle_service>
+{
+public:
+  // The native type of an object handle.
+  typedef HANDLE native_handle_type;
+
+  // The implementation type of the object handle.
+  class implementation_type
+  {
+   public:
+    // Default constructor.
+    implementation_type()
+      : handle_(INVALID_HANDLE_VALUE),
+        wait_handle_(INVALID_HANDLE_VALUE),
+        owner_(0),
+        next_(0),
+        prev_(0)
+    {
+    }
+
+  private:
+    // Only this service will have access to the internal values.
+    friend class win_object_handle_service;
+
+    // The native object handle representation. May be accessed or modified
+    // without locking the mutex.
+    native_handle_type handle_;
+
+    // The handle used to unregister the wait operation. The mutex must be
+    // locked when accessing or modifying this member.
+    HANDLE wait_handle_;
+
+    // The operations waiting on the object handle. If there is a registered
+    // wait then the mutex must be locked when accessing or modifying this
+    // member
+    op_queue<wait_op> op_queue_;
+
+    // The service instance that owns the object handle implementation.
+    win_object_handle_service* owner_;
+
+    // Pointers to adjacent handle implementations in linked list. The mutex
+    // must be locked when accessing or modifying these members.
+    implementation_type* next_;
+    implementation_type* prev_;
+  };
+
+  // Constructor.
+  ASIO_DECL win_object_handle_service(execution_context& context);
+
+  // Destroy all user-defined handler objects owned by the service.
+  ASIO_DECL void shutdown();
+
+  // Construct a new handle implementation.
+  ASIO_DECL void construct(implementation_type& impl);
+
+  // Move-construct a new handle implementation.
+  ASIO_DECL void move_construct(implementation_type& impl,
+      implementation_type& other_impl);
+
+  // Move-assign from another handle implementation.
+  ASIO_DECL void move_assign(implementation_type& impl,
+      win_object_handle_service& other_service,
+      implementation_type& other_impl);
+
+  // Destroy a handle implementation.
+  ASIO_DECL void destroy(implementation_type& impl);
+
+  // Assign a native handle to a handle implementation.
+  ASIO_DECL asio::error_code assign(implementation_type& impl,
+      const native_handle_type& handle, asio::error_code& ec);
+
+  // Determine whether the handle is open.
+  bool is_open(const implementation_type& impl) const
+  {
+    return impl.handle_ != INVALID_HANDLE_VALUE && impl.handle_ != 0;
+  }
+
+  // Destroy a handle implementation.
+  ASIO_DECL asio::error_code close(implementation_type& impl,
+      asio::error_code& ec);
+
+  // Get the native handle representation.
+  native_handle_type native_handle(const implementation_type& impl) const
+  {
+    return impl.handle_;
+  }
+
+  // Cancel all operations associated with the handle.
+  ASIO_DECL asio::error_code cancel(implementation_type& impl,
+      asio::error_code& ec);
+
+  // Perform a synchronous wait for the object to enter a signalled state.
+  ASIO_DECL void wait(implementation_type& impl,
+      asio::error_code& ec);
+
+  /// Start an asynchronous wait.
+  template <typename Handler, typename IoExecutor>
+  void async_wait(implementation_type& impl,
+      Handler& handler, const IoExecutor& io_ex)
+  {
+    // Allocate and construct an operation to wrap the handler.
+    typedef wait_handler<Handler, IoExecutor> op;
+    typename op::ptr p = { asio::detail::addressof(handler),
+      op::ptr::allocate(handler), 0 };
+    p.p = new (p.v) op(handler, io_ex);
+
+    ASIO_HANDLER_CREATION((scheduler_.context(), *p.p, "object_handle",
+          &impl, reinterpret_cast<uintmax_t>(impl.wait_handle_), "async_wait"));
+
+    start_wait_op(impl, p.p);
+    p.v = p.p = 0;
+  }
+
+private:
+  // Helper function to start an asynchronous wait operation.
+  ASIO_DECL void start_wait_op(implementation_type& impl, wait_op* op);
+
+  // Helper function to register a wait operation.
+  ASIO_DECL void register_wait_callback(
+      implementation_type& impl, mutex::scoped_lock& lock);
+
+  // Callback function invoked when the registered wait completes.
+  static ASIO_DECL VOID CALLBACK wait_callback(
+      PVOID param, BOOLEAN timeout);
+
+  // The scheduler used to post completions.
+#if defined(ASIO_HAS_IOCP)
+  typedef class win_iocp_io_context scheduler_impl;
+#else
+  typedef class scheduler scheduler_impl;
+#endif
+  scheduler_impl& scheduler_;
+
+  // Mutex to protect access to internal state.
+  mutex mutex_;
+
+  // The head of a linked list of all implementations.
+  implementation_type* impl_list_;
+
+  // Flag to indicate that the dispatcher has been shut down.
+  bool shutdown_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/win_object_handle_service.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // defined(ASIO_HAS_WINDOWS_OBJECT_HANDLE)
+
+#endif // ASIO_DETAIL_WIN_OBJECT_HANDLE_SERVICE_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/win_static_mutex.hpp b/link/modules/asio-standalone/asio/include/asio/detail/win_static_mutex.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/win_static_mutex.hpp
@@ -0,0 +1,74 @@
+//
+// detail/win_static_mutex.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_WIN_STATIC_MUTEX_HPP
+#define ASIO_DETAIL_WIN_STATIC_MUTEX_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_WINDOWS)
+
+#include "asio/detail/scoped_lock.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+struct win_static_mutex
+{
+  typedef asio::detail::scoped_lock<win_static_mutex> scoped_lock;
+
+  // Initialise the mutex.
+  ASIO_DECL void init();
+
+  // Initialisation must be performed in a separate function to the "public"
+  // init() function since the compiler does not support the use of structured
+  // exceptions and C++ exceptions in the same function.
+  ASIO_DECL int do_init();
+
+  // Lock the mutex.
+  void lock()
+  {
+    ::EnterCriticalSection(&crit_section_);
+  }
+
+  // Unlock the mutex.
+  void unlock()
+  {
+    ::LeaveCriticalSection(&crit_section_);
+  }
+
+  bool initialised_;
+  ::CRITICAL_SECTION crit_section_;
+};
+
+#if defined(UNDER_CE)
+# define ASIO_WIN_STATIC_MUTEX_INIT { false, { 0, 0, 0, 0, 0 } }
+#else // defined(UNDER_CE)
+# define ASIO_WIN_STATIC_MUTEX_INIT { false, { 0, 0, 0, 0, 0, 0 } }
+#endif // defined(UNDER_CE)
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/win_static_mutex.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // defined(ASIO_WINDOWS)
+
+#endif // ASIO_DETAIL_WIN_STATIC_MUTEX_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/win_thread.hpp b/link/modules/asio-standalone/asio/include/asio/detail/win_thread.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/win_thread.hpp
@@ -0,0 +1,147 @@
+//
+// detail/win_thread.hpp
+// ~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_WIN_THREAD_HPP
+#define ASIO_DETAIL_WIN_THREAD_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_WINDOWS) \
+  && !defined(ASIO_WINDOWS_APP) \
+  && !defined(UNDER_CE)
+
+#include <cstddef>
+#include "asio/detail/noncopyable.hpp"
+#include "asio/detail/socket_types.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+ASIO_DECL unsigned int __stdcall win_thread_function(void* arg);
+
+#if defined(WINVER) && (WINVER < 0x0500)
+ASIO_DECL void __stdcall apc_function(ULONG data);
+#else
+ASIO_DECL void __stdcall apc_function(ULONG_PTR data);
+#endif
+
+template <typename T>
+class win_thread_base
+{
+public:
+  static bool terminate_threads()
+  {
+    return ::InterlockedExchangeAdd(&terminate_threads_, 0) != 0;
+  }
+
+  static void set_terminate_threads(bool b)
+  {
+    ::InterlockedExchange(&terminate_threads_, b ? 1 : 0);
+  }
+
+private:
+  static long terminate_threads_;
+};
+
+template <typename T>
+long win_thread_base<T>::terminate_threads_ = 0;
+
+class win_thread
+  : private noncopyable,
+    public win_thread_base<win_thread>
+{
+public:
+  // Constructor.
+  template <typename Function>
+  win_thread(Function f, unsigned int stack_size = 0)
+    : thread_(0),
+      exit_event_(0)
+  {
+    start_thread(new func<Function>(f), stack_size);
+  }
+
+  // Destructor.
+  ASIO_DECL ~win_thread();
+
+  // Wait for the thread to exit.
+  ASIO_DECL void join();
+
+  // Get number of CPUs.
+  ASIO_DECL static std::size_t hardware_concurrency();
+
+private:
+  friend ASIO_DECL unsigned int __stdcall win_thread_function(void* arg);
+
+#if defined(WINVER) && (WINVER < 0x0500)
+  friend ASIO_DECL void __stdcall apc_function(ULONG);
+#else
+  friend ASIO_DECL void __stdcall apc_function(ULONG_PTR);
+#endif
+
+  class func_base
+  {
+  public:
+    virtual ~func_base() {}
+    virtual void run() = 0;
+    ::HANDLE entry_event_;
+    ::HANDLE exit_event_;
+  };
+
+  struct auto_func_base_ptr
+  {
+    func_base* ptr;
+    ~auto_func_base_ptr() { delete ptr; }
+  };
+
+  template <typename Function>
+  class func
+    : public func_base
+  {
+  public:
+    func(Function f)
+      : f_(f)
+    {
+    }
+
+    virtual void run()
+    {
+      f_();
+    }
+
+  private:
+    Function f_;
+  };
+
+  ASIO_DECL void start_thread(func_base* arg, unsigned int stack_size);
+
+  ::HANDLE thread_;
+  ::HANDLE exit_event_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/win_thread.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // defined(ASIO_WINDOWS)
+       // && !defined(ASIO_WINDOWS_APP)
+       // && !defined(UNDER_CE)
+
+#endif // ASIO_DETAIL_WIN_THREAD_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/win_tss_ptr.hpp b/link/modules/asio-standalone/asio/include/asio/detail/win_tss_ptr.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/win_tss_ptr.hpp
@@ -0,0 +1,79 @@
+//
+// detail/win_tss_ptr.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_WIN_TSS_PTR_HPP
+#define ASIO_DETAIL_WIN_TSS_PTR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_WINDOWS)
+
+#include "asio/detail/noncopyable.hpp"
+#include "asio/detail/socket_types.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+// Helper function to create thread-specific storage.
+ASIO_DECL DWORD win_tss_ptr_create();
+
+template <typename T>
+class win_tss_ptr
+  : private noncopyable
+{
+public:
+  // Constructor.
+  win_tss_ptr()
+    : tss_key_(win_tss_ptr_create())
+  {
+  }
+
+  // Destructor.
+  ~win_tss_ptr()
+  {
+    ::TlsFree(tss_key_);
+  }
+
+  // Get the value.
+  operator T*() const
+  {
+    return static_cast<T*>(::TlsGetValue(tss_key_));
+  }
+
+  // Set the value.
+  void operator=(T* value)
+  {
+    ::TlsSetValue(tss_key_, value);
+  }
+
+private:
+  // Thread-specific storage to allow unlocked access to determine whether a
+  // thread is a member of the pool.
+  DWORD tss_key_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/win_tss_ptr.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // defined(ASIO_WINDOWS)
+
+#endif // ASIO_DETAIL_WIN_TSS_PTR_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/winapp_thread.hpp b/link/modules/asio-standalone/asio/include/asio/detail/winapp_thread.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/winapp_thread.hpp
@@ -0,0 +1,124 @@
+//
+// detail/winapp_thread.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_WINAPP_THREAD_HPP
+#define ASIO_DETAIL_WINAPP_THREAD_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_WINDOWS) && defined(ASIO_WINDOWS_APP)
+
+#include "asio/detail/noncopyable.hpp"
+#include "asio/detail/scoped_ptr.hpp"
+#include "asio/detail/socket_types.hpp"
+#include "asio/detail/throw_error.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+DWORD WINAPI winapp_thread_function(LPVOID arg);
+
+class winapp_thread
+  : private noncopyable
+{
+public:
+  // Constructor.
+  template <typename Function>
+  winapp_thread(Function f, unsigned int = 0)
+  {
+    scoped_ptr<func_base> arg(new func<Function>(f));
+    DWORD thread_id = 0;
+    thread_ = ::CreateThread(0, 0, winapp_thread_function,
+        arg.get(), 0, &thread_id);
+    if (!thread_)
+    {
+      DWORD last_error = ::GetLastError();
+      asio::error_code ec(last_error,
+          asio::error::get_system_category());
+      asio::detail::throw_error(ec, "thread");
+    }
+    arg.release();
+  }
+
+  // Destructor.
+  ~winapp_thread()
+  {
+    ::CloseHandle(thread_);
+  }
+
+  // Wait for the thread to exit.
+  void join()
+  {
+    ::WaitForSingleObjectEx(thread_, INFINITE, false);
+  }
+
+  // Get number of CPUs.
+  static std::size_t hardware_concurrency()
+  {
+    SYSTEM_INFO system_info;
+    ::GetNativeSystemInfo(&system_info);
+    return system_info.dwNumberOfProcessors;
+  }
+
+private:
+  friend DWORD WINAPI winapp_thread_function(LPVOID arg);
+
+  class func_base
+  {
+  public:
+    virtual ~func_base() {}
+    virtual void run() = 0;
+  };
+
+  template <typename Function>
+  class func
+    : public func_base
+  {
+  public:
+    func(Function f)
+      : f_(f)
+    {
+    }
+
+    virtual void run()
+    {
+      f_();
+    }
+
+  private:
+    Function f_;
+  };
+
+  ::HANDLE thread_;
+};
+
+inline DWORD WINAPI winapp_thread_function(LPVOID arg)
+{
+  scoped_ptr<winapp_thread::func_base> func(
+      static_cast<winapp_thread::func_base*>(arg));
+  func->run();
+  return 0;
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_WINDOWS) && defined(ASIO_WINDOWS_APP)
+
+#endif // ASIO_DETAIL_WINAPP_THREAD_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/wince_thread.hpp b/link/modules/asio-standalone/asio/include/asio/detail/wince_thread.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/wince_thread.hpp
@@ -0,0 +1,124 @@
+//
+// detail/wince_thread.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_WINCE_THREAD_HPP
+#define ASIO_DETAIL_WINCE_THREAD_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_WINDOWS) && defined(UNDER_CE)
+
+#include "asio/detail/noncopyable.hpp"
+#include "asio/detail/scoped_ptr.hpp"
+#include "asio/detail/socket_types.hpp"
+#include "asio/detail/throw_error.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+DWORD WINAPI wince_thread_function(LPVOID arg);
+
+class wince_thread
+  : private noncopyable
+{
+public:
+  // Constructor.
+  template <typename Function>
+  wince_thread(Function f, unsigned int = 0)
+  {
+    scoped_ptr<func_base> arg(new func<Function>(f));
+    DWORD thread_id = 0;
+    thread_ = ::CreateThread(0, 0, wince_thread_function,
+        arg.get(), 0, &thread_id);
+    if (!thread_)
+    {
+      DWORD last_error = ::GetLastError();
+      asio::error_code ec(last_error,
+          asio::error::get_system_category());
+      asio::detail::throw_error(ec, "thread");
+    }
+    arg.release();
+  }
+
+  // Destructor.
+  ~wince_thread()
+  {
+    ::CloseHandle(thread_);
+  }
+
+  // Wait for the thread to exit.
+  void join()
+  {
+    ::WaitForSingleObject(thread_, INFINITE);
+  }
+
+  // Get number of CPUs.
+  static std::size_t hardware_concurrency()
+  {
+    SYSTEM_INFO system_info;
+    ::GetSystemInfo(&system_info);
+    return system_info.dwNumberOfProcessors;
+  }
+
+private:
+  friend DWORD WINAPI wince_thread_function(LPVOID arg);
+
+  class func_base
+  {
+  public:
+    virtual ~func_base() {}
+    virtual void run() = 0;
+  };
+
+  template <typename Function>
+  class func
+    : public func_base
+  {
+  public:
+    func(Function f)
+      : f_(f)
+    {
+    }
+
+    virtual void run()
+    {
+      f_();
+    }
+
+  private:
+    Function f_;
+  };
+
+  ::HANDLE thread_;
+};
+
+inline DWORD WINAPI wince_thread_function(LPVOID arg)
+{
+  scoped_ptr<wince_thread::func_base> func(
+      static_cast<wince_thread::func_base*>(arg));
+  func->run();
+  return 0;
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_WINDOWS) && defined(UNDER_CE)
+
+#endif // ASIO_DETAIL_WINCE_THREAD_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/winrt_async_manager.hpp b/link/modules/asio-standalone/asio/include/asio/detail/winrt_async_manager.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/winrt_async_manager.hpp
@@ -0,0 +1,305 @@
+//
+// detail/winrt_async_manager.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_WINRT_ASYNC_MANAGER_HPP
+#define ASIO_DETAIL_WINRT_ASYNC_MANAGER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_WINDOWS_RUNTIME)
+
+#include <future>
+#include "asio/detail/atomic_count.hpp"
+#include "asio/detail/winrt_async_op.hpp"
+#include "asio/error.hpp"
+#include "asio/execution_context.hpp"
+
+#if defined(ASIO_HAS_IOCP)
+# include "asio/detail/win_iocp_io_context.hpp"
+#else // defined(ASIO_HAS_IOCP)
+# include "asio/detail/scheduler.hpp"
+#endif // defined(ASIO_HAS_IOCP)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class winrt_async_manager
+  : public execution_context_service_base<winrt_async_manager>
+{
+public:
+  // Constructor.
+  winrt_async_manager(execution_context& context)
+    : execution_context_service_base<winrt_async_manager>(context),
+      scheduler_(use_service<scheduler_impl>(context)),
+      outstanding_ops_(1)
+  {
+  }
+
+  // Destructor.
+  ~winrt_async_manager()
+  {
+  }
+
+  // Destroy all user-defined handler objects owned by the service.
+  void shutdown()
+  {
+    if (--outstanding_ops_ > 0)
+    {
+      // Block until last operation is complete.
+      std::future<void> f = promise_.get_future();
+      f.wait();
+    }
+  }
+
+  void sync(Windows::Foundation::IAsyncAction^ action,
+      asio::error_code& ec)
+  {
+    using namespace Windows::Foundation;
+    using Windows::Foundation::AsyncStatus;
+
+    auto promise = std::make_shared<std::promise<asio::error_code>>();
+    auto future = promise->get_future();
+
+    action->Completed = ref new AsyncActionCompletedHandler(
+      [promise](IAsyncAction^ action, AsyncStatus status)
+      {
+        switch (status)
+        {
+        case AsyncStatus::Canceled:
+          promise->set_value(asio::error::operation_aborted);
+          break;
+        case AsyncStatus::Error:
+        case AsyncStatus::Completed:
+        default:
+          asio::error_code ec(
+              action->ErrorCode.Value,
+              asio::system_category());
+          promise->set_value(ec);
+          break;
+        }
+      });
+
+    ec = future.get();
+  }
+
+  template <typename TResult>
+  TResult sync(Windows::Foundation::IAsyncOperation<TResult>^ operation,
+      asio::error_code& ec)
+  {
+    using namespace Windows::Foundation;
+    using Windows::Foundation::AsyncStatus;
+
+    auto promise = std::make_shared<std::promise<asio::error_code>>();
+    auto future = promise->get_future();
+
+    operation->Completed = ref new AsyncOperationCompletedHandler<TResult>(
+      [promise](IAsyncOperation<TResult>^ operation, AsyncStatus status)
+      {
+        switch (status)
+        {
+        case AsyncStatus::Canceled:
+          promise->set_value(asio::error::operation_aborted);
+          break;
+        case AsyncStatus::Error:
+        case AsyncStatus::Completed:
+        default:
+          asio::error_code ec(
+              operation->ErrorCode.Value,
+              asio::system_category());
+          promise->set_value(ec);
+          break;
+        }
+      });
+
+    ec = future.get();
+    return operation->GetResults();
+  }
+
+  template <typename TResult, typename TProgress>
+  TResult sync(
+      Windows::Foundation::IAsyncOperationWithProgress<
+        TResult, TProgress>^ operation,
+      asio::error_code& ec)
+  {
+    using namespace Windows::Foundation;
+    using Windows::Foundation::AsyncStatus;
+
+    auto promise = std::make_shared<std::promise<asio::error_code>>();
+    auto future = promise->get_future();
+
+    operation->Completed
+      = ref new AsyncOperationWithProgressCompletedHandler<TResult, TProgress>(
+        [promise](IAsyncOperationWithProgress<TResult, TProgress>^ operation,
+          AsyncStatus status)
+        {
+          switch (status)
+          {
+          case AsyncStatus::Canceled:
+            promise->set_value(asio::error::operation_aborted);
+            break;
+          case AsyncStatus::Started:
+            break;
+          case AsyncStatus::Error:
+          case AsyncStatus::Completed:
+          default:
+            asio::error_code ec(
+                operation->ErrorCode.Value,
+                asio::system_category());
+            promise->set_value(ec);
+            break;
+          }
+        });
+
+    ec = future.get();
+    return operation->GetResults();
+  }
+
+  void async(Windows::Foundation::IAsyncAction^ action,
+      winrt_async_op<void>* handler)
+  {
+    using namespace Windows::Foundation;
+    using Windows::Foundation::AsyncStatus;
+
+    auto on_completed = ref new AsyncActionCompletedHandler(
+      [this, handler](IAsyncAction^ action, AsyncStatus status)
+      {
+        switch (status)
+        {
+        case AsyncStatus::Canceled:
+          handler->ec_ = asio::error::operation_aborted;
+          break;
+        case AsyncStatus::Started:
+          return;
+        case AsyncStatus::Completed:
+        case AsyncStatus::Error:
+        default:
+          handler->ec_ = asio::error_code(
+              action->ErrorCode.Value,
+              asio::system_category());
+          break;
+        }
+        scheduler_.post_deferred_completion(handler);
+        if (--outstanding_ops_ == 0)
+          promise_.set_value();
+      });
+
+    scheduler_.work_started();
+    ++outstanding_ops_;
+    action->Completed = on_completed;
+  }
+
+  template <typename TResult>
+  void async(Windows::Foundation::IAsyncOperation<TResult>^ operation,
+      winrt_async_op<TResult>* handler)
+  {
+    using namespace Windows::Foundation;
+    using Windows::Foundation::AsyncStatus;
+
+    auto on_completed = ref new AsyncOperationCompletedHandler<TResult>(
+      [this, handler](IAsyncOperation<TResult>^ operation, AsyncStatus status)
+      {
+        switch (status)
+        {
+        case AsyncStatus::Canceled:
+          handler->ec_ = asio::error::operation_aborted;
+          break;
+        case AsyncStatus::Started:
+          return;
+        case AsyncStatus::Completed:
+          handler->result_ = operation->GetResults();
+          // Fall through.
+        case AsyncStatus::Error:
+        default:
+          handler->ec_ = asio::error_code(
+              operation->ErrorCode.Value,
+              asio::system_category());
+          break;
+        }
+        scheduler_.post_deferred_completion(handler);
+        if (--outstanding_ops_ == 0)
+          promise_.set_value();
+      });
+
+    scheduler_.work_started();
+    ++outstanding_ops_;
+    operation->Completed = on_completed;
+  }
+
+  template <typename TResult, typename TProgress>
+  void async(
+      Windows::Foundation::IAsyncOperationWithProgress<
+        TResult, TProgress>^ operation,
+      winrt_async_op<TResult>* handler)
+  {
+    using namespace Windows::Foundation;
+    using Windows::Foundation::AsyncStatus;
+
+    auto on_completed
+      = ref new AsyncOperationWithProgressCompletedHandler<TResult, TProgress>(
+        [this, handler](IAsyncOperationWithProgress<
+          TResult, TProgress>^ operation, AsyncStatus status)
+        {
+          switch (status)
+          {
+          case AsyncStatus::Canceled:
+            handler->ec_ = asio::error::operation_aborted;
+            break;
+          case AsyncStatus::Started:
+            return;
+          case AsyncStatus::Completed:
+            handler->result_ = operation->GetResults();
+            // Fall through.
+          case AsyncStatus::Error:
+          default:
+            handler->ec_ = asio::error_code(
+                operation->ErrorCode.Value,
+                asio::system_category());
+            break;
+          }
+          scheduler_.post_deferred_completion(handler);
+          if (--outstanding_ops_ == 0)
+            promise_.set_value();
+        });
+
+    scheduler_.work_started();
+    ++outstanding_ops_;
+    operation->Completed = on_completed;
+  }
+
+private:
+  // The scheduler implementation used to post completed handlers.
+#if defined(ASIO_HAS_IOCP)
+  typedef class win_iocp_io_context scheduler_impl;
+#else
+  typedef class scheduler scheduler_impl;
+#endif
+  scheduler_impl& scheduler_;
+
+  // Count of outstanding operations.
+  atomic_count outstanding_ops_;
+
+  // Used to keep wait for outstanding operations to complete.
+  std::promise<void> promise_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_WINDOWS_RUNTIME)
+
+#endif // ASIO_DETAIL_WINRT_ASYNC_MANAGER_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/winrt_async_op.hpp b/link/modules/asio-standalone/asio/include/asio/detail/winrt_async_op.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/winrt_async_op.hpp
@@ -0,0 +1,65 @@
+//
+// detail/winrt_async_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_WINRT_ASYNC_OP_HPP
+#define ASIO_DETAIL_WINRT_ASYNC_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/operation.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename TResult>
+class winrt_async_op
+  : public operation
+{
+public:
+  // The error code to be passed to the completion handler.
+  asio::error_code ec_;
+
+  // The result of the operation, to be passed to the completion handler.
+  TResult result_;
+
+protected:
+  winrt_async_op(func_type complete_func)
+    : operation(complete_func),
+      result_()
+  {
+  }
+};
+
+template <>
+class winrt_async_op<void>
+  : public operation
+{
+public:
+  // The error code to be passed to the completion handler.
+  asio::error_code ec_;
+
+protected:
+  winrt_async_op(func_type complete_func)
+    : operation(complete_func)
+  {
+  }
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_WINRT_ASYNC_OP_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/winrt_resolve_op.hpp b/link/modules/asio-standalone/asio/include/asio/detail/winrt_resolve_op.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/winrt_resolve_op.hpp
@@ -0,0 +1,125 @@
+//
+// detail/winrt_resolve_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_WINRT_RESOLVE_OP_HPP
+#define ASIO_DETAIL_WINRT_RESOLVE_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_WINDOWS_RUNTIME)
+
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/handler_work.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/detail/winrt_async_op.hpp"
+#include "asio/ip/basic_resolver_results.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Protocol, typename Handler, typename IoExecutor>
+class winrt_resolve_op :
+  public winrt_async_op<
+    Windows::Foundation::Collections::IVectorView<
+      Windows::Networking::EndpointPair^>^>
+{
+public:
+  ASIO_DEFINE_HANDLER_PTR(winrt_resolve_op);
+
+  typedef typename Protocol::endpoint endpoint_type;
+  typedef asio::ip::basic_resolver_query<Protocol> query_type;
+  typedef asio::ip::basic_resolver_results<Protocol> results_type;
+
+  winrt_resolve_op(const query_type& query,
+      Handler& handler, const IoExecutor& io_ex)
+    : winrt_async_op<
+        Windows::Foundation::Collections::IVectorView<
+          Windows::Networking::EndpointPair^>^>(
+            &winrt_resolve_op::do_complete),
+      query_(query),
+      handler_(ASIO_MOVE_CAST(Handler)(handler)),
+      work_(handler_, io_ex)
+  {
+  }
+
+  static void do_complete(void* owner, operation* base,
+      const asio::error_code&, std::size_t)
+  {
+    // Take ownership of the operation object.
+    winrt_resolve_op* o(static_cast<winrt_resolve_op*>(base));
+    ptr p = { asio::detail::addressof(o->handler_), o, o };
+
+    ASIO_HANDLER_COMPLETION((*o));
+
+    // Take ownership of the operation's outstanding work.
+    handler_work<Handler, IoExecutor> w(
+        ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)(
+          o->work_));
+
+    results_type results = results_type();
+    if (!o->ec_)
+    {
+      try
+      {
+        results = results_type::create(o->result_, o->query_.hints(),
+            o->query_.host_name(), o->query_.service_name());
+      }
+      catch (Platform::Exception^ e)
+      {
+        o->ec_ = asio::error_code(e->HResult,
+            asio::system_category());
+      }
+    }
+
+    // Make a copy of the handler so that the memory can be deallocated before
+    // the upcall is made. Even if we're not about to make an upcall, a
+    // sub-object of the handler may be the true owner of the memory associated
+    // with the handler. Consequently, a local copy of the handler is required
+    // to ensure that any owning sub-object remains valid until after we have
+    // deallocated the memory here.
+    detail::binder2<Handler, asio::error_code, results_type>
+      handler(o->handler_, o->ec_, results);
+    p.h = asio::detail::addressof(handler.handler_);
+    p.reset();
+
+    // Make the upcall if required.
+    if (owner)
+    {
+      fenced_block b(fenced_block::half);
+      ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, "..."));
+      w.complete(handler, handler.handler_);
+      ASIO_HANDLER_INVOCATION_END;
+    }
+  }
+
+private:
+  query_type query_;
+  Handler handler_;
+  handler_work<Handler, IoExecutor> executor_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_WINDOWS_RUNTIME)
+
+#endif // ASIO_DETAIL_WINRT_RESOLVE_OP_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/winrt_resolver_service.hpp b/link/modules/asio-standalone/asio/include/asio/detail/winrt_resolver_service.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/winrt_resolver_service.hpp
@@ -0,0 +1,212 @@
+//
+// detail/winrt_resolver_service.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_WINRT_RESOLVER_SERVICE_HPP
+#define ASIO_DETAIL_WINRT_RESOLVER_SERVICE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_WINDOWS_RUNTIME)
+
+#include "asio/ip/basic_resolver_query.hpp"
+#include "asio/ip/basic_resolver_results.hpp"
+#include "asio/post.hpp"
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/detail/socket_ops.hpp"
+#include "asio/detail/winrt_async_manager.hpp"
+#include "asio/detail/winrt_resolve_op.hpp"
+#include "asio/detail/winrt_utils.hpp"
+
+#if defined(ASIO_HAS_IOCP)
+# include "asio/detail/win_iocp_io_context.hpp"
+#else // defined(ASIO_HAS_IOCP)
+# include "asio/detail/scheduler.hpp"
+#endif // defined(ASIO_HAS_IOCP)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Protocol>
+class winrt_resolver_service :
+  public execution_context_service_base<winrt_resolver_service<Protocol> >
+{
+public:
+  // The implementation type of the resolver. A cancellation token is used to
+  // indicate to the asynchronous operation that the operation has been
+  // cancelled.
+  typedef socket_ops::shared_cancel_token_type implementation_type;
+
+  // The endpoint type.
+  typedef typename Protocol::endpoint endpoint_type;
+
+  // The query type.
+  typedef asio::ip::basic_resolver_query<Protocol> query_type;
+
+  // The results type.
+  typedef asio::ip::basic_resolver_results<Protocol> results_type;
+
+  // Constructor.
+  winrt_resolver_service(execution_context& context)
+    : execution_context_service_base<
+        winrt_resolver_service<Protocol> >(context),
+      scheduler_(use_service<scheduler_impl>(context)),
+      async_manager_(use_service<winrt_async_manager>(context))
+  {
+  }
+
+  // Destructor.
+  ~winrt_resolver_service()
+  {
+  }
+
+  // Destroy all user-defined handler objects owned by the service.
+  void shutdown()
+  {
+  }
+
+  // Perform any fork-related housekeeping.
+  void notify_fork(execution_context::fork_event)
+  {
+  }
+
+  // Construct a new resolver implementation.
+  void construct(implementation_type&)
+  {
+  }
+
+  // Move-construct a new resolver implementation.
+  void move_construct(implementation_type&,
+      implementation_type&)
+  {
+  }
+
+  // Move-assign from another resolver implementation.
+  void move_assign(implementation_type&,
+      winrt_resolver_service&, implementation_type&)
+  {
+  }
+
+  // Destroy a resolver implementation.
+  void destroy(implementation_type&)
+  {
+  }
+
+  // Cancel pending asynchronous operations.
+  void cancel(implementation_type&)
+  {
+  }
+
+  // Resolve a query to a list of entries.
+  results_type resolve(implementation_type&,
+      const query_type& query, asio::error_code& ec)
+  {
+    try
+    {
+      using namespace Windows::Networking::Sockets;
+      auto endpoint_pairs = async_manager_.sync(
+          DatagramSocket::GetEndpointPairsAsync(
+            winrt_utils::host_name(query.host_name()),
+            winrt_utils::string(query.service_name())), ec);
+
+      if (ec)
+        return results_type();
+
+      return results_type::create(
+          endpoint_pairs, query.hints(),
+          query.host_name(), query.service_name());
+    }
+    catch (Platform::Exception^ e)
+    {
+      ec = asio::error_code(e->HResult,
+          asio::system_category());
+      return results_type();
+    }
+  }
+
+  // Asynchronously resolve a query to a list of entries.
+  template <typename Handler, typename IoExecutor>
+  void async_resolve(implementation_type& impl, const query_type& query,
+      Handler& handler, const IoExecutor& io_ex)
+  {
+    bool is_continuation =
+      asio_handler_cont_helpers::is_continuation(handler);
+
+    // Allocate and construct an operation to wrap the handler.
+    typedef winrt_resolve_op<Protocol, Handler, IoExecutor> op;
+    typename op::ptr p = { asio::detail::addressof(handler),
+      op::ptr::allocate(handler), 0 };
+    p.p = new (p.v) op(query, handler, io_ex);
+
+    ASIO_HANDLER_CREATION((scheduler_.context(),
+          *p.p, "resolver", &impl, 0, "async_resolve"));
+    (void)impl;
+
+    try
+    {
+      using namespace Windows::Networking::Sockets;
+      async_manager_.async(DatagramSocket::GetEndpointPairsAsync(
+            winrt_utils::host_name(query.host_name()),
+            winrt_utils::string(query.service_name())), p.p);
+      p.v = p.p = 0;
+    }
+    catch (Platform::Exception^ e)
+    {
+      p.p->ec_ = asio::error_code(
+          e->HResult, asio::system_category());
+      scheduler_.post_immediate_completion(p.p, is_continuation);
+      p.v = p.p = 0;
+    }
+  }
+
+  // Resolve an endpoint to a list of entries.
+  results_type resolve(implementation_type&,
+      const endpoint_type&, asio::error_code& ec)
+  {
+    ec = asio::error::operation_not_supported;
+    return results_type();
+  }
+
+  // Asynchronously resolve an endpoint to a list of entries.
+  template <typename Handler, typename IoExecutor>
+  void async_resolve(implementation_type&, const endpoint_type&,
+      Handler& handler, const IoExecutor& io_ex)
+  {
+    asio::error_code ec = asio::error::operation_not_supported;
+    const results_type results;
+    asio::post(io_ex, detail::bind_handler(handler, ec, results));
+  }
+
+private:
+  // The scheduler implementation used for delivering completions.
+#if defined(ASIO_HAS_IOCP)
+  typedef class win_iocp_io_context scheduler_impl;
+#else
+  typedef class scheduler scheduler_impl;
+#endif
+  scheduler_impl& scheduler_;
+
+  winrt_async_manager& async_manager_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_WINDOWS_RUNTIME)
+
+#endif // ASIO_DETAIL_WINRT_RESOLVER_SERVICE_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/winrt_socket_connect_op.hpp b/link/modules/asio-standalone/asio/include/asio/detail/winrt_socket_connect_op.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/winrt_socket_connect_op.hpp
@@ -0,0 +1,98 @@
+//
+// detail/winrt_socket_connect_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_WINRT_SOCKET_CONNECT_OP_HPP
+#define ASIO_DETAIL_WINRT_SOCKET_CONNECT_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_WINDOWS_RUNTIME)
+
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/buffer_sequence_adapter.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/handler_work.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/detail/winrt_async_op.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Handler, typename IoExecutor>
+class winrt_socket_connect_op :
+  public winrt_async_op<void>
+{
+public:
+  ASIO_DEFINE_HANDLER_PTR(winrt_socket_connect_op);
+
+  winrt_socket_connect_op(Handler& handler, const IoExecutor& io_ex)
+    : winrt_async_op<void>(&winrt_socket_connect_op::do_complete),
+      handler_(ASIO_MOVE_CAST(Handler)(handler)),
+      work_(handler_, io_ex)
+  {
+  }
+
+  static void do_complete(void* owner, operation* base,
+      const asio::error_code&, std::size_t)
+  {
+    // Take ownership of the operation object.
+    winrt_socket_connect_op* o(static_cast<winrt_socket_connect_op*>(base));
+    ptr p = { asio::detail::addressof(o->handler_), o, o };
+
+    ASIO_HANDLER_COMPLETION((*o));
+
+    // Take ownership of the operation's outstanding work.
+    handler_work<Handler, IoExecutor> w(
+        ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)(
+          o->work_));
+
+    // Make a copy of the handler so that the memory can be deallocated before
+    // the upcall is made. Even if we're not about to make an upcall, a
+    // sub-object of the handler may be the true owner of the memory associated
+    // with the handler. Consequently, a local copy of the handler is required
+    // to ensure that any owning sub-object remains valid until after we have
+    // deallocated the memory here.
+    detail::binder1<Handler, asio::error_code>
+      handler(o->handler_, o->ec_);
+    p.h = asio::detail::addressof(handler.handler_);
+    p.reset();
+
+    // Make the upcall if required.
+    if (owner)
+    {
+      fenced_block b(fenced_block::half);
+      ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_));
+      w.complete(handler, handler.handler_);
+      ASIO_HANDLER_INVOCATION_END;
+    }
+  }
+
+private:
+  Handler handler_;
+  handler_work<Handler, IoExecutor> executor_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_WINDOWS_RUNTIME)
+
+#endif // ASIO_DETAIL_WINRT_SOCKET_CONNECT_OP_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/winrt_socket_recv_op.hpp b/link/modules/asio-standalone/asio/include/asio/detail/winrt_socket_recv_op.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/winrt_socket_recv_op.hpp
@@ -0,0 +1,119 @@
+//
+// detail/winrt_socket_recv_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_WINRT_SOCKET_RECV_OP_HPP
+#define ASIO_DETAIL_WINRT_SOCKET_RECV_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_WINDOWS_RUNTIME)
+
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/buffer_sequence_adapter.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/handler_work.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/detail/winrt_async_op.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename MutableBufferSequence, typename Handler, typename IoExecutor>
+class winrt_socket_recv_op :
+  public winrt_async_op<Windows::Storage::Streams::IBuffer^>
+{
+public:
+  ASIO_DEFINE_HANDLER_PTR(winrt_socket_recv_op);
+
+  winrt_socket_recv_op(const MutableBufferSequence& buffers,
+      Handler& handler, const IoExecutor& io_ex)
+    : winrt_async_op<Windows::Storage::Streams::IBuffer^>(
+          &winrt_socket_recv_op::do_complete),
+      buffers_(buffers),
+      handler_(ASIO_MOVE_CAST(Handler)(handler)),
+      work_(handler_, io_ex)
+  {
+  }
+
+  static void do_complete(void* owner, operation* base,
+      const asio::error_code&, std::size_t)
+  {
+    // Take ownership of the operation object.
+    winrt_socket_recv_op* o(static_cast<winrt_socket_recv_op*>(base));
+    ptr p = { asio::detail::addressof(o->handler_), o, o };
+
+    ASIO_HANDLER_COMPLETION((*o));
+
+    // Take ownership of the operation's outstanding work.
+    handler_work<Handler, IoExecutor> w(
+        ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)(
+          o->work_));
+
+#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
+    // Check whether buffers are still valid.
+    if (owner)
+    {
+      buffer_sequence_adapter<asio::mutable_buffer,
+          MutableBufferSequence>::validate(o->buffers_);
+    }
+#endif // defined(ASIO_ENABLE_BUFFER_DEBUGGING)
+
+    std::size_t bytes_transferred = o->result_ ? o->result_->Length : 0;
+    if (bytes_transferred == 0 && !o->ec_ &&
+        !buffer_sequence_adapter<asio::mutable_buffer,
+          MutableBufferSequence>::all_empty(o->buffers_))
+    {
+      o->ec_ = asio::error::eof;
+    }
+
+    // Make a copy of the handler so that the memory can be deallocated before
+    // the upcall is made. Even if we're not about to make an upcall, a
+    // sub-object of the handler may be the true owner of the memory associated
+    // with the handler. Consequently, a local copy of the handler is required
+    // to ensure that any owning sub-object remains valid until after we have
+    // deallocated the memory here.
+    detail::binder2<Handler, asio::error_code, std::size_t>
+      handler(o->handler_, o->ec_, bytes_transferred);
+    p.h = asio::detail::addressof(handler.handler_);
+    p.reset();
+
+    // Make the upcall if required.
+    if (owner)
+    {
+      fenced_block b(fenced_block::half);
+      ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_));
+      w.complete(handler, handler.handler_);
+      ASIO_HANDLER_INVOCATION_END;
+    }
+  }
+
+private:
+  MutableBufferSequence buffers_;
+  Handler handler_;
+  handler_work<Handler, IoExecutor> executor_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_WINDOWS_RUNTIME)
+
+#endif // ASIO_DETAIL_WINRT_SOCKET_RECV_OP_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/winrt_socket_send_op.hpp b/link/modules/asio-standalone/asio/include/asio/detail/winrt_socket_send_op.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/winrt_socket_send_op.hpp
@@ -0,0 +1,110 @@
+//
+// detail/winrt_socket_send_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_WINRT_SOCKET_SEND_OP_HPP
+#define ASIO_DETAIL_WINRT_SOCKET_SEND_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_WINDOWS_RUNTIME)
+
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/buffer_sequence_adapter.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/handler_work.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/detail/winrt_async_op.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename ConstBufferSequence, typename Handler, typename IoExecutor>
+class winrt_socket_send_op :
+  public winrt_async_op<unsigned int>
+{
+public:
+  ASIO_DEFINE_HANDLER_PTR(winrt_socket_send_op);
+
+  winrt_socket_send_op(const ConstBufferSequence& buffers,
+      Handler& handler, const IoExecutor& io_ex)
+    : winrt_async_op<unsigned int>(&winrt_socket_send_op::do_complete),
+      buffers_(buffers),
+      handler_(ASIO_MOVE_CAST(Handler)(handler)),
+      work_(handler_, io_ex)
+  {
+  }
+
+  static void do_complete(void* owner, operation* base,
+      const asio::error_code&, std::size_t)
+  {
+    // Take ownership of the operation object.
+    winrt_socket_send_op* o(static_cast<winrt_socket_send_op*>(base));
+    ptr p = { asio::detail::addressof(o->handler_), o, o };
+
+    ASIO_HANDLER_COMPLETION((*o));
+
+    // Take ownership of the operation's outstanding work.
+    handler_work<Handler, IoExecutor> w(
+        ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)(
+          o->work_));
+
+#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
+    // Check whether buffers are still valid.
+    if (owner)
+    {
+      buffer_sequence_adapter<asio::const_buffer,
+          ConstBufferSequence>::validate(o->buffers_);
+    }
+#endif // defined(ASIO_ENABLE_BUFFER_DEBUGGING)
+
+    // Make a copy of the handler so that the memory can be deallocated before
+    // the upcall is made. Even if we're not about to make an upcall, a
+    // sub-object of the handler may be the true owner of the memory associated
+    // with the handler. Consequently, a local copy of the handler is required
+    // to ensure that any owning sub-object remains valid until after we have
+    // deallocated the memory here.
+    detail::binder2<Handler, asio::error_code, std::size_t>
+      handler(o->handler_, o->ec_, o->result_);
+    p.h = asio::detail::addressof(handler.handler_);
+    p.reset();
+
+    // Make the upcall if required.
+    if (owner)
+    {
+      fenced_block b(fenced_block::half);
+      ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_));
+      w.complete(handler, handler.handler_);
+      ASIO_HANDLER_INVOCATION_END;
+    }
+  }
+
+private:
+  ConstBufferSequence buffers_;
+  Handler handler_;
+  handler_work<Handler, IoExecutor> executor_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_WINDOWS_RUNTIME)
+
+#endif // ASIO_DETAIL_WINRT_SOCKET_SEND_OP_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/winrt_ssocket_service.hpp b/link/modules/asio-standalone/asio/include/asio/detail/winrt_ssocket_service.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/winrt_ssocket_service.hpp
@@ -0,0 +1,250 @@
+//
+// detail/winrt_ssocket_service.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_WINRT_SSOCKET_SERVICE_HPP
+#define ASIO_DETAIL_WINRT_SSOCKET_SERVICE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_WINDOWS_RUNTIME)
+
+#include "asio/error.hpp"
+#include "asio/execution_context.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/detail/winrt_socket_connect_op.hpp"
+#include "asio/detail/winrt_ssocket_service_base.hpp"
+#include "asio/detail/winrt_utils.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Protocol>
+class winrt_ssocket_service :
+  public execution_context_service_base<winrt_ssocket_service<Protocol> >,
+  public winrt_ssocket_service_base
+{
+public:
+  // The protocol type.
+  typedef Protocol protocol_type;
+
+  // The endpoint type.
+  typedef typename Protocol::endpoint endpoint_type;
+
+  // The native type of a socket.
+  typedef Windows::Networking::Sockets::StreamSocket^ native_handle_type;
+
+  // The implementation type of the socket.
+  struct implementation_type : base_implementation_type
+  {
+    // Default constructor.
+    implementation_type()
+      : base_implementation_type(),
+        protocol_(endpoint_type().protocol())
+    {
+    }
+
+    // The protocol associated with the socket.
+    protocol_type protocol_;
+  };
+
+  // Constructor.
+  winrt_ssocket_service(execution_context& context)
+    : execution_context_service_base<winrt_ssocket_service<Protocol> >(context),
+      winrt_ssocket_service_base(context)
+  {
+  }
+
+  // Destroy all user-defined handler objects owned by the service.
+  void shutdown()
+  {
+    this->base_shutdown();
+  }
+
+  // Move-construct a new socket implementation.
+  void move_construct(implementation_type& impl,
+      implementation_type& other_impl) ASIO_NOEXCEPT
+  {
+    this->base_move_construct(impl, other_impl);
+
+    impl.protocol_ = other_impl.protocol_;
+    other_impl.protocol_ = endpoint_type().protocol();
+  }
+
+  // Move-assign from another socket implementation.
+  void move_assign(implementation_type& impl,
+      winrt_ssocket_service& other_service,
+      implementation_type& other_impl)
+  {
+    this->base_move_assign(impl, other_service, other_impl);
+
+    impl.protocol_ = other_impl.protocol_;
+    other_impl.protocol_ = endpoint_type().protocol();
+  }
+
+  // Move-construct a new socket implementation from another protocol type.
+  template <typename Protocol1>
+  void converting_move_construct(implementation_type& impl,
+      winrt_ssocket_service<Protocol1>&,
+      typename winrt_ssocket_service<
+        Protocol1>::implementation_type& other_impl)
+  {
+    this->base_move_construct(impl, other_impl);
+
+    impl.protocol_ = protocol_type(other_impl.protocol_);
+    other_impl.protocol_ = typename Protocol1::endpoint().protocol();
+  }
+
+  // Open a new socket implementation.
+  asio::error_code open(implementation_type& impl,
+      const protocol_type& protocol, asio::error_code& ec)
+  {
+    if (is_open(impl))
+    {
+      ec = asio::error::already_open;
+      return ec;
+    }
+
+    try
+    {
+      impl.socket_ = ref new Windows::Networking::Sockets::StreamSocket;
+      impl.protocol_ = protocol;
+      ec = asio::error_code();
+    }
+    catch (Platform::Exception^ e)
+    {
+      ec = asio::error_code(e->HResult,
+            asio::system_category());
+    }
+
+    return ec;
+  }
+
+  // Assign a native socket to a socket implementation.
+  asio::error_code assign(implementation_type& impl,
+      const protocol_type& protocol, const native_handle_type& native_socket,
+      asio::error_code& ec)
+  {
+    if (is_open(impl))
+    {
+      ec = asio::error::already_open;
+      return ec;
+    }
+
+    impl.socket_ = native_socket;
+    impl.protocol_ = protocol;
+    ec = asio::error_code();
+
+    return ec;
+  }
+
+  // Bind the socket to the specified local endpoint.
+  asio::error_code bind(implementation_type&,
+      const endpoint_type&, asio::error_code& ec)
+  {
+    ec = asio::error::operation_not_supported;
+    return ec;
+  }
+
+  // Get the local endpoint.
+  endpoint_type local_endpoint(const implementation_type& impl,
+      asio::error_code& ec) const
+  {
+    endpoint_type endpoint;
+    endpoint.resize(do_get_endpoint(impl, true,
+          endpoint.data(), endpoint.size(), ec));
+    return endpoint;
+  }
+
+  // Get the remote endpoint.
+  endpoint_type remote_endpoint(const implementation_type& impl,
+      asio::error_code& ec) const
+  {
+    endpoint_type endpoint;
+    endpoint.resize(do_get_endpoint(impl, false,
+          endpoint.data(), endpoint.size(), ec));
+    return endpoint;
+  }
+
+  // Disable sends or receives on the socket.
+  asio::error_code shutdown(implementation_type&,
+      socket_base::shutdown_type, asio::error_code& ec)
+  {
+    ec = asio::error::operation_not_supported;
+    return ec;
+  }
+
+  // Set a socket option.
+  template <typename Option>
+  asio::error_code set_option(implementation_type& impl,
+      const Option& option, asio::error_code& ec)
+  {
+    return do_set_option(impl, option.level(impl.protocol_),
+        option.name(impl.protocol_), option.data(impl.protocol_),
+        option.size(impl.protocol_), ec);
+  }
+
+  // Get a socket option.
+  template <typename Option>
+  asio::error_code get_option(const implementation_type& impl,
+      Option& option, asio::error_code& ec) const
+  {
+    std::size_t size = option.size(impl.protocol_);
+    do_get_option(impl, option.level(impl.protocol_),
+        option.name(impl.protocol_),
+        option.data(impl.protocol_), &size, ec);
+    if (!ec)
+      option.resize(impl.protocol_, size);
+    return ec;
+  }
+
+  // Connect the socket to the specified endpoint.
+  asio::error_code connect(implementation_type& impl,
+      const endpoint_type& peer_endpoint, asio::error_code& ec)
+  {
+    return do_connect(impl, peer_endpoint.data(), ec);
+  }
+
+  // Start an asynchronous connect.
+  template <typename Handler, typename IoExecutor>
+  void async_connect(implementation_type& impl,
+      const endpoint_type& peer_endpoint,
+      Handler& handler, const IoExecutor& io_ex)
+  {
+    bool is_continuation =
+      asio_handler_cont_helpers::is_continuation(handler);
+
+    // Allocate and construct an operation to wrap the handler.
+    typedef winrt_socket_connect_op<Handler, IoExecutor> op;
+    typename op::ptr p = { asio::detail::addressof(handler),
+      op::ptr::allocate(handler), 0 };
+    p.p = new (p.v) op(handler, io_ex);
+
+    ASIO_HANDLER_CREATION((scheduler_.context(),
+          *p.p, "socket", &impl, 0, "async_connect"));
+
+    start_connect_op(impl, peer_endpoint.data(), p.p, is_continuation);
+    p.v = p.p = 0;
+  }
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_WINDOWS_RUNTIME)
+
+#endif // ASIO_DETAIL_WINRT_SSOCKET_SERVICE_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/winrt_ssocket_service_base.hpp b/link/modules/asio-standalone/asio/include/asio/detail/winrt_ssocket_service_base.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/winrt_ssocket_service_base.hpp
@@ -0,0 +1,362 @@
+//
+// detail/winrt_ssocket_service_base.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_WINRT_SSOCKET_SERVICE_BASE_HPP
+#define ASIO_DETAIL_WINRT_SSOCKET_SERVICE_BASE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_WINDOWS_RUNTIME)
+
+#include "asio/buffer.hpp"
+#include "asio/error.hpp"
+#include "asio/execution_context.hpp"
+#include "asio/socket_base.hpp"
+#include "asio/detail/buffer_sequence_adapter.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/detail/socket_types.hpp"
+#include "asio/detail/winrt_async_manager.hpp"
+#include "asio/detail/winrt_socket_recv_op.hpp"
+#include "asio/detail/winrt_socket_send_op.hpp"
+
+#if defined(ASIO_HAS_IOCP)
+# include "asio/detail/win_iocp_io_context.hpp"
+#else // defined(ASIO_HAS_IOCP)
+# include "asio/detail/scheduler.hpp"
+#endif // defined(ASIO_HAS_IOCP)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class winrt_ssocket_service_base
+{
+public:
+  // The native type of a socket.
+  typedef Windows::Networking::Sockets::StreamSocket^ native_handle_type;
+
+  // The implementation type of the socket.
+  struct base_implementation_type
+  {
+    // Default constructor.
+    base_implementation_type()
+      : socket_(nullptr),
+        next_(0),
+        prev_(0)
+    {
+    }
+
+    // The underlying native socket.
+    native_handle_type socket_;
+
+    // Pointers to adjacent socket implementations in linked list.
+    base_implementation_type* next_;
+    base_implementation_type* prev_;
+  };
+
+  // Constructor.
+  ASIO_DECL winrt_ssocket_service_base(execution_context& context);
+
+  // Destroy all user-defined handler objects owned by the service.
+  ASIO_DECL void base_shutdown();
+
+  // Construct a new socket implementation.
+  ASIO_DECL void construct(base_implementation_type&);
+
+  // Move-construct a new socket implementation.
+  ASIO_DECL void base_move_construct(base_implementation_type& impl,
+      base_implementation_type& other_impl) ASIO_NOEXCEPT;
+
+  // Move-assign from another socket implementation.
+  ASIO_DECL void base_move_assign(base_implementation_type& impl,
+      winrt_ssocket_service_base& other_service,
+      base_implementation_type& other_impl);
+
+  // Destroy a socket implementation.
+  ASIO_DECL void destroy(base_implementation_type& impl);
+
+  // Determine whether the socket is open.
+  bool is_open(const base_implementation_type& impl) const
+  {
+    return impl.socket_ != nullptr;
+  }
+
+  // Destroy a socket implementation.
+  ASIO_DECL asio::error_code close(
+      base_implementation_type& impl, asio::error_code& ec);
+
+  // Release ownership of the socket.
+  ASIO_DECL native_handle_type release(
+      base_implementation_type& impl, asio::error_code& ec);
+
+  // Get the native socket representation.
+  native_handle_type native_handle(base_implementation_type& impl)
+  {
+    return impl.socket_;
+  }
+
+  // Cancel all operations associated with the socket.
+  asio::error_code cancel(base_implementation_type&,
+      asio::error_code& ec)
+  {
+    ec = asio::error::operation_not_supported;
+    return ec;
+  }
+
+  // Determine whether the socket is at the out-of-band data mark.
+  bool at_mark(const base_implementation_type&,
+      asio::error_code& ec) const
+  {
+    ec = asio::error::operation_not_supported;
+    return false;
+  }
+
+  // Determine the number of bytes available for reading.
+  std::size_t available(const base_implementation_type&,
+      asio::error_code& ec) const
+  {
+    ec = asio::error::operation_not_supported;
+    return 0;
+  }
+
+  // Perform an IO control command on the socket.
+  template <typename IO_Control_Command>
+  asio::error_code io_control(base_implementation_type&,
+      IO_Control_Command&, asio::error_code& ec)
+  {
+    ec = asio::error::operation_not_supported;
+    return ec;
+  }
+
+  // Gets the non-blocking mode of the socket.
+  bool non_blocking(const base_implementation_type&) const
+  {
+    return false;
+  }
+
+  // Sets the non-blocking mode of the socket.
+  asio::error_code non_blocking(base_implementation_type&,
+      bool, asio::error_code& ec)
+  {
+    ec = asio::error::operation_not_supported;
+    return ec;
+  }
+
+  // Gets the non-blocking mode of the native socket implementation.
+  bool native_non_blocking(const base_implementation_type&) const
+  {
+    return false;
+  }
+
+  // Sets the non-blocking mode of the native socket implementation.
+  asio::error_code native_non_blocking(base_implementation_type&,
+      bool, asio::error_code& ec)
+  {
+    ec = asio::error::operation_not_supported;
+    return ec;
+  }
+
+  // Send the given data to the peer.
+  template <typename ConstBufferSequence>
+  std::size_t send(base_implementation_type& impl,
+      const ConstBufferSequence& buffers,
+      socket_base::message_flags flags, asio::error_code& ec)
+  {
+    return do_send(impl,
+        buffer_sequence_adapter<asio::const_buffer,
+          ConstBufferSequence>::first(buffers), flags, ec);
+  }
+
+  // Wait until data can be sent without blocking.
+  std::size_t send(base_implementation_type&, const null_buffers&,
+      socket_base::message_flags, asio::error_code& ec)
+  {
+    ec = asio::error::operation_not_supported;
+    return 0;
+  }
+
+  // Start an asynchronous send. The data being sent must be valid for the
+  // lifetime of the asynchronous operation.
+  template <typename ConstBufferSequence, typename Handler, typename IoExecutor>
+  void async_send(base_implementation_type& impl,
+      const ConstBufferSequence& buffers, socket_base::message_flags flags,
+      Handler& handler, const IoExecutor& io_ex)
+  {
+    bool is_continuation =
+      asio_handler_cont_helpers::is_continuation(handler);
+
+    // Allocate and construct an operation to wrap the handler.
+    typedef winrt_socket_send_op<ConstBufferSequence, Handler, IoExecutor> op;
+    typename op::ptr p = { asio::detail::addressof(handler),
+      op::ptr::allocate(handler), 0 };
+    p.p = new (p.v) op(buffers, handler, io_ex);
+
+    ASIO_HANDLER_CREATION((scheduler_.context(),
+          *p.p, "socket", &impl, 0, "async_send"));
+
+    start_send_op(impl,
+        buffer_sequence_adapter<asio::const_buffer,
+          ConstBufferSequence>::first(buffers),
+        flags, p.p, is_continuation);
+    p.v = p.p = 0;
+  }
+
+  // Start an asynchronous wait until data can be sent without blocking.
+  template <typename Handler, typename IoExecutor>
+  void async_send(base_implementation_type&, const null_buffers&,
+      socket_base::message_flags, Handler& handler, const IoExecutor& io_ex)
+  {
+    asio::error_code ec = asio::error::operation_not_supported;
+    const std::size_t bytes_transferred = 0;
+    asio::post(io_ex,
+        detail::bind_handler(handler, ec, bytes_transferred));
+  }
+
+  // Receive some data from the peer. Returns the number of bytes received.
+  template <typename MutableBufferSequence>
+  std::size_t receive(base_implementation_type& impl,
+      const MutableBufferSequence& buffers,
+      socket_base::message_flags flags, asio::error_code& ec)
+  {
+    return do_receive(impl,
+        buffer_sequence_adapter<asio::mutable_buffer,
+          MutableBufferSequence>::first(buffers), flags, ec);
+  }
+
+  // Wait until data can be received without blocking.
+  std::size_t receive(base_implementation_type&, const null_buffers&,
+      socket_base::message_flags, asio::error_code& ec)
+  {
+    ec = asio::error::operation_not_supported;
+    return 0;
+  }
+
+  // Start an asynchronous receive. The buffer for the data being received
+  // must be valid for the lifetime of the asynchronous operation.
+  template <typename MutableBufferSequence,
+      typename Handler, typename IoExecutor>
+  void async_receive(base_implementation_type& impl,
+      const MutableBufferSequence& buffers, socket_base::message_flags flags,
+      Handler& handler, const IoExecutor& io_ex)
+  {
+    bool is_continuation =
+      asio_handler_cont_helpers::is_continuation(handler);
+
+    // Allocate and construct an operation to wrap the handler.
+    typedef winrt_socket_recv_op<MutableBufferSequence, Handler, IoExecutor> op;
+    typename op::ptr p = { asio::detail::addressof(handler),
+      op::ptr::allocate(handler), 0 };
+    p.p = new (p.v) op(buffers, handler, io_ex);
+
+    ASIO_HANDLER_CREATION((scheduler_.context(),
+          *p.p, "socket", &impl, 0, "async_receive"));
+
+    start_receive_op(impl,
+        buffer_sequence_adapter<asio::mutable_buffer,
+          MutableBufferSequence>::first(buffers),
+        flags, p.p, is_continuation);
+    p.v = p.p = 0;
+  }
+
+  // Wait until data can be received without blocking.
+  template <typename Handler, typename IoExecutor>
+  void async_receive(base_implementation_type&, const null_buffers&,
+      socket_base::message_flags, Handler& handler, const IoExecutor& io_ex)
+  {
+    asio::error_code ec = asio::error::operation_not_supported;
+    const std::size_t bytes_transferred = 0;
+    asio::post(io_ex,
+        detail::bind_handler(handler, ec, bytes_transferred));
+  }
+
+protected:
+  // Helper function to obtain endpoints associated with the connection.
+  ASIO_DECL std::size_t do_get_endpoint(
+      const base_implementation_type& impl, bool local,
+      void* addr, std::size_t addr_len, asio::error_code& ec) const;
+
+  // Helper function to set a socket option.
+  ASIO_DECL asio::error_code do_set_option(
+      base_implementation_type& impl,
+      int level, int optname, const void* optval,
+      std::size_t optlen, asio::error_code& ec);
+
+  // Helper function to get a socket option.
+  ASIO_DECL void do_get_option(
+      const base_implementation_type& impl,
+      int level, int optname, void* optval,
+      std::size_t* optlen, asio::error_code& ec) const;
+
+  // Helper function to perform a synchronous connect.
+  ASIO_DECL asio::error_code do_connect(
+      base_implementation_type& impl,
+      const void* addr, asio::error_code& ec);
+
+  // Helper function to start an asynchronous connect.
+  ASIO_DECL void start_connect_op(
+      base_implementation_type& impl, const void* addr,
+      winrt_async_op<void>* op, bool is_continuation);
+
+  // Helper function to perform a synchronous send.
+  ASIO_DECL std::size_t do_send(
+      base_implementation_type& impl, const asio::const_buffer& data,
+      socket_base::message_flags flags, asio::error_code& ec);
+
+  // Helper function to start an asynchronous send.
+  ASIO_DECL void start_send_op(base_implementation_type& impl,
+      const asio::const_buffer& data, socket_base::message_flags flags,
+      winrt_async_op<unsigned int>* op, bool is_continuation);
+
+  // Helper function to perform a synchronous receive.
+  ASIO_DECL std::size_t do_receive(
+      base_implementation_type& impl, const asio::mutable_buffer& data,
+      socket_base::message_flags flags, asio::error_code& ec);
+
+  // Helper function to start an asynchronous receive.
+  ASIO_DECL void start_receive_op(base_implementation_type& impl,
+      const asio::mutable_buffer& data, socket_base::message_flags flags,
+      winrt_async_op<Windows::Storage::Streams::IBuffer^>* op,
+      bool is_continuation);
+
+  // The scheduler implementation used for delivering completions.
+#if defined(ASIO_HAS_IOCP)
+  typedef class win_iocp_io_context scheduler_impl;
+#else
+  typedef class scheduler scheduler_impl;
+#endif
+  scheduler_impl& scheduler_;
+
+  // The manager that keeps track of outstanding operations.
+  winrt_async_manager& async_manager_;
+
+  // Mutex to protect access to the linked list of implementations. 
+  asio::detail::mutex mutex_;
+
+  // The head of a linked list of all implementations.
+  base_implementation_type* impl_list_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/winrt_ssocket_service_base.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // defined(ASIO_WINDOWS_RUNTIME)
+
+#endif // ASIO_DETAIL_WINRT_SSOCKET_SERVICE_BASE_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/winrt_timer_scheduler.hpp b/link/modules/asio-standalone/asio/include/asio/detail/winrt_timer_scheduler.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/winrt_timer_scheduler.hpp
@@ -0,0 +1,147 @@
+//
+// detail/winrt_timer_scheduler.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_WINRT_TIMER_SCHEDULER_HPP
+#define ASIO_DETAIL_WINRT_TIMER_SCHEDULER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_WINDOWS_RUNTIME)
+
+#include <cstddef>
+#include "asio/detail/event.hpp"
+#include "asio/detail/limits.hpp"
+#include "asio/detail/mutex.hpp"
+#include "asio/detail/op_queue.hpp"
+#include "asio/detail/thread.hpp"
+#include "asio/detail/timer_queue_base.hpp"
+#include "asio/detail/timer_queue_set.hpp"
+#include "asio/detail/wait_op.hpp"
+#include "asio/execution_context.hpp"
+
+#if defined(ASIO_HAS_IOCP)
+# include "asio/detail/win_iocp_io_context.hpp"
+#else // defined(ASIO_HAS_IOCP)
+# include "asio/detail/scheduler.hpp"
+#endif // defined(ASIO_HAS_IOCP)
+
+#if defined(ASIO_HAS_IOCP)
+# include "asio/detail/thread.hpp"
+#endif // defined(ASIO_HAS_IOCP)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class winrt_timer_scheduler
+  : public execution_context_service_base<winrt_timer_scheduler>
+{
+public:
+  // Constructor.
+  ASIO_DECL winrt_timer_scheduler(execution_context& context);
+
+  // Destructor.
+  ASIO_DECL ~winrt_timer_scheduler();
+
+  // Destroy all user-defined handler objects owned by the service.
+  ASIO_DECL void shutdown();
+
+  // Recreate internal descriptors following a fork.
+  ASIO_DECL void notify_fork(execution_context::fork_event fork_ev);
+
+  // Initialise the task. No effect as this class uses its own thread.
+  ASIO_DECL void init_task();
+
+  // Add a new timer queue to the reactor.
+  template <typename Time_Traits>
+  void add_timer_queue(timer_queue<Time_Traits>& queue);
+
+  // Remove a timer queue from the reactor.
+  template <typename Time_Traits>
+  void remove_timer_queue(timer_queue<Time_Traits>& queue);
+
+  // Schedule a new operation in the given timer queue to expire at the
+  // specified absolute time.
+  template <typename Time_Traits>
+  void schedule_timer(timer_queue<Time_Traits>& queue,
+      const typename Time_Traits::time_type& time,
+      typename timer_queue<Time_Traits>::per_timer_data& timer, wait_op* op);
+
+  // Cancel the timer operations associated with the given token. Returns the
+  // number of operations that have been posted or dispatched.
+  template <typename Time_Traits>
+  std::size_t cancel_timer(timer_queue<Time_Traits>& queue,
+      typename timer_queue<Time_Traits>::per_timer_data& timer,
+      std::size_t max_cancelled = (std::numeric_limits<std::size_t>::max)());
+
+  // Move the timer operations associated with the given timer.
+  template <typename Time_Traits>
+  void move_timer(timer_queue<Time_Traits>& queue,
+      typename timer_queue<Time_Traits>::per_timer_data& to,
+      typename timer_queue<Time_Traits>::per_timer_data& from);
+
+private:
+  // Run the select loop in the thread.
+  ASIO_DECL void run_thread();
+
+  // Entry point for the select loop thread.
+  ASIO_DECL static void call_run_thread(winrt_timer_scheduler* reactor);
+
+  // Helper function to add a new timer queue.
+  ASIO_DECL void do_add_timer_queue(timer_queue_base& queue);
+
+  // Helper function to remove a timer queue.
+  ASIO_DECL void do_remove_timer_queue(timer_queue_base& queue);
+
+  // The scheduler implementation used to post completions.
+#if defined(ASIO_HAS_IOCP)
+  typedef class win_iocp_io_context scheduler_impl;
+#else
+  typedef class scheduler scheduler_impl;
+#endif
+  scheduler_impl& scheduler_;
+
+  // Mutex used to protect internal variables.
+  asio::detail::mutex mutex_;
+
+  // Event used to wake up background thread.
+  asio::detail::event event_;
+
+  // The timer queues.
+  timer_queue_set timer_queues_;
+
+  // The background thread that is waiting for timers to expire.
+  asio::detail::thread* thread_;
+
+  // Does the background thread need to stop.
+  bool stop_thread_;
+
+  // Whether the service has been shut down.
+  bool shutdown_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/detail/impl/winrt_timer_scheduler.hpp"
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/winrt_timer_scheduler.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // defined(ASIO_WINDOWS_RUNTIME)
+
+#endif // ASIO_DETAIL_WINRT_TIMER_SCHEDULER_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/winrt_utils.hpp b/link/modules/asio-standalone/asio/include/asio/detail/winrt_utils.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/winrt_utils.hpp
@@ -0,0 +1,106 @@
+//
+// detail/winrt_utils.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_WINRT_UTILS_HPP
+#define ASIO_DETAIL_WINRT_UTILS_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_WINDOWS_RUNTIME)
+
+#include <codecvt>
+#include <cstdlib>
+#include <future>
+#include <locale>
+#include <robuffer.h>
+#include <windows.storage.streams.h>
+#include <wrl/implements.h>
+#include "asio/buffer.hpp"
+#include "asio/error_code.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/detail/socket_ops.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+namespace winrt_utils {
+
+inline Platform::String^ string(const char* from)
+{
+  std::wstring tmp(from, from + std::strlen(from));
+  return ref new Platform::String(tmp.c_str());
+}
+
+inline Platform::String^ string(const std::string& from)
+{
+  std::wstring tmp(from.begin(), from.end());
+  return ref new Platform::String(tmp.c_str());
+}
+
+inline std::string string(Platform::String^ from)
+{
+  std::wstring_convert<std::codecvt_utf8<wchar_t>> converter;
+  return converter.to_bytes(from->Data());
+}
+
+inline Platform::String^ string(unsigned short from)
+{
+  return string(std::to_string(from));
+}
+
+template <typename T>
+inline Platform::String^ string(const T& from)
+{
+  return string(from.to_string());
+}
+
+inline int integer(Platform::String^ from)
+{
+  return _wtoi(from->Data());
+}
+
+template <typename T>
+inline Windows::Networking::HostName^ host_name(const T& from)
+{
+  return ref new Windows::Networking::HostName((string)(from));
+}
+
+template <typename ConstBufferSequence>
+inline Windows::Storage::Streams::IBuffer^ buffer_dup(
+    const ConstBufferSequence& buffers)
+{
+  using Microsoft::WRL::ComPtr;
+  using asio::buffer_size;
+  std::size_t size = buffer_size(buffers);
+  auto b = ref new Windows::Storage::Streams::Buffer(size);
+  ComPtr<IInspectable> insp = reinterpret_cast<IInspectable*>(b);
+  ComPtr<Windows::Storage::Streams::IBufferByteAccess> bacc;
+  insp.As(&bacc);
+  byte* bytes = nullptr;
+  bacc->Buffer(&bytes);
+  asio::buffer_copy(asio::buffer(bytes, size), buffers);
+  b->Length = size;
+  return b;
+}
+
+} // namespace winrt_utils
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_WINDOWS_RUNTIME)
+
+#endif // ASIO_DETAIL_WINRT_UTILS_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/winsock_init.hpp b/link/modules/asio-standalone/asio/include/asio/detail/winsock_init.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/winsock_init.hpp
@@ -0,0 +1,128 @@
+//
+// detail/winsock_init.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_WINSOCK_INIT_HPP
+#define ASIO_DETAIL_WINSOCK_INIT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+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_;
+  };
+
+  ASIO_DECL static void startup(data& d,
+      unsigned char major, unsigned char minor);
+
+  ASIO_DECL static void manual_startup(data& d);
+
+  ASIO_DECL static void cleanup(data& d);
+
+  ASIO_DECL static void manual_cleanup(data& d);
+
+  ASIO_DECL static void throw_on_error(data& d);
+};
+
+template <int Major = 2, int Minor = 0>
+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_);
+  }
+
+  // This class may be used to indicate that user code will manage Winsock
+  // initialisation and cleanup. This may be required in the case of a DLL, for
+  // example, where it is not safe to initialise Winsock from global object
+  // constructors.
+  //
+  // To prevent asio from initialising Winsock, the object must be constructed
+  // before any Asio's own global objects. With MSVC, this may be accomplished
+  // by adding the following code to the DLL:
+  //
+  //   #pragma warning(push)
+  //   #pragma warning(disable:4073)
+  //   #pragma init_seg(lib)
+  //   asio::detail::winsock_init<>::manual manual_winsock_init;
+  //   #pragma warning(pop)
+  class manual
+  {
+  public:
+    manual()
+    {
+      manual_startup(data_);
+    }
+
+    manual(const manual&)
+    {
+      manual_startup(data_);
+    }
+
+    ~manual()
+    {
+      manual_cleanup(data_);
+    }
+  };
+
+private:
+  friend class manual;
+  static data data_;
+};
+
+template <int Major, int Minor>
+winsock_init_base::data winsock_init<Major, Minor>::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 asio
+
+#include "asio/detail/pop_options.hpp"
+
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/winsock_init.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+
+#endif // ASIO_DETAIL_WINSOCK_INIT_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/work_dispatcher.hpp b/link/modules/asio-standalone/asio/include/asio/detail/work_dispatcher.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/work_dispatcher.hpp
@@ -0,0 +1,148 @@
+//
+// detail/work_dispatcher.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_WORK_DISPATCHER_HPP
+#define ASIO_DETAIL_WORK_DISPATCHER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/type_traits.hpp"
+#include "asio/associated_executor.hpp"
+#include "asio/associated_allocator.hpp"
+#include "asio/executor_work_guard.hpp"
+#include "asio/execution/executor.hpp"
+#include "asio/execution/allocator.hpp"
+#include "asio/execution/blocking.hpp"
+#include "asio/execution/outstanding_work.hpp"
+#include "asio/prefer.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Handler, typename Executor, typename = void>
+struct is_work_dispatcher_required : true_type
+{
+};
+
+template <typename Handler, typename Executor>
+struct is_work_dispatcher_required<Handler, Executor,
+    typename enable_if<
+      is_same<
+        typename associated_executor<Handler,
+          Executor>::asio_associated_executor_is_unspecialised,
+        void
+      >::value
+    >::type> : false_type
+{
+};
+
+template <typename Handler, typename Executor, typename = void>
+class work_dispatcher
+{
+public:
+  template <typename CompletionHandler>
+  work_dispatcher(ASIO_MOVE_ARG(CompletionHandler) handler,
+      const Executor& handler_ex)
+    : handler_(ASIO_MOVE_CAST(CompletionHandler)(handler)),
+      executor_(asio::prefer(handler_ex,
+          execution::outstanding_work.tracked))
+  {
+  }
+
+#if defined(ASIO_HAS_MOVE)
+  work_dispatcher(const work_dispatcher& other)
+    : handler_(other.handler_),
+      executor_(other.executor_)
+  {
+  }
+
+  work_dispatcher(work_dispatcher&& other)
+    : handler_(ASIO_MOVE_CAST(Handler)(other.handler_)),
+      executor_(ASIO_MOVE_CAST(work_executor_type)(other.executor_))
+  {
+  }
+#endif // defined(ASIO_HAS_MOVE)
+
+  void operator()()
+  {
+    execution::execute(
+        asio::prefer(executor_,
+          execution::blocking.possibly,
+          execution::allocator((get_associated_allocator)(handler_))),
+        ASIO_MOVE_CAST(Handler)(handler_));
+  }
+
+private:
+  typedef typename decay<
+      typename prefer_result<const Executor&,
+        execution::outstanding_work_t::tracked_t
+      >::type
+    >::type work_executor_type;
+
+  Handler handler_;
+  work_executor_type executor_;
+};
+
+#if !defined(ASIO_NO_TS_EXECUTORS)
+
+template <typename Handler, typename Executor>
+class work_dispatcher<Handler, Executor,
+    typename enable_if<!execution::is_executor<Executor>::value>::type>
+{
+public:
+  template <typename CompletionHandler>
+  work_dispatcher(ASIO_MOVE_ARG(CompletionHandler) handler,
+      const Executor& handler_ex)
+    : work_(handler_ex),
+      handler_(ASIO_MOVE_CAST(CompletionHandler)(handler))
+  {
+  }
+
+#if defined(ASIO_HAS_MOVE)
+  work_dispatcher(const work_dispatcher& other)
+    : work_(other.work_),
+      handler_(other.handler_)
+  {
+  }
+
+  work_dispatcher(work_dispatcher&& other)
+    : work_(ASIO_MOVE_CAST(executor_work_guard<Executor>)(other.work_)),
+      handler_(ASIO_MOVE_CAST(Handler)(other.handler_))
+  {
+  }
+#endif // defined(ASIO_HAS_MOVE)
+
+  void operator()()
+  {
+    typename associated_allocator<Handler>::type alloc(
+        (get_associated_allocator)(handler_));
+    work_.get_executor().dispatch(
+        ASIO_MOVE_CAST(Handler)(handler_), alloc);
+    work_.reset();
+  }
+
+private:
+  executor_work_guard<Executor> work_;
+  Handler handler_;
+};
+
+#endif // !defined(ASIO_NO_TS_EXECUTORS)
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_WORK_DISPATCHER_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/detail/wrapped_handler.hpp b/link/modules/asio-standalone/asio/include/asio/detail/wrapped_handler.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/detail/wrapped_handler.hpp
@@ -0,0 +1,327 @@
+//
+// detail/wrapped_handler.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DETAIL_WRAPPED_HANDLER_HPP
+#define ASIO_DETAIL_WRAPPED_HANDLER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_cont_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+struct is_continuation_delegated
+{
+  template <typename Dispatcher, typename Handler>
+  bool operator()(Dispatcher&, Handler& handler) const
+  {
+    return asio_handler_cont_helpers::is_continuation(handler);
+  }
+};
+
+struct is_continuation_if_running
+{
+  template <typename Dispatcher, typename Handler>
+  bool operator()(Dispatcher& dispatcher, Handler&) const
+  {
+    return dispatcher.running_in_this_thread();
+  }
+};
+
+template <typename Dispatcher, typename Handler,
+    typename IsContinuation = is_continuation_delegated>
+class wrapped_handler
+{
+public:
+  typedef void result_type;
+
+  wrapped_handler(Dispatcher dispatcher, Handler& handler)
+    : dispatcher_(dispatcher),
+      handler_(ASIO_MOVE_CAST(Handler)(handler))
+  {
+  }
+
+#if defined(ASIO_HAS_MOVE)
+  wrapped_handler(const wrapped_handler& other)
+    : dispatcher_(other.dispatcher_),
+      handler_(other.handler_)
+  {
+  }
+
+  wrapped_handler(wrapped_handler&& other)
+    : dispatcher_(other.dispatcher_),
+      handler_(ASIO_MOVE_CAST(Handler)(other.handler_))
+  {
+  }
+#endif // defined(ASIO_HAS_MOVE)
+
+  void operator()()
+  {
+    dispatcher_.dispatch(ASIO_MOVE_CAST(Handler)(handler_));
+  }
+
+  void operator()() const
+  {
+    dispatcher_.dispatch(handler_);
+  }
+
+  template <typename Arg1>
+  void operator()(const Arg1& arg1)
+  {
+    dispatcher_.dispatch(detail::bind_handler(handler_, arg1));
+  }
+
+  template <typename Arg1>
+  void operator()(const Arg1& arg1) const
+  {
+    dispatcher_.dispatch(detail::bind_handler(handler_, arg1));
+  }
+
+  template <typename Arg1, typename Arg2>
+  void operator()(const Arg1& arg1, const Arg2& arg2)
+  {
+    dispatcher_.dispatch(detail::bind_handler(handler_, arg1, arg2));
+  }
+
+  template <typename Arg1, typename Arg2>
+  void operator()(const Arg1& arg1, const Arg2& arg2) const
+  {
+    dispatcher_.dispatch(detail::bind_handler(handler_, arg1, arg2));
+  }
+
+  template <typename Arg1, typename Arg2, typename Arg3>
+  void operator()(const Arg1& arg1, const Arg2& arg2, const Arg3& arg3)
+  {
+    dispatcher_.dispatch(detail::bind_handler(handler_, arg1, arg2, arg3));
+  }
+
+  template <typename Arg1, typename Arg2, typename Arg3>
+  void operator()(const Arg1& arg1, const Arg2& arg2, const Arg3& arg3) const
+  {
+    dispatcher_.dispatch(detail::bind_handler(handler_, arg1, arg2, arg3));
+  }
+
+  template <typename Arg1, typename Arg2, typename Arg3, typename Arg4>
+  void operator()(const Arg1& arg1, const Arg2& arg2, const Arg3& arg3,
+      const Arg4& arg4)
+  {
+    dispatcher_.dispatch(
+        detail::bind_handler(handler_, arg1, arg2, arg3, arg4));
+  }
+
+  template <typename Arg1, typename Arg2, typename Arg3, typename Arg4>
+  void operator()(const Arg1& arg1, const Arg2& arg2, const Arg3& arg3,
+      const Arg4& arg4) const
+  {
+    dispatcher_.dispatch(
+        detail::bind_handler(handler_, arg1, arg2, arg3, arg4));
+  }
+
+  template <typename Arg1, typename Arg2, typename Arg3, typename Arg4,
+      typename Arg5>
+  void operator()(const Arg1& arg1, const Arg2& arg2, const Arg3& arg3,
+      const Arg4& arg4, const Arg5& arg5)
+  {
+    dispatcher_.dispatch(
+        detail::bind_handler(handler_, arg1, arg2, arg3, arg4, arg5));
+  }
+
+  template <typename Arg1, typename Arg2, typename Arg3, typename Arg4,
+      typename Arg5>
+  void operator()(const Arg1& arg1, const Arg2& arg2, const Arg3& arg3,
+      const Arg4& arg4, const Arg5& arg5) const
+  {
+    dispatcher_.dispatch(
+        detail::bind_handler(handler_, arg1, arg2, arg3, arg4, arg5));
+  }
+
+//private:
+  Dispatcher dispatcher_;
+  Handler handler_;
+};
+
+template <typename Handler, typename Context>
+class rewrapped_handler
+{
+public:
+  explicit rewrapped_handler(Handler& handler, const Context& context)
+    : context_(context),
+      handler_(ASIO_MOVE_CAST(Handler)(handler))
+  {
+  }
+
+  explicit rewrapped_handler(const Handler& handler, const Context& context)
+    : context_(context),
+      handler_(handler)
+  {
+  }
+
+#if defined(ASIO_HAS_MOVE)
+  rewrapped_handler(const rewrapped_handler& other)
+    : context_(other.context_),
+      handler_(other.handler_)
+  {
+  }
+
+  rewrapped_handler(rewrapped_handler&& other)
+    : context_(ASIO_MOVE_CAST(Context)(other.context_)),
+      handler_(ASIO_MOVE_CAST(Handler)(other.handler_))
+  {
+  }
+#endif // defined(ASIO_HAS_MOVE)
+
+  void operator()()
+  {
+    handler_();
+  }
+
+  void operator()() const
+  {
+    handler_();
+  }
+
+//private:
+  Context context_;
+  Handler handler_;
+};
+
+template <typename Dispatcher, typename Handler, typename IsContinuation>
+inline asio_handler_allocate_is_deprecated
+asio_handler_allocate(std::size_t size,
+    wrapped_handler<Dispatcher, Handler, IsContinuation>* this_handler)
+{
+#if defined(ASIO_NO_DEPRECATED)
+  asio_handler_alloc_helpers::allocate(size, this_handler->handler_);
+  return asio_handler_allocate_is_no_longer_used();
+#else // defined(ASIO_NO_DEPRECATED)
+  return asio_handler_alloc_helpers::allocate(
+      size, this_handler->handler_);
+#endif // defined(ASIO_NO_DEPRECATED)
+}
+
+template <typename Dispatcher, typename Handler, typename IsContinuation>
+inline asio_handler_deallocate_is_deprecated
+asio_handler_deallocate(void* pointer, std::size_t size,
+    wrapped_handler<Dispatcher, Handler, IsContinuation>* this_handler)
+{
+  asio_handler_alloc_helpers::deallocate(
+      pointer, size, this_handler->handler_);
+#if defined(ASIO_NO_DEPRECATED)
+  return asio_handler_deallocate_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+}
+
+template <typename Dispatcher, typename Handler, typename IsContinuation>
+inline bool asio_handler_is_continuation(
+    wrapped_handler<Dispatcher, Handler, IsContinuation>* this_handler)
+{
+  return IsContinuation()(this_handler->dispatcher_, this_handler->handler_);
+}
+
+template <typename Function, typename Dispatcher,
+    typename Handler, typename IsContinuation>
+inline asio_handler_invoke_is_deprecated
+asio_handler_invoke(Function& function,
+    wrapped_handler<Dispatcher, Handler, IsContinuation>* this_handler)
+{
+  this_handler->dispatcher_.dispatch(
+      rewrapped_handler<Function, Handler>(
+        function, this_handler->handler_));
+#if defined(ASIO_NO_DEPRECATED)
+  return asio_handler_invoke_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+}
+
+template <typename Function, typename Dispatcher,
+    typename Handler, typename IsContinuation>
+inline asio_handler_invoke_is_deprecated
+asio_handler_invoke(const Function& function,
+    wrapped_handler<Dispatcher, Handler, IsContinuation>* this_handler)
+{
+  this_handler->dispatcher_.dispatch(
+      rewrapped_handler<Function, Handler>(
+        function, this_handler->handler_));
+#if defined(ASIO_NO_DEPRECATED)
+  return asio_handler_invoke_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+}
+
+template <typename Handler, typename Context>
+inline asio_handler_allocate_is_deprecated
+asio_handler_allocate(std::size_t size,
+    rewrapped_handler<Handler, Context>* this_handler)
+{
+#if defined(ASIO_NO_DEPRECATED)
+  asio_handler_alloc_helpers::allocate(size, this_handler->handler_);
+  return asio_handler_allocate_is_no_longer_used();
+#else // defined(ASIO_NO_DEPRECATED)
+  return asio_handler_alloc_helpers::allocate(
+      size, this_handler->handler_);
+#endif // defined(ASIO_NO_DEPRECATED)
+}
+
+template <typename Handler, typename Context>
+inline asio_handler_deallocate_is_deprecated
+asio_handler_deallocate(void* pointer, std::size_t size,
+    rewrapped_handler<Handler, Context>* this_handler)
+{
+  asio_handler_alloc_helpers::deallocate(
+      pointer, size, this_handler->context_);
+#if defined(ASIO_NO_DEPRECATED)
+  return asio_handler_deallocate_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+}
+
+template <typename Dispatcher, typename Context>
+inline bool asio_handler_is_continuation(
+    rewrapped_handler<Dispatcher, Context>* this_handler)
+{
+  return asio_handler_cont_helpers::is_continuation(
+      this_handler->context_);
+}
+
+template <typename Function, typename Handler, typename Context>
+inline asio_handler_invoke_is_deprecated
+asio_handler_invoke(Function& function,
+    rewrapped_handler<Handler, Context>* this_handler)
+{
+  asio_handler_invoke_helpers::invoke(
+      function, this_handler->context_);
+#if defined(ASIO_NO_DEPRECATED)
+  return asio_handler_invoke_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+}
+
+template <typename Function, typename Handler, typename Context>
+inline asio_handler_invoke_is_deprecated
+asio_handler_invoke(const Function& function,
+    rewrapped_handler<Handler, Context>* this_handler)
+{
+  asio_handler_invoke_helpers::invoke(
+      function, this_handler->context_);
+#if defined(ASIO_NO_DEPRECATED)
+  return asio_handler_invoke_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_WRAPPED_HANDLER_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/dispatch.hpp b/link/modules/asio-standalone/asio/include/asio/dispatch.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/dispatch.hpp
@@ -0,0 +1,121 @@
+//
+// dispatch.hpp
+// ~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_DISPATCH_HPP
+#define ASIO_DISPATCH_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/async_result.hpp"
+#include "asio/detail/type_traits.hpp"
+#include "asio/execution_context.hpp"
+#include "asio/execution/executor.hpp"
+#include "asio/is_executor.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+/// Submits a completion token or function object for execution.
+/**
+ * This function submits an object for execution using the object's associated
+ * executor. The function object may be called from the current thread prior to
+ * returning from <tt>dispatch()</tt>. Otherwise, it is queued for execution.
+ *
+ * This function has the following effects:
+ *
+ * @li Constructs a function object handler of type @c Handler, initialized
+ * with <tt>handler(forward<CompletionToken>(token))</tt>.
+ *
+ * @li Constructs an object @c result of type <tt>async_result<Handler></tt>,
+ * initializing the object as <tt>result(handler)</tt>.
+ *
+ * @li Obtains the handler's associated executor object @c ex by performing
+ * <tt>get_associated_executor(handler)</tt>.
+ *
+ * @li Obtains the handler's associated allocator object @c alloc by performing
+ * <tt>get_associated_allocator(handler)</tt>.
+ *
+ * @li Performs <tt>ex.dispatch(std::move(handler), alloc)</tt>.
+ *
+ * @li Returns <tt>result.get()</tt>.
+ */
+template <ASIO_COMPLETION_TOKEN_FOR(void()) CompletionToken>
+ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void()) dispatch(
+    ASIO_MOVE_ARG(CompletionToken) token);
+
+/// Submits a completion token or function object for execution.
+/**
+ * This function submits an object for execution using the specified executor.
+ * The function object may be called from the current thread prior to returning
+ * from <tt>dispatch()</tt>. Otherwise, it is queued for execution.
+ *
+ * This function has the following effects:
+ *
+ * @li Constructs a function object handler of type @c Handler, initialized
+ * with <tt>handler(forward<CompletionToken>(token))</tt>.
+ *
+ * @li Constructs an object @c result of type <tt>async_result<Handler></tt>,
+ * initializing the object as <tt>result(handler)</tt>.
+ *
+ * @li Obtains the handler's associated executor object @c ex1 by performing
+ * <tt>get_associated_executor(handler)</tt>.
+ *
+ * @li Creates a work object @c w by performing <tt>make_work(ex1)</tt>.
+ *
+ * @li Obtains the handler's associated allocator object @c alloc by performing
+ * <tt>get_associated_allocator(handler)</tt>.
+ *
+ * @li Constructs a function object @c f with a function call operator that
+ * performs <tt>ex1.dispatch(std::move(handler), alloc)</tt> followed by
+ * <tt>w.reset()</tt>.
+ *
+ * @li Performs <tt>Executor(ex).dispatch(std::move(f), alloc)</tt>.
+ *
+ * @li Returns <tt>result.get()</tt>.
+ */
+template <typename Executor,
+    ASIO_COMPLETION_TOKEN_FOR(void()) CompletionToken
+      ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(Executor)>
+ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void()) dispatch(
+    const Executor& ex,
+    ASIO_MOVE_ARG(CompletionToken) token
+      ASIO_DEFAULT_COMPLETION_TOKEN(Executor),
+    typename enable_if<
+      execution::is_executor<Executor>::value || is_executor<Executor>::value
+    >::type* = 0);
+
+/// Submits a completion token or function object for execution.
+/**
+ * @returns <tt>dispatch(ctx.get_executor(),
+ * forward<CompletionToken>(token))</tt>.
+ */
+template <typename ExecutionContext,
+    ASIO_COMPLETION_TOKEN_FOR(void()) CompletionToken
+      ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(
+        typename ExecutionContext::executor_type)>
+ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void()) dispatch(
+    ExecutionContext& ctx,
+    ASIO_MOVE_ARG(CompletionToken) token
+      ASIO_DEFAULT_COMPLETION_TOKEN(
+        typename ExecutionContext::executor_type),
+    typename enable_if<is_convertible<
+      ExecutionContext&, execution_context&>::value>::type* = 0);
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/impl/dispatch.hpp"
+
+#endif // ASIO_DISPATCH_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/error.hpp b/link/modules/asio-standalone/asio/include/asio/error.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/error.hpp
@@ -0,0 +1,356 @@
+//
+// error.hpp
+// ~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_ERROR_HPP
+#define ASIO_ERROR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/error_code.hpp"
+#include "asio/system_error.hpp"
+#if defined(ASIO_WINDOWS) \
+  || defined(__CYGWIN__) \
+  || defined(ASIO_WINDOWS_RUNTIME)
+# include <winerror.h>
+#else
+# include <cerrno>
+# include <netdb.h>
+#endif
+
+#if defined(GENERATING_DOCUMENTATION)
+/// INTERNAL ONLY.
+# define ASIO_NATIVE_ERROR(e) implementation_defined
+/// INTERNAL ONLY.
+# define ASIO_SOCKET_ERROR(e) implementation_defined
+/// INTERNAL ONLY.
+# define ASIO_NETDB_ERROR(e) implementation_defined
+/// INTERNAL ONLY.
+# define ASIO_GETADDRINFO_ERROR(e) implementation_defined
+/// INTERNAL ONLY.
+# define ASIO_WIN_OR_POSIX(e_win, e_posix) implementation_defined
+#elif defined(ASIO_WINDOWS_RUNTIME)
+# define ASIO_NATIVE_ERROR(e) __HRESULT_FROM_WIN32(e)
+# define ASIO_SOCKET_ERROR(e) __HRESULT_FROM_WIN32(WSA ## e)
+# define ASIO_NETDB_ERROR(e) __HRESULT_FROM_WIN32(WSA ## e)
+# define ASIO_GETADDRINFO_ERROR(e) __HRESULT_FROM_WIN32(WSA ## e)
+# define ASIO_WIN_OR_POSIX(e_win, e_posix) e_win
+#elif defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+# define ASIO_NATIVE_ERROR(e) e
+# define ASIO_SOCKET_ERROR(e) WSA ## e
+# define ASIO_NETDB_ERROR(e) WSA ## e
+# define ASIO_GETADDRINFO_ERROR(e) WSA ## e
+# define ASIO_WIN_OR_POSIX(e_win, e_posix) e_win
+#else
+# define ASIO_NATIVE_ERROR(e) e
+# define ASIO_SOCKET_ERROR(e) e
+# define ASIO_NETDB_ERROR(e) e
+# define ASIO_GETADDRINFO_ERROR(e) e
+# define ASIO_WIN_OR_POSIX(e_win, e_posix) e_posix
+#endif
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace error {
+
+enum basic_errors
+{
+  /// Permission denied.
+  access_denied = ASIO_SOCKET_ERROR(EACCES),
+
+  /// Address family not supported by protocol.
+  address_family_not_supported = ASIO_SOCKET_ERROR(EAFNOSUPPORT),
+
+  /// Address already in use.
+  address_in_use = ASIO_SOCKET_ERROR(EADDRINUSE),
+
+  /// Transport endpoint is already connected.
+  already_connected = ASIO_SOCKET_ERROR(EISCONN),
+
+  /// Operation already in progress.
+  already_started = ASIO_SOCKET_ERROR(EALREADY),
+
+  /// Broken pipe.
+  broken_pipe = ASIO_WIN_OR_POSIX(
+      ASIO_NATIVE_ERROR(ERROR_BROKEN_PIPE),
+      ASIO_NATIVE_ERROR(EPIPE)),
+
+  /// A connection has been aborted.
+  connection_aborted = ASIO_SOCKET_ERROR(ECONNABORTED),
+
+  /// Connection refused.
+  connection_refused = ASIO_SOCKET_ERROR(ECONNREFUSED),
+
+  /// Connection reset by peer.
+  connection_reset = ASIO_SOCKET_ERROR(ECONNRESET),
+
+  /// Bad file descriptor.
+  bad_descriptor = ASIO_SOCKET_ERROR(EBADF),
+
+  /// Bad address.
+  fault = ASIO_SOCKET_ERROR(EFAULT),
+
+  /// No route to host.
+  host_unreachable = ASIO_SOCKET_ERROR(EHOSTUNREACH),
+
+  /// Operation now in progress.
+  in_progress = ASIO_SOCKET_ERROR(EINPROGRESS),
+
+  /// Interrupted system call.
+  interrupted = ASIO_SOCKET_ERROR(EINTR),
+
+  /// Invalid argument.
+  invalid_argument = ASIO_SOCKET_ERROR(EINVAL),
+
+  /// Message too long.
+  message_size = ASIO_SOCKET_ERROR(EMSGSIZE),
+
+  /// The name was too long.
+  name_too_long = ASIO_SOCKET_ERROR(ENAMETOOLONG),
+
+  /// Network is down.
+  network_down = ASIO_SOCKET_ERROR(ENETDOWN),
+
+  /// Network dropped connection on reset.
+  network_reset = ASIO_SOCKET_ERROR(ENETRESET),
+
+  /// Network is unreachable.
+  network_unreachable = ASIO_SOCKET_ERROR(ENETUNREACH),
+
+  /// Too many open files.
+  no_descriptors = ASIO_SOCKET_ERROR(EMFILE),
+
+  /// No buffer space available.
+  no_buffer_space = ASIO_SOCKET_ERROR(ENOBUFS),
+
+  /// Cannot allocate memory.
+  no_memory = ASIO_WIN_OR_POSIX(
+      ASIO_NATIVE_ERROR(ERROR_OUTOFMEMORY),
+      ASIO_NATIVE_ERROR(ENOMEM)),
+
+  /// Operation not permitted.
+  no_permission = ASIO_WIN_OR_POSIX(
+      ASIO_NATIVE_ERROR(ERROR_ACCESS_DENIED),
+      ASIO_NATIVE_ERROR(EPERM)),
+
+  /// Protocol not available.
+  no_protocol_option = ASIO_SOCKET_ERROR(ENOPROTOOPT),
+
+  /// No such device.
+  no_such_device = ASIO_WIN_OR_POSIX(
+      ASIO_NATIVE_ERROR(ERROR_BAD_UNIT),
+      ASIO_NATIVE_ERROR(ENODEV)),
+
+  /// Transport endpoint is not connected.
+  not_connected = ASIO_SOCKET_ERROR(ENOTCONN),
+
+  /// Socket operation on non-socket.
+  not_socket = ASIO_SOCKET_ERROR(ENOTSOCK),
+
+  /// Operation cancelled.
+  operation_aborted = ASIO_WIN_OR_POSIX(
+      ASIO_NATIVE_ERROR(ERROR_OPERATION_ABORTED),
+      ASIO_NATIVE_ERROR(ECANCELED)),
+
+  /// Operation not supported.
+  operation_not_supported = ASIO_SOCKET_ERROR(EOPNOTSUPP),
+
+  /// Cannot send after transport endpoint shutdown.
+  shut_down = ASIO_SOCKET_ERROR(ESHUTDOWN),
+
+  /// Connection timed out.
+  timed_out = ASIO_SOCKET_ERROR(ETIMEDOUT),
+
+  /// Resource temporarily unavailable.
+  try_again = ASIO_WIN_OR_POSIX(
+      ASIO_NATIVE_ERROR(ERROR_RETRY),
+      ASIO_NATIVE_ERROR(EAGAIN)),
+
+  /// The socket is marked non-blocking and the requested operation would block.
+  would_block = ASIO_SOCKET_ERROR(EWOULDBLOCK)
+};
+
+enum netdb_errors
+{
+  /// Host not found (authoritative).
+  host_not_found = ASIO_NETDB_ERROR(HOST_NOT_FOUND),
+
+  /// Host not found (non-authoritative).
+  host_not_found_try_again = ASIO_NETDB_ERROR(TRY_AGAIN),
+
+  /// The query is valid but does not have associated address data.
+  no_data = ASIO_NETDB_ERROR(NO_DATA),
+
+  /// A non-recoverable error occurred.
+  no_recovery = ASIO_NETDB_ERROR(NO_RECOVERY)
+};
+
+enum addrinfo_errors
+{
+  /// The service is not supported for the given socket type.
+  service_not_found = ASIO_WIN_OR_POSIX(
+      ASIO_NATIVE_ERROR(WSATYPE_NOT_FOUND),
+      ASIO_GETADDRINFO_ERROR(EAI_SERVICE)),
+
+  /// The socket type is not supported.
+  socket_type_not_supported = ASIO_WIN_OR_POSIX(
+      ASIO_NATIVE_ERROR(WSAESOCKTNOSUPPORT),
+      ASIO_GETADDRINFO_ERROR(EAI_SOCKTYPE))
+};
+
+enum misc_errors
+{
+  /// Already open.
+  already_open = 1,
+
+  /// End of file or stream.
+  eof,
+
+  /// Element not found.
+  not_found,
+
+  /// The descriptor cannot fit into the select system call's fd_set.
+  fd_set_failure
+};
+
+inline const asio::error_category& get_system_category()
+{
+  return asio::system_category();
+}
+
+#if !defined(ASIO_WINDOWS) && !defined(__CYGWIN__)
+
+extern ASIO_DECL
+const asio::error_category& get_netdb_category();
+
+extern ASIO_DECL
+const asio::error_category& get_addrinfo_category();
+
+#else // !defined(ASIO_WINDOWS) && !defined(__CYGWIN__)
+
+inline const asio::error_category& get_netdb_category()
+{
+  return get_system_category();
+}
+
+inline const asio::error_category& get_addrinfo_category()
+{
+  return get_system_category();
+}
+
+#endif // !defined(ASIO_WINDOWS) && !defined(__CYGWIN__)
+
+extern ASIO_DECL
+const asio::error_category& get_misc_category();
+
+static const asio::error_category&
+  system_category ASIO_UNUSED_VARIABLE
+  = asio::error::get_system_category();
+static const asio::error_category&
+  netdb_category ASIO_UNUSED_VARIABLE
+  = asio::error::get_netdb_category();
+static const asio::error_category&
+  addrinfo_category ASIO_UNUSED_VARIABLE
+  = asio::error::get_addrinfo_category();
+static const asio::error_category&
+  misc_category ASIO_UNUSED_VARIABLE
+  = asio::error::get_misc_category();
+
+} // namespace error
+} // namespace asio
+
+#if defined(ASIO_HAS_STD_SYSTEM_ERROR)
+namespace std {
+
+template<> struct is_error_code_enum<asio::error::basic_errors>
+{
+  static const bool value = true;
+};
+
+template<> struct is_error_code_enum<asio::error::netdb_errors>
+{
+  static const bool value = true;
+};
+
+template<> struct is_error_code_enum<asio::error::addrinfo_errors>
+{
+  static const bool value = true;
+};
+
+template<> struct is_error_code_enum<asio::error::misc_errors>
+{
+  static const bool value = true;
+};
+
+} // namespace std
+#endif // defined(ASIO_HAS_STD_SYSTEM_ERROR)
+
+namespace asio {
+namespace error {
+
+inline asio::error_code make_error_code(basic_errors e)
+{
+  return asio::error_code(
+      static_cast<int>(e), get_system_category());
+}
+
+inline asio::error_code make_error_code(netdb_errors e)
+{
+  return asio::error_code(
+      static_cast<int>(e), get_netdb_category());
+}
+
+inline asio::error_code make_error_code(addrinfo_errors e)
+{
+  return asio::error_code(
+      static_cast<int>(e), get_addrinfo_category());
+}
+
+inline asio::error_code make_error_code(misc_errors e)
+{
+  return asio::error_code(
+      static_cast<int>(e), get_misc_category());
+}
+
+} // namespace error
+namespace stream_errc {
+  // Simulates the proposed stream_errc scoped enum.
+  using error::eof;
+  using error::not_found;
+} // namespace stream_errc
+namespace socket_errc {
+  // Simulates the proposed socket_errc scoped enum.
+  using error::already_open;
+  using error::not_found;
+} // namespace socket_errc
+namespace resolver_errc {
+  // Simulates the proposed resolver_errc scoped enum.
+  using error::host_not_found;
+  const error::netdb_errors try_again = error::host_not_found_try_again;
+  using error::service_not_found;
+} // namespace resolver_errc
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#undef ASIO_NATIVE_ERROR
+#undef ASIO_SOCKET_ERROR
+#undef ASIO_NETDB_ERROR
+#undef ASIO_GETADDRINFO_ERROR
+#undef ASIO_WIN_OR_POSIX
+
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/impl/error.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // ASIO_ERROR_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/error_code.hpp b/link/modules/asio-standalone/asio/include/asio/error_code.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/error_code.hpp
@@ -0,0 +1,202 @@
+//
+// error_code.hpp
+// ~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_ERROR_CODE_HPP
+#define ASIO_ERROR_CODE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_STD_SYSTEM_ERROR)
+# include <system_error>
+#else // defined(ASIO_HAS_STD_SYSTEM_ERROR)
+# include <string>
+# include "asio/detail/noncopyable.hpp"
+# if !defined(ASIO_NO_IOSTREAM)
+#  include <iosfwd>
+# endif // !defined(ASIO_NO_IOSTREAM)
+#endif // defined(ASIO_HAS_STD_SYSTEM_ERROR)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+#if defined(ASIO_HAS_STD_SYSTEM_ERROR)
+
+typedef std::error_category error_category;
+
+#else // defined(ASIO_HAS_STD_SYSTEM_ERROR)
+
+/// Base class for all error categories.
+class error_category : private noncopyable
+{
+public:
+  /// Destructor.
+  virtual ~error_category()
+  {
+  }
+
+  /// Returns a string naming the error gategory.
+  virtual const char* name() const = 0;
+
+  /// Returns a string describing the error denoted by @c value.
+  virtual std::string message(int value) const = 0;
+
+  /// Equality operator to compare two error categories.
+  bool operator==(const error_category& rhs) const
+  {
+    return this == &rhs;
+  }
+
+  /// Inequality operator to compare two error categories.
+  bool operator!=(const error_category& rhs) const
+  {
+    return !(*this == rhs);
+  }
+};
+
+#endif // defined(ASIO_HAS_STD_SYSTEM_ERROR)
+
+/// Returns the error category used for the system errors produced by asio.
+extern ASIO_DECL const error_category& system_category();
+
+#if defined(ASIO_HAS_STD_SYSTEM_ERROR)
+
+typedef std::error_code error_code;
+
+#else // defined(ASIO_HAS_STD_SYSTEM_ERROR)
+
+/// Class to represent an error code value.
+class error_code
+{
+public:
+  /// Default constructor.
+  error_code()
+    : value_(0),
+      category_(&system_category())
+  {
+  }
+
+  /// Construct with specific error code and category.
+  error_code(int v, const error_category& c)
+    : value_(v),
+      category_(&c)
+  {
+  }
+
+  /// Construct from an error code enum.
+  template <typename ErrorEnum>
+  error_code(ErrorEnum e)
+  {
+    *this = make_error_code(e);
+  }
+
+  /// Clear the error value to the default.
+  void clear()
+  {
+    value_ = 0;
+    category_ = &system_category();
+  }
+
+  /// Assign a new error value.
+  void assign(int v, const error_category& c)
+  {
+    value_ = v;
+    category_ = &c;
+  }
+
+  /// Get the error value.
+  int value() const
+  {
+    return value_;
+  }
+
+  /// Get the error category.
+  const error_category& category() const
+  {
+    return *category_;
+  }
+
+  /// Get the message associated with the error.
+  std::string message() const
+  {
+    return category_->message(value_);
+  }
+
+  struct unspecified_bool_type_t
+  {
+  };
+
+  typedef void (*unspecified_bool_type)(unspecified_bool_type_t);
+
+  static void unspecified_bool_true(unspecified_bool_type_t) {}
+
+  /// Operator returns non-null if there is a non-success error code.
+  operator unspecified_bool_type() const
+  {
+    if (value_ == 0)
+      return 0;
+    else
+      return &error_code::unspecified_bool_true;
+  }
+
+  /// Operator to test if the error represents success.
+  bool operator!() const
+  {
+    return value_ == 0;
+  }
+
+  /// Equality operator to compare two error objects.
+  friend bool operator==(const error_code& e1, const error_code& e2)
+  {
+    return e1.value_ == e2.value_ && e1.category_ == e2.category_;
+  }
+
+  /// Inequality operator to compare two error objects.
+  friend bool operator!=(const error_code& e1, const error_code& e2)
+  {
+    return e1.value_ != e2.value_ || e1.category_ != e2.category_;
+  }
+
+private:
+  // The value associated with the error code.
+  int value_;
+
+  // The category associated with the error code.
+  const error_category* category_;
+};
+
+# if !defined(ASIO_NO_IOSTREAM)
+
+/// Output an error code.
+template <typename Elem, typename Traits>
+std::basic_ostream<Elem, Traits>& operator<<(
+    std::basic_ostream<Elem, Traits>& os, const error_code& ec)
+{
+  os << ec.category().name() << ':' << ec.value();
+  return os;
+}
+
+# endif // !defined(ASIO_NO_IOSTREAM)
+
+#endif // defined(ASIO_HAS_STD_SYSTEM_ERROR)
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/impl/error_code.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // ASIO_ERROR_CODE_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/execution.hpp b/link/modules/asio-standalone/asio/include/asio/execution.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/execution.hpp
@@ -0,0 +1,48 @@
+//
+// execution.hpp
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_EXECUTION_HPP
+#define ASIO_EXECUTION_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/execution/allocator.hpp"
+#include "asio/execution/any_executor.hpp"
+#include "asio/execution/bad_executor.hpp"
+#include "asio/execution/blocking.hpp"
+#include "asio/execution/blocking_adaptation.hpp"
+#include "asio/execution/bulk_execute.hpp"
+#include "asio/execution/bulk_guarantee.hpp"
+#include "asio/execution/connect.hpp"
+#include "asio/execution/context.hpp"
+#include "asio/execution/context_as.hpp"
+#include "asio/execution/execute.hpp"
+#include "asio/execution/executor.hpp"
+#include "asio/execution/invocable_archetype.hpp"
+#include "asio/execution/mapping.hpp"
+#include "asio/execution/occupancy.hpp"
+#include "asio/execution/operation_state.hpp"
+#include "asio/execution/outstanding_work.hpp"
+#include "asio/execution/prefer_only.hpp"
+#include "asio/execution/receiver.hpp"
+#include "asio/execution/receiver_invocation_error.hpp"
+#include "asio/execution/relationship.hpp"
+#include "asio/execution/schedule.hpp"
+#include "asio/execution/scheduler.hpp"
+#include "asio/execution/sender.hpp"
+#include "asio/execution/set_done.hpp"
+#include "asio/execution/set_error.hpp"
+#include "asio/execution/set_value.hpp"
+#include "asio/execution/start.hpp"
+#include "asio/execution/submit.hpp"
+
+#endif // ASIO_EXECUTION_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/execution/allocator.hpp b/link/modules/asio-standalone/asio/include/asio/execution/allocator.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/execution/allocator.hpp
@@ -0,0 +1,249 @@
+//
+// execution/allocator.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_EXECUTION_ALLOCATOR_HPP
+#define ASIO_EXECUTION_ALLOCATOR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/type_traits.hpp"
+#include "asio/execution/executor.hpp"
+#include "asio/execution/scheduler.hpp"
+#include "asio/execution/sender.hpp"
+#include "asio/is_applicable_property.hpp"
+#include "asio/traits/query_static_constexpr_member.hpp"
+#include "asio/traits/static_query.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+#if defined(GENERATING_DOCUMENTATION)
+
+namespace execution {
+
+/// A property to describe which allocator an executor will use to allocate the
+/// memory required to store a submitted function object.
+template <typename ProtoAllocator>
+struct allocator_t
+{
+  /// The allocator_t property applies to executors, senders, and schedulers.
+  template <typename T>
+  static constexpr bool is_applicable_property_v =
+    is_executor_v<T> || is_sender_v<T> || is_scheduler_v<T>;
+
+  /// The allocator_t property can be required.
+  static constexpr bool is_requirable = true;
+
+  /// The allocator_t property can be preferred.
+  static constexpr bool is_preferable = true;
+
+  /// Default constructor.
+  constexpr allocator_t();
+
+  /// Obtain the allocator stored in the allocator_t property object.
+  /**
+   * Present only if @c ProtoAllocator is non-void.
+   */
+  constexpr ProtoAllocator value() const;
+
+  /// Create an allocator_t object with a different allocator.
+  /**
+   * Present only if @c ProtoAllocator is void.
+   */
+  template <typename OtherAllocator>
+  allocator_t<OtherAllocator operator()(const OtherAllocator& a);
+};
+
+/// A special value used for accessing the allocator_t property.
+constexpr allocator_t<void> allocator;
+
+} // namespace execution
+
+#else // defined(GENERATING_DOCUMENTATION)
+
+namespace execution {
+
+template <typename ProtoAllocator>
+struct allocator_t
+{
+#if defined(ASIO_HAS_VARIABLE_TEMPLATES)
+  template <typename T>
+  ASIO_STATIC_CONSTEXPR(bool,
+    is_applicable_property_v = is_executor<T>::value
+      || is_sender<T>::value || is_scheduler<T>::value);
+#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+  ASIO_STATIC_CONSTEXPR(bool, is_requirable = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_preferable = true);
+
+#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \
+  && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+  template <typename T>
+  static ASIO_CONSTEXPR
+  typename traits::query_static_constexpr_member<T, allocator_t>::result_type
+  static_query()
+    ASIO_NOEXCEPT_IF((
+      traits::query_static_constexpr_member<T, allocator_t>::is_noexcept))
+  {
+    return traits::query_static_constexpr_member<T, allocator_t>::value();
+  }
+
+  template <typename E, typename T = decltype(allocator_t::static_query<E>())>
+  static ASIO_CONSTEXPR const T static_query_v
+    = allocator_t::static_query<E>();
+#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)
+       //   && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+
+  ASIO_CONSTEXPR ProtoAllocator value() const
+  {
+    return a_;
+  }
+
+private:
+  friend struct allocator_t<void>;
+
+  explicit ASIO_CONSTEXPR allocator_t(const ProtoAllocator& a)
+    : a_(a)
+  {
+  }
+
+  ProtoAllocator a_;
+};
+
+#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \
+  && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+template <typename ProtoAllocator> template <typename E, typename T>
+const T allocator_t<ProtoAllocator>::static_query_v;
+#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)
+       //   && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+
+template <>
+struct allocator_t<void>
+{
+#if defined(ASIO_HAS_VARIABLE_TEMPLATES)
+  template <typename T>
+  ASIO_STATIC_CONSTEXPR(bool,
+    is_applicable_property_v = is_executor<T>::value
+      || is_sender<T>::value || is_scheduler<T>::value);
+#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+  ASIO_STATIC_CONSTEXPR(bool, is_requirable = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_preferable = true);
+
+  ASIO_CONSTEXPR allocator_t()
+  {
+  }
+
+#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \
+  && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+  template <typename T>
+  static ASIO_CONSTEXPR
+  typename traits::query_static_constexpr_member<T, allocator_t>::result_type
+  static_query()
+    ASIO_NOEXCEPT_IF((
+      traits::query_static_constexpr_member<T, allocator_t>::is_noexcept))
+  {
+    return traits::query_static_constexpr_member<T, allocator_t>::value();
+  }
+
+  template <typename E, typename T = decltype(allocator_t::static_query<E>())>
+  static ASIO_CONSTEXPR const T static_query_v
+    = allocator_t::static_query<E>();
+#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)
+       //   && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+
+  template <typename OtherProtoAllocator>
+  ASIO_CONSTEXPR allocator_t<OtherProtoAllocator> operator()(
+      const OtherProtoAllocator& a) const
+  {
+    return allocator_t<OtherProtoAllocator>(a);
+  }
+};
+
+#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \
+  && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+template <typename E, typename T>
+const T allocator_t<void>::static_query_v;
+#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)
+       //   && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+
+#if defined(ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION)
+constexpr allocator_t<void> allocator;
+#else // defined(ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION)
+template <typename T>
+struct allocator_instance
+{
+  static allocator_t<T> instance;
+};
+
+template <typename T>
+allocator_t<T> allocator_instance<T>::instance;
+
+namespace {
+static const allocator_t<void>& allocator = allocator_instance<void>::instance;
+} // namespace
+#endif
+
+} // namespace execution
+
+#if !defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+template <typename T, typename ProtoAllocator>
+struct is_applicable_property<T, execution::allocator_t<ProtoAllocator> >
+  : integral_constant<bool,
+      execution::is_executor<T>::value
+        || execution::is_sender<T>::value
+        || execution::is_scheduler<T>::value>
+{
+};
+
+#endif // !defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+namespace traits {
+
+#if !defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \
+  || !defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+
+template <typename T, typename ProtoAllocator>
+struct static_query<T, execution::allocator_t<ProtoAllocator>,
+  typename enable_if<
+    traits::query_static_constexpr_member<T,
+      execution::allocator_t<ProtoAllocator> >::is_valid
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
+
+  typedef typename traits::query_static_constexpr_member<T,
+    execution::allocator_t<ProtoAllocator> >::result_type result_type;
+
+  static ASIO_CONSTEXPR result_type value()
+  {
+    return traits::query_static_constexpr_member<T,
+      execution::allocator_t<ProtoAllocator> >::value();
+  }
+};
+
+#endif // !defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)
+       //   || !defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+
+} // namespace traits
+
+#endif // defined(GENERATING_DOCUMENTATION)
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_EXECUTION_ALLOCATOR_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/execution/any_executor.hpp b/link/modules/asio-standalone/asio/include/asio/execution/any_executor.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/execution/any_executor.hpp
@@ -0,0 +1,2264 @@
+//
+// execution/any_executor.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_EXECUTION_ANY_EXECUTOR_HPP
+#define ASIO_EXECUTION_ANY_EXECUTOR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <new>
+#include <typeinfo>
+#include "asio/detail/assert.hpp"
+#include "asio/detail/cstddef.hpp"
+#include "asio/detail/executor_function.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/detail/non_const_lvalue.hpp"
+#include "asio/detail/scoped_ptr.hpp"
+#include "asio/detail/type_traits.hpp"
+#include "asio/detail/throw_exception.hpp"
+#include "asio/detail/variadic_templates.hpp"
+#include "asio/execution/bad_executor.hpp"
+#include "asio/execution/blocking.hpp"
+#include "asio/execution/execute.hpp"
+#include "asio/execution/executor.hpp"
+#include "asio/prefer.hpp"
+#include "asio/query.hpp"
+#include "asio/require.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+#if defined(GENERATING_DOCUMENTATION)
+
+namespace execution {
+
+/// Polymorphic executor wrapper.
+template <typename... SupportableProperties>
+class any_executor
+{
+public:
+  /// Default constructor.
+  any_executor() noexcept;
+
+  /// Construct in an empty state. Equivalent effects to default constructor.
+  any_executor(nullptr_t) noexcept;
+
+  /// Copy constructor.
+  any_executor(const any_executor& e) noexcept;
+
+  /// Move constructor.
+  any_executor(any_executor&& e) noexcept;
+
+  /// Construct to point to the same target as another any_executor.
+  template <class... OtherSupportableProperties>
+    any_executor(any_executor<OtherSupportableProperties...> e);
+
+  /// Construct a polymorphic wrapper for the specified executor.
+  template <typename Executor>
+  any_executor(Executor e);
+
+  /// Assignment operator.
+  any_executor& operator=(const any_executor& e) noexcept;
+
+  /// Move assignment operator.
+  any_executor& operator=(any_executor&& e) noexcept;
+
+  /// Assignment operator that sets the polymorphic wrapper to the empty state.
+  any_executor& operator=(nullptr_t);
+
+  /// Assignment operator to create a polymorphic wrapper for the specified
+  /// executor.
+  template <typename Executor>
+  any_executor& operator=(Executor e);
+
+  /// Destructor.
+  ~any_executor();
+
+  /// Swap targets with another polymorphic wrapper.
+  void swap(any_executor& other) noexcept;
+
+  /// Obtain a polymorphic wrapper with the specified property.
+  /**
+   * Do not call this function directly. It is intended for use with the
+   * asio::require and asio::prefer customisation points.
+   *
+   * For example:
+   * @code execution::any_executor<execution::blocking_t::possibly_t> ex = ...;
+   * auto ex2 = asio::requre(ex, execution::blocking.possibly); @endcode
+   */
+  template <typename Property>
+  any_executor require(Property) const;
+
+  /// Obtain a polymorphic wrapper with the specified property.
+  /**
+   * Do not call this function directly. It is intended for use with the
+   * asio::prefer customisation point.
+   *
+   * For example:
+   * @code execution::any_executor<execution::blocking_t::possibly_t> ex = ...;
+   * auto ex2 = asio::prefer(ex, execution::blocking.possibly); @endcode
+   */
+  template <typename Property>
+  any_executor prefer(Property) const;
+
+  /// Obtain the value associated with the specified property.
+  /**
+   * Do not call this function directly. It is intended for use with the
+   * asio::query customisation point.
+   *
+   * For example:
+   * @code execution::any_executor<execution::occupancy_t> ex = ...;
+   * size_t n = asio::query(ex, execution::occupancy); @endcode
+   */
+  template <typename Property>
+  typename Property::polymorphic_query_result_type query(Property) const;
+
+  /// Execute the function on the target executor.
+  /**
+   * Do not call this function directly. It is intended for use with the
+   * execution::execute customisation point.
+   *
+   * For example:
+   * @code execution::any_executor<> ex = ...;
+   * execution::execute(ex, my_function_object); @endcode
+   *
+   * Throws asio::bad_executor if the polymorphic wrapper has no target.
+   */
+  template <typename Function>
+  void execute(Function&& f) const;
+
+  /// Obtain the underlying execution context.
+  /**
+   * This function is provided for backward compatibility. It is automatically
+   * defined when the @c SupportableProperties... list includes a property of
+   * type <tt>execution::context_as<U></tt>, for some type <tt>U</tt>.
+   */
+  automatically_determined context() const;
+
+  /// Determine whether the wrapper has a target executor.
+  /**
+   * @returns @c true if the polymorphic wrapper has a target executor,
+   * otherwise false.
+   */
+  explicit operator bool() const noexcept;
+
+  /// Get the type of the target executor.
+  const type_info& target_type() const noexcept;
+
+  /// Get a pointer to the target executor.
+  template <typename Executor> Executor* target() noexcept;
+
+  /// Get a pointer to the target executor.
+  template <typename Executor> const Executor* target() const noexcept;
+};
+
+/// Equality operator.
+/**
+ * @relates any_executor
+ */
+template <typename... SupportableProperties>
+bool operator==(const any_executor<SupportableProperties...>& a,
+    const any_executor<SupportableProperties...>& b) noexcept;
+
+/// Equality operator.
+/**
+ * @relates any_executor
+ */
+template <typename... SupportableProperties>
+bool operator==(const any_executor<SupportableProperties...>& a,
+    nullptr_t) noexcept;
+
+/// Equality operator.
+/**
+ * @relates any_executor
+ */
+template <typename... SupportableProperties>
+bool operator==(nullptr_t,
+    const any_executor<SupportableProperties...>& b) noexcept;
+
+/// Inequality operator.
+/**
+ * @relates any_executor
+ */
+template <typename... SupportableProperties>
+bool operator!=(const any_executor<SupportableProperties...>& a,
+    const any_executor<SupportableProperties...>& b) noexcept;
+
+/// Inequality operator.
+/**
+ * @relates any_executor
+ */
+template <typename... SupportableProperties>
+bool operator!=(const any_executor<SupportableProperties...>& a,
+    nullptr_t) noexcept;
+
+/// Inequality operator.
+/**
+ * @relates any_executor
+ */
+template <typename... SupportableProperties>
+bool operator!=(nullptr_t,
+    const any_executor<SupportableProperties...>& b) noexcept;
+
+} // namespace execution
+
+#else // defined(GENERATING_DOCUMENTATION)
+
+namespace execution {
+
+#if !defined(ASIO_EXECUTION_ANY_EXECUTOR_FWD_DECL)
+#define ASIO_EXECUTION_ANY_EXECUTOR_FWD_DECL
+
+#if defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+template <typename... SupportableProperties>
+class any_executor;
+
+#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+template <typename = void, typename = void, typename = void,
+    typename = void, typename = void, typename = void,
+    typename = void, typename = void, typename = void>
+class any_executor;
+
+#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+#endif // !defined(ASIO_EXECUTION_ANY_EXECUTOR_FWD_DECL)
+
+template <typename U>
+struct context_as_t;
+
+namespace detail {
+
+// Traits used to detect whether a property is requirable or preferable, taking
+// into account that T::is_requirable or T::is_preferable may not not be well
+// formed.
+
+template <typename T, typename = void>
+struct is_requirable : false_type {};
+
+template <typename T>
+struct is_requirable<T, typename enable_if<T::is_requirable>::type> :
+  true_type {};
+
+template <typename T, typename = void>
+struct is_preferable : false_type {};
+
+template <typename T>
+struct is_preferable<T, typename enable_if<T::is_preferable>::type> :
+  true_type {};
+
+// Trait used to detect context_as property, for backward compatibility.
+
+template <typename T>
+struct is_context_as : false_type {};
+
+template <typename U>
+struct is_context_as<context_as_t<U> > : true_type {};
+
+// Helper template to:
+// - Check if a target can supply the supportable properties.
+// - Find the first convertible-from-T property in the list.
+
+template <std::size_t I, typename Props>
+struct supportable_properties;
+
+template <std::size_t I, typename Prop>
+struct supportable_properties<I, void(Prop)>
+{
+  template <typename T>
+  struct is_valid_target : integral_constant<bool,
+      (
+        is_requirable<Prop>::value
+          ? can_require<T, Prop>::value
+          : true
+      )
+      &&
+      (
+        is_preferable<Prop>::value
+          ? can_prefer<T, Prop>::value
+          : true
+      )
+      &&
+      (
+        !is_requirable<Prop>::value && !is_preferable<Prop>::value
+          ? can_query<T, Prop>::value
+          : true
+      )
+    >
+  {
+  };
+
+  struct found
+  {
+    ASIO_STATIC_CONSTEXPR(bool, value = true);
+    typedef Prop type;
+    typedef typename Prop::polymorphic_query_result_type query_result_type;
+    ASIO_STATIC_CONSTEXPR(std::size_t, index = I);
+  };
+
+  struct not_found
+  {
+    ASIO_STATIC_CONSTEXPR(bool, value = false);
+  };
+
+  template <typename T>
+  struct find_convertible_property :
+      conditional<
+        is_same<T, Prop>::value || is_convertible<T, Prop>::value,
+        found,
+        not_found
+      >::type {};
+
+  template <typename T>
+  struct find_convertible_requirable_property :
+      conditional<
+        is_requirable<Prop>::value
+          && (is_same<T, Prop>::value || is_convertible<T, Prop>::value),
+        found,
+        not_found
+      >::type {};
+
+  template <typename T>
+  struct find_convertible_preferable_property :
+      conditional<
+        is_preferable<Prop>::value
+          && (is_same<T, Prop>::value || is_convertible<T, Prop>::value),
+        found,
+        not_found
+      >::type {};
+
+  struct find_context_as_property :
+      conditional<
+        is_context_as<Prop>::value,
+        found,
+        not_found
+      >::type {};
+};
+
+#if defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+template <std::size_t I, typename Head, typename... Tail>
+struct supportable_properties<I, void(Head, Tail...)>
+{
+  template <typename T>
+  struct is_valid_target : integral_constant<bool,
+      (
+        supportable_properties<I,
+          void(Head)>::template is_valid_target<T>::value
+        &&
+        supportable_properties<I + 1,
+          void(Tail...)>::template is_valid_target<T>::value
+      )
+    >
+  {
+  };
+
+  template <typename T>
+  struct find_convertible_property :
+      conditional<
+        is_convertible<T, Head>::value,
+        typename supportable_properties<I, void(Head)>::found,
+        typename supportable_properties<I + 1,
+            void(Tail...)>::template find_convertible_property<T>
+      >::type {};
+
+  template <typename T>
+  struct find_convertible_requirable_property :
+      conditional<
+        is_requirable<Head>::value
+          && is_convertible<T, Head>::value,
+        typename supportable_properties<I, void(Head)>::found,
+        typename supportable_properties<I + 1,
+            void(Tail...)>::template find_convertible_requirable_property<T>
+      >::type {};
+
+  template <typename T>
+  struct find_convertible_preferable_property :
+      conditional<
+        is_preferable<Head>::value
+          && is_convertible<T, Head>::value,
+        typename supportable_properties<I, void(Head)>::found,
+        typename supportable_properties<I + 1,
+            void(Tail...)>::template find_convertible_preferable_property<T>
+      >::type {};
+
+  struct find_context_as_property :
+      conditional<
+        is_context_as<Head>::value,
+        typename supportable_properties<I, void(Head)>::found,
+        typename supportable_properties<I + 1,
+            void(Tail...)>::find_context_as_property
+      >::type {};
+};
+
+#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+#define ASIO_PRIVATE_ANY_EXECUTOR_PROPS_BASE_DEF(n) \
+  template <std::size_t I, \
+    typename Head, ASIO_VARIADIC_TPARAMS(n)> \
+  struct supportable_properties<I, \
+      void(Head, ASIO_VARIADIC_TARGS(n))> \
+  { \
+    template <typename T> \
+    struct is_valid_target : integral_constant<bool, \
+        ( \
+          supportable_properties<I, \
+            void(Head)>::template is_valid_target<T>::value \
+          && \
+          supportable_properties<I + 1, \
+              void(ASIO_VARIADIC_TARGS(n))>::template \
+                is_valid_target<T>::value \
+        ) \
+      > \
+    { \
+    }; \
+  \
+    template <typename T> \
+    struct find_convertible_property : \
+        conditional< \
+          is_convertible<T, Head>::value, \
+          typename supportable_properties<I, void(Head)>::found, \
+          typename supportable_properties<I + 1, \
+              void(ASIO_VARIADIC_TARGS(n))>::template \
+                find_convertible_property<T> \
+        >::type {}; \
+  \
+    template <typename T> \
+    struct find_convertible_requirable_property : \
+        conditional< \
+          is_requirable<Head>::value \
+            && is_convertible<T, Head>::value, \
+          typename supportable_properties<I, void(Head)>::found, \
+          typename supportable_properties<I + 1, \
+              void(ASIO_VARIADIC_TARGS(n))>::template \
+                find_convertible_requirable_property<T> \
+        >::type {}; \
+  \
+    template <typename T> \
+    struct find_convertible_preferable_property : \
+        conditional< \
+          is_preferable<Head>::value \
+            && is_convertible<T, Head>::value, \
+          typename supportable_properties<I, void(Head)>::found, \
+          typename supportable_properties<I + 1, \
+              void(ASIO_VARIADIC_TARGS(n))>::template \
+                find_convertible_preferable_property<T> \
+        >::type {}; \
+  \
+    struct find_context_as_property : \
+        conditional< \
+          is_context_as<Head>::value, \
+          typename supportable_properties<I, void(Head)>::found, \
+          typename supportable_properties<I + 1, void( \
+            ASIO_VARIADIC_TARGS(n))>::find_context_as_property \
+        >::type {}; \
+  }; \
+  /**/
+ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_ANY_EXECUTOR_PROPS_BASE_DEF)
+#undef ASIO_PRIVATE_ANY_EXECUTOR_PROPS_BASE_DEF
+
+#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+template <typename T, typename Props>
+struct is_valid_target_executor :
+  conditional<
+    is_executor<T>::value,
+    typename supportable_properties<0, Props>::template is_valid_target<T>,
+    false_type
+  >::type
+{
+};
+
+class any_executor_base
+{
+public:
+  any_executor_base() ASIO_NOEXCEPT
+    : object_fns_(object_fns_table<void>()),
+      target_(0),
+      target_fns_(target_fns_table<void>())
+  {
+  }
+
+  template <ASIO_EXECUTION_EXECUTOR Executor>
+  any_executor_base(Executor ex, false_type)
+    : target_fns_(target_fns_table<Executor>(
+          any_executor_base::query_blocking(ex,
+            can_query<const Executor&, const execution::blocking_t&>())
+          == execution::blocking.always))
+  {
+    any_executor_base::construct_object(ex,
+        integral_constant<bool,
+          sizeof(Executor) <= sizeof(object_type)
+            && alignment_of<Executor>::value <= alignment_of<object_type>::value
+        >());
+  }
+
+  template <ASIO_EXECUTION_EXECUTOR Executor>
+  any_executor_base(Executor other, true_type)
+    : object_fns_(object_fns_table<asio::detail::shared_ptr<void> >()),
+      target_fns_(other.target_fns_)
+  {
+    asio::detail::shared_ptr<Executor> p =
+      asio::detail::make_shared<Executor>(
+          ASIO_MOVE_CAST(Executor)(other));
+    target_ = p->template target<void>();
+    new (&object_) asio::detail::shared_ptr<void>(
+        ASIO_MOVE_CAST(asio::detail::shared_ptr<Executor>)(p));
+  }
+
+  any_executor_base(const any_executor_base& other) ASIO_NOEXCEPT
+    : object_fns_(other.object_fns_),
+      target_fns_(other.target_fns_)
+  {
+    object_fns_->copy(*this, other);
+  }
+
+  ~any_executor_base() ASIO_NOEXCEPT
+  {
+    object_fns_->destroy(*this);
+  }
+
+  any_executor_base& operator=(
+      const any_executor_base& other) ASIO_NOEXCEPT
+  {
+    if (this != &other)
+    {
+      object_fns_->destroy(*this);
+      object_fns_ = other.object_fns_;
+      target_fns_ = other.target_fns_;
+      object_fns_->copy(*this, other);
+    }
+    return *this;
+  }
+
+  any_executor_base& operator=(nullptr_t) ASIO_NOEXCEPT
+  {
+    object_fns_->destroy(*this);
+    target_ = 0;
+    object_fns_ = object_fns_table<void>();
+    target_fns_ = target_fns_table<void>();
+    return *this;
+  }
+
+#if defined(ASIO_HAS_MOVE)
+
+  any_executor_base(any_executor_base&& other) ASIO_NOEXCEPT
+    : object_fns_(other.object_fns_),
+      target_fns_(other.target_fns_)
+  {
+    other.object_fns_ = object_fns_table<void>();
+    other.target_fns_ = target_fns_table<void>();
+    object_fns_->move(*this, other);
+    other.target_ = 0;
+  }
+
+  any_executor_base& operator=(
+      any_executor_base&& other) ASIO_NOEXCEPT
+  {
+    if (this != &other)
+    {
+      object_fns_->destroy(*this);
+      object_fns_ = other.object_fns_;
+      other.object_fns_ = object_fns_table<void>();
+      target_fns_ = other.target_fns_;
+      other.target_fns_ = target_fns_table<void>();
+      object_fns_->move(*this, other);
+      other.target_ = 0;
+    }
+    return *this;
+  }
+
+#endif // defined(ASIO_HAS_MOVE)
+
+  void swap(any_executor_base& other) ASIO_NOEXCEPT
+  {
+    if (this != &other)
+    {
+      any_executor_base tmp(ASIO_MOVE_CAST(any_executor_base)(other));
+      other = ASIO_MOVE_CAST(any_executor_base)(*this);
+      *this = ASIO_MOVE_CAST(any_executor_base)(tmp);
+    }
+  }
+
+  template <typename F>
+  void execute(ASIO_MOVE_ARG(F) f) const
+  {
+    if (target_fns_->blocking_execute != 0)
+    {
+      asio::detail::non_const_lvalue<F> f2(f);
+      target_fns_->blocking_execute(*this, function_view(f2.value));
+    }
+    else
+    {
+      target_fns_->execute(*this,
+          function(ASIO_MOVE_CAST(F)(f), std::allocator<void>()));
+    }
+  }
+
+  template <typename Executor>
+  Executor* target()
+  {
+    return static_cast<Executor*>(target_);
+  }
+
+  template <typename Executor>
+  const Executor* target() const
+  {
+    return static_cast<Executor*>(target_);
+  }
+
+  const std::type_info& target_type() const
+  {
+    return target_fns_->target_type();
+  }
+
+  struct unspecified_bool_type_t {};
+  typedef void (*unspecified_bool_type)(unspecified_bool_type_t);
+  static void unspecified_bool_true(unspecified_bool_type_t) {}
+
+  operator unspecified_bool_type() const ASIO_NOEXCEPT
+  {
+    return target_ ? &any_executor_base::unspecified_bool_true : 0;
+  }
+
+  bool operator!() const ASIO_NOEXCEPT
+  {
+    return target_ == 0;
+  }
+
+protected:
+  bool equality_helper(const any_executor_base& other) const ASIO_NOEXCEPT
+  {
+    if (target_ == other.target_)
+      return true;
+    if (target_ && !other.target_)
+      return false;
+    if (!target_ && other.target_)
+      return false;
+    if (target_fns_ != other.target_fns_)
+      return false;
+    return target_fns_->equal(*this, other);
+  }
+
+  template <typename Ex>
+  Ex& object()
+  {
+    return *static_cast<Ex*>(static_cast<void*>(&object_));
+  }
+
+  template <typename Ex>
+  const Ex& object() const
+  {
+    return *static_cast<const Ex*>(static_cast<const void*>(&object_));
+  }
+
+  struct object_fns
+  {
+    void (*destroy)(any_executor_base&);
+    void (*copy)(any_executor_base&, const any_executor_base&);
+    void (*move)(any_executor_base&, any_executor_base&);
+    const void* (*target)(const any_executor_base&);
+  };
+
+  static void destroy_void(any_executor_base&)
+  {
+  }
+
+  static void copy_void(any_executor_base& ex1, const any_executor_base&)
+  {
+    ex1.target_ = 0;
+  }
+
+  static void move_void(any_executor_base& ex1, any_executor_base&)
+  {
+    ex1.target_ = 0;
+  }
+
+  static const void* target_void(const any_executor_base&)
+  {
+    return 0;
+  }
+
+  template <typename Obj>
+  static const object_fns* object_fns_table(
+      typename enable_if<
+        is_same<Obj, void>::value
+      >::type* = 0)
+  {
+    static const object_fns fns =
+    {
+      &any_executor_base::destroy_void,
+      &any_executor_base::copy_void,
+      &any_executor_base::move_void,
+      &any_executor_base::target_void
+    };
+    return &fns;
+  }
+
+  static void destroy_shared(any_executor_base& ex)
+  {
+    typedef asio::detail::shared_ptr<void> type;
+    ex.object<type>().~type();
+  }
+
+  static void copy_shared(any_executor_base& ex1, const any_executor_base& ex2)
+  {
+    typedef asio::detail::shared_ptr<void> type;
+    new (&ex1.object_) type(ex2.object<type>());
+    ex1.target_ = ex2.target_;
+  }
+
+  static void move_shared(any_executor_base& ex1, any_executor_base& ex2)
+  {
+    typedef asio::detail::shared_ptr<void> type;
+    new (&ex1.object_) type(ASIO_MOVE_CAST(type)(ex2.object<type>()));
+    ex1.target_ = ex2.target_;
+    ex2.object<type>().~type();
+  }
+
+  static const void* target_shared(const any_executor_base& ex)
+  {
+    typedef asio::detail::shared_ptr<void> type;
+    return ex.object<type>().get();
+  }
+
+  template <typename Obj>
+  static const object_fns* object_fns_table(
+      typename enable_if<
+        is_same<Obj, asio::detail::shared_ptr<void> >::value
+      >::type* = 0)
+  {
+    static const object_fns fns =
+    {
+      &any_executor_base::destroy_shared,
+      &any_executor_base::copy_shared,
+      &any_executor_base::move_shared,
+      &any_executor_base::target_shared
+    };
+    return &fns;
+  }
+
+  template <typename Obj>
+  static void destroy_object(any_executor_base& ex)
+  {
+    ex.object<Obj>().~Obj();
+  }
+
+  template <typename Obj>
+  static void copy_object(any_executor_base& ex1, const any_executor_base& ex2)
+  {
+    new (&ex1.object_) Obj(ex2.object<Obj>());
+    ex1.target_ = &ex1.object<Obj>();
+  }
+
+  template <typename Obj>
+  static void move_object(any_executor_base& ex1, any_executor_base& ex2)
+  {
+    new (&ex1.object_) Obj(ASIO_MOVE_CAST(Obj)(ex2.object<Obj>()));
+    ex1.target_ = &ex1.object<Obj>();
+    ex2.object<Obj>().~Obj();
+  }
+
+  template <typename Obj>
+  static const void* target_object(const any_executor_base& ex)
+  {
+    return &ex.object<Obj>();
+  }
+
+  template <typename Obj>
+  static const object_fns* object_fns_table(
+      typename enable_if<
+        !is_same<Obj, void>::value
+          && !is_same<Obj, asio::detail::shared_ptr<void> >::value
+      >::type* = 0)
+  {
+    static const object_fns fns =
+    {
+      &any_executor_base::destroy_object<Obj>,
+      &any_executor_base::copy_object<Obj>,
+      &any_executor_base::move_object<Obj>,
+      &any_executor_base::target_object<Obj>
+    };
+    return &fns;
+  }
+
+  typedef asio::detail::executor_function function;
+  typedef asio::detail::executor_function_view function_view;
+
+  struct target_fns
+  {
+    const std::type_info& (*target_type)();
+    bool (*equal)(const any_executor_base&, const any_executor_base&);
+    void (*execute)(const any_executor_base&, ASIO_MOVE_ARG(function));
+    void (*blocking_execute)(const any_executor_base&, function_view);
+  };
+
+  static const std::type_info& target_type_void()
+  {
+    return typeid(void);
+  }
+
+  static bool equal_void(const any_executor_base&, const any_executor_base&)
+  {
+    return true;
+  }
+
+  static void execute_void(const any_executor_base&,
+      ASIO_MOVE_ARG(function))
+  {
+    bad_executor ex;
+    asio::detail::throw_exception(ex);
+  }
+
+  static void blocking_execute_void(const any_executor_base&, function_view)
+  {
+    bad_executor ex;
+    asio::detail::throw_exception(ex);
+  }
+
+  template <typename Ex>
+  static const target_fns* target_fns_table(
+      typename enable_if<
+        is_same<Ex, void>::value
+      >::type* = 0)
+  {
+    static const target_fns fns =
+    {
+      &any_executor_base::target_type_void,
+      &any_executor_base::equal_void,
+      &any_executor_base::execute_void,
+      &any_executor_base::blocking_execute_void
+    };
+    return &fns;
+  }
+
+  template <typename Ex>
+  static const std::type_info& target_type_ex()
+  {
+    return typeid(Ex);
+  }
+
+  template <typename Ex>
+  static bool equal_ex(const any_executor_base& ex1,
+      const any_executor_base& ex2)
+  {
+    return *ex1.target<Ex>() == *ex2.target<Ex>();
+  }
+
+  template <typename Ex>
+  static void execute_ex(const any_executor_base& ex,
+      ASIO_MOVE_ARG(function) f)
+  {
+    execution::execute(*ex.target<Ex>(), ASIO_MOVE_CAST(function)(f));
+  }
+
+  template <typename Ex>
+  static void blocking_execute_ex(const any_executor_base& ex, function_view f)
+  {
+    execution::execute(*ex.target<Ex>(), f);
+  }
+
+  template <typename Ex>
+  static const target_fns* target_fns_table(bool is_always_blocking,
+      typename enable_if<
+        !is_same<Ex, void>::value
+      >::type* = 0)
+  {
+    static const target_fns fns_with_execute =
+    {
+      &any_executor_base::target_type_ex<Ex>,
+      &any_executor_base::equal_ex<Ex>,
+      &any_executor_base::execute_ex<Ex>,
+      0
+    };
+
+    static const target_fns fns_with_blocking_execute =
+    {
+      &any_executor_base::target_type_ex<Ex>,
+      &any_executor_base::equal_ex<Ex>,
+      0,
+      &any_executor_base::blocking_execute_ex<Ex>
+    };
+
+    return is_always_blocking ? &fns_with_blocking_execute : &fns_with_execute;
+  }
+
+#if defined(ASIO_MSVC)
+# pragma warning (push)
+# pragma warning (disable:4702)
+#endif // defined(ASIO_MSVC)
+
+  static void query_fn_void(void*, const void*, const void*)
+  {
+    bad_executor ex;
+    asio::detail::throw_exception(ex);
+  }
+
+  template <typename Ex, class Prop>
+  static void query_fn_non_void(void*, const void* ex, const void* prop,
+      typename enable_if<
+        asio::can_query<const Ex&, const Prop&>::value
+          && is_same<typename Prop::polymorphic_query_result_type, void>::value
+      >::type*)
+  {
+    asio::query(*static_cast<const Ex*>(ex),
+        *static_cast<const Prop*>(prop));
+  }
+
+  template <typename Ex, class Prop>
+  static void query_fn_non_void(void*, const void*, const void*,
+      typename enable_if<
+        !asio::can_query<const Ex&, const Prop&>::value
+          && is_same<typename Prop::polymorphic_query_result_type, void>::value
+      >::type*)
+  {
+  }
+
+  template <typename Ex, class Prop>
+  static void query_fn_non_void(void* result, const void* ex, const void* prop,
+      typename enable_if<
+        asio::can_query<const Ex&, const Prop&>::value
+          && !is_same<typename Prop::polymorphic_query_result_type, void>::value
+          && is_reference<typename Prop::polymorphic_query_result_type>::value
+      >::type*)
+  {
+    *static_cast<typename remove_reference<
+      typename Prop::polymorphic_query_result_type>::type**>(result)
+        = &static_cast<typename Prop::polymorphic_query_result_type>(
+            asio::query(*static_cast<const Ex*>(ex),
+              *static_cast<const Prop*>(prop)));
+  }
+
+  template <typename Ex, class Prop>
+  static void query_fn_non_void(void*, const void*, const void*,
+      typename enable_if<
+        !asio::can_query<const Ex&, const Prop&>::value
+          && !is_same<typename Prop::polymorphic_query_result_type, void>::value
+          && is_reference<typename Prop::polymorphic_query_result_type>::value
+      >::type*)
+  {
+    std::terminate(); // Combination should not be possible.
+  }
+
+  template <typename Ex, class Prop>
+  static void query_fn_non_void(void* result, const void* ex, const void* prop,
+      typename enable_if<
+        asio::can_query<const Ex&, const Prop&>::value
+          && !is_same<typename Prop::polymorphic_query_result_type, void>::value
+          && is_scalar<typename Prop::polymorphic_query_result_type>::value
+      >::type*)
+  {
+    *static_cast<typename Prop::polymorphic_query_result_type*>(result)
+      = static_cast<typename Prop::polymorphic_query_result_type>(
+          asio::query(*static_cast<const Ex*>(ex),
+            *static_cast<const Prop*>(prop)));
+  }
+
+  template <typename Ex, class Prop>
+  static void query_fn_non_void(void* result, const void*, const void*,
+      typename enable_if<
+        !asio::can_query<const Ex&, const Prop&>::value
+          && !is_same<typename Prop::polymorphic_query_result_type, void>::value
+          && is_scalar<typename Prop::polymorphic_query_result_type>::value
+      >::type*)
+  {
+    *static_cast<typename Prop::polymorphic_query_result_type*>(result)
+      = typename Prop::polymorphic_query_result_type();
+  }
+
+  template <typename Ex, class Prop>
+  static void query_fn_non_void(void* result, const void* ex, const void* prop,
+      typename enable_if<
+        asio::can_query<const Ex&, const Prop&>::value
+          && !is_same<typename Prop::polymorphic_query_result_type, void>::value
+          && !is_reference<typename Prop::polymorphic_query_result_type>::value
+          && !is_scalar<typename Prop::polymorphic_query_result_type>::value
+      >::type*)
+  {
+    *static_cast<typename Prop::polymorphic_query_result_type**>(result)
+      = new typename Prop::polymorphic_query_result_type(
+          asio::query(*static_cast<const Ex*>(ex),
+            *static_cast<const Prop*>(prop)));
+  }
+
+  template <typename Ex, class Prop>
+  static void query_fn_non_void(void* result, const void*, const void*, ...)
+  {
+    *static_cast<typename Prop::polymorphic_query_result_type**>(result)
+      = new typename Prop::polymorphic_query_result_type();
+  }
+
+  template <typename Ex, class Prop>
+  static void query_fn_impl(void* result, const void* ex, const void* prop,
+      typename enable_if<
+        is_same<Ex, void>::value
+      >::type*)
+  {
+    query_fn_void(result, ex, prop);
+  }
+
+  template <typename Ex, class Prop>
+  static void query_fn_impl(void* result, const void* ex, const void* prop,
+      typename enable_if<
+        !is_same<Ex, void>::value
+      >::type*)
+  {
+    query_fn_non_void<Ex, Prop>(result, ex, prop, 0);
+  }
+
+  template <typename Ex, class Prop>
+  static void query_fn(void* result, const void* ex, const void* prop)
+  {
+    query_fn_impl<Ex, Prop>(result, ex, prop, 0);
+  }
+
+  template <typename Poly, typename Ex, class Prop>
+  static Poly require_fn_impl(const void*, const void*,
+      typename enable_if<
+        is_same<Ex, void>::value
+      >::type*)
+  {
+    bad_executor ex;
+    asio::detail::throw_exception(ex);
+    return Poly();
+  }
+
+  template <typename Poly, typename Ex, class Prop>
+  static Poly require_fn_impl(const void* ex, const void* prop,
+      typename enable_if<
+        !is_same<Ex, void>::value && Prop::is_requirable
+      >::type*)
+  {
+    return asio::require(*static_cast<const Ex*>(ex),
+        *static_cast<const Prop*>(prop));
+  }
+
+  template <typename Poly, typename Ex, class Prop>
+  static Poly require_fn_impl(const void*, const void*, ...)
+  {
+    return Poly();
+  }
+
+  template <typename Poly, typename Ex, class Prop>
+  static Poly require_fn(const void* ex, const void* prop)
+  {
+    return require_fn_impl<Poly, Ex, Prop>(ex, prop, 0);
+  }
+
+  template <typename Poly, typename Ex, class Prop>
+  static Poly prefer_fn_impl(const void*, const void*,
+      typename enable_if<
+        is_same<Ex, void>::value
+      >::type*)
+  {
+    bad_executor ex;
+    asio::detail::throw_exception(ex);
+    return Poly();
+  }
+
+  template <typename Poly, typename Ex, class Prop>
+  static Poly prefer_fn_impl(const void* ex, const void* prop,
+      typename enable_if<
+        !is_same<Ex, void>::value && Prop::is_preferable
+      >::type*)
+  {
+    return asio::prefer(*static_cast<const Ex*>(ex),
+        *static_cast<const Prop*>(prop));
+  }
+
+  template <typename Poly, typename Ex, class Prop>
+  static Poly prefer_fn_impl(const void*, const void*, ...)
+  {
+    return Poly();
+  }
+
+  template <typename Poly, typename Ex, class Prop>
+  static Poly prefer_fn(const void* ex, const void* prop)
+  {
+    return prefer_fn_impl<Poly, Ex, Prop>(ex, prop, 0);
+  }
+
+  template <typename Poly>
+  struct prop_fns
+  {
+    void (*query)(void*, const void*, const void*);
+    Poly (*require)(const void*, const void*);
+    Poly (*prefer)(const void*, const void*);
+  };
+
+#if defined(ASIO_MSVC)
+# pragma warning (pop)
+#endif // defined(ASIO_MSVC)
+
+private:
+  template <typename Executor>
+  static execution::blocking_t query_blocking(const Executor& ex, true_type)
+  {
+    return asio::query(ex, execution::blocking);
+  }
+
+  template <typename Executor>
+  static execution::blocking_t query_blocking(const Executor&, false_type)
+  {
+    return execution::blocking_t();
+  }
+
+  template <typename Executor>
+  void construct_object(Executor& ex, true_type)
+  {
+    object_fns_ = object_fns_table<Executor>();
+    target_ = new (&object_) Executor(ASIO_MOVE_CAST(Executor)(ex));
+  }
+
+  template <typename Executor>
+  void construct_object(Executor& ex, false_type)
+  {
+    object_fns_ = object_fns_table<asio::detail::shared_ptr<void> >();
+    asio::detail::shared_ptr<Executor> p =
+      asio::detail::make_shared<Executor>(
+          ASIO_MOVE_CAST(Executor)(ex));
+    target_ = p.get();
+    new (&object_) asio::detail::shared_ptr<void>(
+        ASIO_MOVE_CAST(asio::detail::shared_ptr<Executor>)(p));
+  }
+
+/*private:*/public:
+//  template <typename...> friend class any_executor;
+
+  typedef aligned_storage<
+      sizeof(asio::detail::shared_ptr<void>),
+      alignment_of<asio::detail::shared_ptr<void> >::value
+    >::type object_type;
+
+  object_type object_;
+  const object_fns* object_fns_;
+  void* target_;
+  const target_fns* target_fns_;
+};
+
+template <typename Derived, typename Property, typename = void>
+struct any_executor_context
+{
+};
+
+#if !defined(ASIO_NO_TS_EXECUTORS)
+
+template <typename Derived, typename Property>
+struct any_executor_context<Derived, Property,
+    typename enable_if<Property::value>::type>
+{
+  typename Property::query_result_type context() const
+  {
+    return static_cast<const Derived*>(this)->query(typename Property::type());
+  }
+};
+
+#endif // !defined(ASIO_NO_TS_EXECUTORS)
+
+} // namespace detail
+
+template <>
+class any_executor<> : public detail::any_executor_base
+{
+public:
+  any_executor() ASIO_NOEXCEPT
+    : detail::any_executor_base()
+  {
+  }
+
+  any_executor(nullptr_t) ASIO_NOEXCEPT
+    : detail::any_executor_base()
+  {
+  }
+
+  template <typename Executor>
+  any_executor(Executor ex,
+      typename enable_if<
+        conditional<
+          !is_same<Executor, any_executor>::value
+            && !is_base_of<detail::any_executor_base, Executor>::value,
+          is_executor<Executor>,
+          false_type
+        >::type::value
+      >::type* = 0)
+    : detail::any_executor_base(
+        ASIO_MOVE_CAST(Executor)(ex), false_type())
+  {
+  }
+
+#if defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+  template <typename... OtherSupportableProperties>
+  any_executor(any_executor<OtherSupportableProperties...> other)
+    : detail::any_executor_base(
+        static_cast<const detail::any_executor_base&>(other))
+  {
+  }
+
+#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+  template <typename U0, typename U1, typename U2, typename U3,
+      typename U4, typename U5, typename U6, typename U7>
+  any_executor(any_executor<U0, U1, U2, U3, U4, U5, U6, U7> other)
+    : detail::any_executor_base(
+        static_cast<const detail::any_executor_base&>(other))
+  {
+  }
+
+#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+  any_executor(const any_executor& other) ASIO_NOEXCEPT
+    : detail::any_executor_base(
+        static_cast<const detail::any_executor_base&>(other))
+  {
+  }
+
+  any_executor& operator=(const any_executor& other) ASIO_NOEXCEPT
+  {
+    if (this != &other)
+    {
+      detail::any_executor_base::operator=(
+          static_cast<const detail::any_executor_base&>(other));
+    }
+    return *this;
+  }
+
+  any_executor& operator=(nullptr_t p) ASIO_NOEXCEPT
+  {
+    detail::any_executor_base::operator=(p);
+    return *this;
+  }
+
+#if defined(ASIO_HAS_MOVE)
+
+  any_executor(any_executor&& other) ASIO_NOEXCEPT
+    : detail::any_executor_base(
+        static_cast<any_executor_base&&>(
+          static_cast<any_executor_base&>(other)))
+  {
+  }
+
+  any_executor& operator=(any_executor&& other) ASIO_NOEXCEPT
+  {
+    if (this != &other)
+    {
+      detail::any_executor_base::operator=(
+          static_cast<detail::any_executor_base&&>(
+            static_cast<detail::any_executor_base&>(other)));
+    }
+    return *this;
+  }
+
+#endif // defined(ASIO_HAS_MOVE)
+
+  void swap(any_executor& other) ASIO_NOEXCEPT
+  {
+    detail::any_executor_base::swap(
+        static_cast<detail::any_executor_base&>(other));
+  }
+
+  using detail::any_executor_base::execute;
+  using detail::any_executor_base::target;
+  using detail::any_executor_base::target_type;
+  using detail::any_executor_base::operator unspecified_bool_type;
+  using detail::any_executor_base::operator!;
+
+  bool equality_helper(const any_executor& other) const ASIO_NOEXCEPT
+  {
+    return any_executor_base::equality_helper(other);
+  }
+};
+
+inline bool operator==(const any_executor<>& a,
+    const any_executor<>& b) ASIO_NOEXCEPT
+{
+  return a.equality_helper(b);
+}
+
+inline bool operator==(const any_executor<>& a, nullptr_t) ASIO_NOEXCEPT
+{
+  return !a;
+}
+
+inline bool operator==(nullptr_t, const any_executor<>& b) ASIO_NOEXCEPT
+{
+  return !b;
+}
+
+inline bool operator!=(const any_executor<>& a,
+    const any_executor<>& b) ASIO_NOEXCEPT
+{
+  return !a.equality_helper(b);
+}
+
+inline bool operator!=(const any_executor<>& a, nullptr_t) ASIO_NOEXCEPT
+{
+  return !!a;
+}
+
+inline bool operator!=(nullptr_t, const any_executor<>& b) ASIO_NOEXCEPT
+{
+  return !!b;
+}
+
+inline void swap(any_executor<>& a, any_executor<>& b) ASIO_NOEXCEPT
+{
+  return a.swap(b);
+}
+
+#if defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+template <typename... SupportableProperties>
+class any_executor :
+  public detail::any_executor_base,
+  public detail::any_executor_context<
+    any_executor<SupportableProperties...>,
+      typename detail::supportable_properties<
+        0, void(SupportableProperties...)>::find_context_as_property>
+{
+public:
+  any_executor() ASIO_NOEXCEPT
+    : detail::any_executor_base(),
+      prop_fns_(prop_fns_table<void>())
+  {
+  }
+
+  any_executor(nullptr_t) ASIO_NOEXCEPT
+    : detail::any_executor_base(),
+      prop_fns_(prop_fns_table<void>())
+  {
+  }
+
+  template <typename Executor>
+  any_executor(Executor ex,
+      typename enable_if<
+        conditional<
+          !is_same<Executor, any_executor>::value
+            && !is_base_of<detail::any_executor_base, Executor>::value,
+          detail::is_valid_target_executor<
+            Executor, void(SupportableProperties...)>,
+          false_type
+        >::type::value
+      >::type* = 0)
+    : detail::any_executor_base(
+        ASIO_MOVE_CAST(Executor)(ex), false_type()),
+      prop_fns_(prop_fns_table<Executor>())
+  {
+  }
+
+  template <typename... OtherSupportableProperties>
+  any_executor(any_executor<OtherSupportableProperties...> other,
+      typename enable_if<
+        conditional<
+          !is_same<
+            any_executor<OtherSupportableProperties...>,
+            any_executor
+          >::value,
+          typename detail::supportable_properties<
+            0, void(SupportableProperties...)>::template is_valid_target<
+              any_executor<OtherSupportableProperties...> >,
+          false_type
+        >::type::value
+      >::type* = 0)
+    : detail::any_executor_base(ASIO_MOVE_CAST(
+          any_executor<OtherSupportableProperties...>)(other), true_type()),
+      prop_fns_(prop_fns_table<any_executor<OtherSupportableProperties...> >())
+  {
+  }
+
+  any_executor(const any_executor& other) ASIO_NOEXCEPT
+    : detail::any_executor_base(
+        static_cast<const detail::any_executor_base&>(other)),
+      prop_fns_(other.prop_fns_)
+  {
+  }
+
+  any_executor& operator=(const any_executor& other) ASIO_NOEXCEPT
+  {
+    if (this != &other)
+    {
+      prop_fns_ = other.prop_fns_;
+      detail::any_executor_base::operator=(
+          static_cast<const detail::any_executor_base&>(other));
+    }
+    return *this;
+  }
+
+  any_executor& operator=(nullptr_t p) ASIO_NOEXCEPT
+  {
+    prop_fns_ = prop_fns_table<void>();
+    detail::any_executor_base::operator=(p);
+    return *this;
+  }
+
+#if defined(ASIO_HAS_MOVE)
+
+  any_executor(any_executor&& other) ASIO_NOEXCEPT
+    : detail::any_executor_base(
+        static_cast<any_executor_base&&>(
+          static_cast<any_executor_base&>(other))),
+      prop_fns_(other.prop_fns_)
+  {
+    other.prop_fns_ = prop_fns_table<void>();
+  }
+
+  any_executor& operator=(any_executor&& other) ASIO_NOEXCEPT
+  {
+    if (this != &other)
+    {
+      prop_fns_ = other.prop_fns_;
+      detail::any_executor_base::operator=(
+          static_cast<detail::any_executor_base&&>(
+            static_cast<detail::any_executor_base&>(other)));
+    }
+    return *this;
+  }
+
+#endif // defined(ASIO_HAS_MOVE)
+
+  void swap(any_executor& other) ASIO_NOEXCEPT
+  {
+    if (this != &other)
+    {
+      detail::any_executor_base::swap(
+          static_cast<detail::any_executor_base&>(other));
+      const prop_fns<any_executor>* tmp_prop_fns = other.prop_fns_;
+      other.prop_fns_ = prop_fns_;
+      prop_fns_ = tmp_prop_fns;
+    }
+  }
+
+  using detail::any_executor_base::execute;
+  using detail::any_executor_base::target;
+  using detail::any_executor_base::target_type;
+  using detail::any_executor_base::operator unspecified_bool_type;
+  using detail::any_executor_base::operator!;
+
+  bool equality_helper(const any_executor& other) const ASIO_NOEXCEPT
+  {
+    return any_executor_base::equality_helper(other);
+  }
+
+  template <typename T>
+  struct find_convertible_property :
+      detail::supportable_properties<
+        0, void(SupportableProperties...)>::template
+          find_convertible_property<T> {};
+
+  template <typename Property>
+  void query(const Property& p,
+      typename enable_if<
+        is_same<
+          typename find_convertible_property<Property>::query_result_type,
+          void
+        >::value
+      >::type* = 0) const
+  {
+    typedef find_convertible_property<Property> found;
+    prop_fns_[found::index].query(0, object_fns_->target(*this),
+        &static_cast<const typename found::type&>(p));
+  }
+
+  template <typename Property>
+  typename find_convertible_property<Property>::query_result_type
+  query(const Property& p,
+      typename enable_if<
+        !is_same<
+          typename find_convertible_property<Property>::query_result_type,
+          void
+        >::value
+        &&
+        is_reference<
+          typename find_convertible_property<Property>::query_result_type
+        >::value
+      >::type* = 0) const
+  {
+    typedef find_convertible_property<Property> found;
+    typename remove_reference<
+      typename found::query_result_type>::type* result = 0;
+    prop_fns_[found::index].query(&result, object_fns_->target(*this),
+        &static_cast<const typename found::type&>(p));
+    return *result;
+  }
+
+  template <typename Property>
+  typename find_convertible_property<Property>::query_result_type
+  query(const Property& p,
+      typename enable_if<
+        !is_same<
+          typename find_convertible_property<Property>::query_result_type,
+          void
+        >::value
+        &&
+        is_scalar<
+          typename find_convertible_property<Property>::query_result_type
+        >::value
+      >::type* = 0) const
+  {
+    typedef find_convertible_property<Property> found;
+    typename found::query_result_type result;
+    prop_fns_[found::index].query(&result, object_fns_->target(*this),
+        &static_cast<const typename found::type&>(p));
+    return result;
+  }
+
+  template <typename Property>
+  typename find_convertible_property<Property>::query_result_type
+  query(const Property& p,
+      typename enable_if<
+        !is_same<
+          typename find_convertible_property<Property>::query_result_type,
+          void
+        >::value
+        &&
+        !is_reference<
+          typename find_convertible_property<Property>::query_result_type
+        >::value
+        &&
+        !is_scalar<
+          typename find_convertible_property<Property>::query_result_type
+        >::value
+      >::type* = 0) const
+  {
+    typedef find_convertible_property<Property> found;
+    typename found::query_result_type* result;
+    prop_fns_[found::index].query(&result, object_fns_->target(*this),
+        &static_cast<const typename found::type&>(p));
+    return *asio::detail::scoped_ptr<
+      typename found::query_result_type>(result);
+  }
+
+  template <typename T>
+  struct find_convertible_requirable_property :
+      detail::supportable_properties<
+        0, void(SupportableProperties...)>::template
+          find_convertible_requirable_property<T> {};
+
+  template <typename Property>
+  any_executor require(const Property& p,
+      typename enable_if<
+        find_convertible_requirable_property<Property>::value
+      >::type* = 0) const
+  {
+    typedef find_convertible_requirable_property<Property> found;
+    return prop_fns_[found::index].require(object_fns_->target(*this),
+        &static_cast<const typename found::type&>(p));
+  }
+
+  template <typename T>
+  struct find_convertible_preferable_property :
+      detail::supportable_properties<
+        0, void(SupportableProperties...)>::template
+          find_convertible_preferable_property<T> {};
+
+  template <typename Property>
+  any_executor prefer(const Property& p,
+      typename enable_if<
+        find_convertible_preferable_property<Property>::value
+      >::type* = 0) const
+  {
+    typedef find_convertible_preferable_property<Property> found;
+    return prop_fns_[found::index].prefer(object_fns_->target(*this),
+        &static_cast<const typename found::type&>(p));
+  }
+
+//private:
+  template <typename Ex>
+  static const prop_fns<any_executor>* prop_fns_table()
+  {
+    static const prop_fns<any_executor> fns[] =
+    {
+      {
+        &detail::any_executor_base::query_fn<
+            Ex, SupportableProperties>,
+        &detail::any_executor_base::require_fn<
+            any_executor, Ex, SupportableProperties>,
+        &detail::any_executor_base::prefer_fn<
+            any_executor, Ex, SupportableProperties>
+      }...
+    };
+    return fns;
+  }
+
+  const prop_fns<any_executor>* prop_fns_;
+};
+
+template <typename... SupportableProperties>
+inline bool operator==(const any_executor<SupportableProperties...>& a,
+    const any_executor<SupportableProperties...>& b) ASIO_NOEXCEPT
+{
+  return a.equality_helper(b);
+}
+
+template <typename... SupportableProperties>
+inline bool operator==(const any_executor<SupportableProperties...>& a,
+    nullptr_t) ASIO_NOEXCEPT
+{
+  return !a;
+}
+
+template <typename... SupportableProperties>
+inline bool operator==(nullptr_t,
+    const any_executor<SupportableProperties...>& b) ASIO_NOEXCEPT
+{
+  return !b;
+}
+
+template <typename... SupportableProperties>
+inline bool operator!=(const any_executor<SupportableProperties...>& a,
+    const any_executor<SupportableProperties...>& b) ASIO_NOEXCEPT
+{
+  return !a.equality_helper(b);
+}
+
+template <typename... SupportableProperties>
+inline bool operator!=(const any_executor<SupportableProperties...>& a,
+    nullptr_t) ASIO_NOEXCEPT
+{
+  return !!a;
+}
+
+template <typename... SupportableProperties>
+inline bool operator!=(nullptr_t,
+    const any_executor<SupportableProperties...>& b) ASIO_NOEXCEPT
+{
+  return !!b;
+}
+
+template <typename... SupportableProperties>
+inline void swap(any_executor<SupportableProperties...>& a,
+    any_executor<SupportableProperties...>& b) ASIO_NOEXCEPT
+{
+  return a.swap(b);
+}
+
+#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+#define ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS(n) \
+  ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_##n
+
+#define ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_1 \
+  {  \
+    &detail::any_executor_base::query_fn<Ex, T1>, \
+    &detail::any_executor_base::require_fn<any_executor, Ex, T1>, \
+    &detail::any_executor_base::prefer_fn<any_executor, Ex, T1> \
+  }
+#define ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_2 \
+  ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_1, \
+  { \
+    &detail::any_executor_base::query_fn<Ex, T2>, \
+    &detail::any_executor_base::require_fn<any_executor, Ex, T2>, \
+    &detail::any_executor_base::prefer_fn<any_executor, Ex, T2> \
+  }
+#define ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_3 \
+  ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_2, \
+  { \
+    &detail::any_executor_base::query_fn<Ex, T3>, \
+    &detail::any_executor_base::require_fn<any_executor, Ex, T3>, \
+    &detail::any_executor_base::prefer_fn<any_executor, Ex, T3> \
+  }
+#define ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_4 \
+  ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_3, \
+  { \
+    &detail::any_executor_base::query_fn<Ex, T4>, \
+    &detail::any_executor_base::require_fn<any_executor, Ex, T4>, \
+    &detail::any_executor_base::prefer_fn<any_executor, Ex, T4> \
+  }
+#define ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_5 \
+  ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_4, \
+  { \
+    &detail::any_executor_base::query_fn<Ex, T5>, \
+    &detail::any_executor_base::require_fn<any_executor, Ex, T5>, \
+    &detail::any_executor_base::prefer_fn<any_executor, Ex, T5> \
+  }
+#define ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_6 \
+  ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_5, \
+  { \
+    &detail::any_executor_base::query_fn<Ex, T6>, \
+    &detail::any_executor_base::require_fn<any_executor, Ex, T6>, \
+    &detail::any_executor_base::prefer_fn<any_executor, Ex, T6> \
+  }
+#define ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_7 \
+  ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_6, \
+  { \
+    &detail::any_executor_base::query_fn<Ex, T7>, \
+    &detail::any_executor_base::require_fn<any_executor, Ex, T7>, \
+    &detail::any_executor_base::prefer_fn<any_executor, Ex, T7> \
+  }
+#define ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_8 \
+  ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_7, \
+  { \
+    &detail::any_executor_base::query_fn<Ex, T8>, \
+    &detail::any_executor_base::require_fn<any_executor, Ex, T8>, \
+    &detail::any_executor_base::prefer_fn<any_executor, Ex, T8> \
+  }
+
+#if defined(ASIO_HAS_MOVE)
+
+# define ASIO_PRIVATE_ANY_EXECUTOR_MOVE_OPS \
+  any_executor(any_executor&& other) ASIO_NOEXCEPT \
+    : detail::any_executor_base( \
+        static_cast<any_executor_base&&>( \
+          static_cast<any_executor_base&>(other))), \
+      prop_fns_(other.prop_fns_) \
+  { \
+    other.prop_fns_ = prop_fns_table<void>(); \
+  } \
+  \
+  any_executor& operator=(any_executor&& other) ASIO_NOEXCEPT \
+  { \
+    if (this != &other) \
+    { \
+      prop_fns_ = other.prop_fns_; \
+      detail::any_executor_base::operator=( \
+          static_cast<detail::any_executor_base&&>( \
+            static_cast<detail::any_executor_base&>(other))); \
+    } \
+    return *this; \
+  } \
+  /**/
+#else // defined(ASIO_HAS_MOVE)
+
+# define ASIO_PRIVATE_ANY_EXECUTOR_MOVE_OPS
+
+#endif // defined(ASIO_HAS_MOVE)
+
+#define ASIO_PRIVATE_ANY_EXECUTOR_DEF(n) \
+  template <ASIO_VARIADIC_TPARAMS(n)> \
+  class any_executor<ASIO_VARIADIC_TARGS(n)> : \
+    public detail::any_executor_base, \
+    public detail::any_executor_context< \
+      any_executor<ASIO_VARIADIC_TARGS(n)>, \
+        typename detail::supportable_properties< \
+          0, void(ASIO_VARIADIC_TARGS(n))>::find_context_as_property> \
+  { \
+  public: \
+    any_executor() ASIO_NOEXCEPT \
+      : detail::any_executor_base(), \
+        prop_fns_(prop_fns_table<void>()) \
+    { \
+    } \
+    \
+    any_executor(nullptr_t) ASIO_NOEXCEPT \
+      : detail::any_executor_base(), \
+        prop_fns_(prop_fns_table<void>()) \
+    { \
+    } \
+    \
+    template <ASIO_EXECUTION_EXECUTOR Executor> \
+    any_executor(Executor ex, \
+        typename enable_if< \
+          conditional< \
+            !is_same<Executor, any_executor>::value \
+              && !is_base_of<detail::any_executor_base, Executor>::value, \
+            detail::is_valid_target_executor< \
+              Executor, void(ASIO_VARIADIC_TARGS(n))>, \
+            false_type \
+          >::type::value \
+        >::type* = 0) \
+      : detail::any_executor_base(ASIO_MOVE_CAST( \
+            Executor)(ex), false_type()), \
+        prop_fns_(prop_fns_table<Executor>()) \
+    { \
+    } \
+    \
+    any_executor(const any_executor& other) ASIO_NOEXCEPT \
+      : detail::any_executor_base( \
+          static_cast<const detail::any_executor_base&>(other)), \
+        prop_fns_(other.prop_fns_) \
+    { \
+    } \
+    \
+    any_executor(any_executor<> other) \
+      : detail::any_executor_base(ASIO_MOVE_CAST( \
+            any_executor<>)(other), true_type()), \
+        prop_fns_(prop_fns_table<any_executor<> >()) \
+    { \
+    } \
+    \
+    template <typename OtherAnyExecutor> \
+    any_executor(OtherAnyExecutor other, \
+        typename enable_if< \
+          conditional< \
+            !is_same<OtherAnyExecutor, any_executor>::value \
+              && is_base_of<detail::any_executor_base, \
+                OtherAnyExecutor>::value, \
+            typename detail::supportable_properties< \
+              0, void(ASIO_VARIADIC_TARGS(n))>::template \
+                is_valid_target<OtherAnyExecutor>, \
+            false_type \
+          >::type::value \
+        >::type* = 0) \
+      : detail::any_executor_base(ASIO_MOVE_CAST( \
+            OtherAnyExecutor)(other), true_type()), \
+        prop_fns_(prop_fns_table<OtherAnyExecutor>()) \
+    { \
+    } \
+    \
+    any_executor& operator=(const any_executor& other) ASIO_NOEXCEPT \
+    { \
+      if (this != &other) \
+      { \
+        prop_fns_ = other.prop_fns_; \
+        detail::any_executor_base::operator=( \
+            static_cast<const detail::any_executor_base&>(other)); \
+      } \
+      return *this; \
+    } \
+    \
+    any_executor& operator=(nullptr_t p) ASIO_NOEXCEPT \
+    { \
+      prop_fns_ = prop_fns_table<void>(); \
+      detail::any_executor_base::operator=(p); \
+      return *this; \
+    } \
+    \
+    ASIO_PRIVATE_ANY_EXECUTOR_MOVE_OPS \
+    \
+    void swap(any_executor& other) ASIO_NOEXCEPT \
+    { \
+      if (this != &other) \
+      { \
+        detail::any_executor_base::swap( \
+            static_cast<detail::any_executor_base&>(other)); \
+        const prop_fns<any_executor>* tmp_prop_fns = other.prop_fns_; \
+        other.prop_fns_ = prop_fns_; \
+        prop_fns_ = tmp_prop_fns; \
+      } \
+    } \
+    \
+    using detail::any_executor_base::execute; \
+    using detail::any_executor_base::target; \
+    using detail::any_executor_base::target_type; \
+    using detail::any_executor_base::operator unspecified_bool_type; \
+    using detail::any_executor_base::operator!; \
+    \
+    bool equality_helper(const any_executor& other) const ASIO_NOEXCEPT \
+    { \
+      return any_executor_base::equality_helper(other); \
+    } \
+    \
+    template <typename T> \
+    struct find_convertible_property : \
+        detail::supportable_properties< \
+          0, void(ASIO_VARIADIC_TARGS(n))>::template \
+            find_convertible_property<T> {}; \
+    \
+    template <typename Property> \
+    void query(const Property& p, \
+        typename enable_if< \
+          is_same< \
+            typename find_convertible_property<Property>::query_result_type, \
+            void \
+          >::value \
+        >::type* = 0) const \
+    { \
+      typedef find_convertible_property<Property> found; \
+      prop_fns_[found::index].query(0, object_fns_->target(*this), \
+          &static_cast<const typename found::type&>(p)); \
+    } \
+    \
+    template <typename Property> \
+    typename find_convertible_property<Property>::query_result_type \
+    query(const Property& p, \
+        typename enable_if< \
+          !is_same< \
+            typename find_convertible_property<Property>::query_result_type, \
+            void \
+          >::value \
+          && \
+          is_reference< \
+            typename find_convertible_property<Property>::query_result_type \
+          >::value \
+        >::type* = 0) const \
+    { \
+      typedef find_convertible_property<Property> found; \
+      typename remove_reference< \
+        typename found::query_result_type>::type* result; \
+      prop_fns_[found::index].query(&result, object_fns_->target(*this), \
+          &static_cast<const typename found::type&>(p)); \
+      return *result; \
+    } \
+    \
+    template <typename Property> \
+    typename find_convertible_property<Property>::query_result_type \
+    query(const Property& p, \
+        typename enable_if< \
+          !is_same< \
+            typename find_convertible_property<Property>::query_result_type, \
+            void \
+          >::value \
+          && \
+          is_scalar< \
+            typename find_convertible_property<Property>::query_result_type \
+          >::value \
+        >::type* = 0) const \
+    { \
+      typedef find_convertible_property<Property> found; \
+      typename found::query_result_type result; \
+      prop_fns_[found::index].query(&result, object_fns_->target(*this), \
+          &static_cast<const typename found::type&>(p)); \
+      return result; \
+    } \
+    \
+    template <typename Property> \
+    typename find_convertible_property<Property>::query_result_type \
+    query(const Property& p, \
+        typename enable_if< \
+          !is_same< \
+            typename find_convertible_property<Property>::query_result_type, \
+            void \
+          >::value \
+          && \
+          !is_reference< \
+            typename find_convertible_property<Property>::query_result_type \
+          >::value \
+          && \
+          !is_scalar< \
+            typename find_convertible_property<Property>::query_result_type \
+          >::value \
+        >::type* = 0) const \
+    { \
+      typedef find_convertible_property<Property> found; \
+      typename found::query_result_type* result; \
+      prop_fns_[found::index].query(&result, object_fns_->target(*this), \
+          &static_cast<const typename found::type&>(p)); \
+      return *asio::detail::scoped_ptr< \
+        typename found::query_result_type>(result); \
+    } \
+    \
+    template <typename T> \
+    struct find_convertible_requirable_property : \
+        detail::supportable_properties< \
+          0, void(ASIO_VARIADIC_TARGS(n))>::template \
+            find_convertible_requirable_property<T> {}; \
+    \
+    template <typename Property> \
+    any_executor require(const Property& p, \
+        typename enable_if< \
+          find_convertible_requirable_property<Property>::value \
+        >::type* = 0) const \
+    { \
+      typedef find_convertible_requirable_property<Property> found; \
+      return prop_fns_[found::index].require(object_fns_->target(*this), \
+          &static_cast<const typename found::type&>(p)); \
+    } \
+    \
+    template <typename T> \
+    struct find_convertible_preferable_property : \
+        detail::supportable_properties< \
+          0, void(ASIO_VARIADIC_TARGS(n))>::template \
+            find_convertible_preferable_property<T> {}; \
+    \
+    template <typename Property> \
+    any_executor prefer(const Property& p, \
+        typename enable_if< \
+          find_convertible_preferable_property<Property>::value \
+        >::type* = 0) const \
+    { \
+      typedef find_convertible_preferable_property<Property> found; \
+      return prop_fns_[found::index].prefer(object_fns_->target(*this), \
+          &static_cast<const typename found::type&>(p)); \
+    } \
+    \
+    template <typename Ex> \
+    static const prop_fns<any_executor>* prop_fns_table() \
+    { \
+      static const prop_fns<any_executor> fns[] = \
+      { \
+        ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS(n) \
+      }; \
+      return fns; \
+    } \
+    \
+    const prop_fns<any_executor>* prop_fns_; \
+    typedef detail::supportable_properties<0, \
+        void(ASIO_VARIADIC_TARGS(n))> supportable_properties_type; \
+  }; \
+  \
+  template <ASIO_VARIADIC_TPARAMS(n)> \
+  inline bool operator==(const any_executor<ASIO_VARIADIC_TARGS(n)>& a, \
+      const any_executor<ASIO_VARIADIC_TARGS(n)>& b) ASIO_NOEXCEPT \
+  { \
+    return a.equality_helper(b); \
+  } \
+  \
+  template <ASIO_VARIADIC_TPARAMS(n)> \
+  inline bool operator==(const any_executor<ASIO_VARIADIC_TARGS(n)>& a, \
+      nullptr_t) ASIO_NOEXCEPT \
+  { \
+    return !a; \
+  } \
+  \
+  template <ASIO_VARIADIC_TPARAMS(n)> \
+  inline bool operator==(nullptr_t, \
+      const any_executor<ASIO_VARIADIC_TARGS(n)>& b) ASIO_NOEXCEPT \
+  { \
+    return !b; \
+  } \
+  \
+  template <ASIO_VARIADIC_TPARAMS(n)> \
+  inline bool operator!=(const any_executor<ASIO_VARIADIC_TARGS(n)>& a, \
+      const any_executor<ASIO_VARIADIC_TARGS(n)>& b) ASIO_NOEXCEPT \
+  { \
+    return !a.equality_helper(b); \
+  } \
+  \
+  template <ASIO_VARIADIC_TPARAMS(n)> \
+  inline bool operator!=(const any_executor<ASIO_VARIADIC_TARGS(n)>& a, \
+      nullptr_t) ASIO_NOEXCEPT \
+  { \
+    return !!a; \
+  } \
+  \
+  template <ASIO_VARIADIC_TPARAMS(n)> \
+  inline bool operator!=(nullptr_t, \
+      const any_executor<ASIO_VARIADIC_TARGS(n)>& b) ASIO_NOEXCEPT \
+  { \
+    return !!b; \
+  } \
+  \
+  template <ASIO_VARIADIC_TPARAMS(n)> \
+  inline void swap(any_executor<ASIO_VARIADIC_TARGS(n)>& a, \
+      any_executor<ASIO_VARIADIC_TARGS(n)>& b) ASIO_NOEXCEPT \
+  { \
+    return a.swap(b); \
+  } \
+  /**/
+  ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_ANY_EXECUTOR_DEF)
+#undef ASIO_PRIVATE_ANY_EXECUTOR_DEF
+#undef ASIO_PRIVATE_ANY_EXECUTOR_MOVE_OPS
+#undef ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS
+#undef ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_1
+#undef ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_2
+#undef ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_3
+#undef ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_4
+#undef ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_5
+#undef ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_6
+#undef ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_7
+#undef ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_8
+
+#endif // if defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+} // namespace execution
+namespace traits {
+
+#if !defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)
+#if defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+template <typename... SupportableProperties>
+struct equality_comparable<execution::any_executor<SupportableProperties...> >
+{
+  static const bool is_valid = true;
+  static const bool is_noexcept = true;
+};
+
+#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+template <>
+struct equality_comparable<execution::any_executor<> >
+{
+  static const bool is_valid = true;
+  static const bool is_noexcept = true;
+};
+
+#define ASIO_PRIVATE_ANY_EXECUTOR_EQUALITY_COMPARABLE_DEF(n) \
+  template <ASIO_VARIADIC_TPARAMS(n)> \
+  struct equality_comparable< \
+      execution::any_executor<ASIO_VARIADIC_TARGS(n)> > \
+  { \
+    static const bool is_valid = true; \
+    static const bool is_noexcept = true; \
+  }; \
+  /**/
+  ASIO_VARIADIC_GENERATE(
+      ASIO_PRIVATE_ANY_EXECUTOR_EQUALITY_COMPARABLE_DEF)
+#undef ASIO_PRIVATE_ANY_EXECUTOR_EQUALITY_COMPARABLE_DEF
+
+#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+#endif // !defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)
+
+#if !defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)
+#if defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+template <typename F, typename... SupportableProperties>
+struct execute_member<execution::any_executor<SupportableProperties...>, F>
+{
+  static const bool is_valid = true;
+  static const bool is_noexcept = false;
+  typedef void result_type;
+};
+
+#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+template <typename F>
+struct execute_member<execution::any_executor<>, F>
+{
+  static const bool is_valid = true;
+  static const bool is_noexcept = false;
+  typedef void result_type;
+};
+
+#define ASIO_PRIVATE_ANY_EXECUTOR_EXECUTE_MEMBER_DEF(n) \
+  template <typename F, ASIO_VARIADIC_TPARAMS(n)> \
+  struct execute_member< \
+      execution::any_executor<ASIO_VARIADIC_TARGS(n)>, F> \
+  { \
+    static const bool is_valid = true; \
+    static const bool is_noexcept = false; \
+    typedef void result_type; \
+  }; \
+  /**/
+  ASIO_VARIADIC_GENERATE(
+      ASIO_PRIVATE_ANY_EXECUTOR_EXECUTE_MEMBER_DEF)
+#undef ASIO_PRIVATE_ANY_EXECUTOR_EXECUTE_MEMBER_DEF
+
+#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+#endif // !defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)
+
+#if !defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT)
+#if defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+template <typename Prop, typename... SupportableProperties>
+struct query_member<
+    execution::any_executor<SupportableProperties...>, Prop,
+    typename enable_if<
+      execution::detail::supportable_properties<
+        0, void(SupportableProperties...)>::template
+          find_convertible_property<Prop>::value
+    >::type>
+{
+  static const bool is_valid = true;
+  static const bool is_noexcept = false;
+  typedef typename execution::detail::supportable_properties<
+      0, void(SupportableProperties...)>::template
+        find_convertible_property<Prop>::query_result_type result_type;
+};
+
+#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+#define ASIO_PRIVATE_ANY_EXECUTOR_QUERY_MEMBER_DEF(n) \
+  template <typename Prop, ASIO_VARIADIC_TPARAMS(n)> \
+  struct query_member< \
+      execution::any_executor<ASIO_VARIADIC_TARGS(n)>, Prop, \
+      typename enable_if< \
+        execution::detail::supportable_properties< \
+          0, void(ASIO_VARIADIC_TARGS(n))>::template \
+            find_convertible_property<Prop>::value \
+    >::type> \
+  { \
+    static const bool is_valid = true; \
+    static const bool is_noexcept = false; \
+    typedef typename execution::detail::supportable_properties< \
+        0, void(ASIO_VARIADIC_TARGS(n))>::template \
+          find_convertible_property<Prop>::query_result_type result_type; \
+  }; \
+  /**/
+  ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_ANY_EXECUTOR_QUERY_MEMBER_DEF)
+#undef ASIO_PRIVATE_ANY_EXECUTOR_QUERY_MEMBER_DEF
+
+#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+#endif // !defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT)
+
+#if !defined(ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT)
+#if defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+template <typename Prop, typename... SupportableProperties>
+struct require_member<
+    execution::any_executor<SupportableProperties...>, Prop,
+    typename enable_if<
+      execution::detail::supportable_properties<
+        0, void(SupportableProperties...)>::template
+          find_convertible_requirable_property<Prop>::value
+    >::type>
+{
+  static const bool is_valid = true;
+  static const bool is_noexcept = false;
+  typedef execution::any_executor<SupportableProperties...> result_type;
+};
+
+#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+#define ASIO_PRIVATE_ANY_EXECUTOR_REQUIRE_MEMBER_DEF(n) \
+  template <typename Prop, ASIO_VARIADIC_TPARAMS(n)> \
+  struct require_member< \
+      execution::any_executor<ASIO_VARIADIC_TARGS(n)>, Prop, \
+      typename enable_if< \
+        execution::detail::supportable_properties< \
+          0, void(ASIO_VARIADIC_TARGS(n))>::template \
+            find_convertible_requirable_property<Prop>::value \
+      >::type> \
+  { \
+    static const bool is_valid = true; \
+    static const bool is_noexcept = false; \
+    typedef execution::any_executor<ASIO_VARIADIC_TARGS(n)> result_type; \
+  }; \
+  /**/
+  ASIO_VARIADIC_GENERATE(
+      ASIO_PRIVATE_ANY_EXECUTOR_REQUIRE_MEMBER_DEF)
+#undef ASIO_PRIVATE_ANY_EXECUTOR_REQUIRE_MEMBER_DEF
+
+#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+#endif // !defined(ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT)
+
+#if !defined(ASIO_HAS_DEDUCED_PREFER_FREE_TRAIT)
+#if defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+template <typename Prop, typename... SupportableProperties>
+struct prefer_member<
+    execution::any_executor<SupportableProperties...>, Prop,
+    typename enable_if<
+      execution::detail::supportable_properties<
+        0, void(SupportableProperties...)>::template
+          find_convertible_preferable_property<Prop>::value
+    >::type>
+{
+  static const bool is_valid = true;
+  static const bool is_noexcept = false;
+  typedef execution::any_executor<SupportableProperties...> result_type;
+};
+
+#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+#define ASIO_PRIVATE_ANY_EXECUTOR_PREFER_FREE_DEF(n) \
+  template <typename Prop, ASIO_VARIADIC_TPARAMS(n)> \
+  struct prefer_member< \
+      execution::any_executor<ASIO_VARIADIC_TARGS(n)>, Prop, \
+      typename enable_if< \
+        execution::detail::supportable_properties< \
+          0, void(ASIO_VARIADIC_TARGS(n))>::template \
+            find_convertible_preferable_property<Prop>::value \
+      >::type> \
+  { \
+    static const bool is_valid = true; \
+    static const bool is_noexcept = false; \
+    typedef execution::any_executor<ASIO_VARIADIC_TARGS(n)> result_type; \
+  }; \
+  /**/
+  ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_ANY_EXECUTOR_PREFER_FREE_DEF)
+#undef ASIO_PRIVATE_ANY_EXECUTOR_PREFER_FREE_DEF
+
+#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+#endif // !defined(ASIO_HAS_DEDUCED_PREFER_FREE_TRAIT)
+
+} // namespace traits
+
+#endif // defined(GENERATING_DOCUMENTATION)
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_EXECUTION_ANY_EXECUTOR_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/execution/bad_executor.hpp b/link/modules/asio-standalone/asio/include/asio/execution/bad_executor.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/execution/bad_executor.hpp
@@ -0,0 +1,47 @@
+//
+// execution/bad_executor.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_EXECUTION_BAD_EXECUTOR_HPP
+#define ASIO_EXECUTION_BAD_EXECUTOR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <exception>
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace execution {
+
+/// Exception thrown when trying to access an empty polymorphic executor.
+class bad_executor
+  : public std::exception
+{
+public:
+  /// Constructor.
+  ASIO_DECL bad_executor() ASIO_NOEXCEPT;
+
+  /// Obtain message associated with exception.
+  ASIO_DECL virtual const char* what() const
+    ASIO_NOEXCEPT_OR_NOTHROW;
+};
+
+} // namespace execution
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/execution/impl/bad_executor.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // ASIO_EXECUTION_BAD_EXECUTOR_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/execution/blocking.hpp b/link/modules/asio-standalone/asio/include/asio/execution/blocking.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/execution/blocking.hpp
@@ -0,0 +1,1351 @@
+//
+// execution/blocking.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_EXECUTION_BLOCKING_HPP
+#define ASIO_EXECUTION_BLOCKING_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/type_traits.hpp"
+#include "asio/execution/execute.hpp"
+#include "asio/execution/executor.hpp"
+#include "asio/execution/scheduler.hpp"
+#include "asio/execution/sender.hpp"
+#include "asio/is_applicable_property.hpp"
+#include "asio/prefer.hpp"
+#include "asio/query.hpp"
+#include "asio/require.hpp"
+#include "asio/traits/query_free.hpp"
+#include "asio/traits/query_member.hpp"
+#include "asio/traits/query_static_constexpr_member.hpp"
+#include "asio/traits/static_query.hpp"
+#include "asio/traits/static_require.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+#if defined(GENERATING_DOCUMENTATION)
+
+namespace execution {
+
+/// A property to describe what guarantees an executor makes about the blocking
+/// behaviour of their execution functions.
+struct blocking_t
+{
+  /// The blocking_t property applies to executors, senders, and schedulers.
+  template <typename T>
+  static constexpr bool is_applicable_property_v =
+    is_executor_v<T> || is_sender_v<T> || is_scheduler_v<T>;
+
+  /// The top-level blocking_t property cannot be required.
+  static constexpr bool is_requirable = false;
+
+  /// The top-level blocking_t property cannot be preferred.
+  static constexpr bool is_preferable = false;
+
+  /// The type returned by queries against an @c any_executor.
+  typedef blocking_t polymorphic_query_result_type;
+
+  /// A sub-property that indicates that invocation of an executor's execution
+  /// function may block pending completion of one or more invocations of the
+  /// submitted function object.
+  struct possibly_t
+  {
+    /// The blocking_t::possibly_t property applies to executors, senders, and
+    /// schedulers.
+    template <typename T>
+    static constexpr bool is_applicable_property_v =
+      is_executor_v<T> || is_sender_v<T> || is_scheduler_v<T>;
+
+    /// The blocking_t::possibly_t property can be required.
+    static constexpr bool is_requirable = true;
+
+    /// The blocking_t::possibly_t property can be preferred.
+    static constexpr bool is_preferable = true;
+
+    /// The type returned by queries against an @c any_executor.
+    typedef blocking_t polymorphic_query_result_type;
+
+    /// Default constructor.
+    constexpr possibly_t();
+
+    /// Get the value associated with a property object.
+    /**
+     * @returns possibly_t();
+     */
+    static constexpr blocking_t value();
+  };
+
+  /// A sub-property that indicates that invocation of an executor's execution
+  /// function shall block until completion of all invocations of the submitted
+  /// function object.
+  struct always_t
+  {
+    /// The blocking_t::always_t property applies to executors, senders, and
+    /// schedulers.
+    template <typename T>
+    static constexpr bool is_applicable_property_v =
+      is_executor_v<T> || is_sender_v<T> || is_scheduler_v<T>;
+
+    /// The blocking_t::always_t property can be required.
+    static constexpr bool is_requirable = true;
+
+    /// The blocking_t::always_t property can be preferred.
+    static constexpr bool is_preferable = false;
+
+    /// The type returned by queries against an @c any_executor.
+    typedef blocking_t polymorphic_query_result_type;
+
+    /// Default constructor.
+    constexpr always_t();
+
+    /// Get the value associated with a property object.
+    /**
+     * @returns always_t();
+     */
+    static constexpr blocking_t value();
+  };
+
+  /// A sub-property that indicates that invocation of an executor's execution
+  /// function shall not block pending completion of the invocations of the
+  /// submitted function object.
+  struct never_t
+  {
+    /// The blocking_t::never_t property applies to executors, senders, and
+    /// schedulers.
+    template <typename T>
+    static constexpr bool is_applicable_property_v =
+      is_executor_v<T> || is_sender_v<T> || is_scheduler_v<T>;
+
+    /// The blocking_t::never_t property can be required.
+    static constexpr bool is_requirable = true;
+
+    /// The blocking_t::never_t property can be preferred.
+    static constexpr bool is_preferable = true;
+
+    /// The type returned by queries against an @c any_executor.
+    typedef blocking_t polymorphic_query_result_type;
+
+    /// Default constructor.
+    constexpr never_t();
+
+    /// Get the value associated with a property object.
+    /**
+     * @returns never_t();
+     */
+    static constexpr blocking_t value();
+  };
+
+  /// A special value used for accessing the blocking_t::possibly_t property.
+  static constexpr possibly_t possibly;
+
+  /// A special value used for accessing the blocking_t::always_t property.
+  static constexpr always_t always;
+
+  /// A special value used for accessing the blocking_t::never_t property.
+  static constexpr never_t never;
+
+  /// Default constructor.
+  constexpr blocking_t();
+
+  /// Construct from a sub-property value.
+  constexpr blocking_t(possibly_t);
+
+  /// Construct from a sub-property value.
+  constexpr blocking_t(always_t);
+
+  /// Construct from a sub-property value.
+  constexpr blocking_t(never_t);
+
+  /// Compare property values for equality.
+  friend constexpr bool operator==(
+      const blocking_t& a, const blocking_t& b) noexcept;
+
+  /// Compare property values for inequality.
+  friend constexpr bool operator!=(
+      const blocking_t& a, const blocking_t& b) noexcept;
+};
+
+/// A special value used for accessing the blocking_t property.
+constexpr blocking_t blocking;
+
+} // namespace execution
+
+#else // defined(GENERATING_DOCUMENTATION)
+
+namespace execution {
+namespace detail {
+namespace blocking {
+
+template <int I> struct possibly_t;
+template <int I> struct always_t;
+template <int I> struct never_t;
+
+} // namespace blocking
+namespace blocking_adaptation {
+
+template <int I> struct allowed_t;
+
+template <typename Executor, typename Function>
+void blocking_execute(
+    ASIO_MOVE_ARG(Executor) ex,
+    ASIO_MOVE_ARG(Function) func);
+
+} // namespace blocking_adaptation
+
+template <int I = 0>
+struct blocking_t
+{
+#if defined(ASIO_HAS_VARIABLE_TEMPLATES)
+  template <typename T>
+  ASIO_STATIC_CONSTEXPR(bool,
+    is_applicable_property_v = is_executor<T>::value
+      || is_sender<T>::value || is_scheduler<T>::value);
+#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+  ASIO_STATIC_CONSTEXPR(bool, is_requirable = false);
+  ASIO_STATIC_CONSTEXPR(bool, is_preferable = false);
+  typedef blocking_t polymorphic_query_result_type;
+
+  typedef detail::blocking::possibly_t<I> possibly_t;
+  typedef detail::blocking::always_t<I> always_t;
+  typedef detail::blocking::never_t<I> never_t;
+
+  ASIO_CONSTEXPR blocking_t()
+    : value_(-1)
+  {
+  }
+
+  ASIO_CONSTEXPR blocking_t(possibly_t)
+    : value_(0)
+  {
+  }
+
+  ASIO_CONSTEXPR blocking_t(always_t)
+    : value_(1)
+  {
+  }
+
+  ASIO_CONSTEXPR blocking_t(never_t)
+    : value_(2)
+  {
+  }
+
+#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \
+  && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+  template <typename T>
+  static ASIO_CONSTEXPR
+  typename traits::query_static_constexpr_member<T, blocking_t>::result_type
+  static_query()
+    ASIO_NOEXCEPT_IF((
+      traits::query_static_constexpr_member<T, blocking_t>::is_noexcept))
+  {
+    return traits::query_static_constexpr_member<T, blocking_t>::value();
+  }
+
+  template <typename T>
+  static ASIO_CONSTEXPR
+  typename traits::static_query<T, possibly_t>::result_type
+  static_query(
+      typename enable_if<
+        !traits::query_static_constexpr_member<T, blocking_t>::is_valid
+          && !traits::query_member<T, blocking_t>::is_valid
+          && traits::static_query<T, possibly_t>::is_valid
+      >::type* = 0) ASIO_NOEXCEPT
+  {
+    return traits::static_query<T, possibly_t>::value();
+  }
+
+  template <typename T>
+  static ASIO_CONSTEXPR
+  typename traits::static_query<T, always_t>::result_type
+  static_query(
+      typename enable_if<
+        !traits::query_static_constexpr_member<T, blocking_t>::is_valid
+          && !traits::query_member<T, blocking_t>::is_valid
+          && !traits::static_query<T, possibly_t>::is_valid
+          && traits::static_query<T, always_t>::is_valid
+      >::type* = 0) ASIO_NOEXCEPT
+  {
+    return traits::static_query<T, always_t>::value();
+  }
+
+  template <typename T>
+  static ASIO_CONSTEXPR
+  typename traits::static_query<T, never_t>::result_type
+  static_query(
+      typename enable_if<
+        !traits::query_static_constexpr_member<T, blocking_t>::is_valid
+          && !traits::query_member<T, blocking_t>::is_valid
+          && !traits::static_query<T, possibly_t>::is_valid
+          && !traits::static_query<T, always_t>::is_valid
+          && traits::static_query<T, never_t>::is_valid
+      >::type* = 0) ASIO_NOEXCEPT
+  {
+    return traits::static_query<T, never_t>::value();
+  }
+
+  template <typename E, typename T = decltype(blocking_t::static_query<E>())>
+  static ASIO_CONSTEXPR const T static_query_v
+    = blocking_t::static_query<E>();
+#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)
+       //   && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+
+  friend ASIO_CONSTEXPR bool operator==(
+      const blocking_t& a, const blocking_t& b)
+  {
+    return a.value_ == b.value_;
+  }
+
+  friend ASIO_CONSTEXPR bool operator!=(
+      const blocking_t& a, const blocking_t& b)
+  {
+    return a.value_ != b.value_;
+  }
+
+  struct convertible_from_blocking_t
+  {
+    ASIO_CONSTEXPR convertible_from_blocking_t(blocking_t) {}
+  };
+
+  template <typename Executor>
+  friend ASIO_CONSTEXPR blocking_t query(
+      const Executor& ex, convertible_from_blocking_t,
+      typename enable_if<
+        can_query<const Executor&, possibly_t>::value
+      >::type* = 0)
+#if !defined(__clang__) // Clang crashes if noexcept is used here.
+#if defined(ASIO_MSVC) // Visual C++ wants the type to be qualified.
+    ASIO_NOEXCEPT_IF((
+      is_nothrow_query<const Executor&, blocking_t<>::possibly_t>::value))
+#else // defined(ASIO_MSVC)
+    ASIO_NOEXCEPT_IF((
+      is_nothrow_query<const Executor&, possibly_t>::value))
+#endif // defined(ASIO_MSVC)
+#endif // !defined(__clang__)
+  {
+    return asio::query(ex, possibly_t());
+  }
+
+  template <typename Executor>
+  friend ASIO_CONSTEXPR blocking_t query(
+      const Executor& ex, convertible_from_blocking_t,
+      typename enable_if<
+        !can_query<const Executor&, possibly_t>::value
+          && can_query<const Executor&, always_t>::value
+      >::type* = 0)
+#if !defined(__clang__) // Clang crashes if noexcept is used here.
+#if defined(ASIO_MSVC) // Visual C++ wants the type to be qualified.
+    ASIO_NOEXCEPT_IF((
+      is_nothrow_query<const Executor&, blocking_t<>::always_t>::value))
+#else // defined(ASIO_MSVC)
+    ASIO_NOEXCEPT_IF((
+      is_nothrow_query<const Executor&, always_t>::value))
+#endif // defined(ASIO_MSVC)
+#endif // !defined(__clang__)
+  {
+    return asio::query(ex, always_t());
+  }
+
+  template <typename Executor>
+  friend ASIO_CONSTEXPR blocking_t query(
+      const Executor& ex, convertible_from_blocking_t,
+      typename enable_if<
+        !can_query<const Executor&, possibly_t>::value
+          && !can_query<const Executor&, always_t>::value
+          && can_query<const Executor&, never_t>::value
+      >::type* = 0)
+#if !defined(__clang__) // Clang crashes if noexcept is used here.
+#if defined(ASIO_MSVC) // Visual C++ wants the type to be qualified.
+    ASIO_NOEXCEPT_IF((
+      is_nothrow_query<const Executor&, blocking_t<>::never_t>::value))
+#else // defined(ASIO_MSVC)
+    ASIO_NOEXCEPT_IF((
+      is_nothrow_query<const Executor&, never_t>::value))
+#endif // defined(ASIO_MSVC)
+#endif // !defined(__clang__)
+  {
+    return asio::query(ex, never_t());
+  }
+
+  ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(possibly_t, possibly);
+  ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(always_t, always);
+  ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(never_t, never);
+
+#if !defined(ASIO_HAS_CONSTEXPR)
+  static const blocking_t instance;
+#endif // !defined(ASIO_HAS_CONSTEXPR)
+
+private:
+  int value_;
+};
+
+#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \
+  && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+template <int I> template <typename E, typename T>
+const T blocking_t<I>::static_query_v;
+#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)
+       //   && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+
+#if !defined(ASIO_HAS_CONSTEXPR)
+template <int I>
+const blocking_t<I> blocking_t<I>::instance;
+#endif
+
+template <int I>
+const typename blocking_t<I>::possibly_t blocking_t<I>::possibly;
+
+template <int I>
+const typename blocking_t<I>::always_t blocking_t<I>::always;
+
+template <int I>
+const typename blocking_t<I>::never_t blocking_t<I>::never;
+
+namespace blocking {
+
+template <int I = 0>
+struct possibly_t
+{
+#if defined(ASIO_HAS_VARIABLE_TEMPLATES)
+  template <typename T>
+  ASIO_STATIC_CONSTEXPR(bool,
+    is_applicable_property_v = is_executor<T>::value
+      || is_sender<T>::value || is_scheduler<T>::value);
+#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+  ASIO_STATIC_CONSTEXPR(bool, is_requirable = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_preferable = true);
+  typedef blocking_t<I> polymorphic_query_result_type;
+
+  ASIO_CONSTEXPR possibly_t()
+  {
+  }
+
+#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \
+  && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+  template <typename T>
+  static ASIO_CONSTEXPR
+  typename traits::query_static_constexpr_member<T, possibly_t>::result_type
+  static_query()
+    ASIO_NOEXCEPT_IF((
+      traits::query_static_constexpr_member<T, possibly_t>::is_noexcept))
+  {
+    return traits::query_static_constexpr_member<T, possibly_t>::value();
+  }
+
+  template <typename T>
+  static ASIO_CONSTEXPR possibly_t static_query(
+      typename enable_if<
+        !traits::query_static_constexpr_member<T, possibly_t>::is_valid
+          && !traits::query_member<T, possibly_t>::is_valid
+          && !traits::query_free<T, possibly_t>::is_valid
+          && !can_query<T, always_t<I> >::value
+          && !can_query<T, never_t<I> >::value
+      >::type* = 0) ASIO_NOEXCEPT
+  {
+    return possibly_t();
+  }
+
+  template <typename E, typename T = decltype(possibly_t::static_query<E>())>
+  static ASIO_CONSTEXPR const T static_query_v
+    = possibly_t::static_query<E>();
+#endif // defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+       //   && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+
+  static ASIO_CONSTEXPR blocking_t<I> value()
+  {
+    return possibly_t();
+  }
+
+  friend ASIO_CONSTEXPR bool operator==(
+      const possibly_t&, const possibly_t&)
+  {
+    return true;
+  }
+
+  friend ASIO_CONSTEXPR bool operator!=(
+      const possibly_t&, const possibly_t&)
+  {
+    return false;
+  }
+
+  friend ASIO_CONSTEXPR bool operator==(
+      const possibly_t&, const always_t<I>&)
+  {
+    return false;
+  }
+
+  friend ASIO_CONSTEXPR bool operator!=(
+      const possibly_t&, const always_t<I>&)
+  {
+    return true;
+  }
+
+  friend ASIO_CONSTEXPR bool operator==(
+      const possibly_t&, const never_t<I>&)
+  {
+    return false;
+  }
+
+  friend ASIO_CONSTEXPR bool operator!=(
+      const possibly_t&, const never_t<I>&)
+  {
+    return true;
+  }
+};
+
+#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \
+  && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+template <int I> template <typename E, typename T>
+const T possibly_t<I>::static_query_v;
+#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)
+       //   && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+
+template <typename Executor>
+class adapter
+{
+public:
+  adapter(int, const Executor& e) ASIO_NOEXCEPT
+    : executor_(e)
+  {
+  }
+
+  adapter(const adapter& other) ASIO_NOEXCEPT
+    : executor_(other.executor_)
+  {
+  }
+
+#if defined(ASIO_HAS_MOVE)
+  adapter(adapter&& other) ASIO_NOEXCEPT
+    : executor_(ASIO_MOVE_CAST(Executor)(other.executor_))
+  {
+  }
+#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+
+  template <int I>
+  static ASIO_CONSTEXPR always_t<I> query(
+      blocking_t<I>) ASIO_NOEXCEPT
+  {
+    return always_t<I>();
+  }
+
+  template <int I>
+  static ASIO_CONSTEXPR always_t<I> query(
+      possibly_t<I>) ASIO_NOEXCEPT
+  {
+    return always_t<I>();
+  }
+
+  template <int I>
+  static ASIO_CONSTEXPR always_t<I> query(
+      always_t<I>) ASIO_NOEXCEPT
+  {
+    return always_t<I>();
+  }
+
+  template <int I>
+  static ASIO_CONSTEXPR always_t<I> query(
+      never_t<I>) ASIO_NOEXCEPT
+  {
+    return always_t<I>();
+  }
+
+  template <typename Property>
+  typename enable_if<
+    can_query<const Executor&, Property>::value,
+    typename query_result<const Executor&, Property>::type
+  >::type query(const Property& p) const
+    ASIO_NOEXCEPT_IF((
+      is_nothrow_query<const Executor&, Property>::value))
+  {
+    return asio::query(executor_, p);
+  }
+
+  template <int I>
+  typename enable_if<
+    can_require<const Executor&, possibly_t<I> >::value,
+    typename require_result<const Executor&, possibly_t<I> >::type
+  >::type require(possibly_t<I>) const ASIO_NOEXCEPT
+  {
+    return asio::require(executor_, possibly_t<I>());
+  }
+
+  template <int I>
+  typename enable_if<
+    can_require<const Executor&, never_t<I> >::value,
+    typename require_result<const Executor&, never_t<I> >::type
+  >::type require(never_t<I>) const ASIO_NOEXCEPT
+  {
+    return asio::require(executor_, never_t<I>());
+  }
+
+  template <typename Property>
+  typename enable_if<
+    can_require<const Executor&, Property>::value,
+    adapter<typename decay<
+      typename require_result<const Executor&, Property>::type
+    >::type>
+  >::type require(const Property& p) const
+    ASIO_NOEXCEPT_IF((
+      is_nothrow_require<const Executor&, Property>::value))
+  {
+    return adapter<typename decay<
+      typename require_result<const Executor&, Property>::type
+        >::type>(0, asio::require(executor_, p));
+  }
+
+  template <typename Property>
+  typename enable_if<
+    can_prefer<const Executor&, Property>::value,
+    adapter<typename decay<
+      typename prefer_result<const Executor&, Property>::type
+    >::type>
+  >::type prefer(const Property& p) const
+    ASIO_NOEXCEPT_IF((
+      is_nothrow_prefer<const Executor&, Property>::value))
+  {
+    return adapter<typename decay<
+      typename prefer_result<const Executor&, Property>::type
+        >::type>(0, asio::prefer(executor_, p));
+  }
+
+  template <typename Function>
+  typename enable_if<
+    execution::can_execute<const Executor&, Function>::value
+  >::type execute(ASIO_MOVE_ARG(Function) f) const
+  {
+    blocking_adaptation::blocking_execute(
+        executor_, ASIO_MOVE_CAST(Function)(f));
+  }
+
+  friend bool operator==(const adapter& a, const adapter& b) ASIO_NOEXCEPT
+  {
+    return a.executor_ == b.executor_;
+  }
+
+  friend bool operator!=(const adapter& a, const adapter& b) ASIO_NOEXCEPT
+  {
+    return a.executor_ != b.executor_;
+  }
+
+private:
+  Executor executor_;
+};
+
+template <int I = 0>
+struct always_t
+{
+#if defined(ASIO_HAS_VARIABLE_TEMPLATES)
+  template <typename T>
+  ASIO_STATIC_CONSTEXPR(bool,
+    is_applicable_property_v = is_executor<T>::value
+      || is_sender<T>::value || is_scheduler<T>::value);
+#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+  ASIO_STATIC_CONSTEXPR(bool, is_requirable = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_preferable = false);
+  typedef blocking_t<I> polymorphic_query_result_type;
+
+  ASIO_CONSTEXPR always_t()
+  {
+  }
+
+#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \
+  && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+  template <typename T>
+  static ASIO_CONSTEXPR
+  typename traits::query_static_constexpr_member<T, always_t>::result_type
+  static_query()
+    ASIO_NOEXCEPT_IF((
+      traits::query_static_constexpr_member<T, always_t>::is_noexcept))
+  {
+    return traits::query_static_constexpr_member<T, always_t>::value();
+  }
+
+  template <typename E, typename T = decltype(always_t::static_query<E>())>
+  static ASIO_CONSTEXPR const T static_query_v
+    = always_t::static_query<E>();
+#endif // defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+       //   && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+
+  static ASIO_CONSTEXPR blocking_t<I> value()
+  {
+    return always_t();
+  }
+
+  friend ASIO_CONSTEXPR bool operator==(
+      const always_t&, const always_t&)
+  {
+    return true;
+  }
+
+  friend ASIO_CONSTEXPR bool operator!=(
+      const always_t&, const always_t&)
+  {
+    return false;
+  }
+
+  friend ASIO_CONSTEXPR bool operator==(
+      const always_t&, const possibly_t<I>&)
+  {
+    return false;
+  }
+
+  friend ASIO_CONSTEXPR bool operator!=(
+      const always_t&, const possibly_t<I>&)
+  {
+    return true;
+  }
+
+  friend ASIO_CONSTEXPR bool operator==(
+      const always_t&, const never_t<I>&)
+  {
+    return false;
+  }
+
+  friend ASIO_CONSTEXPR bool operator!=(
+      const always_t&, const never_t<I>&)
+  {
+    return true;
+  }
+
+  template <typename Executor>
+  friend adapter<Executor> require(
+      const Executor& e, const always_t&,
+      typename enable_if<
+        is_executor<Executor>::value
+        && traits::static_require<
+          const Executor&,
+          blocking_adaptation::allowed_t<0>
+        >::is_valid
+      >::type* = 0)
+  {
+    return adapter<Executor>(0, e);
+  }
+};
+
+#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \
+  && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+template <int I> template <typename E, typename T>
+const T always_t<I>::static_query_v;
+#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)
+       //   && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+
+template <int I>
+struct never_t
+{
+#if defined(ASIO_HAS_VARIABLE_TEMPLATES)
+  template <typename T>
+  ASIO_STATIC_CONSTEXPR(bool,
+    is_applicable_property_v = is_executor<T>::value
+      || is_sender<T>::value || is_scheduler<T>::value);
+#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+  ASIO_STATIC_CONSTEXPR(bool, is_requirable = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_preferable = true);
+  typedef blocking_t<I> polymorphic_query_result_type;
+
+  ASIO_CONSTEXPR never_t()
+  {
+  }
+
+#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \
+  && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+  template <typename T>
+  static ASIO_CONSTEXPR
+  typename traits::query_static_constexpr_member<T, never_t>::result_type
+  static_query()
+    ASIO_NOEXCEPT_IF((
+      traits::query_static_constexpr_member<T, never_t>::is_noexcept))
+  {
+    return traits::query_static_constexpr_member<T, never_t>::value();
+  }
+
+  template <typename E, typename T = decltype(never_t::static_query<E>())>
+  static ASIO_CONSTEXPR const T static_query_v
+    = never_t::static_query<E>();
+#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)
+       //   && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+
+  static ASIO_CONSTEXPR blocking_t<I> value()
+  {
+    return never_t();
+  }
+
+  friend ASIO_CONSTEXPR bool operator==(
+      const never_t&, const never_t&)
+  {
+    return true;
+  }
+
+  friend ASIO_CONSTEXPR bool operator!=(
+      const never_t&, const never_t&)
+  {
+    return false;
+  }
+
+  friend ASIO_CONSTEXPR bool operator==(
+      const never_t&, const possibly_t<I>&)
+  {
+    return false;
+  }
+
+  friend ASIO_CONSTEXPR bool operator!=(
+      const never_t&, const possibly_t<I>&)
+  {
+    return true;
+  }
+
+  friend ASIO_CONSTEXPR bool operator==(
+      const never_t&, const always_t<I>&)
+  {
+    return false;
+  }
+
+  friend ASIO_CONSTEXPR bool operator!=(
+      const never_t&, const always_t<I>&)
+  {
+    return true;
+  }
+};
+
+#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \
+  && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+template <int I> template <typename E, typename T>
+const T never_t<I>::static_query_v;
+#endif // defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+
+} // namespace blocking
+} // namespace detail
+
+typedef detail::blocking_t<> blocking_t;
+
+#if defined(ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION)
+constexpr blocking_t blocking;
+#else // defined(ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION)
+namespace { static const blocking_t& blocking = blocking_t::instance; }
+#endif
+
+} // namespace execution
+
+#if !defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+template <typename T>
+struct is_applicable_property<T, execution::blocking_t>
+  : integral_constant<bool,
+      execution::is_executor<T>::value
+        || execution::is_sender<T>::value
+        || execution::is_scheduler<T>::value>
+{
+};
+
+template <typename T>
+struct is_applicable_property<T, execution::blocking_t::possibly_t>
+  : integral_constant<bool,
+      execution::is_executor<T>::value
+        || execution::is_sender<T>::value
+        || execution::is_scheduler<T>::value>
+{
+};
+
+template <typename T>
+struct is_applicable_property<T, execution::blocking_t::always_t>
+  : integral_constant<bool,
+      execution::is_executor<T>::value
+        || execution::is_sender<T>::value
+        || execution::is_scheduler<T>::value>
+{
+};
+
+template <typename T>
+struct is_applicable_property<T, execution::blocking_t::never_t>
+  : integral_constant<bool,
+      execution::is_executor<T>::value
+        || execution::is_sender<T>::value
+        || execution::is_scheduler<T>::value>
+{
+};
+
+#endif // !defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+namespace traits {
+
+#if !defined(ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT)
+
+template <typename T>
+struct query_free_default<T, execution::blocking_t,
+  typename enable_if<
+    can_query<T, execution::blocking_t::possibly_t>::value
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept =
+    (is_nothrow_query<T, execution::blocking_t::possibly_t>::value));
+
+  typedef execution::blocking_t result_type;
+};
+
+template <typename T>
+struct query_free_default<T, execution::blocking_t,
+  typename enable_if<
+    !can_query<T, execution::blocking_t::possibly_t>::value
+      && can_query<T, execution::blocking_t::always_t>::value
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept =
+    (is_nothrow_query<T, execution::blocking_t::always_t>::value));
+
+  typedef execution::blocking_t result_type;
+};
+
+template <typename T>
+struct query_free_default<T, execution::blocking_t,
+  typename enable_if<
+    !can_query<T, execution::blocking_t::possibly_t>::value
+      && !can_query<T, execution::blocking_t::always_t>::value
+      && can_query<T, execution::blocking_t::never_t>::value
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept =
+    (is_nothrow_query<T, execution::blocking_t::never_t>::value));
+
+  typedef execution::blocking_t result_type;
+};
+
+#endif // !defined(ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT)
+
+#if !defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \
+  || !defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+
+template <typename T>
+struct static_query<T, execution::blocking_t,
+  typename enable_if<
+    traits::query_static_constexpr_member<T,
+      execution::blocking_t>::is_valid
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
+
+  typedef typename traits::query_static_constexpr_member<T,
+    execution::blocking_t>::result_type result_type;
+
+  static ASIO_CONSTEXPR result_type value()
+  {
+    return traits::query_static_constexpr_member<T,
+      execution::blocking_t>::value();
+  }
+};
+
+template <typename T>
+struct static_query<T, execution::blocking_t,
+  typename enable_if<
+    !traits::query_static_constexpr_member<T, execution::blocking_t>::is_valid
+      && !traits::query_member<T, execution::blocking_t>::is_valid
+      && traits::static_query<T, execution::blocking_t::possibly_t>::is_valid
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
+
+  typedef typename traits::static_query<T,
+    execution::blocking_t::possibly_t>::result_type result_type;
+
+  static ASIO_CONSTEXPR result_type value()
+  {
+    return traits::static_query<T, execution::blocking_t::possibly_t>::value();
+  }
+};
+
+template <typename T>
+struct static_query<T, execution::blocking_t,
+  typename enable_if<
+    !traits::query_static_constexpr_member<T, execution::blocking_t>::is_valid
+      && !traits::query_member<T, execution::blocking_t>::is_valid
+      && !traits::static_query<T, execution::blocking_t::possibly_t>::is_valid
+      && traits::static_query<T, execution::blocking_t::always_t>::is_valid
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
+
+  typedef typename traits::static_query<T,
+    execution::blocking_t::always_t>::result_type result_type;
+
+  static ASIO_CONSTEXPR result_type value()
+  {
+    return traits::static_query<T, execution::blocking_t::always_t>::value();
+  }
+};
+
+template <typename T>
+struct static_query<T, execution::blocking_t,
+  typename enable_if<
+    !traits::query_static_constexpr_member<T, execution::blocking_t>::is_valid
+      && !traits::query_member<T, execution::blocking_t>::is_valid
+      && !traits::static_query<T, execution::blocking_t::possibly_t>::is_valid
+      && !traits::static_query<T, execution::blocking_t::always_t>::is_valid
+      && traits::static_query<T, execution::blocking_t::never_t>::is_valid
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
+
+  typedef typename traits::static_query<T,
+    execution::blocking_t::never_t>::result_type result_type;
+
+  static ASIO_CONSTEXPR result_type value()
+  {
+    return traits::static_query<T, execution::blocking_t::never_t>::value();
+  }
+};
+
+template <typename T>
+struct static_query<T, execution::blocking_t::possibly_t,
+  typename enable_if<
+    traits::query_static_constexpr_member<T,
+      execution::blocking_t::possibly_t>::is_valid
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
+
+  typedef typename traits::query_static_constexpr_member<T,
+    execution::blocking_t::possibly_t>::result_type result_type;
+
+  static ASIO_CONSTEXPR result_type value()
+  {
+    return traits::query_static_constexpr_member<T,
+      execution::blocking_t::possibly_t>::value();
+  }
+};
+
+template <typename T>
+struct static_query<T, execution::blocking_t::possibly_t,
+  typename enable_if<
+    !traits::query_static_constexpr_member<T,
+      execution::blocking_t::possibly_t>::is_valid
+      && !traits::query_member<T, execution::blocking_t::possibly_t>::is_valid
+      && !traits::query_free<T, execution::blocking_t::possibly_t>::is_valid
+      && !can_query<T, execution::blocking_t::always_t>::value
+      && !can_query<T, execution::blocking_t::never_t>::value
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
+
+  typedef execution::blocking_t::possibly_t result_type;
+
+  static ASIO_CONSTEXPR result_type value()
+  {
+    return result_type();
+  }
+};
+
+template <typename T>
+struct static_query<T, execution::blocking_t::always_t,
+  typename enable_if<
+    traits::query_static_constexpr_member<T,
+      execution::blocking_t::always_t>::is_valid
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
+
+  typedef typename traits::query_static_constexpr_member<T,
+    execution::blocking_t::always_t>::result_type result_type;
+
+  static ASIO_CONSTEXPR result_type value()
+  {
+    return traits::query_static_constexpr_member<T,
+      execution::blocking_t::always_t>::value();
+  }
+};
+
+template <typename T>
+struct static_query<T, execution::blocking_t::never_t,
+  typename enable_if<
+    traits::query_static_constexpr_member<T,
+      execution::blocking_t::never_t>::is_valid
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
+
+  typedef typename traits::query_static_constexpr_member<T,
+    execution::blocking_t::never_t>::result_type result_type;
+
+  static ASIO_CONSTEXPR result_type value()
+  {
+    return traits::query_static_constexpr_member<T,
+      execution::blocking_t::never_t>::value();
+  }
+};
+
+#endif // !defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)
+       //   || !defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+
+#if !defined(ASIO_HAS_DEDUCED_STATIC_REQUIRE_TRAIT)
+
+template <typename T>
+struct static_require<T, execution::blocking_t::possibly_t,
+  typename enable_if<
+    static_query<T, execution::blocking_t::possibly_t>::is_valid
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid =
+    (is_same<typename static_query<T,
+      execution::blocking_t::possibly_t>::result_type,
+        execution::blocking_t::possibly_t>::value));
+};
+
+template <typename T>
+struct static_require<T, execution::blocking_t::always_t,
+  typename enable_if<
+    static_query<T, execution::blocking_t::always_t>::is_valid
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid =
+    (is_same<typename static_query<T,
+      execution::blocking_t::always_t>::result_type,
+        execution::blocking_t::always_t>::value));
+};
+
+template <typename T>
+struct static_require<T, execution::blocking_t::never_t,
+  typename enable_if<
+    static_query<T, execution::blocking_t::never_t>::is_valid
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid =
+    (is_same<typename static_query<T,
+      execution::blocking_t::never_t>::result_type,
+        execution::blocking_t::never_t>::value));
+};
+
+#endif // !defined(ASIO_HAS_DEDUCED_STATIC_REQUIRE_TRAIT)
+
+#if !defined(ASIO_HAS_DEDUCED_REQUIRE_FREE_TRAIT)
+
+template <typename T>
+struct require_free_default<T, execution::blocking_t::always_t,
+  typename enable_if<
+    is_same<T, typename decay<T>::type>::value
+      && execution::is_executor<T>::value
+      && traits::static_require<
+          const T&,
+          execution::detail::blocking_adaptation::allowed_t<0>
+        >::is_valid
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
+  typedef execution::detail::blocking::adapter<T> result_type;
+};
+
+#endif // !defined(ASIO_HAS_DEDUCED_REQUIRE_FREE_TRAIT)
+
+#if !defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)
+
+template <typename Executor>
+struct equality_comparable<
+  execution::detail::blocking::adapter<Executor> >
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
+};
+
+#endif // !defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)
+
+#if !defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)
+
+template <typename Executor, typename Function>
+struct execute_member<
+  execution::detail::blocking::adapter<Executor>, Function>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
+  typedef void result_type;
+};
+
+#endif // !defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)
+
+#if !defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT)
+
+template <typename Executor, int I>
+struct query_static_constexpr_member<
+  execution::detail::blocking::adapter<Executor>,
+  execution::detail::blocking_t<I> >
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
+  typedef execution::blocking_t::always_t result_type;
+
+  static ASIO_CONSTEXPR result_type value() ASIO_NOEXCEPT
+  {
+    return result_type();
+  }
+};
+
+template <typename Executor, int I>
+struct query_static_constexpr_member<
+  execution::detail::blocking::adapter<Executor>,
+  execution::detail::blocking::always_t<I> >
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
+  typedef execution::blocking_t::always_t result_type;
+
+  static ASIO_CONSTEXPR result_type value() ASIO_NOEXCEPT
+  {
+    return result_type();
+  }
+};
+
+template <typename Executor, int I>
+struct query_static_constexpr_member<
+  execution::detail::blocking::adapter<Executor>,
+  execution::detail::blocking::possibly_t<I> >
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
+  typedef execution::blocking_t::always_t result_type;
+
+  static ASIO_CONSTEXPR result_type value() ASIO_NOEXCEPT
+  {
+    return result_type();
+  }
+};
+
+template <typename Executor, int I>
+struct query_static_constexpr_member<
+  execution::detail::blocking::adapter<Executor>,
+  execution::detail::blocking::never_t<I> >
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
+  typedef execution::blocking_t::always_t result_type;
+
+  static ASIO_CONSTEXPR result_type value() ASIO_NOEXCEPT
+  {
+    return result_type();
+  }
+};
+
+#endif // !defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT)
+
+#if !defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT)
+
+template <typename Executor, typename Property>
+struct query_member<
+  execution::detail::blocking::adapter<Executor>, Property,
+  typename enable_if<
+    can_query<const Executor&, Property>::value
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept =
+      (is_nothrow_query<Executor, Property>::value));
+  typedef typename query_result<Executor, Property>::type result_type;
+};
+
+#endif // !defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT)
+
+#if !defined(ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT)
+
+template <typename Executor, int I>
+struct require_member<
+  execution::detail::blocking::adapter<Executor>,
+  execution::detail::blocking::possibly_t<I>,
+  typename enable_if<
+    can_require<
+      const Executor&,
+      execution::detail::blocking::possibly_t<I>
+    >::value
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept =
+      (is_nothrow_require<const Executor&,
+        execution::detail::blocking::possibly_t<I> >::value));
+  typedef typename require_result<const Executor&,
+    execution::detail::blocking::possibly_t<I> >::type result_type;
+};
+
+template <typename Executor, int I>
+struct require_member<
+  execution::detail::blocking::adapter<Executor>,
+  execution::detail::blocking::never_t<I>,
+  typename enable_if<
+    can_require<
+      const Executor&,
+      execution::detail::blocking::never_t<I>
+    >::value
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept =
+      (is_nothrow_require<const Executor&,
+        execution::detail::blocking::never_t<I> >::value));
+  typedef typename require_result<const Executor&,
+    execution::detail::blocking::never_t<I> >::type result_type;
+};
+
+template <typename Executor, typename Property>
+struct require_member<
+  execution::detail::blocking::adapter<Executor>, Property,
+  typename enable_if<
+    can_require<const Executor&, Property>::value
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept =
+      (is_nothrow_require<Executor, Property>::value));
+  typedef execution::detail::blocking::adapter<typename decay<
+    typename require_result<Executor, Property>::type
+      >::type> result_type;
+};
+
+#endif // !defined(ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT)
+
+#if !defined(ASIO_HAS_DEDUCED_PREFER_MEMBER_TRAIT)
+
+template <typename Executor, typename Property>
+struct prefer_member<
+  execution::detail::blocking::adapter<Executor>, Property,
+  typename enable_if<
+    can_prefer<const Executor&, Property>::value
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept =
+      (is_nothrow_prefer<Executor, Property>::value));
+  typedef execution::detail::blocking::adapter<typename decay<
+    typename prefer_result<Executor, Property>::type
+      >::type> result_type;
+};
+
+#endif // !defined(ASIO_HAS_DEDUCED_PREFER_MEMBER_TRAIT)
+
+} // namespace traits
+
+#endif // defined(GENERATING_DOCUMENTATION)
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_EXECUTION_BLOCKING_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/execution/blocking_adaptation.hpp b/link/modules/asio-standalone/asio/include/asio/execution/blocking_adaptation.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/execution/blocking_adaptation.hpp
@@ -0,0 +1,1064 @@
+//
+// execution/blocking_adaptation.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_EXECUTION_BLOCKING_ADAPTATION_HPP
+#define ASIO_EXECUTION_BLOCKING_ADAPTATION_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/event.hpp"
+#include "asio/detail/mutex.hpp"
+#include "asio/detail/type_traits.hpp"
+#include "asio/execution/execute.hpp"
+#include "asio/execution/executor.hpp"
+#include "asio/execution/scheduler.hpp"
+#include "asio/execution/sender.hpp"
+#include "asio/is_applicable_property.hpp"
+#include "asio/prefer.hpp"
+#include "asio/query.hpp"
+#include "asio/require.hpp"
+#include "asio/traits/prefer_member.hpp"
+#include "asio/traits/query_free.hpp"
+#include "asio/traits/query_member.hpp"
+#include "asio/traits/query_static_constexpr_member.hpp"
+#include "asio/traits/require_member.hpp"
+#include "asio/traits/static_query.hpp"
+#include "asio/traits/static_require.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+#if defined(GENERATING_DOCUMENTATION)
+
+namespace execution {
+
+/// A property to describe whether automatic adaptation of an executor is
+/// allowed in order to apply the blocking_adaptation_t::allowed_t property.
+struct blocking_adaptation_t
+{
+  /// The blocking_adaptation_t property applies to executors, senders, and
+  /// schedulers.
+  template <typename T>
+  static constexpr bool is_applicable_property_v =
+    is_executor_v<T> || is_sender_v<T> || is_scheduler_v<T>;
+
+  /// The top-level blocking_adaptation_t property cannot be required.
+  static constexpr bool is_requirable = false;
+
+  /// The top-level blocking_adaptation_t property cannot be preferred.
+  static constexpr bool is_preferable = false;
+
+  /// The type returned by queries against an @c any_executor.
+  typedef blocking_adaptation_t polymorphic_query_result_type;
+
+  /// A sub-property that indicates that automatic adaptation is not allowed.
+  struct disallowed_t
+  {
+    /// The blocking_adaptation_t::disallowed_t property applies to executors,
+    /// senders, and schedulers.
+    template <typename T>
+    static constexpr bool is_applicable_property_v =
+      is_executor_v<T> || is_sender_v<T> || is_scheduler_v<T>;
+
+    /// The blocking_adaptation_t::disallowed_t property can be required.
+    static constexpr bool is_requirable = true;
+
+    /// The blocking_adaptation_t::disallowed_t property can be preferred.
+    static constexpr bool is_preferable = true;
+
+    /// The type returned by queries against an @c any_executor.
+    typedef blocking_adaptation_t polymorphic_query_result_type;
+
+    /// Default constructor.
+    constexpr disallowed_t();
+
+    /// Get the value associated with a property object.
+    /**
+     * @returns disallowed_t();
+     */
+    static constexpr blocking_adaptation_t value();
+  };
+
+  /// A sub-property that indicates that automatic adaptation is allowed.
+  struct allowed_t
+  {
+    /// The blocking_adaptation_t::allowed_t property applies to executors,
+    /// senders, and schedulers.
+    template <typename T>
+    static constexpr bool is_applicable_property_v =
+      is_executor_v<T> || is_sender_v<T> || is_scheduler_v<T>;
+
+    /// The blocking_adaptation_t::allowed_t property can be required.
+    static constexpr bool is_requirable = true;
+
+    /// The blocking_adaptation_t::allowed_t property can be preferred.
+    static constexpr bool is_preferable = false;
+
+    /// The type returned by queries against an @c any_executor.
+    typedef blocking_adaptation_t polymorphic_query_result_type;
+
+    /// Default constructor.
+    constexpr allowed_t();
+
+    /// Get the value associated with a property object.
+    /**
+     * @returns allowed_t();
+     */
+    static constexpr blocking_adaptation_t value();
+  };
+
+  /// A special value used for accessing the blocking_adaptation_t::disallowed_t
+  /// property.
+  static constexpr disallowed_t disallowed;
+
+  /// A special value used for accessing the blocking_adaptation_t::allowed_t
+  /// property.
+  static constexpr allowed_t allowed;
+
+  /// Default constructor.
+  constexpr blocking_adaptation_t();
+
+  /// Construct from a sub-property value.
+  constexpr blocking_adaptation_t(disallowed_t);
+
+  /// Construct from a sub-property value.
+  constexpr blocking_adaptation_t(allowed_t);
+
+  /// Compare property values for equality.
+  friend constexpr bool operator==(
+      const blocking_adaptation_t& a, const blocking_adaptation_t& b) noexcept;
+
+  /// Compare property values for inequality.
+  friend constexpr bool operator!=(
+      const blocking_adaptation_t& a, const blocking_adaptation_t& b) noexcept;
+};
+
+/// A special value used for accessing the blocking_adaptation_t property.
+constexpr blocking_adaptation_t blocking_adaptation;
+
+} // namespace execution
+
+#else // defined(GENERATING_DOCUMENTATION)
+
+namespace execution {
+namespace detail {
+namespace blocking_adaptation {
+
+template <int I> struct disallowed_t;
+template <int I> struct allowed_t;
+
+} // namespace blocking_adaptation
+
+template <int I = 0>
+struct blocking_adaptation_t
+{
+#if defined(ASIO_HAS_VARIABLE_TEMPLATES)
+  template <typename T>
+  ASIO_STATIC_CONSTEXPR(bool,
+    is_applicable_property_v = is_executor<T>::value
+      || is_sender<T>::value || is_scheduler<T>::value);
+#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+  ASIO_STATIC_CONSTEXPR(bool, is_requirable = false);
+  ASIO_STATIC_CONSTEXPR(bool, is_preferable = false);
+  typedef blocking_adaptation_t polymorphic_query_result_type;
+
+  typedef detail::blocking_adaptation::disallowed_t<I> disallowed_t;
+  typedef detail::blocking_adaptation::allowed_t<I> allowed_t;
+
+  ASIO_CONSTEXPR blocking_adaptation_t()
+    : value_(-1)
+  {
+  }
+
+  ASIO_CONSTEXPR blocking_adaptation_t(disallowed_t)
+    : value_(0)
+  {
+  }
+
+  ASIO_CONSTEXPR blocking_adaptation_t(allowed_t)
+    : value_(1)
+  {
+  }
+
+#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \
+  && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+  template <typename T>
+  static ASIO_CONSTEXPR
+  typename traits::query_static_constexpr_member<
+      T, blocking_adaptation_t>::result_type
+  static_query()
+    ASIO_NOEXCEPT_IF((
+      traits::query_static_constexpr_member<
+        T, blocking_adaptation_t
+      >::is_noexcept))
+  {
+    return traits::query_static_constexpr_member<
+        T, blocking_adaptation_t>::value();
+  }
+
+  template <typename T>
+  static ASIO_CONSTEXPR
+  typename traits::static_query<T, disallowed_t>::result_type
+  static_query(
+      typename enable_if<
+        !traits::query_static_constexpr_member<
+            T, blocking_adaptation_t>::is_valid
+          && !traits::query_member<T, blocking_adaptation_t>::is_valid
+          && traits::static_query<T, disallowed_t>::is_valid
+      >::type* = 0) ASIO_NOEXCEPT
+  {
+    return traits::static_query<T, disallowed_t>::value();
+  }
+
+  template <typename T>
+  static ASIO_CONSTEXPR
+  typename traits::static_query<T, allowed_t>::result_type
+  static_query(
+      typename enable_if<
+        !traits::query_static_constexpr_member<
+            T, blocking_adaptation_t>::is_valid
+          && !traits::query_member<T, blocking_adaptation_t>::is_valid
+          && !traits::static_query<T, disallowed_t>::is_valid
+          && traits::static_query<T, allowed_t>::is_valid
+      >::type* = 0) ASIO_NOEXCEPT
+  {
+    return traits::static_query<T, allowed_t>::value();
+  }
+
+  template <typename E,
+      typename T = decltype(blocking_adaptation_t::static_query<E>())>
+  static ASIO_CONSTEXPR const T static_query_v
+    = blocking_adaptation_t::static_query<E>();
+#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)
+       //   && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+
+  friend ASIO_CONSTEXPR bool operator==(
+      const blocking_adaptation_t& a, const blocking_adaptation_t& b)
+  {
+    return a.value_ == b.value_;
+  }
+
+  friend ASIO_CONSTEXPR bool operator!=(
+      const blocking_adaptation_t& a, const blocking_adaptation_t& b)
+  {
+    return a.value_ != b.value_;
+  }
+
+  struct convertible_from_blocking_adaptation_t
+  {
+    ASIO_CONSTEXPR convertible_from_blocking_adaptation_t(
+        blocking_adaptation_t)
+    {
+    }
+  };
+
+  template <typename Executor>
+  friend ASIO_CONSTEXPR blocking_adaptation_t query(
+      const Executor& ex, convertible_from_blocking_adaptation_t,
+      typename enable_if<
+        can_query<const Executor&, disallowed_t>::value
+      >::type* = 0)
+#if !defined(__clang__) // Clang crashes if noexcept is used here.
+#if defined(ASIO_MSVC) // Visual C++ wants the type to be qualified.
+    ASIO_NOEXCEPT_IF((
+      is_nothrow_query<const Executor&,
+        blocking_adaptation_t<>::disallowed_t>::value))
+#else // defined(ASIO_MSVC)
+    ASIO_NOEXCEPT_IF((
+      is_nothrow_query<const Executor&, disallowed_t>::value))
+#endif // defined(ASIO_MSVC)
+#endif // !defined(__clang__)
+  {
+    return asio::query(ex, disallowed_t());
+  }
+
+  template <typename Executor>
+  friend ASIO_CONSTEXPR blocking_adaptation_t query(
+      const Executor& ex, convertible_from_blocking_adaptation_t,
+      typename enable_if<
+        !can_query<const Executor&, disallowed_t>::value
+          && can_query<const Executor&, allowed_t>::value
+      >::type* = 0)
+#if !defined(__clang__) // Clang crashes if noexcept is used here.
+#if defined(ASIO_MSVC) // Visual C++ wants the type to be qualified.
+    ASIO_NOEXCEPT_IF((
+      is_nothrow_query<const Executor&,
+        blocking_adaptation_t<>::allowed_t>::value))
+#else // defined(ASIO_MSVC)
+    ASIO_NOEXCEPT_IF((
+      is_nothrow_query<const Executor&, allowed_t>::value))
+#endif // defined(ASIO_MSVC)
+#endif // !defined(__clang__)
+  {
+    return asio::query(ex, allowed_t());
+  }
+
+  ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(disallowed_t, disallowed);
+  ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(allowed_t, allowed);
+
+#if !defined(ASIO_HAS_CONSTEXPR)
+  static const blocking_adaptation_t instance;
+#endif // !defined(ASIO_HAS_CONSTEXPR)
+
+private:
+  int value_;
+};
+
+#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \
+  && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+template <int I> template <typename E, typename T>
+const T blocking_adaptation_t<I>::static_query_v;
+#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)
+       //   && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+
+#if !defined(ASIO_HAS_CONSTEXPR)
+template <int I>
+const blocking_adaptation_t<I> blocking_adaptation_t<I>::instance;
+#endif
+
+template <int I>
+const typename blocking_adaptation_t<I>::disallowed_t
+blocking_adaptation_t<I>::disallowed;
+
+template <int I>
+const typename blocking_adaptation_t<I>::allowed_t
+blocking_adaptation_t<I>::allowed;
+
+namespace blocking_adaptation {
+
+template <int I = 0>
+struct disallowed_t
+{
+#if defined(ASIO_HAS_VARIABLE_TEMPLATES)
+  template <typename T>
+  ASIO_STATIC_CONSTEXPR(bool,
+    is_applicable_property_v = is_executor<T>::value
+      || is_sender<T>::value || is_scheduler<T>::value);
+#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+  ASIO_STATIC_CONSTEXPR(bool, is_requirable = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_preferable = true);
+  typedef blocking_adaptation_t<I> polymorphic_query_result_type;
+
+  ASIO_CONSTEXPR disallowed_t()
+  {
+  }
+
+#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \
+  && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+  template <typename T>
+  static ASIO_CONSTEXPR
+  typename traits::query_static_constexpr_member<T, disallowed_t>::result_type
+  static_query()
+    ASIO_NOEXCEPT_IF((
+      traits::query_static_constexpr_member<T, disallowed_t>::is_noexcept))
+  {
+    return traits::query_static_constexpr_member<T, disallowed_t>::value();
+  }
+
+  template <typename T>
+  static ASIO_CONSTEXPR disallowed_t static_query(
+      typename enable_if<
+        !traits::query_static_constexpr_member<T, disallowed_t>::is_valid
+          && !traits::query_member<T, disallowed_t>::is_valid
+          && !traits::query_free<T, disallowed_t>::is_valid
+          && !can_query<T, allowed_t<I> >::value
+      >::type* = 0) ASIO_NOEXCEPT
+  {
+    return disallowed_t();
+  }
+
+  template <typename E, typename T = decltype(disallowed_t::static_query<E>())>
+  static ASIO_CONSTEXPR const T static_query_v
+    = disallowed_t::static_query<E>();
+#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)
+       //   && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+
+  static ASIO_CONSTEXPR blocking_adaptation_t<I> value()
+  {
+    return disallowed_t();
+  }
+
+  friend ASIO_CONSTEXPR bool operator==(
+      const disallowed_t&, const disallowed_t&)
+  {
+    return true;
+  }
+
+  friend ASIO_CONSTEXPR bool operator!=(
+      const disallowed_t&, const disallowed_t&)
+  {
+    return false;
+  }
+};
+
+#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \
+  && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+template <int I> template <typename E, typename T>
+const T disallowed_t<I>::static_query_v;
+#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)
+       //   && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+
+template <typename Executor>
+class adapter
+{
+public:
+  adapter(int, const Executor& e) ASIO_NOEXCEPT
+    : executor_(e)
+  {
+  }
+
+  adapter(const adapter& other) ASIO_NOEXCEPT
+    : executor_(other.executor_)
+  {
+  }
+
+#if defined(ASIO_HAS_MOVE)
+  adapter(adapter&& other) ASIO_NOEXCEPT
+    : executor_(ASIO_MOVE_CAST(Executor)(other.executor_))
+  {
+  }
+#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+
+  template <int I>
+  static ASIO_CONSTEXPR allowed_t<I> query(
+      blocking_adaptation_t<I>) ASIO_NOEXCEPT
+  {
+    return allowed_t<I>();
+  }
+
+  template <int I>
+  static ASIO_CONSTEXPR allowed_t<I> query(
+      allowed_t<I>) ASIO_NOEXCEPT
+  {
+    return allowed_t<I>();
+  }
+
+  template <int I>
+  static ASIO_CONSTEXPR allowed_t<I> query(
+      disallowed_t<I>) ASIO_NOEXCEPT
+  {
+    return allowed_t<I>();
+  }
+
+  template <typename Property>
+  typename enable_if<
+    can_query<const Executor&, Property>::value,
+    typename query_result<const Executor&, Property>::type
+  >::type query(const Property& p) const
+    ASIO_NOEXCEPT_IF((
+      is_nothrow_query<const Executor&, Property>::value))
+  {
+    return asio::query(executor_, p);
+  }
+
+  template <int I>
+  Executor require(disallowed_t<I>) const ASIO_NOEXCEPT
+  {
+    return executor_;
+  }
+
+  template <typename Property>
+  typename enable_if<
+    can_require<const Executor&, Property>::value,
+    adapter<typename decay<
+      typename require_result<const Executor&, Property>::type
+    >::type>
+  >::type require(const Property& p) const
+    ASIO_NOEXCEPT_IF((
+      is_nothrow_require<const Executor&, Property>::value))
+  {
+    return adapter<typename decay<
+      typename require_result<const Executor&, Property>::type
+        >::type>(0, asio::require(executor_, p));
+  }
+
+  template <typename Property>
+  typename enable_if<
+    can_prefer<const Executor&, Property>::value,
+    adapter<typename decay<
+      typename prefer_result<const Executor&, Property>::type
+    >::type>
+  >::type prefer(const Property& p) const
+    ASIO_NOEXCEPT_IF((
+      is_nothrow_prefer<const Executor&, Property>::value))
+  {
+    return adapter<typename decay<
+      typename prefer_result<const Executor&, Property>::type
+        >::type>(0, asio::prefer(executor_, p));
+  }
+
+  template <typename Function>
+  typename enable_if<
+    execution::can_execute<const Executor&, Function>::value
+  >::type execute(ASIO_MOVE_ARG(Function) f) const
+  {
+    execution::execute(executor_, ASIO_MOVE_CAST(Function)(f));
+  }
+
+  friend bool operator==(const adapter& a, const adapter& b) ASIO_NOEXCEPT
+  {
+    return a.executor_ == b.executor_;
+  }
+
+  friend bool operator!=(const adapter& a, const adapter& b) ASIO_NOEXCEPT
+  {
+    return a.executor_ != b.executor_;
+  }
+
+private:
+  Executor executor_;
+};
+
+template <int I = 0>
+struct allowed_t
+{
+#if defined(ASIO_HAS_VARIABLE_TEMPLATES)
+  template <typename T>
+  ASIO_STATIC_CONSTEXPR(bool,
+    is_applicable_property_v = is_executor<T>::value
+      || is_sender<T>::value || is_scheduler<T>::value);
+#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+  ASIO_STATIC_CONSTEXPR(bool, is_requirable = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_preferable = false);
+  typedef blocking_adaptation_t<I> polymorphic_query_result_type;
+
+  ASIO_CONSTEXPR allowed_t()
+  {
+  }
+
+#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \
+  && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+  template <typename T>
+  static ASIO_CONSTEXPR
+  typename traits::query_static_constexpr_member<T, allowed_t>::result_type
+  static_query()
+    ASIO_NOEXCEPT_IF((
+      traits::query_static_constexpr_member<T, allowed_t>::is_noexcept))
+  {
+    return traits::query_static_constexpr_member<T, allowed_t>::value();
+  }
+
+  template <typename E, typename T = decltype(allowed_t::static_query<E>())>
+  static ASIO_CONSTEXPR const T static_query_v
+    = allowed_t::static_query<E>();
+#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)
+       //   && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+
+  static ASIO_CONSTEXPR blocking_adaptation_t<I> value()
+  {
+    return allowed_t();
+  }
+
+  friend ASIO_CONSTEXPR bool operator==(
+      const allowed_t&, const allowed_t&)
+  {
+    return true;
+  }
+
+  friend ASIO_CONSTEXPR bool operator!=(
+      const allowed_t&, const allowed_t&)
+  {
+    return false;
+  }
+
+  template <typename Executor>
+  friend adapter<Executor> require(
+      const Executor& e, const allowed_t&,
+      typename enable_if<
+        is_executor<Executor>::value
+      >::type* = 0)
+  {
+    return adapter<Executor>(0, e);
+  }
+};
+
+#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \
+  && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+template <int I> template <typename E, typename T>
+const T allowed_t<I>::static_query_v;
+#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)
+       //   && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+
+template <typename Function>
+class blocking_execute_state
+{
+public:
+  template <typename F>
+  blocking_execute_state(ASIO_MOVE_ARG(F) f)
+    : func_(ASIO_MOVE_CAST(F)(f)),
+      is_complete_(false)
+  {
+  }
+
+  template <typename Executor>
+  void execute_and_wait(ASIO_MOVE_ARG(Executor) ex)
+  {
+    handler h = { this };
+    execution::execute(ASIO_MOVE_CAST(Executor)(ex), h);
+    asio::detail::mutex::scoped_lock lock(mutex_);
+    while (!is_complete_)
+      event_.wait(lock);
+  }
+
+  struct cleanup
+  {
+    ~cleanup()
+    {
+      asio::detail::mutex::scoped_lock lock(state_->mutex_);
+      state_->is_complete_ = true;
+      state_->event_.unlock_and_signal_one_for_destruction(lock);
+    }
+
+    blocking_execute_state* state_;
+  };
+
+  struct handler
+  {
+    void operator()()
+    {
+      cleanup c = { state_ };
+      state_->func_();
+    }
+
+    blocking_execute_state* state_;
+  };
+
+  Function func_;
+  asio::detail::mutex mutex_;
+  asio::detail::event event_;
+  bool is_complete_;
+};
+
+template <typename Executor, typename Function>
+void blocking_execute(
+    ASIO_MOVE_ARG(Executor) ex,
+    ASIO_MOVE_ARG(Function) func)
+{
+  typedef typename decay<Function>::type func_t;
+  blocking_execute_state<func_t> state(ASIO_MOVE_CAST(Function)(func));
+  state.execute_and_wait(ex);
+}
+
+} // namespace blocking_adaptation
+} // namespace detail
+
+typedef detail::blocking_adaptation_t<> blocking_adaptation_t;
+
+#if defined(ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION)
+constexpr blocking_adaptation_t blocking_adaptation;
+#else // defined(ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION)
+namespace { static const blocking_adaptation_t&
+  blocking_adaptation = blocking_adaptation_t::instance; }
+#endif
+
+} // namespace execution
+
+#if !defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+template <typename T>
+struct is_applicable_property<T, execution::blocking_adaptation_t>
+  : integral_constant<bool,
+      execution::is_executor<T>::value
+        || execution::is_sender<T>::value
+        || execution::is_scheduler<T>::value>
+{
+};
+
+template <typename T>
+struct is_applicable_property<T, execution::blocking_adaptation_t::disallowed_t>
+  : integral_constant<bool,
+      execution::is_executor<T>::value
+        || execution::is_sender<T>::value
+        || execution::is_scheduler<T>::value>
+{
+};
+
+template <typename T>
+struct is_applicable_property<T, execution::blocking_adaptation_t::allowed_t>
+  : integral_constant<bool,
+      execution::is_executor<T>::value
+        || execution::is_sender<T>::value
+        || execution::is_scheduler<T>::value>
+{
+};
+
+#endif // !defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+namespace traits {
+
+#if !defined(ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT)
+
+template <typename T>
+struct query_free_default<T, execution::blocking_adaptation_t,
+  typename enable_if<
+    can_query<T, execution::blocking_adaptation_t::disallowed_t>::value
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = (is_nothrow_query<T,
+      execution::blocking_adaptation_t::disallowed_t>::value));
+
+  typedef execution::blocking_adaptation_t result_type;
+};
+
+template <typename T>
+struct query_free_default<T, execution::blocking_adaptation_t,
+  typename enable_if<
+    !can_query<T, execution::blocking_adaptation_t::disallowed_t>::value
+      && can_query<T, execution::blocking_adaptation_t::allowed_t>::value
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept =
+    (is_nothrow_query<T, execution::blocking_adaptation_t::allowed_t>::value));
+
+  typedef execution::blocking_adaptation_t result_type;
+};
+
+#endif // !defined(ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT)
+
+#if !defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \
+  || !defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+
+template <typename T>
+struct static_query<T, execution::blocking_adaptation_t,
+  typename enable_if<
+    traits::query_static_constexpr_member<T,
+      execution::blocking_adaptation_t>::is_valid
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
+
+  typedef typename traits::query_static_constexpr_member<T,
+    execution::blocking_adaptation_t>::result_type result_type;
+
+  static ASIO_CONSTEXPR result_type value()
+  {
+    return traits::query_static_constexpr_member<T,
+      execution::blocking_adaptation_t>::value();
+  }
+};
+
+template <typename T>
+struct static_query<T, execution::blocking_adaptation_t,
+  typename enable_if<
+    !traits::query_static_constexpr_member<T,
+        execution::blocking_adaptation_t>::is_valid
+      && !traits::query_member<T,
+        execution::blocking_adaptation_t>::is_valid
+      && traits::static_query<T,
+        execution::blocking_adaptation_t::disallowed_t>::is_valid
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
+
+  typedef typename traits::static_query<T,
+    execution::blocking_adaptation_t::disallowed_t>::result_type result_type;
+
+  static ASIO_CONSTEXPR result_type value()
+  {
+    return traits::static_query<T,
+        execution::blocking_adaptation_t::disallowed_t>::value();
+  }
+};
+
+template <typename T>
+struct static_query<T, execution::blocking_adaptation_t,
+  typename enable_if<
+    !traits::query_static_constexpr_member<T,
+        execution::blocking_adaptation_t>::is_valid
+      && !traits::query_member<T,
+        execution::blocking_adaptation_t>::is_valid
+      && !traits::static_query<T,
+        execution::blocking_adaptation_t::disallowed_t>::is_valid
+      && traits::static_query<T,
+        execution::blocking_adaptation_t::allowed_t>::is_valid
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
+
+  typedef typename traits::static_query<T,
+    execution::blocking_adaptation_t::allowed_t>::result_type result_type;
+
+  static ASIO_CONSTEXPR result_type value()
+  {
+    return traits::static_query<T,
+        execution::blocking_adaptation_t::allowed_t>::value();
+  }
+};
+
+template <typename T>
+struct static_query<T, execution::blocking_adaptation_t::disallowed_t,
+  typename enable_if<
+    traits::query_static_constexpr_member<T,
+      execution::blocking_adaptation_t::disallowed_t>::is_valid
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
+
+  typedef typename traits::query_static_constexpr_member<T,
+    execution::blocking_adaptation_t::disallowed_t>::result_type result_type;
+
+  static ASIO_CONSTEXPR result_type value()
+  {
+    return traits::query_static_constexpr_member<T,
+      execution::blocking_adaptation_t::disallowed_t>::value();
+  }
+};
+
+template <typename T>
+struct static_query<T, execution::blocking_adaptation_t::disallowed_t,
+  typename enable_if<
+    !traits::query_static_constexpr_member<T,
+        execution::blocking_adaptation_t::disallowed_t>::is_valid
+      && !traits::query_member<T,
+        execution::blocking_adaptation_t::disallowed_t>::is_valid
+      && !traits::query_free<T,
+        execution::blocking_adaptation_t::disallowed_t>::is_valid
+      && !can_query<T, execution::blocking_adaptation_t::allowed_t>::value
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
+
+  typedef execution::blocking_adaptation_t::disallowed_t result_type;
+
+  static ASIO_CONSTEXPR result_type value()
+  {
+    return result_type();
+  }
+};
+
+template <typename T>
+struct static_query<T, execution::blocking_adaptation_t::allowed_t,
+  typename enable_if<
+    traits::query_static_constexpr_member<T,
+      execution::blocking_adaptation_t::allowed_t>::is_valid
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
+
+  typedef typename traits::query_static_constexpr_member<T,
+    execution::blocking_adaptation_t::allowed_t>::result_type result_type;
+
+  static ASIO_CONSTEXPR result_type value()
+  {
+    return traits::query_static_constexpr_member<T,
+      execution::blocking_adaptation_t::allowed_t>::value();
+  }
+};
+
+#endif // !defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)
+       //   || !defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+
+#if !defined(ASIO_HAS_DEDUCED_STATIC_REQUIRE_TRAIT)
+
+template <typename T>
+struct static_require<T, execution::blocking_adaptation_t::disallowed_t,
+  typename enable_if<
+    static_query<T, execution::blocking_adaptation_t::disallowed_t>::is_valid
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid =
+    (is_same<typename static_query<T,
+      execution::blocking_adaptation_t::disallowed_t>::result_type,
+        execution::blocking_adaptation_t::disallowed_t>::value));
+};
+
+template <typename T>
+struct static_require<T, execution::blocking_adaptation_t::allowed_t,
+  typename enable_if<
+    static_query<T, execution::blocking_adaptation_t::allowed_t>::is_valid
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid =
+    (is_same<typename static_query<T,
+      execution::blocking_adaptation_t::allowed_t>::result_type,
+        execution::blocking_adaptation_t::allowed_t>::value));
+};
+
+#endif // !defined(ASIO_HAS_DEDUCED_STATIC_REQUIRE_TRAIT)
+
+#if !defined(ASIO_HAS_DEDUCED_REQUIRE_FREE_TRAIT)
+
+template <typename T>
+struct require_free_default<T, execution::blocking_adaptation_t::allowed_t,
+  typename enable_if<
+    is_same<T, typename decay<T>::type>::value
+      && execution::is_executor<T>::value
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
+  typedef execution::detail::blocking_adaptation::adapter<T> result_type;
+};
+
+#endif // !defined(ASIO_HAS_DEDUCED_REQUIRE_FREE_TRAIT)
+
+#if !defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)
+
+template <typename Executor>
+struct equality_comparable<
+  execution::detail::blocking_adaptation::adapter<Executor> >
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
+};
+
+#endif // !defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)
+
+#if !defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)
+
+template <typename Executor, typename Function>
+struct execute_member<
+  execution::detail::blocking_adaptation::adapter<Executor>, Function>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
+  typedef void result_type;
+};
+
+#endif // !defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)
+
+#if !defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT)
+
+template <typename Executor, int I>
+struct query_static_constexpr_member<
+  execution::detail::blocking_adaptation::adapter<Executor>,
+  execution::detail::blocking_adaptation_t<I> >
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
+  typedef execution::blocking_adaptation_t::allowed_t result_type;
+
+  static ASIO_CONSTEXPR result_type value() ASIO_NOEXCEPT
+  {
+    return result_type();
+  }
+};
+
+template <typename Executor, int I>
+struct query_static_constexpr_member<
+  execution::detail::blocking_adaptation::adapter<Executor>,
+  execution::detail::blocking_adaptation::allowed_t<I> >
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
+  typedef execution::blocking_adaptation_t::allowed_t result_type;
+
+  static ASIO_CONSTEXPR result_type value() ASIO_NOEXCEPT
+  {
+    return result_type();
+  }
+};
+
+template <typename Executor, int I>
+struct query_static_constexpr_member<
+  execution::detail::blocking_adaptation::adapter<Executor>,
+  execution::detail::blocking_adaptation::disallowed_t<I> >
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
+  typedef execution::blocking_adaptation_t::allowed_t result_type;
+
+  static ASIO_CONSTEXPR result_type value() ASIO_NOEXCEPT
+  {
+    return result_type();
+  }
+};
+
+#endif // !defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT)
+
+#if !defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT)
+
+template <typename Executor, typename Property>
+struct query_member<
+  execution::detail::blocking_adaptation::adapter<Executor>, Property,
+  typename enable_if<
+    can_query<const Executor&, Property>::value
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept =
+      (is_nothrow_query<Executor, Property>::value));
+  typedef typename query_result<Executor, Property>::type result_type;
+};
+
+#endif // !defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT)
+
+#if !defined(ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT)
+
+template <typename Executor, int I>
+struct require_member<
+  execution::detail::blocking_adaptation::adapter<Executor>,
+  execution::detail::blocking_adaptation::disallowed_t<I> >
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
+  typedef Executor result_type;
+};
+
+template <typename Executor, typename Property>
+struct require_member<
+  execution::detail::blocking_adaptation::adapter<Executor>, Property,
+  typename enable_if<
+    can_require<const Executor&, Property>::value
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept =
+      (is_nothrow_require<Executor, Property>::value));
+  typedef execution::detail::blocking_adaptation::adapter<typename decay<
+    typename require_result<Executor, Property>::type
+      >::type> result_type;
+};
+
+#endif // !defined(ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT)
+
+#if !defined(ASIO_HAS_DEDUCED_PREFER_MEMBER_TRAIT)
+
+template <typename Executor, typename Property>
+struct prefer_member<
+  execution::detail::blocking_adaptation::adapter<Executor>, Property,
+  typename enable_if<
+    can_prefer<const Executor&, Property>::value
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept =
+      (is_nothrow_prefer<Executor, Property>::value));
+  typedef execution::detail::blocking_adaptation::adapter<typename decay<
+    typename prefer_result<Executor, Property>::type
+      >::type> result_type;
+};
+
+#endif // !defined(ASIO_HAS_DEDUCED_PREFER_MEMBER_TRAIT)
+
+} // namespace traits
+
+#endif // defined(GENERATING_DOCUMENTATION)
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_EXECUTION_BLOCKING_ADAPTATION_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/execution/bulk_execute.hpp b/link/modules/asio-standalone/asio/include/asio/execution/bulk_execute.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/execution/bulk_execute.hpp
@@ -0,0 +1,390 @@
+//
+// execution/bulk_execute.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_EXECUTION_BULK_EXECUTE_HPP
+#define ASIO_EXECUTION_BULK_EXECUTE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/type_traits.hpp"
+#include "asio/execution/bulk_guarantee.hpp"
+#include "asio/execution/detail/bulk_sender.hpp"
+#include "asio/execution/executor.hpp"
+#include "asio/execution/sender.hpp"
+#include "asio/traits/bulk_execute_member.hpp"
+#include "asio/traits/bulk_execute_free.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+#if defined(GENERATING_DOCUMENTATION)
+
+namespace asio {
+namespace execution {
+
+/// A customisation point that creates a bulk sender.
+/**
+ * The name <tt>execution::bulk_execute</tt> denotes a customisation point
+ * object. If <tt>is_convertible_v<N, size_t></tt> is true, then the expression
+ * <tt>execution::bulk_execute(S, F, N)</tt> for some subexpressions
+ * <tt>S</tt>, <tt>F</tt>, and <tt>N</tt> is expression-equivalent to:
+ *
+ * @li <tt>S.bulk_execute(F, N)</tt>, if that expression is valid. If the
+ *   function selected does not execute <tt>N</tt> invocations of the function
+ *   object <tt>F</tt> on the executor <tt>S</tt> in bulk with forward progress
+ *   guarantee <tt>asio::query(S, execution::bulk_guarantee)</tt>, and
+ *   the result of that function does not model <tt>sender<void></tt>, the
+ *   program is ill-formed with no diagnostic required.
+ *
+ * @li Otherwise, <tt>bulk_execute(S, F, N)</tt>, if that expression is valid,
+ *   with overload resolution performed in a context that includes the
+ *   declaration <tt>void bulk_execute();</tt> and that does not include a
+ *   declaration of <tt>execution::bulk_execute</tt>. If the function selected
+ *   by overload resolution does not execute <tt>N</tt> invocations of the
+ *   function object <tt>F</tt> on the executor <tt>S</tt> in bulk with forward
+ *   progress guarantee <tt>asio::query(E,
+ *   execution::bulk_guarantee)</tt>, and the result of that function does not
+ *   model <tt>sender<void></tt>, the program is ill-formed with no diagnostic
+ *   required.
+ *
+ * @li Otherwise, if the types <tt>F</tt> and
+ *   <tt>executor_index_t<remove_cvref_t<S>></tt> model <tt>invocable</tt> and
+ *   if <tt>asio::query(S, execution::bulk_guarantee)</tt> equals
+ *   <tt>execution::bulk_guarantee.unsequenced</tt>, then
+ *
+ *    - Evaluates <tt>DECAY_COPY(std::forward<decltype(F)>(F))</tt> on the
+ *      calling thread to create a function object <tt>cf</tt>. [Note:
+ *      Additional copies of <tt>cf</tt> may subsequently be created. --end
+ *      note.]
+ *
+ *    - For each value of <tt>i</tt> in <tt>N</tt>, <tt>cf(i)</tt> (or copy of
+ *      <tt>cf</tt>)) will be invoked at most once by an execution agent that is
+ *      unique for each value of <tt>i</tt>.
+ *
+ *    - May block pending completion of one or more invocations of <tt>cf</tt>.
+ *
+ *    - Synchronizes with (C++Std [intro.multithread]) the invocations of
+ *      <tt>cf</tt>.
+ *
+ * @li Otherwise, <tt>execution::bulk_execute(S, F, N)</tt> is ill-formed.
+ */
+inline constexpr unspecified bulk_execute = unspecified;
+
+/// A type trait that determines whether a @c bulk_execute expression is
+/// well-formed.
+/**
+ * Class template @c can_bulk_execute is a trait that is derived from @c
+ * true_type if the expression <tt>execution::bulk_execute(std::declval<S>(),
+ * std::declval<F>(), std::declval<N>)</tt> is well formed; otherwise @c
+ * false_type.
+ */
+template <typename S, typename F, typename N>
+struct can_bulk_execute :
+  integral_constant<bool, automatically_determined>
+{
+};
+
+} // namespace execution
+} // namespace asio
+
+#else // defined(GENERATING_DOCUMENTATION)
+
+namespace asio_execution_bulk_execute_fn {
+
+using asio::declval;
+using asio::enable_if;
+using asio::execution::bulk_guarantee_t;
+using asio::execution::detail::bulk_sender;
+using asio::execution::executor_index;
+using asio::execution::is_sender;
+using asio::is_convertible;
+using asio::is_same;
+using asio::remove_cvref;
+using asio::result_of;
+using asio::traits::bulk_execute_free;
+using asio::traits::bulk_execute_member;
+using asio::traits::static_require;
+
+void bulk_execute();
+
+enum overload_type
+{
+  call_member,
+  call_free,
+  adapter,
+  ill_formed
+};
+
+template <typename S, typename Args, typename = void>
+struct call_traits
+{
+  ASIO_STATIC_CONSTEXPR(overload_type, overload = ill_formed);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
+  typedef void result_type;
+};
+
+template <typename S, typename F, typename N>
+struct call_traits<S, void(F, N),
+  typename enable_if<
+    (
+      is_convertible<N, std::size_t>::value
+      &&
+      bulk_execute_member<S, F, N>::is_valid
+      &&
+      is_sender<
+        typename bulk_execute_member<S, F, N>::result_type
+      >::value
+    )
+  >::type> :
+  bulk_execute_member<S, F, N>
+{
+  ASIO_STATIC_CONSTEXPR(overload_type, overload = call_member);
+};
+
+template <typename S, typename F, typename N>
+struct call_traits<S, void(F, N),
+  typename enable_if<
+    (
+      is_convertible<N, std::size_t>::value
+      &&
+      !bulk_execute_member<S, F, N>::is_valid
+      &&
+      bulk_execute_free<S, F, N>::is_valid
+      &&
+      is_sender<
+        typename bulk_execute_free<S, F, N>::result_type
+      >::value
+    )
+  >::type> :
+  bulk_execute_free<S, F, N>
+{
+  ASIO_STATIC_CONSTEXPR(overload_type, overload = call_free);
+};
+
+template <typename S, typename F, typename N>
+struct call_traits<S, void(F, N),
+  typename enable_if<
+    (
+      is_convertible<N, std::size_t>::value
+      &&
+      !bulk_execute_member<S, F, N>::is_valid
+      &&
+      !bulk_execute_free<S, F, N>::is_valid
+      &&
+      is_sender<S>::value
+      &&
+      is_same<
+        typename result_of<
+          F(typename executor_index<typename remove_cvref<S>::type>::type)
+        >::type,
+        typename result_of<
+          F(typename executor_index<typename remove_cvref<S>::type>::type)
+        >::type
+      >::value
+      &&
+      static_require<S, bulk_guarantee_t::unsequenced_t>::is_valid
+    )
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(overload_type, overload = adapter);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
+  typedef bulk_sender<S, F, N> result_type;
+};
+
+struct impl
+{
+#if defined(ASIO_HAS_MOVE)
+  template <typename S, typename F, typename N>
+  ASIO_CONSTEXPR typename enable_if<
+    call_traits<S, void(F, N)>::overload == call_member,
+    typename call_traits<S, void(F, N)>::result_type
+  >::type
+  operator()(S&& s, F&& f, N&& n) const
+    ASIO_NOEXCEPT_IF((
+      call_traits<S, void(F, N)>::is_noexcept))
+  {
+    return ASIO_MOVE_CAST(S)(s).bulk_execute(
+        ASIO_MOVE_CAST(F)(f), ASIO_MOVE_CAST(N)(n));
+  }
+
+  template <typename S, typename F, typename N>
+  ASIO_CONSTEXPR typename enable_if<
+    call_traits<S, void(F, N)>::overload == call_free,
+    typename call_traits<S, void(F, N)>::result_type
+  >::type
+  operator()(S&& s, F&& f, N&& n) const
+    ASIO_NOEXCEPT_IF((
+      call_traits<S, void(F, N)>::is_noexcept))
+  {
+    return bulk_execute(ASIO_MOVE_CAST(S)(s),
+        ASIO_MOVE_CAST(F)(f), ASIO_MOVE_CAST(N)(n));
+  }
+
+  template <typename S, typename F, typename N>
+  ASIO_CONSTEXPR typename enable_if<
+    call_traits<S, void(F, N)>::overload == adapter,
+    typename call_traits<S, void(F, N)>::result_type
+  >::type
+  operator()(S&& s, F&& f, N&& n) const
+    ASIO_NOEXCEPT_IF((
+      call_traits<S, void(F, N)>::is_noexcept))
+  {
+    return typename call_traits<S, void(F, N)>::result_type(
+        ASIO_MOVE_CAST(S)(s), ASIO_MOVE_CAST(F)(f),
+        ASIO_MOVE_CAST(N)(n));
+  }
+#else // defined(ASIO_HAS_MOVE)
+  template <typename S, typename F, typename N>
+  ASIO_CONSTEXPR typename enable_if<
+    call_traits<S, void(const F&, const N&)>::overload == call_member,
+    typename call_traits<S, void(const F&, const N&)>::result_type
+  >::type
+  operator()(S& s, const F& f, const N& n) const
+    ASIO_NOEXCEPT_IF((
+      call_traits<S, void(const F&, const N&)>::is_noexcept))
+  {
+    return s.bulk_execute(ASIO_MOVE_CAST(F)(f),
+        ASIO_MOVE_CAST(N)(n));
+  }
+
+  template <typename S, typename F, typename N>
+  ASIO_CONSTEXPR typename enable_if<
+    call_traits<S, void(const F&, const N&)>::overload == call_member,
+    typename call_traits<S, void(const F&, const N&)>::result_type
+  >::type
+  operator()(const S& s, const F& f, const N& n) const
+    ASIO_NOEXCEPT_IF((
+      call_traits<S, void(const F&, const N&)>::is_noexcept))
+  {
+    return s.bulk_execute(ASIO_MOVE_CAST(F)(f),
+        ASIO_MOVE_CAST(N)(n));
+  }
+
+  template <typename S, typename F, typename N>
+  ASIO_CONSTEXPR typename enable_if<
+    call_traits<S, void(const F&, const N&)>::overload == call_free,
+    typename call_traits<S, void(const F&, const N&)>::result_type
+  >::type
+  operator()(S& s, const F& f, const N& n) const
+    ASIO_NOEXCEPT_IF((
+      call_traits<S, void(const F&, const N&)>::is_noexcept))
+  {
+    return bulk_execute(s, ASIO_MOVE_CAST(F)(f),
+        ASIO_MOVE_CAST(N)(n));
+  }
+
+  template <typename S, typename F, typename N>
+  ASIO_CONSTEXPR typename enable_if<
+    call_traits<S, void(const F&, const N&)>::overload == call_free,
+    typename call_traits<S, void(const F&, const N&)>::result_type
+  >::type
+  operator()(const S& s, const F& f, const N& n) const
+    ASIO_NOEXCEPT_IF((
+      call_traits<S, void(const F&, const N&)>::is_noexcept))
+  {
+    return bulk_execute(s, ASIO_MOVE_CAST(F)(f),
+        ASIO_MOVE_CAST(N)(n));
+  }
+
+  template <typename S, typename F, typename N>
+  ASIO_CONSTEXPR typename enable_if<
+    call_traits<S, void(const F&, const N&)>::overload == adapter,
+    typename call_traits<S, void(const F&, const N&)>::result_type
+  >::type
+  operator()(S& s, const F& f, const N& n) const
+    ASIO_NOEXCEPT_IF((
+      call_traits<S, void(const F&, const N&)>::is_noexcept))
+  {
+    return typename call_traits<S, void(const F&, const N&)>::result_type(
+        s, ASIO_MOVE_CAST(F)(f), ASIO_MOVE_CAST(N)(n));
+  }
+
+  template <typename S, typename F, typename N>
+  ASIO_CONSTEXPR typename enable_if<
+    call_traits<S, void(const F&, const N&)>::overload == adapter,
+    typename call_traits<S, void(const F&, const N&)>::result_type
+  >::type
+  operator()(const S& s, const F& f, const N& n) const
+    ASIO_NOEXCEPT_IF((
+      call_traits<S, void(const F&, const N&)>::is_noexcept))
+  {
+    return typename call_traits<S, void(const F&, const N&)>::result_type(
+        s, ASIO_MOVE_CAST(F)(f), ASIO_MOVE_CAST(N)(n));
+  }
+#endif // defined(ASIO_HAS_MOVE)
+};
+
+template <typename T = impl>
+struct static_instance
+{
+  static const T instance;
+};
+
+template <typename T>
+const T static_instance<T>::instance = {};
+
+} // namespace asio_execution_bulk_execute_fn
+namespace asio {
+namespace execution {
+namespace {
+
+static ASIO_CONSTEXPR
+  const asio_execution_bulk_execute_fn::impl& bulk_execute =
+    asio_execution_bulk_execute_fn::static_instance<>::instance;
+
+} // namespace
+
+template <typename S, typename F, typename N>
+struct can_bulk_execute :
+  integral_constant<bool,
+    asio_execution_bulk_execute_fn::call_traits<S, void(F, N)>::overload !=
+      asio_execution_bulk_execute_fn::ill_formed>
+{
+};
+
+#if defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+template <typename S, typename F, typename N>
+constexpr bool can_bulk_execute_v = can_bulk_execute<S, F, N>::value;
+
+#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+template <typename S, typename F, typename N>
+struct is_nothrow_bulk_execute :
+  integral_constant<bool,
+    asio_execution_bulk_execute_fn::call_traits<S, void(F, N)>::is_noexcept>
+{
+};
+
+#if defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+template <typename S, typename F, typename N>
+constexpr bool is_nothrow_bulk_execute_v
+  = is_nothrow_bulk_execute<S, F, N>::value;
+
+#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+template <typename S, typename F, typename N>
+struct bulk_execute_result
+{
+  typedef typename asio_execution_bulk_execute_fn::call_traits<
+      S, void(F, N)>::result_type type;
+};
+
+} // namespace execution
+} // namespace asio
+
+#endif // defined(GENERATING_DOCUMENTATION)
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_EXECUTION_BULK_EXECUTE_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/execution/bulk_guarantee.hpp b/link/modules/asio-standalone/asio/include/asio/execution/bulk_guarantee.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/execution/bulk_guarantee.hpp
@@ -0,0 +1,1018 @@
+//
+// execution/bulk_guarantee.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_EXECUTION_BULK_GUARANTEE_HPP
+#define ASIO_EXECUTION_BULK_GUARANTEE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/type_traits.hpp"
+#include "asio/execution/executor.hpp"
+#include "asio/execution/scheduler.hpp"
+#include "asio/execution/sender.hpp"
+#include "asio/is_applicable_property.hpp"
+#include "asio/query.hpp"
+#include "asio/traits/query_free.hpp"
+#include "asio/traits/query_member.hpp"
+#include "asio/traits/query_static_constexpr_member.hpp"
+#include "asio/traits/static_query.hpp"
+#include "asio/traits/static_require.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+#if defined(GENERATING_DOCUMENTATION)
+
+namespace execution {
+
+/// A property to communicate the forward progress and ordering guarantees of
+/// execution agents associated with the bulk execution.
+struct bulk_guarantee_t
+{
+  /// The bulk_guarantee_t property applies to executors, senders, and
+  /// schedulers.
+  template <typename T>
+  static constexpr bool is_applicable_property_v =
+    is_executor_v<T> || is_sender_v<T> || is_scheduler_v<T>;
+
+  /// The top-level bulk_guarantee_t property cannot be required.
+  static constexpr bool is_requirable = false;
+
+  /// The top-level bulk_guarantee_t property cannot be preferred.
+  static constexpr bool is_preferable = false;
+
+  /// The type returned by queries against an @c any_executor.
+  typedef bulk_guarantee_t polymorphic_query_result_type;
+
+  /// A sub-property that indicates that execution agents within the same bulk
+  /// execution may be parallelised and vectorised.
+  struct unsequenced_t
+  {
+    /// The bulk_guarantee_t::unsequenced_t property applies to executors,
+    /// senders, and schedulers.
+    template <typename T>
+    static constexpr bool is_applicable_property_v =
+      is_executor_v<T> || is_sender_v<T> || is_scheduler_v<T>;
+
+    /// The bulk_guarantee_t::unsequenced_t property can be required.
+    static constexpr bool is_requirable = true;
+
+    /// The bulk_guarantee_t::unsequenced_t property can be preferred.
+    static constexpr bool is_preferable = true;
+
+    /// The type returned by queries against an @c any_executor.
+    typedef bulk_guarantee_t polymorphic_query_result_type;
+
+    /// Default constructor.
+    constexpr unsequenced_t();
+
+    /// Get the value associated with a property object.
+    /**
+     * @returns unsequenced_t();
+     */
+    static constexpr bulk_guarantee_t value();
+  };
+
+  /// A sub-property that indicates that execution agents within the same bulk
+  /// execution may not be parallelised and vectorised.
+  struct sequenced_t
+  {
+    /// The bulk_guarantee_t::sequenced_t property applies to executors,
+    /// senders, and schedulers.
+    template <typename T>
+    static constexpr bool is_applicable_property_v =
+      is_executor_v<T> || is_sender_v<T> || is_scheduler_v<T>;
+
+    /// The bulk_guarantee_t::sequenced_t property can be required.
+    static constexpr bool is_requirable = true;
+
+    /// The bulk_guarantee_t::sequenced_t property can be preferred.
+    static constexpr bool is_preferable = true;
+
+    /// The type returned by queries against an @c any_executor.
+    typedef bulk_guarantee_t polymorphic_query_result_type;
+
+    /// Default constructor.
+    constexpr sequenced_t();
+
+    /// Get the value associated with a property object.
+    /**
+     * @returns sequenced_t();
+     */
+    static constexpr bulk_guarantee_t value();
+  };
+
+  /// A sub-property that indicates that execution agents within the same bulk
+  /// execution may be parallelised.
+  struct parallel_t
+  {
+    /// The bulk_guarantee_t::parallel_t property applies to executors,
+    /// senders, and schedulers.
+    template <typename T>
+    static constexpr bool is_applicable_property_v =
+      is_executor_v<T> || is_sender_v<T> || is_scheduler_v<T>;
+
+    /// The bulk_guarantee_t::parallel_t property can be required.
+    static constexpr bool is_requirable = true;
+
+    /// The bulk_guarantee_t::parallel_t property can be preferred.
+    static constexpr bool is_preferable = true;
+
+    /// The type returned by queries against an @c any_executor.
+    typedef bulk_guarantee_t polymorphic_query_result_type;
+
+    /// Default constructor.
+    constexpr parallel_t();
+
+    /// Get the value associated with a property object.
+    /**
+     * @returns parallel_t();
+     */
+    static constexpr bulk_guarantee_t value();
+  };
+
+  /// A special value used for accessing the bulk_guarantee_t::unsequenced_t
+  /// property.
+  static constexpr unsequenced_t unsequenced;
+
+  /// A special value used for accessing the bulk_guarantee_t::sequenced_t
+  /// property.
+  static constexpr sequenced_t sequenced;
+
+  /// A special value used for accessing the bulk_guarantee_t::parallel_t
+  /// property.
+  static constexpr parallel_t parallel;
+
+  /// Default constructor.
+  constexpr bulk_guarantee_t();
+
+  /// Construct from a sub-property value.
+  constexpr bulk_guarantee_t(unsequenced_t);
+
+  /// Construct from a sub-property value.
+  constexpr bulk_guarantee_t(sequenced_t);
+
+  /// Construct from a sub-property value.
+  constexpr bulk_guarantee_t(parallel_t);
+
+  /// Compare property values for equality.
+  friend constexpr bool operator==(
+      const bulk_guarantee_t& a, const bulk_guarantee_t& b) noexcept;
+
+  /// Compare property values for inequality.
+  friend constexpr bool operator!=(
+      const bulk_guarantee_t& a, const bulk_guarantee_t& b) noexcept;
+};
+
+/// A special value used for accessing the bulk_guarantee_t property.
+constexpr bulk_guarantee_t bulk_guarantee;
+
+} // namespace execution
+
+#else // defined(GENERATING_DOCUMENTATION)
+
+namespace execution {
+namespace detail {
+namespace bulk_guarantee {
+
+template <int I> struct unsequenced_t;
+template <int I> struct sequenced_t;
+template <int I> struct parallel_t;
+
+} // namespace bulk_guarantee
+
+template <int I = 0>
+struct bulk_guarantee_t
+{
+#if defined(ASIO_HAS_VARIABLE_TEMPLATES)
+  template <typename T>
+  ASIO_STATIC_CONSTEXPR(bool,
+    is_applicable_property_v = is_executor<T>::value
+      || is_sender<T>::value || is_scheduler<T>::value);
+#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+  ASIO_STATIC_CONSTEXPR(bool, is_requirable = false);
+  ASIO_STATIC_CONSTEXPR(bool, is_preferable = false);
+  typedef bulk_guarantee_t polymorphic_query_result_type;
+
+  typedef detail::bulk_guarantee::unsequenced_t<I> unsequenced_t;
+  typedef detail::bulk_guarantee::sequenced_t<I> sequenced_t;
+  typedef detail::bulk_guarantee::parallel_t<I> parallel_t;
+
+  ASIO_CONSTEXPR bulk_guarantee_t()
+    : value_(-1)
+  {
+  }
+
+  ASIO_CONSTEXPR bulk_guarantee_t(unsequenced_t)
+    : value_(0)
+  {
+  }
+
+  ASIO_CONSTEXPR bulk_guarantee_t(sequenced_t)
+    : value_(1)
+  {
+  }
+
+  ASIO_CONSTEXPR bulk_guarantee_t(parallel_t)
+    : value_(2)
+  {
+  }
+
+#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \
+  && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+  template <typename T>
+  static ASIO_CONSTEXPR
+  typename traits::query_static_constexpr_member<
+      T, bulk_guarantee_t>::result_type
+  static_query()
+    ASIO_NOEXCEPT_IF((
+      traits::query_static_constexpr_member<T, bulk_guarantee_t>::is_noexcept))
+  {
+    return traits::query_static_constexpr_member<T, bulk_guarantee_t>::value();
+  }
+
+  template <typename T>
+  static ASIO_CONSTEXPR
+  typename traits::static_query<T, unsequenced_t>::result_type
+  static_query(
+      typename enable_if<
+        !traits::query_static_constexpr_member<T, bulk_guarantee_t>::is_valid
+          && !traits::query_member<T, bulk_guarantee_t>::is_valid
+          && traits::static_query<T, unsequenced_t>::is_valid
+      >::type* = 0) ASIO_NOEXCEPT
+  {
+    return traits::static_query<T, unsequenced_t>::value();
+  }
+
+  template <typename T>
+  static ASIO_CONSTEXPR
+  typename traits::static_query<T, sequenced_t>::result_type
+  static_query(
+      typename enable_if<
+        !traits::query_static_constexpr_member<T, bulk_guarantee_t>::is_valid
+          && !traits::query_member<T, bulk_guarantee_t>::is_valid
+          && !traits::static_query<T, unsequenced_t>::is_valid
+          && traits::static_query<T, sequenced_t>::is_valid
+      >::type* = 0) ASIO_NOEXCEPT
+  {
+    return traits::static_query<T, sequenced_t>::value();
+  }
+
+  template <typename T>
+  static ASIO_CONSTEXPR
+  typename traits::static_query<T, parallel_t>::result_type
+  static_query(
+      typename enable_if<
+        !traits::query_static_constexpr_member<T, bulk_guarantee_t>::is_valid
+          && !traits::query_member<T, bulk_guarantee_t>::is_valid
+          && !traits::static_query<T, unsequenced_t>::is_valid
+          && !traits::static_query<T, sequenced_t>::is_valid
+          && traits::static_query<T, parallel_t>::is_valid
+      >::type* = 0) ASIO_NOEXCEPT
+  {
+    return traits::static_query<T, parallel_t>::value();
+  }
+
+  template <typename E,
+      typename T = decltype(bulk_guarantee_t::static_query<E>())>
+  static ASIO_CONSTEXPR const T static_query_v
+    = bulk_guarantee_t::static_query<E>();
+#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)
+       //   && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+
+  friend ASIO_CONSTEXPR bool operator==(
+      const bulk_guarantee_t& a, const bulk_guarantee_t& b)
+  {
+    return a.value_ == b.value_;
+  }
+
+  friend ASIO_CONSTEXPR bool operator!=(
+      const bulk_guarantee_t& a, const bulk_guarantee_t& b)
+  {
+    return a.value_ != b.value_;
+  }
+
+  struct convertible_from_bulk_guarantee_t
+  {
+    ASIO_CONSTEXPR convertible_from_bulk_guarantee_t(bulk_guarantee_t) {}
+  };
+
+  template <typename Executor>
+  friend ASIO_CONSTEXPR bulk_guarantee_t query(
+      const Executor& ex, convertible_from_bulk_guarantee_t,
+      typename enable_if<
+        can_query<const Executor&, unsequenced_t>::value
+      >::type* = 0)
+#if !defined(__clang__) // Clang crashes if noexcept is used here.
+#if defined(ASIO_MSVC) // Visual C++ wants the type to be qualified.
+    ASIO_NOEXCEPT_IF((
+      is_nothrow_query<const Executor&,
+        bulk_guarantee_t<>::unsequenced_t>::value))
+#else // defined(ASIO_MSVC)
+    ASIO_NOEXCEPT_IF((
+      is_nothrow_query<const Executor&, unsequenced_t>::value))
+#endif // defined(ASIO_MSVC)
+#endif // !defined(__clang__)
+  {
+    return asio::query(ex, unsequenced_t());
+  }
+
+  template <typename Executor>
+  friend ASIO_CONSTEXPR bulk_guarantee_t query(
+      const Executor& ex, convertible_from_bulk_guarantee_t,
+      typename enable_if<
+        !can_query<const Executor&, unsequenced_t>::value
+          && can_query<const Executor&, sequenced_t>::value
+      >::type* = 0)
+#if !defined(__clang__) // Clang crashes if noexcept is used here.
+#if defined(ASIO_MSVC) // Visual C++ wants the type to be qualified.
+    ASIO_NOEXCEPT_IF((
+      is_nothrow_query<const Executor&,
+        bulk_guarantee_t<>::sequenced_t>::value))
+#else // defined(ASIO_MSVC)
+    ASIO_NOEXCEPT_IF((
+      is_nothrow_query<const Executor&, sequenced_t>::value))
+#endif // defined(ASIO_MSVC)
+#endif // !defined(__clang__)
+  {
+    return asio::query(ex, sequenced_t());
+  }
+
+  template <typename Executor>
+  friend ASIO_CONSTEXPR bulk_guarantee_t query(
+      const Executor& ex, convertible_from_bulk_guarantee_t,
+      typename enable_if<
+        !can_query<const Executor&, unsequenced_t>::value
+          && !can_query<const Executor&, sequenced_t>::value
+          && can_query<const Executor&, parallel_t>::value
+      >::type* = 0)
+#if !defined(__clang__) // Clang crashes if noexcept is used here.
+#if defined(ASIO_MSVC) // Visual C++ wants the type to be qualified.
+    ASIO_NOEXCEPT_IF((
+      is_nothrow_query<const Executor&, bulk_guarantee_t<>::parallel_t>::value))
+#else // defined(ASIO_MSVC)
+    ASIO_NOEXCEPT_IF((
+      is_nothrow_query<const Executor&, parallel_t>::value))
+#endif // defined(ASIO_MSVC)
+#endif // !defined(__clang__)
+  {
+    return asio::query(ex, parallel_t());
+  }
+
+  ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(unsequenced_t, unsequenced);
+  ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(sequenced_t, sequenced);
+  ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(parallel_t, parallel);
+
+#if !defined(ASIO_HAS_CONSTEXPR)
+  static const bulk_guarantee_t instance;
+#endif // !defined(ASIO_HAS_CONSTEXPR)
+
+private:
+  int value_;
+};
+
+#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \
+  && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+template <int I> template <typename E, typename T>
+const T bulk_guarantee_t<I>::static_query_v;
+#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)
+       //   && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+
+#if !defined(ASIO_HAS_CONSTEXPR)
+template <int I>
+const bulk_guarantee_t<I> bulk_guarantee_t<I>::instance;
+#endif
+
+template <int I>
+const typename bulk_guarantee_t<I>::unsequenced_t
+bulk_guarantee_t<I>::unsequenced;
+
+template <int I>
+const typename bulk_guarantee_t<I>::sequenced_t
+bulk_guarantee_t<I>::sequenced;
+
+template <int I>
+const typename bulk_guarantee_t<I>::parallel_t
+bulk_guarantee_t<I>::parallel;
+
+namespace bulk_guarantee {
+
+template <int I = 0>
+struct unsequenced_t
+{
+#if defined(ASIO_HAS_VARIABLE_TEMPLATES)
+  template <typename T>
+  ASIO_STATIC_CONSTEXPR(bool,
+    is_applicable_property_v = is_executor<T>::value
+      || is_sender<T>::value || is_scheduler<T>::value);
+#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+  ASIO_STATIC_CONSTEXPR(bool, is_requirable = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_preferable = true);
+  typedef bulk_guarantee_t<I> polymorphic_query_result_type;
+
+  ASIO_CONSTEXPR unsequenced_t()
+  {
+  }
+
+#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \
+  && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+  template <typename T>
+  static ASIO_CONSTEXPR
+  typename traits::query_static_constexpr_member<T, unsequenced_t>::result_type
+  static_query()
+    ASIO_NOEXCEPT_IF((
+      traits::query_static_constexpr_member<T, unsequenced_t>::is_noexcept))
+  {
+    return traits::query_static_constexpr_member<T, unsequenced_t>::value();
+  }
+
+  template <typename T>
+  static ASIO_CONSTEXPR unsequenced_t static_query(
+      typename enable_if<
+        !traits::query_static_constexpr_member<T, unsequenced_t>::is_valid
+          && !traits::query_member<T, unsequenced_t>::is_valid
+          && !traits::query_free<T, unsequenced_t>::is_valid
+          && !can_query<T, sequenced_t<I> >::value
+          && !can_query<T, parallel_t<I> >::value
+      >::type* = 0) ASIO_NOEXCEPT
+  {
+    return unsequenced_t();
+  }
+
+  template <typename E, typename T = decltype(unsequenced_t::static_query<E>())>
+  static ASIO_CONSTEXPR const T static_query_v
+    = unsequenced_t::static_query<E>();
+#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)
+       //   && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+
+  static ASIO_CONSTEXPR bulk_guarantee_t<I> value()
+  {
+    return unsequenced_t();
+  }
+
+  friend ASIO_CONSTEXPR bool operator==(
+      const unsequenced_t&, const unsequenced_t&)
+  {
+    return true;
+  }
+
+  friend ASIO_CONSTEXPR bool operator!=(
+      const unsequenced_t&, const unsequenced_t&)
+  {
+    return false;
+  }
+
+  friend ASIO_CONSTEXPR bool operator==(
+      const unsequenced_t&, const sequenced_t<I>&)
+  {
+    return false;
+  }
+
+  friend ASIO_CONSTEXPR bool operator!=(
+      const unsequenced_t&, const sequenced_t<I>&)
+  {
+    return true;
+  }
+
+  friend ASIO_CONSTEXPR bool operator==(
+      const unsequenced_t&, const parallel_t<I>&)
+  {
+    return false;
+  }
+
+  friend ASIO_CONSTEXPR bool operator!=(
+      const unsequenced_t&, const parallel_t<I>&)
+  {
+    return true;
+  }
+};
+
+#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \
+  && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+template <int I> template <typename E, typename T>
+const T unsequenced_t<I>::static_query_v;
+#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)
+       //   && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+
+template <int I = 0>
+struct sequenced_t
+{
+#if defined(ASIO_HAS_VARIABLE_TEMPLATES)
+  template <typename T>
+  ASIO_STATIC_CONSTEXPR(bool,
+    is_applicable_property_v = is_executor<T>::value
+      || is_sender<T>::value || is_scheduler<T>::value);
+#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+  ASIO_STATIC_CONSTEXPR(bool, is_requirable = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_preferable = true);
+  typedef bulk_guarantee_t<I> polymorphic_query_result_type;
+
+  ASIO_CONSTEXPR sequenced_t()
+  {
+  }
+
+#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \
+  && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+  template <typename T>
+  static ASIO_CONSTEXPR
+  typename traits::query_static_constexpr_member<T, sequenced_t>::result_type
+  static_query()
+    ASIO_NOEXCEPT_IF((
+      traits::query_static_constexpr_member<T, sequenced_t>::is_noexcept))
+  {
+    return traits::query_static_constexpr_member<T, sequenced_t>::value();
+  }
+
+  template <typename E, typename T = decltype(sequenced_t::static_query<E>())>
+  static ASIO_CONSTEXPR const T static_query_v
+    = sequenced_t::static_query<E>();
+#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)
+       //   && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+
+  static ASIO_CONSTEXPR bulk_guarantee_t<I> value()
+  {
+    return sequenced_t();
+  }
+
+  friend ASIO_CONSTEXPR bool operator==(
+      const sequenced_t&, const sequenced_t&)
+  {
+    return true;
+  }
+
+  friend ASIO_CONSTEXPR bool operator!=(
+      const sequenced_t&, const sequenced_t&)
+  {
+    return false;
+  }
+
+  friend ASIO_CONSTEXPR bool operator==(
+      const sequenced_t&, const unsequenced_t<I>&)
+  {
+    return false;
+  }
+
+  friend ASIO_CONSTEXPR bool operator!=(
+      const sequenced_t&, const unsequenced_t<I>&)
+  {
+    return true;
+  }
+
+  friend ASIO_CONSTEXPR bool operator==(
+      const sequenced_t&, const parallel_t<I>&)
+  {
+    return false;
+  }
+
+  friend ASIO_CONSTEXPR bool operator!=(
+      const sequenced_t&, const parallel_t<I>&)
+  {
+    return true;
+  }
+};
+
+#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \
+  && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+template <int I> template <typename E, typename T>
+const T sequenced_t<I>::static_query_v;
+#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)
+       //   && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+
+template <int I>
+struct parallel_t
+{
+#if defined(ASIO_HAS_VARIABLE_TEMPLATES)
+  template <typename T>
+  ASIO_STATIC_CONSTEXPR(bool,
+    is_applicable_property_v = is_executor<T>::value
+      || is_sender<T>::value || is_scheduler<T>::value);
+#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+  ASIO_STATIC_CONSTEXPR(bool, is_requirable = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_preferable = true);
+  typedef bulk_guarantee_t<I> polymorphic_query_result_type;
+
+  ASIO_CONSTEXPR parallel_t()
+  {
+  }
+
+#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \
+  && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+  template <typename T>
+  static ASIO_CONSTEXPR
+  typename traits::query_static_constexpr_member<T, parallel_t>::result_type
+  static_query()
+    ASIO_NOEXCEPT_IF((
+      traits::query_static_constexpr_member<T, parallel_t>::is_noexcept))
+  {
+    return traits::query_static_constexpr_member<T, parallel_t>::value();
+  }
+
+  template <typename E, typename T = decltype(parallel_t::static_query<E>())>
+  static ASIO_CONSTEXPR const T static_query_v
+    = parallel_t::static_query<E>();
+#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)
+       //   && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+
+  static ASIO_CONSTEXPR bulk_guarantee_t<I> value()
+  {
+    return parallel_t();
+  }
+
+  friend ASIO_CONSTEXPR bool operator==(
+      const parallel_t&, const parallel_t&)
+  {
+    return true;
+  }
+
+  friend ASIO_CONSTEXPR bool operator!=(
+      const parallel_t&, const parallel_t&)
+  {
+    return false;
+  }
+
+  friend ASIO_CONSTEXPR bool operator==(
+      const parallel_t&, const unsequenced_t<I>&)
+  {
+    return false;
+  }
+
+  friend ASIO_CONSTEXPR bool operator!=(
+      const parallel_t&, const unsequenced_t<I>&)
+  {
+    return true;
+  }
+
+  friend ASIO_CONSTEXPR bool operator==(
+      const parallel_t&, const sequenced_t<I>&)
+  {
+    return false;
+  }
+
+  friend ASIO_CONSTEXPR bool operator!=(
+      const parallel_t&, const sequenced_t<I>&)
+  {
+    return true;
+  }
+};
+
+#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \
+  && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+template <int I> template <typename E, typename T>
+const T parallel_t<I>::static_query_v;
+#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)
+       //   && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+
+} // namespace bulk_guarantee
+} // namespace detail
+
+typedef detail::bulk_guarantee_t<> bulk_guarantee_t;
+
+#if defined(ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION)
+constexpr bulk_guarantee_t bulk_guarantee;
+#else // defined(ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION)
+namespace { static const bulk_guarantee_t&
+  bulk_guarantee = bulk_guarantee_t::instance; }
+#endif
+
+} // namespace execution
+
+#if !defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+template <typename T>
+struct is_applicable_property<T, execution::bulk_guarantee_t>
+  : integral_constant<bool,
+      execution::is_executor<T>::value
+        || execution::is_sender<T>::value
+        || execution::is_scheduler<T>::value>
+{
+};
+
+template <typename T>
+struct is_applicable_property<T, execution::bulk_guarantee_t::unsequenced_t>
+  : integral_constant<bool,
+      execution::is_executor<T>::value
+        || execution::is_sender<T>::value
+        || execution::is_scheduler<T>::value>
+{
+};
+
+template <typename T>
+struct is_applicable_property<T, execution::bulk_guarantee_t::sequenced_t>
+  : integral_constant<bool,
+      execution::is_executor<T>::value
+        || execution::is_sender<T>::value
+        || execution::is_scheduler<T>::value>
+{
+};
+
+template <typename T>
+struct is_applicable_property<T, execution::bulk_guarantee_t::parallel_t>
+  : integral_constant<bool,
+      execution::is_executor<T>::value
+        || execution::is_sender<T>::value
+        || execution::is_scheduler<T>::value>
+{
+};
+
+#endif // !defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+namespace traits {
+
+#if !defined(ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT)
+
+template <typename T>
+struct query_free_default<T, execution::bulk_guarantee_t,
+  typename enable_if<
+    can_query<T, execution::bulk_guarantee_t::unsequenced_t>::value
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept =
+    (is_nothrow_query<T, execution::bulk_guarantee_t::unsequenced_t>::value));
+
+  typedef execution::bulk_guarantee_t result_type;
+};
+
+template <typename T>
+struct query_free_default<T, execution::bulk_guarantee_t,
+  typename enable_if<
+    !can_query<T, execution::bulk_guarantee_t::unsequenced_t>::value
+      && can_query<T, execution::bulk_guarantee_t::sequenced_t>::value
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept =
+    (is_nothrow_query<T, execution::bulk_guarantee_t::sequenced_t>::value));
+
+  typedef execution::bulk_guarantee_t result_type;
+};
+
+template <typename T>
+struct query_free_default<T, execution::bulk_guarantee_t,
+  typename enable_if<
+    !can_query<T, execution::bulk_guarantee_t::unsequenced_t>::value
+      && !can_query<T, execution::bulk_guarantee_t::sequenced_t>::value
+      && can_query<T, execution::bulk_guarantee_t::parallel_t>::value
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept =
+    (is_nothrow_query<T, execution::bulk_guarantee_t::parallel_t>::value));
+
+  typedef execution::bulk_guarantee_t result_type;
+};
+
+#endif // !defined(ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT)
+
+#if !defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \
+  || !defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+
+template <typename T>
+struct static_query<T, execution::bulk_guarantee_t,
+  typename enable_if<
+    traits::query_static_constexpr_member<T,
+      execution::bulk_guarantee_t>::is_valid
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
+
+  typedef typename traits::query_static_constexpr_member<T,
+    execution::bulk_guarantee_t>::result_type result_type;
+
+  static ASIO_CONSTEXPR result_type value()
+  {
+    return traits::query_static_constexpr_member<T,
+      execution::bulk_guarantee_t>::value();
+  }
+};
+
+template <typename T>
+struct static_query<T, execution::bulk_guarantee_t,
+  typename enable_if<
+    !traits::query_static_constexpr_member<T,
+        execution::bulk_guarantee_t>::is_valid
+      && !traits::query_member<T,
+        execution::bulk_guarantee_t>::is_valid
+      && traits::static_query<T,
+        execution::bulk_guarantee_t::unsequenced_t>::is_valid
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
+
+  typedef typename traits::static_query<T,
+    execution::bulk_guarantee_t::unsequenced_t>::result_type result_type;
+
+  static ASIO_CONSTEXPR result_type value()
+  {
+    return traits::static_query<T,
+        execution::bulk_guarantee_t::unsequenced_t>::value();
+  }
+};
+
+template <typename T>
+struct static_query<T, execution::bulk_guarantee_t,
+  typename enable_if<
+    !traits::query_static_constexpr_member<T,
+        execution::bulk_guarantee_t>::is_valid
+      && !traits::query_member<T,
+        execution::bulk_guarantee_t>::is_valid
+      && !traits::static_query<T,
+        execution::bulk_guarantee_t::unsequenced_t>::is_valid
+      && traits::static_query<T,
+        execution::bulk_guarantee_t::sequenced_t>::is_valid
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
+
+  typedef typename traits::static_query<T,
+    execution::bulk_guarantee_t::sequenced_t>::result_type result_type;
+
+  static ASIO_CONSTEXPR result_type value()
+  {
+    return traits::static_query<T,
+        execution::bulk_guarantee_t::sequenced_t>::value();
+  }
+};
+
+template <typename T>
+struct static_query<T, execution::bulk_guarantee_t,
+  typename enable_if<
+    !traits::query_static_constexpr_member<T,
+        execution::bulk_guarantee_t>::is_valid
+      && !traits::query_member<T,
+        execution::bulk_guarantee_t>::is_valid
+      && !traits::static_query<T,
+        execution::bulk_guarantee_t::unsequenced_t>::is_valid
+      && !traits::static_query<T,
+        execution::bulk_guarantee_t::sequenced_t>::is_valid
+      && traits::static_query<T,
+        execution::bulk_guarantee_t::parallel_t>::is_valid
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
+
+  typedef typename traits::static_query<T,
+    execution::bulk_guarantee_t::parallel_t>::result_type result_type;
+
+  static ASIO_CONSTEXPR result_type value()
+  {
+    return traits::static_query<T,
+        execution::bulk_guarantee_t::parallel_t>::value();
+  }
+};
+
+template <typename T>
+struct static_query<T, execution::bulk_guarantee_t::unsequenced_t,
+  typename enable_if<
+    traits::query_static_constexpr_member<T,
+      execution::bulk_guarantee_t::unsequenced_t>::is_valid
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
+
+  typedef typename traits::query_static_constexpr_member<T,
+    execution::bulk_guarantee_t::unsequenced_t>::result_type result_type;
+
+  static ASIO_CONSTEXPR result_type value()
+  {
+    return traits::query_static_constexpr_member<T,
+      execution::bulk_guarantee_t::unsequenced_t>::value();
+  }
+};
+
+template <typename T>
+struct static_query<T, execution::bulk_guarantee_t::unsequenced_t,
+  typename enable_if<
+    !traits::query_static_constexpr_member<T,
+      execution::bulk_guarantee_t::unsequenced_t>::is_valid
+      && !traits::query_member<T,
+        execution::bulk_guarantee_t::unsequenced_t>::is_valid
+      && !traits::query_free<T,
+        execution::bulk_guarantee_t::unsequenced_t>::is_valid
+      && !can_query<T, execution::bulk_guarantee_t::sequenced_t>::value
+      && !can_query<T, execution::bulk_guarantee_t::parallel_t>::value
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
+
+  typedef execution::bulk_guarantee_t::unsequenced_t result_type;
+
+  static ASIO_CONSTEXPR result_type value()
+  {
+    return result_type();
+  }
+};
+
+template <typename T>
+struct static_query<T, execution::bulk_guarantee_t::sequenced_t,
+  typename enable_if<
+    traits::query_static_constexpr_member<T,
+      execution::bulk_guarantee_t::sequenced_t>::is_valid
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
+
+  typedef typename traits::query_static_constexpr_member<T,
+    execution::bulk_guarantee_t::sequenced_t>::result_type result_type;
+
+  static ASIO_CONSTEXPR result_type value()
+  {
+    return traits::query_static_constexpr_member<T,
+      execution::bulk_guarantee_t::sequenced_t>::value();
+  }
+};
+
+template <typename T>
+struct static_query<T, execution::bulk_guarantee_t::parallel_t,
+  typename enable_if<
+    traits::query_static_constexpr_member<T,
+      execution::bulk_guarantee_t::parallel_t>::is_valid
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
+
+  typedef typename traits::query_static_constexpr_member<T,
+    execution::bulk_guarantee_t::parallel_t>::result_type result_type;
+
+  static ASIO_CONSTEXPR result_type value()
+  {
+    return traits::query_static_constexpr_member<T,
+      execution::bulk_guarantee_t::parallel_t>::value();
+  }
+};
+
+#endif // !defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)
+       //   || !defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+
+#if !defined(ASIO_HAS_DEDUCED_STATIC_REQUIRE_TRAIT)
+
+template <typename T>
+struct static_require<T, execution::bulk_guarantee_t::unsequenced_t,
+  typename enable_if<
+    static_query<T, execution::bulk_guarantee_t::unsequenced_t>::is_valid
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid =
+    (is_same<typename static_query<T,
+      execution::bulk_guarantee_t::unsequenced_t>::result_type,
+        execution::bulk_guarantee_t::unsequenced_t>::value));
+};
+
+template <typename T>
+struct static_require<T, execution::bulk_guarantee_t::sequenced_t,
+  typename enable_if<
+    static_query<T, execution::bulk_guarantee_t::sequenced_t>::is_valid
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid =
+    (is_same<typename static_query<T,
+      execution::bulk_guarantee_t::sequenced_t>::result_type,
+        execution::bulk_guarantee_t::sequenced_t>::value));
+};
+
+template <typename T>
+struct static_require<T, execution::bulk_guarantee_t::parallel_t,
+  typename enable_if<
+    static_query<T, execution::bulk_guarantee_t::parallel_t>::is_valid
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid =
+    (is_same<typename static_query<T,
+      execution::bulk_guarantee_t::parallel_t>::result_type,
+        execution::bulk_guarantee_t::parallel_t>::value));
+};
+
+#endif // !defined(ASIO_HAS_DEDUCED_STATIC_REQUIRE_TRAIT)
+
+} // namespace traits
+
+#endif // defined(GENERATING_DOCUMENTATION)
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_EXECUTION_BULK_GUARANTEE_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/execution/connect.hpp b/link/modules/asio-standalone/asio/include/asio/execution/connect.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/execution/connect.hpp
@@ -0,0 +1,486 @@
+//
+// execution/connect.hpp
+// ~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_EXECUTION_CONNECT_HPP
+#define ASIO_EXECUTION_CONNECT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/type_traits.hpp"
+#include "asio/execution/detail/as_invocable.hpp"
+#include "asio/execution/detail/as_operation.hpp"
+#include "asio/execution/detail/as_receiver.hpp"
+#include "asio/execution/executor.hpp"
+#include "asio/execution/operation_state.hpp"
+#include "asio/execution/receiver.hpp"
+#include "asio/execution/sender.hpp"
+#include "asio/traits/connect_member.hpp"
+#include "asio/traits/connect_free.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+#if defined(GENERATING_DOCUMENTATION)
+
+namespace asio {
+namespace execution {
+
+/// A customisation point that connects a sender to a receiver.
+/**
+ * The name <tt>execution::connect</tt> denotes a customisation point object.
+ * For some subexpressions <tt>s</tt> and <tt>r</tt>, let <tt>S</tt> be a type
+ * such that <tt>decltype((s))</tt> is <tt>S</tt> and let <tt>R</tt> be a type
+ * such that <tt>decltype((r))</tt> is <tt>R</tt>. The expression
+ * <tt>execution::connect(s, r)</tt> is expression-equivalent to:
+ *
+ * @li <tt>s.connect(r)</tt>, if that expression is valid, if its type
+ *   satisfies <tt>operation_state</tt>, and if <tt>S</tt> satisfies
+ *   <tt>sender</tt>.
+ *
+ * @li Otherwise, <tt>connect(s, r)</tt>, if that expression is valid, if its
+ *   type satisfies <tt>operation_state</tt>, and if <tt>S</tt> satisfies
+ *   <tt>sender</tt>, with overload resolution performed in a context that
+ *   includes the declaration <tt>void connect();</tt> and that does not include
+ *   a declaration of <tt>execution::connect</tt>.
+ *
+ * @li Otherwise, <tt>as_operation{s, r}</tt>, if <tt>r</tt> is not an instance
+ *  of <tt>as_receiver<F, S></tt> for some type <tt>F</tt>, and if
+ *  <tt>receiver_of<R> && executor_of<remove_cvref_t<S>,
+ *  as_invocable<remove_cvref_t<R>, S>></tt> is <tt>true</tt>, where
+ *  <tt>as_operation</tt> is an implementation-defined class equivalent to
+ *  @code template <class S, class R>
+ *  struct as_operation
+ *  {
+ *    remove_cvref_t<S> e_;
+ *    remove_cvref_t<R> r_;
+ *    void start() noexcept try {
+ *      execution::execute(std::move(e_),
+ *          as_invocable<remove_cvref_t<R>, S>{r_});
+ *    } catch(...) {
+ *      execution::set_error(std::move(r_), current_exception());
+ *    }
+ *  }; @endcode
+ *  and <tt>as_invocable</tt> is a class template equivalent to the following:
+ *  @code template<class R>
+ *  struct as_invocable
+ *  {
+ *    R* r_;
+ *    explicit as_invocable(R& r) noexcept
+ *      : r_(std::addressof(r)) {}
+ *    as_invocable(as_invocable && other) noexcept
+ *      : r_(std::exchange(other.r_, nullptr)) {}
+ *    ~as_invocable() {
+ *      if(r_)
+ *        execution::set_done(std::move(*r_));
+ *    }
+ *    void operator()() & noexcept try {
+ *      execution::set_value(std::move(*r_));
+ *      r_ = nullptr;
+ *    } catch(...) {
+ *      execution::set_error(std::move(*r_), current_exception());
+ *      r_ = nullptr;
+ *    }
+ *  };
+ *  @endcode
+ *
+ * @li Otherwise, <tt>execution::connect(s, r)</tt> is ill-formed.
+ */
+inline constexpr unspecified connect = unspecified;
+
+/// A type trait that determines whether a @c connect expression is
+/// well-formed.
+/**
+ * Class template @c can_connect is a trait that is derived from
+ * @c true_type if the expression <tt>execution::connect(std::declval<S>(),
+ * std::declval<R>())</tt> is well formed; otherwise @c false_type.
+ */
+template <typename S, typename R>
+struct can_connect :
+  integral_constant<bool, automatically_determined>
+{
+};
+
+/// A type trait to determine the result of a @c connect expression.
+template <typename S, typename R>
+struct connect_result
+{
+  /// The type of the connect expression.
+  /**
+   * The type of the expression <tt>execution::connect(std::declval<S>(),
+   * std::declval<R>())</tt>.
+   */
+  typedef automatically_determined type;
+};
+
+/// A type alis to determine the result of a @c connect expression.
+template <typename S, typename R>
+using connect_result_t = typename connect_result<S, R>::type;
+
+} // namespace execution
+} // namespace asio
+
+#else // defined(GENERATING_DOCUMENTATION)
+
+namespace asio_execution_connect_fn {
+
+using asio::conditional;
+using asio::declval;
+using asio::enable_if;
+using asio::execution::detail::as_invocable;
+using asio::execution::detail::as_operation;
+using asio::execution::detail::is_as_receiver;
+using asio::execution::is_executor_of;
+using asio::execution::is_operation_state;
+using asio::execution::is_receiver;
+using asio::execution::is_sender;
+using asio::false_type;
+using asio::remove_cvref;
+using asio::traits::connect_free;
+using asio::traits::connect_member;
+
+void connect();
+
+enum overload_type
+{
+  call_member,
+  call_free,
+  adapter,
+  ill_formed
+};
+
+template <typename S, typename R, typename = void>
+struct call_traits
+{
+  ASIO_STATIC_CONSTEXPR(overload_type, overload = ill_formed);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
+  typedef void result_type;
+};
+
+template <typename S, typename R>
+struct call_traits<S, void(R),
+  typename enable_if<
+    (
+      connect_member<S, R>::is_valid
+      &&
+      is_operation_state<typename connect_member<S, R>::result_type>::value
+      &&
+      is_sender<typename remove_cvref<S>::type>::value
+    )
+  >::type> :
+  connect_member<S, R>
+{
+  ASIO_STATIC_CONSTEXPR(overload_type, overload = call_member);
+};
+
+template <typename S, typename R>
+struct call_traits<S, void(R),
+  typename enable_if<
+    (
+      !connect_member<S, R>::is_valid
+      &&
+      connect_free<S, R>::is_valid
+      &&
+      is_operation_state<typename connect_free<S, R>::result_type>::value
+      &&
+      is_sender<typename remove_cvref<S>::type>::value
+    )
+  >::type> :
+  connect_free<S, R>
+{
+  ASIO_STATIC_CONSTEXPR(overload_type, overload = call_free);
+};
+
+template <typename S, typename R>
+struct call_traits<S, void(R),
+  typename enable_if<
+    (
+      !connect_member<S, R>::is_valid
+      &&
+      !connect_free<S, R>::is_valid
+      &&
+      is_receiver<R>::value
+      &&
+      conditional<
+        !is_as_receiver<
+          typename remove_cvref<R>::type
+        >::value,
+        is_executor_of<
+          typename remove_cvref<S>::type,
+          as_invocable<typename remove_cvref<R>::type, S>
+        >,
+        false_type
+      >::type::value
+    )
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(overload_type, overload = adapter);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
+  typedef as_operation<S, R> result_type;
+};
+
+struct impl
+{
+#if defined(ASIO_HAS_MOVE)
+  template <typename S, typename R>
+  ASIO_CONSTEXPR typename enable_if<
+    call_traits<S, void(R)>::overload == call_member,
+    typename call_traits<S, void(R)>::result_type
+  >::type
+  operator()(S&& s, R&& r) const
+    ASIO_NOEXCEPT_IF((
+      call_traits<S, void(R)>::is_noexcept))
+  {
+    return ASIO_MOVE_CAST(S)(s).connect(ASIO_MOVE_CAST(R)(r));
+  }
+
+  template <typename S, typename R>
+  ASIO_CONSTEXPR typename enable_if<
+    call_traits<S, void(R)>::overload == call_free,
+    typename call_traits<S, void(R)>::result_type
+  >::type
+  operator()(S&& s, R&& r) const
+    ASIO_NOEXCEPT_IF((
+      call_traits<S, void(R)>::is_noexcept))
+  {
+    return connect(ASIO_MOVE_CAST(S)(s), ASIO_MOVE_CAST(R)(r));
+  }
+
+  template <typename S, typename R>
+  ASIO_CONSTEXPR typename enable_if<
+    call_traits<S, void(R)>::overload == adapter,
+    typename call_traits<S, void(R)>::result_type
+  >::type
+  operator()(S&& s, R&& r) const
+    ASIO_NOEXCEPT_IF((
+      call_traits<S, void(R)>::is_noexcept))
+  {
+    return typename call_traits<S, void(R)>::result_type(
+        ASIO_MOVE_CAST(S)(s), ASIO_MOVE_CAST(R)(r));
+  }
+#else // defined(ASIO_HAS_MOVE)
+  template <typename S, typename R>
+  ASIO_CONSTEXPR typename enable_if<
+    call_traits<S&, void(R&)>::overload == call_member,
+    typename call_traits<S&, void(R&)>::result_type
+  >::type
+  operator()(S& s, R& r) const
+    ASIO_NOEXCEPT_IF((
+      call_traits<S&, void(R&)>::is_noexcept))
+  {
+    return s.connect(r);
+  }
+
+  template <typename S, typename R>
+  ASIO_CONSTEXPR typename enable_if<
+    call_traits<const S&, void(R&)>::overload == call_member,
+    typename call_traits<const S&, void(R&)>::result_type
+  >::type
+  operator()(const S& s, R& r) const
+    ASIO_NOEXCEPT_IF((
+      call_traits<const S&, void(R&)>::is_noexcept))
+  {
+    return s.connect(r);
+  }
+
+  template <typename S, typename R>
+  ASIO_CONSTEXPR typename enable_if<
+    call_traits<S&, void(R&)>::overload == call_free,
+    typename call_traits<S&, void(R&)>::result_type
+  >::type
+  operator()(S& s, R& r) const
+    ASIO_NOEXCEPT_IF((
+      call_traits<S&, void(R&)>::is_noexcept))
+  {
+    return connect(s, r);
+  }
+
+  template <typename S, typename R>
+  ASIO_CONSTEXPR typename enable_if<
+    call_traits<const S&, void(R&)>::overload == call_free,
+    typename call_traits<const S&, void(R&)>::result_type
+  >::type
+  operator()(const S& s, R& r) const
+    ASIO_NOEXCEPT_IF((
+      call_traits<const S&, void(R&)>::is_noexcept))
+  {
+    return connect(s, r);
+  }
+
+  template <typename S, typename R>
+  ASIO_CONSTEXPR typename enable_if<
+    call_traits<S&, void(R&)>::overload == adapter,
+    typename call_traits<S&, void(R&)>::result_type
+  >::type
+  operator()(S& s, R& r) const
+    ASIO_NOEXCEPT_IF((
+      call_traits<S&, void(R&)>::is_noexcept))
+  {
+    return typename call_traits<S&, void(R&)>::result_type(s, r);
+  }
+
+  template <typename S, typename R>
+  ASIO_CONSTEXPR typename enable_if<
+    call_traits<const S&, void(R&)>::overload == adapter,
+    typename call_traits<const S&, void(R&)>::result_type
+  >::type
+  operator()(const S& s, R& r) const
+    ASIO_NOEXCEPT_IF((
+      call_traits<const S&, void(R&)>::is_noexcept))
+  {
+    return typename call_traits<const S&, void(R&)>::result_type(s, r);
+  }
+
+  template <typename S, typename R>
+  ASIO_CONSTEXPR typename enable_if<
+    call_traits<S&, void(const R&)>::overload == call_member,
+    typename call_traits<S&, void(const R&)>::result_type
+  >::type
+  operator()(S& s, const R& r) const
+    ASIO_NOEXCEPT_IF((
+      call_traits<S&, void(const R&)>::is_noexcept))
+  {
+    return s.connect(r);
+  }
+
+  template <typename S, typename R>
+  ASIO_CONSTEXPR typename enable_if<
+    call_traits<const S&, void(const R&)>::overload == call_member,
+    typename call_traits<const S&, void(const R&)>::result_type
+  >::type
+  operator()(const S& s, const R& r) const
+    ASIO_NOEXCEPT_IF((
+      call_traits<const S&, void(const R&)>::is_noexcept))
+  {
+    return s.connect(r);
+  }
+
+  template <typename S, typename R>
+  ASIO_CONSTEXPR typename enable_if<
+    call_traits<S&, void(const R&)>::overload == call_free,
+    typename call_traits<S&, void(const R&)>::result_type
+  >::type
+  operator()(S& s, const R& r) const
+    ASIO_NOEXCEPT_IF((
+      call_traits<S&, void(const R&)>::is_noexcept))
+  {
+    return connect(s, r);
+  }
+
+  template <typename S, typename R>
+  ASIO_CONSTEXPR typename enable_if<
+    call_traits<const S&, void(const R&)>::overload == call_free,
+    typename call_traits<const S&, void(const R&)>::result_type
+  >::type
+  operator()(const S& s, const R& r) const
+    ASIO_NOEXCEPT_IF((
+      call_traits<const S&, void(const R&)>::is_noexcept))
+  {
+    return connect(s, r);
+  }
+
+  template <typename S, typename R>
+  ASIO_CONSTEXPR typename enable_if<
+    call_traits<S&, void(const R&)>::overload == adapter,
+    typename call_traits<S&, void(const R&)>::result_type
+  >::type
+  operator()(S& s, const R& r) const
+    ASIO_NOEXCEPT_IF((
+      call_traits<S&, void(const R&)>::is_noexcept))
+  {
+    return typename call_traits<S&, void(const R&)>::result_type(s, r);
+  }
+
+  template <typename S, typename R>
+  ASIO_CONSTEXPR typename enable_if<
+    call_traits<const S&, void(const R&)>::overload == adapter,
+    typename call_traits<const S&, void(const R&)>::result_type
+  >::type
+  operator()(const S& s, const R& r) const
+    ASIO_NOEXCEPT_IF((
+      call_traits<const S&, void(const R&)>::is_noexcept))
+  {
+    return typename call_traits<const S&, void(const R&)>::result_type(s, r);
+  }
+#endif // defined(ASIO_HAS_MOVE)
+};
+
+template <typename T = impl>
+struct static_instance
+{
+  static const T instance;
+};
+
+template <typename T>
+const T static_instance<T>::instance = {};
+
+} // namespace asio_execution_connect_fn
+namespace asio {
+namespace execution {
+namespace {
+
+static ASIO_CONSTEXPR const asio_execution_connect_fn::impl&
+  connect = asio_execution_connect_fn::static_instance<>::instance;
+
+} // namespace
+
+template <typename S, typename R>
+struct can_connect :
+  integral_constant<bool,
+    asio_execution_connect_fn::call_traits<S, void(R)>::overload !=
+      asio_execution_connect_fn::ill_formed>
+{
+};
+
+#if defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+template <typename S, typename R>
+constexpr bool can_connect_v = can_connect<S, R>::value;
+
+#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+template <typename S, typename R>
+struct is_nothrow_connect :
+  integral_constant<bool,
+    asio_execution_connect_fn::call_traits<S, void(R)>::is_noexcept>
+{
+};
+
+#if defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+template <typename S, typename R>
+constexpr bool is_nothrow_connect_v
+  = is_nothrow_connect<S, R>::value;
+
+#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+template <typename S, typename R>
+struct connect_result
+{
+  typedef typename asio_execution_connect_fn::call_traits<
+      S, void(R)>::result_type type;
+};
+
+#if defined(ASIO_HAS_ALIAS_TEMPLATES)
+
+template <typename S, typename R>
+using connect_result_t = typename connect_result<S, R>::type;
+
+#endif // defined(ASIO_HAS_ALIAS_TEMPLATES)
+
+} // namespace execution
+} // namespace asio
+
+#endif // defined(GENERATING_DOCUMENTATION)
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_EXECUTION_CONNECT_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/execution/context.hpp b/link/modules/asio-standalone/asio/include/asio/execution/context.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/execution/context.hpp
@@ -0,0 +1,185 @@
+//
+// execution/context.hpp
+// ~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_EXECUTION_CONTEXT2_HPP
+#define ASIO_EXECUTION_CONTEXT2_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/type_traits.hpp"
+#include "asio/execution/executor.hpp"
+#include "asio/execution/scheduler.hpp"
+#include "asio/execution/sender.hpp"
+#include "asio/is_applicable_property.hpp"
+#include "asio/traits/query_static_constexpr_member.hpp"
+#include "asio/traits/static_query.hpp"
+
+#if defined(ASIO_HAS_STD_ANY)
+# include <any>
+#endif // defined(ASIO_HAS_STD_ANY)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+#if defined(GENERATING_DOCUMENTATION)
+
+namespace execution {
+
+/// A property that is used to obtain the execution context that is associated
+/// with an executor.
+struct context_t
+{
+  /// The context_t property applies to executors, senders, and schedulers.
+  template <typename T>
+  static constexpr bool is_applicable_property_v =
+    is_executor_v<T> || is_sender_v<T> || is_scheduler_v<T>;
+
+  /// The context_t property cannot be required.
+  static constexpr bool is_requirable = false;
+
+  /// The context_t property cannot be preferred.
+  static constexpr bool is_preferable = false;
+
+  /// The type returned by queries against an @c any_executor.
+  typedef std::any polymorphic_query_result_type;
+};
+
+/// A special value used for accessing the context_t property.
+constexpr context_t context;
+
+} // namespace execution
+
+#else // defined(GENERATING_DOCUMENTATION)
+
+namespace execution {
+namespace detail {
+
+template <int I = 0>
+struct context_t
+{
+#if defined(ASIO_HAS_VARIABLE_TEMPLATES)
+  template <typename T>
+  ASIO_STATIC_CONSTEXPR(bool,
+    is_applicable_property_v = is_executor<T>::value
+      || is_sender<T>::value || is_scheduler<T>::value);
+#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+  ASIO_STATIC_CONSTEXPR(bool, is_requirable = false);
+  ASIO_STATIC_CONSTEXPR(bool, is_preferable = false);
+
+#if defined(ASIO_HAS_STD_ANY)
+  typedef std::any polymorphic_query_result_type;
+#endif // defined(ASIO_HAS_STD_ANY)
+
+  ASIO_CONSTEXPR context_t()
+  {
+  }
+
+#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \
+  && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+  template <typename T>
+  static ASIO_CONSTEXPR
+  typename traits::query_static_constexpr_member<T, context_t>::result_type
+  static_query()
+    ASIO_NOEXCEPT_IF((
+      traits::query_static_constexpr_member<T, context_t>::is_noexcept))
+  {
+    return traits::query_static_constexpr_member<T, context_t>::value();
+  }
+
+  template <typename E, typename T = decltype(context_t::static_query<E>())>
+  static ASIO_CONSTEXPR const T static_query_v
+    = context_t::static_query<E>();
+#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)
+       //   && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+
+#if !defined(ASIO_HAS_CONSTEXPR)
+  static const context_t instance;
+#endif // !defined(ASIO_HAS_CONSTEXPR)
+};
+
+#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \
+  && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+template <int I> template <typename E, typename T>
+const T context_t<I>::static_query_v;
+#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)
+       //   && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+
+#if !defined(ASIO_HAS_CONSTEXPR)
+template <int I>
+const context_t<I> context_t<I>::instance;
+#endif
+
+} // namespace detail
+
+typedef detail::context_t<> context_t;
+
+#if defined(ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION)
+constexpr context_t context;
+#else // defined(ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION)
+namespace { static const context_t& context = context_t::instance; }
+#endif
+
+} // namespace execution
+
+#if !defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+template <typename T>
+struct is_applicable_property<T, execution::context_t>
+  : integral_constant<bool,
+      execution::is_executor<T>::value
+        || execution::is_sender<T>::value
+        || execution::is_scheduler<T>::value>
+{
+};
+
+#endif // !defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+namespace traits {
+
+#if !defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \
+  || !defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+
+template <typename T>
+struct static_query<T, execution::context_t,
+  typename enable_if<
+    traits::query_static_constexpr_member<T,
+      execution::context_t>::is_valid
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
+
+  typedef typename traits::query_static_constexpr_member<T,
+    execution::context_t>::result_type result_type;
+
+  static ASIO_CONSTEXPR result_type value()
+  {
+    return traits::query_static_constexpr_member<T,
+      execution::context_t>::value();
+  }
+};
+
+#endif // !defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)
+       //   || !defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+
+} // namespace traits
+
+#endif // defined(GENERATING_DOCUMENTATION)
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_EXECUTION_CONTEXT2_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/execution/context_as.hpp b/link/modules/asio-standalone/asio/include/asio/execution/context_as.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/execution/context_as.hpp
@@ -0,0 +1,201 @@
+//
+// execution/context_as.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_EXECUTION_CONTEXT_AS_HPP
+#define ASIO_EXECUTION_CONTEXT_AS_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/type_traits.hpp"
+#include "asio/execution/context.hpp"
+#include "asio/execution/executor.hpp"
+#include "asio/execution/scheduler.hpp"
+#include "asio/execution/sender.hpp"
+#include "asio/is_applicable_property.hpp"
+#include "asio/query.hpp"
+#include "asio/traits/query_static_constexpr_member.hpp"
+#include "asio/traits/static_query.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+#if defined(GENERATING_DOCUMENTATION)
+
+namespace execution {
+
+/// A property that is used to obtain the execution context that is associated
+/// with an executor.
+template <typename U>
+struct context_as_t
+{
+  /// The context_as_t property applies to executors, senders, and schedulers.
+  template <typename T>
+  static constexpr bool is_applicable_property_v =
+    is_executor_v<T> || is_sender_v<T> || is_scheduler_v<T>;
+
+  /// The context_t property cannot be required.
+  static constexpr bool is_requirable = false;
+
+  /// The context_t property cannot be preferred.
+  static constexpr bool is_preferable = false;
+
+  /// The type returned by queries against an @c any_executor.
+  typedef T polymorphic_query_result_type;
+};
+
+/// A special value used for accessing the context_as_t property.
+template <typename U>
+constexpr context_as_t context_as;
+
+} // namespace execution
+
+#else // defined(GENERATING_DOCUMENTATION)
+
+namespace execution {
+
+template <typename T>
+struct context_as_t
+{
+#if defined(ASIO_HAS_VARIABLE_TEMPLATES)
+  template <typename U>
+  ASIO_STATIC_CONSTEXPR(bool,
+    is_applicable_property_v = is_executor<U>::value
+      || is_sender<U>::value || is_scheduler<U>::value);
+#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+  ASIO_STATIC_CONSTEXPR(bool, is_requirable = false);
+  ASIO_STATIC_CONSTEXPR(bool, is_preferable = false);
+
+  typedef T polymorphic_query_result_type;
+
+  ASIO_CONSTEXPR context_as_t()
+  {
+  }
+
+  ASIO_CONSTEXPR context_as_t(context_t)
+  {
+  }
+
+#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \
+  && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+  template <typename E>
+  static ASIO_CONSTEXPR
+  typename traits::query_static_constexpr_member<E, context_t>::result_type
+  static_query()
+    ASIO_NOEXCEPT_IF((
+      traits::query_static_constexpr_member<E, context_t>::is_noexcept))
+  {
+    return traits::query_static_constexpr_member<E, context_t>::value();
+  }
+
+  template <typename E, typename U = decltype(context_as_t::static_query<E>())>
+  static ASIO_CONSTEXPR const U static_query_v
+    = context_as_t::static_query<E>();
+#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)
+       //   && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+
+  template <typename Executor, typename U>
+  friend ASIO_CONSTEXPR U query(
+      const Executor& ex, const context_as_t<U>&,
+      typename enable_if<
+        is_same<T, U>::value
+          && can_query<const Executor&, const context_t&>::value
+      >::type* = 0)
+#if !defined(__clang__) // Clang crashes if noexcept is used here.
+#if defined(ASIO_MSVC) // Visual C++ wants the type to be qualified.
+    ASIO_NOEXCEPT_IF((
+      is_nothrow_query<const Executor&, const context_t&>::value))
+#else // defined(ASIO_MSVC)
+    ASIO_NOEXCEPT_IF((
+      is_nothrow_query<const Executor&, const context_t&>::value))
+#endif // defined(ASIO_MSVC)
+#endif // !defined(__clang__)
+  {
+    return asio::query(ex, context);
+  }
+};
+
+#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \
+  && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+template <typename T> template <typename E, typename U>
+const U context_as_t<T>::static_query_v;
+#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)
+       //   && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+
+#if (defined(ASIO_HAS_VARIABLE_TEMPLATES) \
+    && defined(ASIO_HAS_CONSTEXPR)) \
+  || defined(GENERATING_DOCUMENTATION)
+template <typename T>
+constexpr context_as_t<T> context_as{};
+#endif // (defined(ASIO_HAS_VARIABLE_TEMPLATES)
+       //     && defined(ASIO_HAS_CONSTEXPR))
+       //   || defined(GENERATING_DOCUMENTATION)
+
+} // namespace execution
+
+#if !defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+template <typename T, typename U>
+struct is_applicable_property<T, execution::context_as_t<U> >
+  : integral_constant<bool,
+      execution::is_executor<T>::value
+        || execution::is_sender<T>::value
+        || execution::is_scheduler<T>::value>
+{
+};
+
+#endif // !defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+namespace traits {
+
+#if !defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \
+  || !defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+
+template <typename T, typename U>
+struct static_query<T, execution::context_as_t<U>,
+  typename enable_if<
+    static_query<T, execution::context_t>::is_valid
+  >::type> : static_query<T, execution::context_t>
+{
+};
+
+#endif // !defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)
+       //   || !defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+
+#if !defined(ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT)
+
+template <typename T, typename U>
+struct query_free<T, execution::context_as_t<U>,
+    typename enable_if<
+      can_query<const T&, const execution::context_t&>::value
+    >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept =
+    (is_nothrow_query<const T&, const execution::context_t&>::value));
+
+  typedef U result_type;
+};
+
+#endif // !defined(ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT)
+
+} // namespace traits
+
+#endif // defined(GENERATING_DOCUMENTATION)
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_EXECUTION_CONTEXT_AS_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/execution/detail/as_invocable.hpp b/link/modules/asio-standalone/asio/include/asio/execution/detail/as_invocable.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/execution/detail/as_invocable.hpp
@@ -0,0 +1,152 @@
+//
+// execution/detail/as_invocable.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_EXECUTION_DETAIL_AS_INVOCABLE_HPP
+#define ASIO_EXECUTION_DETAIL_AS_INVOCABLE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/atomic_count.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/detail/type_traits.hpp"
+#include "asio/execution/receiver_invocation_error.hpp"
+#include "asio/execution/set_done.hpp"
+#include "asio/execution/set_error.hpp"
+#include "asio/execution/set_value.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace execution {
+namespace detail {
+
+#if defined(ASIO_HAS_MOVE)
+
+template <typename Receiver, typename>
+struct as_invocable
+{
+  Receiver* receiver_;
+
+  explicit as_invocable(Receiver& r) ASIO_NOEXCEPT
+    : receiver_(asio::detail::addressof(r))
+  {
+  }
+
+  as_invocable(as_invocable&& other) ASIO_NOEXCEPT
+    : receiver_(other.receiver_)
+  {
+    other.receiver_ = 0;
+  }
+
+  ~as_invocable()
+  {
+    if (receiver_)
+      execution::set_done(ASIO_MOVE_OR_LVALUE(Receiver)(*receiver_));
+  }
+
+  void operator()() ASIO_LVALUE_REF_QUAL ASIO_NOEXCEPT
+  {
+#if !defined(ASIO_NO_EXCEPTIONS)
+    try
+    {
+#endif // !defined(ASIO_NO_EXCEPTIONS)
+      execution::set_value(ASIO_MOVE_CAST(Receiver)(*receiver_));
+      receiver_ = 0;
+#if !defined(ASIO_NO_EXCEPTIONS)
+    }
+    catch (...)
+    {
+#if defined(ASIO_HAS_STD_EXCEPTION_PTR)
+      execution::set_error(ASIO_MOVE_CAST(Receiver)(*receiver_),
+          std::make_exception_ptr(receiver_invocation_error()));
+      receiver_ = 0;
+#else // defined(ASIO_HAS_STD_EXCEPTION_PTR)
+      std::terminate();
+#endif // defined(ASIO_HAS_STD_EXCEPTION_PTR)
+    }
+#endif // !defined(ASIO_NO_EXCEPTIONS)
+  }
+};
+
+#else // defined(ASIO_HAS_MOVE)
+
+template <typename Receiver, typename>
+struct as_invocable
+{
+  Receiver* receiver_;
+  asio::detail::shared_ptr<asio::detail::atomic_count> ref_count_;
+
+  explicit as_invocable(Receiver& r,
+      const asio::detail::shared_ptr<
+        asio::detail::atomic_count>& c) ASIO_NOEXCEPT
+    : receiver_(asio::detail::addressof(r)),
+      ref_count_(c)
+  {
+  }
+
+  as_invocable(const as_invocable& other) ASIO_NOEXCEPT
+    : receiver_(other.receiver_),
+      ref_count_(other.ref_count_)
+  {
+    ++(*ref_count_);
+  }
+
+  ~as_invocable()
+  {
+    if (--(*ref_count_) == 0)
+      execution::set_done(*receiver_);
+  }
+
+  void operator()() ASIO_LVALUE_REF_QUAL ASIO_NOEXCEPT
+  {
+#if !defined(ASIO_NO_EXCEPTIONS)
+    try
+    {
+#endif // !defined(ASIO_NO_EXCEPTIONS)
+      execution::set_value(*receiver_);
+      ++(*ref_count_);
+    }
+#if !defined(ASIO_NO_EXCEPTIONS)
+    catch (...)
+    {
+#if defined(ASIO_HAS_STD_EXCEPTION_PTR)
+      execution::set_error(*receiver_,
+          std::make_exception_ptr(receiver_invocation_error()));
+      ++(*ref_count_);
+#else // defined(ASIO_HAS_STD_EXCEPTION_PTR)
+      std::terminate();
+#endif // defined(ASIO_HAS_STD_EXCEPTION_PTR)
+    }
+#endif // !defined(ASIO_NO_EXCEPTIONS)
+  }
+};
+
+#endif // defined(ASIO_HAS_MOVE)
+
+template <typename T>
+struct is_as_invocable : false_type
+{
+};
+
+template <typename Function, typename T>
+struct is_as_invocable<as_invocable<Function, T> > : true_type
+{
+};
+
+} // namespace detail
+} // namespace execution
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_EXECUTION_DETAIL_AS_INVOCABLE_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/execution/detail/as_operation.hpp b/link/modules/asio-standalone/asio/include/asio/execution/detail/as_operation.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/execution/detail/as_operation.hpp
@@ -0,0 +1,105 @@
+//
+// execution/detail/as_operation.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_EXECUTION_DETAIL_AS_OPERATION_HPP
+#define ASIO_EXECUTION_DETAIL_AS_OPERATION_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/detail/type_traits.hpp"
+#include "asio/execution/detail/as_invocable.hpp"
+#include "asio/execution/execute.hpp"
+#include "asio/execution/set_error.hpp"
+#include "asio/traits/start_member.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace execution {
+namespace detail {
+
+template <typename Executor, typename Receiver>
+struct as_operation
+{
+  typename remove_cvref<Executor>::type ex_;
+  typename remove_cvref<Receiver>::type receiver_;
+#if !defined(ASIO_HAS_MOVE)
+  asio::detail::shared_ptr<asio::detail::atomic_count> ref_count_;
+#endif // !defined(ASIO_HAS_MOVE)
+
+  template <typename E, typename R>
+  explicit as_operation(ASIO_MOVE_ARG(E) e, ASIO_MOVE_ARG(R) r)
+    : ex_(ASIO_MOVE_CAST(E)(e)),
+      receiver_(ASIO_MOVE_CAST(R)(r))
+#if !defined(ASIO_HAS_MOVE)
+      , ref_count_(new asio::detail::atomic_count(1))
+#endif // !defined(ASIO_HAS_MOVE)
+  {
+  }
+
+  void start() ASIO_NOEXCEPT
+  {
+#if !defined(ASIO_NO_EXCEPTIONS)
+    try
+    {
+#endif // !defined(ASIO_NO_EXCEPTIONS)
+      execution::execute(
+          ASIO_MOVE_CAST(typename remove_cvref<Executor>::type)(ex_),
+          as_invocable<typename remove_cvref<Receiver>::type,
+              Executor>(receiver_
+#if !defined(ASIO_HAS_MOVE)
+                , ref_count_
+#endif // !defined(ASIO_HAS_MOVE)
+              ));
+#if !defined(ASIO_NO_EXCEPTIONS)
+    }
+    catch (...)
+    {
+#if defined(ASIO_HAS_STD_EXCEPTION_PTR)
+      execution::set_error(
+          ASIO_MOVE_OR_LVALUE(
+            typename remove_cvref<Receiver>::type)(
+              receiver_),
+          std::current_exception());
+#else // defined(ASIO_HAS_STD_EXCEPTION_PTR)
+      std::terminate();
+#endif // defined(ASIO_HAS_STD_EXCEPTION_PTR)
+    }
+#endif // !defined(ASIO_NO_EXCEPTIONS)
+  }
+};
+
+} // namespace detail
+} // namespace execution
+namespace traits {
+
+#if !defined(ASIO_HAS_DEDUCED_START_MEMBER_TRAIT)
+
+template <typename Executor, typename Receiver>
+struct start_member<
+    asio::execution::detail::as_operation<Executor, Receiver> >
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
+  typedef void result_type;
+};
+
+#endif // !defined(ASIO_HAS_DEDUCED_START_MEMBER_TRAIT)
+
+} // namespace traits
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_EXECUTION_DETAIL_AS_OPERATION_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/execution/detail/as_receiver.hpp b/link/modules/asio-standalone/asio/include/asio/execution/detail/as_receiver.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/execution/detail/as_receiver.hpp
@@ -0,0 +1,128 @@
+//
+// execution/detail/as_receiver.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_EXECUTION_DETAIL_AS_RECEIVER_HPP
+#define ASIO_EXECUTION_DETAIL_AS_RECEIVER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/type_traits.hpp"
+#include "asio/traits/set_done_member.hpp"
+#include "asio/traits/set_error_member.hpp"
+#include "asio/traits/set_value_member.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace execution {
+namespace detail {
+
+template <typename Function, typename>
+struct as_receiver
+{
+  Function f_;
+
+  template <typename F>
+  explicit as_receiver(ASIO_MOVE_ARG(F) f, int)
+    : f_(ASIO_MOVE_CAST(F)(f))
+  {
+  }
+
+#if defined(ASIO_MSVC) && defined(ASIO_HAS_MOVE)
+  as_receiver(as_receiver&& other)
+    : f_(ASIO_MOVE_CAST(Function)(other.f_))
+  {
+  }
+#endif // defined(ASIO_MSVC) && defined(ASIO_HAS_MOVE)
+
+  void set_value()
+    ASIO_NOEXCEPT_IF(noexcept(declval<Function&>()()))
+  {
+    f_();
+  }
+
+  template <typename E>
+  void set_error(E) ASIO_NOEXCEPT
+  {
+    std::terminate();
+  }
+
+  void set_done() ASIO_NOEXCEPT
+  {
+  }
+};
+
+template <typename T>
+struct is_as_receiver : false_type
+{
+};
+
+template <typename Function, typename T>
+struct is_as_receiver<as_receiver<Function, T> > : true_type
+{
+};
+
+} // namespace detail
+} // namespace execution
+namespace traits {
+
+#if !defined(ASIO_HAS_DEDUCED_SET_VALUE_MEMBER_TRAIT)
+
+template <typename Function, typename T>
+struct set_value_member<
+    asio::execution::detail::as_receiver<Function, T>, void()>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+#if defined(ASIO_HAS_NOEXCEPT)
+  ASIO_STATIC_CONSTEXPR(bool,
+      is_noexcept = noexcept(declval<Function&>()()));
+#else // defined(ASIO_HAS_NOEXCEPT)
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
+#endif // defined(ASIO_HAS_NOEXCEPT)
+  typedef void result_type;
+};
+
+#endif // !defined(ASIO_HAS_DEDUCED_SET_VALUE_MEMBER_TRAIT)
+
+#if !defined(ASIO_HAS_DEDUCED_SET_ERROR_MEMBER_TRAIT)
+
+template <typename Function, typename T, typename E>
+struct set_error_member<
+    asio::execution::detail::as_receiver<Function, T>, E>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
+  typedef void result_type;
+};
+
+#endif // !defined(ASIO_HAS_DEDUCED_SET_ERROR_MEMBER_TRAIT)
+
+#if !defined(ASIO_HAS_DEDUCED_SET_DONE_MEMBER_TRAIT)
+
+template <typename Function, typename T>
+struct set_done_member<
+    asio::execution::detail::as_receiver<Function, T> >
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
+  typedef void result_type;
+};
+
+#endif // !defined(ASIO_HAS_DEDUCED_SET_DONE_MEMBER_TRAIT)
+
+} // namespace traits
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_EXECUTION_DETAIL_AS_RECEIVER_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/execution/detail/bulk_sender.hpp b/link/modules/asio-standalone/asio/include/asio/execution/detail/bulk_sender.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/execution/detail/bulk_sender.hpp
@@ -0,0 +1,261 @@
+//
+// execution/detail/bulk_sender.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_EXECUTION_DETAIL_BULK_SENDER_HPP
+#define ASIO_EXECUTION_DETAIL_BULK_SENDER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/type_traits.hpp"
+#include "asio/execution/connect.hpp"
+#include "asio/execution/executor.hpp"
+#include "asio/execution/set_done.hpp"
+#include "asio/execution/set_error.hpp"
+#include "asio/traits/connect_member.hpp"
+#include "asio/traits/set_done_member.hpp"
+#include "asio/traits/set_error_member.hpp"
+#include "asio/traits/set_value_member.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace execution {
+namespace detail {
+
+template <typename Receiver, typename Function, typename Number, typename Index>
+struct bulk_receiver
+{
+  typename remove_cvref<Receiver>::type receiver_;
+  typename decay<Function>::type f_;
+  typename decay<Number>::type n_;
+
+  template <typename R, typename F, typename N>
+  explicit bulk_receiver(ASIO_MOVE_ARG(R) r,
+      ASIO_MOVE_ARG(F) f, ASIO_MOVE_ARG(N) n)
+    : receiver_(ASIO_MOVE_CAST(R)(r)),
+      f_(ASIO_MOVE_CAST(F)(f)),
+      n_(ASIO_MOVE_CAST(N)(n))
+  {
+  }
+
+  void set_value()
+  {
+    for (Index i = 0; i < n_; ++i)
+      f_(i);
+
+    execution::set_value(
+        ASIO_MOVE_OR_LVALUE(
+          typename remove_cvref<Receiver>::type)(receiver_));
+  }
+
+  template <typename Error>
+  void set_error(ASIO_MOVE_ARG(Error) e) ASIO_NOEXCEPT
+  {
+    execution::set_error(
+        ASIO_MOVE_OR_LVALUE(
+          typename remove_cvref<Receiver>::type)(receiver_),
+        ASIO_MOVE_CAST(Error)(e));
+  }
+
+  void set_done() ASIO_NOEXCEPT
+  {
+    execution::set_done(
+        ASIO_MOVE_OR_LVALUE(
+          typename remove_cvref<Receiver>::type)(receiver_));
+  }
+};
+
+template <typename Sender, typename Receiver,
+  typename Function, typename Number>
+struct bulk_receiver_traits
+{
+  typedef bulk_receiver<
+      Receiver, Function, Number,
+      typename execution::executor_index<
+        typename remove_cvref<Sender>::type
+      >::type
+    > type;
+
+#if defined(ASIO_HAS_MOVE)
+  typedef type arg_type;
+#else // defined(ASIO_HAS_MOVE)
+  typedef const type& arg_type;
+#endif // defined(ASIO_HAS_MOVE)
+};
+
+template <typename Sender, typename Function, typename Number>
+struct bulk_sender : sender_base
+{
+  typename remove_cvref<Sender>::type sender_;
+  typename decay<Function>::type f_;
+  typename decay<Number>::type n_;
+
+  template <typename S, typename F, typename N>
+  explicit bulk_sender(ASIO_MOVE_ARG(S) s,
+      ASIO_MOVE_ARG(F) f, ASIO_MOVE_ARG(N) n)
+    : sender_(ASIO_MOVE_CAST(S)(s)),
+      f_(ASIO_MOVE_CAST(F)(f)),
+      n_(ASIO_MOVE_CAST(N)(n))
+  {
+  }
+
+  template <typename Receiver>
+  typename connect_result<
+      ASIO_MOVE_OR_LVALUE_TYPE(typename remove_cvref<Sender>::type),
+      typename bulk_receiver_traits<
+        Sender, Receiver, Function, Number
+      >::arg_type
+  >::type connect(ASIO_MOVE_ARG(Receiver) r,
+      typename enable_if<
+        can_connect<
+          typename remove_cvref<Sender>::type,
+          typename bulk_receiver_traits<
+            Sender, Receiver, Function, Number
+          >::arg_type
+        >::value
+      >::type* = 0) ASIO_RVALUE_REF_QUAL ASIO_NOEXCEPT
+  {
+    return execution::connect(
+        ASIO_MOVE_OR_LVALUE(typename remove_cvref<Sender>::type)(sender_),
+        typename bulk_receiver_traits<Sender, Receiver, Function, Number>::type(
+          ASIO_MOVE_CAST(Receiver)(r),
+          ASIO_MOVE_CAST(typename decay<Function>::type)(f_),
+          ASIO_MOVE_CAST(typename decay<Number>::type)(n_)));
+  }
+
+  template <typename Receiver>
+  typename connect_result<
+      const typename remove_cvref<Sender>::type&,
+      typename bulk_receiver_traits<
+        Sender, Receiver, Function, Number
+      >::arg_type
+  >::type connect(ASIO_MOVE_ARG(Receiver) r,
+      typename enable_if<
+        can_connect<
+          const typename remove_cvref<Sender>::type&,
+          typename bulk_receiver_traits<
+            Sender, Receiver, Function, Number
+          >::arg_type
+        >::value
+      >::type* = 0) const ASIO_LVALUE_REF_QUAL ASIO_NOEXCEPT
+  {
+    return execution::connect(sender_,
+        typename bulk_receiver_traits<Sender, Receiver, Function, Number>::type(
+          ASIO_MOVE_CAST(Receiver)(r), f_, n_));
+  }
+};
+
+} // namespace detail
+} // namespace execution
+namespace traits {
+
+#if !defined(ASIO_HAS_DEDUCED_SET_VALUE_MEMBER_TRAIT)
+
+template <typename Receiver, typename Function, typename Number, typename Index>
+struct set_value_member<
+    execution::detail::bulk_receiver<Receiver, Function, Number, Index>,
+    void()>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
+  typedef void result_type;
+};
+
+#endif // !defined(ASIO_HAS_DEDUCED_SET_VALUE_MEMBER_TRAIT)
+
+#if !defined(ASIO_HAS_DEDUCED_SET_ERROR_MEMBER_TRAIT)
+
+template <typename Receiver, typename Function,
+    typename Number, typename Index, typename Error>
+struct set_error_member<
+    execution::detail::bulk_receiver<Receiver, Function, Number, Index>,
+    Error>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
+  typedef void result_type;
+};
+
+#endif // !defined(ASIO_HAS_DEDUCED_SET_ERROR_MEMBER_TRAIT)
+
+#if !defined(ASIO_HAS_DEDUCED_SET_DONE_MEMBER_TRAIT)
+
+template <typename Receiver, typename Function, typename Number, typename Index>
+struct set_done_member<
+    execution::detail::bulk_receiver<Receiver, Function, Number, Index> >
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
+  typedef void result_type;
+};
+
+#endif // !defined(ASIO_HAS_DEDUCED_SET_DONE_MEMBER_TRAIT)
+
+#if !defined(ASIO_HAS_DEDUCED_CONNECT_MEMBER_TRAIT)
+
+template <typename Sender, typename Function,
+    typename Number, typename Receiver>
+struct connect_member<
+    execution::detail::bulk_sender<Sender, Function, Number>,
+    Receiver,
+    typename enable_if<
+      execution::can_connect<
+        ASIO_MOVE_OR_LVALUE_TYPE(typename remove_cvref<Sender>::type),
+        typename execution::detail::bulk_receiver_traits<
+          Sender, Receiver, Function, Number
+        >::arg_type
+      >::value
+    >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
+  typedef typename execution::connect_result<
+      ASIO_MOVE_OR_LVALUE_TYPE(typename remove_cvref<Sender>::type),
+      typename execution::detail::bulk_receiver_traits<
+        Sender, Receiver, Function, Number
+      >::arg_type
+    >::type result_type;
+};
+
+template <typename Sender, typename Function,
+    typename Number, typename Receiver>
+struct connect_member<
+    const execution::detail::bulk_sender<Sender, Function, Number>,
+    Receiver,
+    typename enable_if<
+      execution::can_connect<
+        const typename remove_cvref<Sender>::type&,
+        typename execution::detail::bulk_receiver_traits<
+          Sender, Receiver, Function, Number
+        >::arg_type
+      >::value
+    >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
+  typedef typename execution::connect_result<
+      const typename remove_cvref<Sender>::type&,
+      typename execution::detail::bulk_receiver_traits<
+        Sender, Receiver, Function, Number
+      >::arg_type
+    >::type result_type;
+};
+
+#endif // !defined(ASIO_HAS_DEDUCED_CONNECT_MEMBER_TRAIT)
+
+} // namespace traits
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_EXECUTION_DETAIL_BULK_SENDER_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/execution/detail/submit_receiver.hpp b/link/modules/asio-standalone/asio/include/asio/execution/detail/submit_receiver.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/execution/detail/submit_receiver.hpp
@@ -0,0 +1,233 @@
+//
+// execution/detail/submit_receiver.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_EXECUTION_DETAIL_SUBMIT_RECEIVER_HPP
+#define ASIO_EXECUTION_DETAIL_SUBMIT_RECEIVER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/type_traits.hpp"
+#include "asio/detail/variadic_templates.hpp"
+#include "asio/execution/connect.hpp"
+#include "asio/execution/receiver.hpp"
+#include "asio/execution/set_done.hpp"
+#include "asio/execution/set_error.hpp"
+#include "asio/execution/set_value.hpp"
+#include "asio/traits/set_done_member.hpp"
+#include "asio/traits/set_error_member.hpp"
+#include "asio/traits/set_value_member.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace execution {
+namespace detail {
+
+template <typename Sender, typename Receiver>
+struct submit_receiver;
+
+template <typename Sender, typename Receiver>
+struct submit_receiver_wrapper
+{
+  submit_receiver<Sender, Receiver>* p_;
+
+  explicit submit_receiver_wrapper(submit_receiver<Sender, Receiver>* p)
+    : p_(p)
+  {
+  }
+
+#if defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+  template <typename... Args>
+  typename enable_if<is_receiver_of<Receiver, Args...>::value>::type
+  set_value(ASIO_MOVE_ARG(Args)... args) ASIO_RVALUE_REF_QUAL
+    ASIO_NOEXCEPT_IF((is_nothrow_receiver_of<Receiver, Args...>::value))
+  {
+    execution::set_value(
+        ASIO_MOVE_OR_LVALUE(
+          typename remove_cvref<Receiver>::type)(p_->r_),
+        ASIO_MOVE_CAST(Args)(args)...);
+    delete p_;
+  }
+
+#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+  void set_value() ASIO_RVALUE_REF_QUAL
+    ASIO_NOEXCEPT_IF((is_nothrow_receiver_of<Receiver>::value))
+  {
+    execution::set_value(
+        ASIO_MOVE_OR_LVALUE(
+          typename remove_cvref<Receiver>::type)(p_->r_));
+    delete p_;
+  }
+
+#define ASIO_PRIVATE_SUBMIT_RECEIVER_SET_VALUE_DEF(n) \
+  template <ASIO_VARIADIC_TPARAMS(n)> \
+  typename enable_if<is_receiver_of<Receiver, \
+    ASIO_VARIADIC_TARGS(n)>::value>::type \
+  set_value(ASIO_VARIADIC_MOVE_PARAMS(n)) ASIO_RVALUE_REF_QUAL \
+    ASIO_NOEXCEPT_IF((is_nothrow_receiver_of< \
+      Receiver, ASIO_VARIADIC_TARGS(n)>::value)) \
+  { \
+    execution::set_value( \
+        ASIO_MOVE_OR_LVALUE( \
+          typename remove_cvref<Receiver>::type)(p_->r_), \
+        ASIO_VARIADIC_MOVE_ARGS(n)); \
+    delete p_; \
+  } \
+  /**/
+ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_SUBMIT_RECEIVER_SET_VALUE_DEF)
+#undef ASIO_PRIVATE_SUBMIT_RECEIVER_SET_VALUE_DEF
+
+#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+  template <typename E>
+  void set_error(ASIO_MOVE_ARG(E) e)
+    ASIO_RVALUE_REF_QUAL ASIO_NOEXCEPT
+  {
+    execution::set_error(
+        ASIO_MOVE_OR_LVALUE(
+          typename remove_cvref<Receiver>::type)(p_->r_),
+        ASIO_MOVE_CAST(E)(e));
+    delete p_;
+  }
+
+  void set_done() ASIO_RVALUE_REF_QUAL ASIO_NOEXCEPT
+  {
+    execution::set_done(
+        ASIO_MOVE_OR_LVALUE(
+          typename remove_cvref<Receiver>::type)(p_->r_));
+    delete p_;
+  }
+};
+
+template <typename Sender, typename Receiver>
+struct submit_receiver
+{
+  typename remove_cvref<Receiver>::type r_;
+#if defined(ASIO_HAS_MOVE)
+  typename connect_result<Sender,
+      submit_receiver_wrapper<Sender, Receiver> >::type state_;
+#else // defined(ASIO_HAS_MOVE)
+  typename connect_result<Sender,
+      const submit_receiver_wrapper<Sender, Receiver>& >::type state_;
+#endif // defined(ASIO_HAS_MOVE)
+
+#if defined(ASIO_HAS_MOVE)
+  template <typename S, typename R>
+  explicit submit_receiver(ASIO_MOVE_ARG(S) s, ASIO_MOVE_ARG(R) r)
+    : r_(ASIO_MOVE_CAST(R)(r)),
+      state_(execution::connect(ASIO_MOVE_CAST(S)(s),
+            submit_receiver_wrapper<Sender, Receiver>(this)))
+  {
+  }
+#else // defined(ASIO_HAS_MOVE)
+  explicit submit_receiver(Sender s, Receiver r)
+    : r_(r),
+      state_(execution::connect(s,
+            submit_receiver_wrapper<Sender, Receiver>(this)))
+  {
+  }
+#endif // defined(ASIO_HAS_MOVE)
+};
+
+} // namespace detail
+} // namespace execution
+namespace traits {
+
+#if !defined(ASIO_HAS_DEDUCED_SET_VALUE_MEMBER_TRAIT)
+
+#if defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+template <typename Sender, typename Receiver, typename... Args>
+struct set_value_member<
+    asio::execution::detail::submit_receiver_wrapper<
+      Sender, Receiver>,
+    void(Args...)>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept =
+    (asio::execution::is_nothrow_receiver_of<Receiver, Args...>::value));
+  typedef void result_type;
+};
+
+#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+template <typename Sender, typename Receiver>
+struct set_value_member<
+    asio::execution::detail::submit_receiver_wrapper<
+      Sender, Receiver>,
+    void()>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept =
+    asio::execution::is_nothrow_receiver_of<Receiver>::value);
+  typedef void result_type;
+};
+
+#define ASIO_PRIVATE_SUBMIT_RECEIVER_TRAIT_DEF(n) \
+  template <typename Sender, typename Receiver, \
+      ASIO_VARIADIC_TPARAMS(n)> \
+  struct set_value_member< \
+      asio::execution::detail::submit_receiver_wrapper< \
+        Sender, Receiver>, \
+      void(ASIO_VARIADIC_TARGS(n))> \
+  { \
+    ASIO_STATIC_CONSTEXPR(bool, is_valid = true); \
+    ASIO_STATIC_CONSTEXPR(bool, is_noexcept = \
+      (asio::execution::is_nothrow_receiver_of<Receiver, \
+        ASIO_VARIADIC_TARGS(n)>::value)); \
+    typedef void result_type; \
+  }; \
+  /**/
+ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_SUBMIT_RECEIVER_TRAIT_DEF)
+#undef ASIO_PRIVATE_SUBMIT_RECEIVER_TRAIT_DEF
+
+#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+#endif // !defined(ASIO_HAS_DEDUCED_SET_VALUE_MEMBER_TRAIT)
+
+#if !defined(ASIO_HAS_DEDUCED_SET_ERROR_MEMBER_TRAIT)
+
+template <typename Sender, typename Receiver, typename E>
+struct set_error_member<
+    asio::execution::detail::submit_receiver_wrapper<
+      Sender, Receiver>, E>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
+  typedef void result_type;
+};
+
+#endif // !defined(ASIO_HAS_DEDUCED_SET_ERROR_MEMBER_TRAIT)
+
+#if !defined(ASIO_HAS_DEDUCED_SET_DONE_MEMBER_TRAIT)
+
+template <typename Sender, typename Receiver>
+struct set_done_member<
+    asio::execution::detail::submit_receiver_wrapper<
+      Sender, Receiver> >
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
+  typedef void result_type;
+};
+
+#endif // !defined(ASIO_HAS_DEDUCED_SET_DONE_MEMBER_TRAIT)
+
+} // namespace traits
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_EXECUTION_DETAIL_SUBMIT_RECEIVER_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/execution/detail/void_receiver.hpp b/link/modules/asio-standalone/asio/include/asio/execution/detail/void_receiver.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/execution/detail/void_receiver.hpp
@@ -0,0 +1,90 @@
+//
+// execution/detail/void_receiver.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_EXECUTION_DETAIL_VOID_RECEIVER_HPP
+#define ASIO_EXECUTION_DETAIL_VOID_RECEIVER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/traits/set_done_member.hpp"
+#include "asio/traits/set_error_member.hpp"
+#include "asio/traits/set_value_member.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace execution {
+namespace detail {
+
+struct void_receiver
+{
+  void set_value() ASIO_NOEXCEPT
+  {
+  }
+
+  template <typename E>
+  void set_error(ASIO_MOVE_ARG(E)) ASIO_NOEXCEPT
+  {
+  }
+
+  void set_done() ASIO_NOEXCEPT
+  {
+  }
+};
+
+} // namespace detail
+} // namespace execution
+namespace traits {
+
+#if !defined(ASIO_HAS_DEDUCED_SET_VALUE_MEMBER_TRAIT)
+
+template <>
+struct set_value_member<asio::execution::detail::void_receiver, void()>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
+  typedef void result_type;
+};
+
+#endif // !defined(ASIO_HAS_DEDUCED_SET_VALUE_MEMBER_TRAIT)
+
+#if !defined(ASIO_HAS_DEDUCED_SET_ERROR_MEMBER_TRAIT)
+
+template <typename E>
+struct set_error_member<asio::execution::detail::void_receiver, E>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
+  typedef void result_type;
+};
+
+#endif // !defined(ASIO_HAS_DEDUCED_SET_ERROR_MEMBER_TRAIT)
+
+#if !defined(ASIO_HAS_DEDUCED_SET_DONE_MEMBER_TRAIT)
+
+template <>
+struct set_done_member<asio::execution::detail::void_receiver>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
+  typedef void result_type;
+};
+
+#endif // !defined(ASIO_HAS_DEDUCED_SET_DONE_MEMBER_TRAIT)
+
+} // namespace traits
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_EXECUTION_DETAIL_VOID_RECEIVER_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/execution/execute.hpp b/link/modules/asio-standalone/asio/include/asio/execution/execute.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/execution/execute.hpp
@@ -0,0 +1,264 @@
+//
+// execution/execute.hpp
+// ~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_EXECUTION_EXECUTE_HPP
+#define ASIO_EXECUTION_EXECUTE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/type_traits.hpp"
+#include "asio/execution/detail/as_invocable.hpp"
+#include "asio/execution/detail/as_receiver.hpp"
+#include "asio/traits/execute_member.hpp"
+#include "asio/traits/execute_free.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+#if defined(GENERATING_DOCUMENTATION)
+
+namespace asio {
+namespace execution {
+
+/// A customisation point that executes a function on an executor.
+/**
+ * The name <tt>execution::execute</tt> denotes a customisation point object.
+ *
+ * For some subexpressions <tt>e</tt> and <tt>f</tt>, let <tt>E</tt> be a type
+ * such that <tt>decltype((e))</tt> is <tt>E</tt> and let <tt>F</tt> be a type
+ * such that <tt>decltype((f))</tt> is <tt>F</tt>. The expression
+ * <tt>execution::execute(e, f)</tt> is ill-formed if <tt>F</tt> does not model
+ * <tt>invocable</tt>, or if <tt>E</tt> does not model either <tt>executor</tt>
+ * or <tt>sender</tt>. Otherwise, it is expression-equivalent to:
+ *
+ * @li <tt>e.execute(f)</tt>, if that expression is valid. If the function
+ *   selected does not execute the function object <tt>f</tt> on the executor
+ *   <tt>e</tt>, the program is ill-formed with no diagnostic required.
+ *
+ * @li Otherwise, <tt>execute(e, f)</tt>, if that expression is valid, with
+ *   overload resolution performed in a context that includes the declaration
+ *   <tt>void execute();</tt> and that does not include a declaration of
+ *   <tt>execution::execute</tt>. If the function selected by overload
+ *   resolution does not execute the function object <tt>f</tt> on the executor
+ *   <tt>e</tt>, the program is ill-formed with no diagnostic required.
+ */
+inline constexpr unspecified execute = unspecified;
+
+/// A type trait that determines whether a @c execute expression is well-formed.
+/**
+ * Class template @c can_execute is a trait that is derived from
+ * @c true_type if the expression <tt>execution::execute(std::declval<T>(),
+ * std::declval<F>())</tt> is well formed; otherwise @c false_type.
+ */
+template <typename T, typename F>
+struct can_execute :
+  integral_constant<bool, automatically_determined>
+{
+};
+
+} // namespace execution
+} // namespace asio
+
+#else // defined(GENERATING_DOCUMENTATION)
+
+namespace asio {
+namespace execution {
+
+template <typename T, typename R>
+struct is_sender_to;
+
+namespace detail {
+
+template <typename S, typename R>
+void submit_helper(ASIO_MOVE_ARG(S) s, ASIO_MOVE_ARG(R) r);
+
+} // namespace detail
+} // namespace execution
+} // namespace asio
+namespace asio_execution_execute_fn {
+
+using asio::conditional;
+using asio::decay;
+using asio::declval;
+using asio::enable_if;
+using asio::execution::detail::as_receiver;
+using asio::execution::detail::is_as_invocable;
+using asio::execution::is_sender_to;
+using asio::false_type;
+using asio::result_of;
+using asio::traits::execute_free;
+using asio::traits::execute_member;
+using asio::true_type;
+
+void execute();
+
+enum overload_type
+{
+  call_member,
+  call_free,
+  adapter,
+  ill_formed
+};
+
+template <typename T, typename F, typename = void>
+struct call_traits
+{
+  ASIO_STATIC_CONSTEXPR(overload_type, overload = ill_formed);
+};
+
+template <typename T, typename F>
+struct call_traits<T, void(F),
+  typename enable_if<
+    (
+      execute_member<T, F>::is_valid
+    )
+  >::type> :
+  execute_member<T, F>
+{
+  ASIO_STATIC_CONSTEXPR(overload_type, overload = call_member);
+};
+
+template <typename T, typename F>
+struct call_traits<T, void(F),
+  typename enable_if<
+    (
+      !execute_member<T, F>::is_valid
+      &&
+      execute_free<T, F>::is_valid
+    )
+  >::type> :
+  execute_free<T, F>
+{
+  ASIO_STATIC_CONSTEXPR(overload_type, overload = call_free);
+};
+
+template <typename T, typename F>
+struct call_traits<T, void(F),
+  typename enable_if<
+    (
+      !execute_member<T, F>::is_valid
+      &&
+      !execute_free<T, F>::is_valid
+      &&
+      conditional<true, true_type,
+       typename result_of<typename decay<F>::type&()>::type
+      >::type::value
+      &&
+      conditional<
+        !is_as_invocable<
+          typename decay<F>::type
+        >::value,
+        is_sender_to<
+          T,
+          as_receiver<typename decay<F>::type, T>
+        >,
+        false_type
+      >::type::value
+    )
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(overload_type, overload = adapter);
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
+  typedef void result_type;
+};
+
+struct impl
+{
+  template <typename T, typename F>
+  ASIO_CONSTEXPR typename enable_if<
+    call_traits<T, void(F)>::overload == call_member,
+    typename call_traits<T, void(F)>::result_type
+  >::type
+  operator()(
+      ASIO_MOVE_ARG(T) t,
+      ASIO_MOVE_ARG(F) f) const
+    ASIO_NOEXCEPT_IF((
+      call_traits<T, void(F)>::is_noexcept))
+  {
+    return ASIO_MOVE_CAST(T)(t).execute(ASIO_MOVE_CAST(F)(f));
+  }
+
+  template <typename T, typename F>
+  ASIO_CONSTEXPR typename enable_if<
+    call_traits<T, void(F)>::overload == call_free,
+    typename call_traits<T, void(F)>::result_type
+  >::type
+  operator()(
+      ASIO_MOVE_ARG(T) t,
+      ASIO_MOVE_ARG(F) f) const
+    ASIO_NOEXCEPT_IF((
+      call_traits<T, void(F)>::is_noexcept))
+  {
+    return execute(ASIO_MOVE_CAST(T)(t), ASIO_MOVE_CAST(F)(f));
+  }
+
+  template <typename T, typename F>
+  ASIO_CONSTEXPR typename enable_if<
+    call_traits<T, void(F)>::overload == adapter,
+    typename call_traits<T, void(F)>::result_type
+  >::type
+  operator()(
+      ASIO_MOVE_ARG(T) t,
+      ASIO_MOVE_ARG(F) f) const
+    ASIO_NOEXCEPT_IF((
+      call_traits<T, void(F)>::is_noexcept))
+  {
+    return asio::execution::detail::submit_helper(
+        ASIO_MOVE_CAST(T)(t),
+        as_receiver<typename decay<F>::type, T>(
+          ASIO_MOVE_CAST(F)(f), 0));
+  }
+};
+
+template <typename T = impl>
+struct static_instance
+{
+  static const T instance;
+};
+
+template <typename T>
+const T static_instance<T>::instance = {};
+
+} // namespace asio_execution_execute_fn
+namespace asio {
+namespace execution {
+namespace {
+
+static ASIO_CONSTEXPR const asio_execution_execute_fn::impl&
+  execute = asio_execution_execute_fn::static_instance<>::instance;
+
+} // namespace
+
+template <typename T, typename F>
+struct can_execute :
+  integral_constant<bool,
+    asio_execution_execute_fn::call_traits<T, void(F)>::overload !=
+      asio_execution_execute_fn::ill_formed>
+{
+};
+
+#if defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+template <typename T, typename F>
+constexpr bool can_execute_v = can_execute<T, F>::value;
+
+#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+} // namespace execution
+} // namespace asio
+
+#endif // defined(GENERATING_DOCUMENTATION)
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_EXECUTION_EXECUTE_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/execution/executor.hpp b/link/modules/asio-standalone/asio/include/asio/execution/executor.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/execution/executor.hpp
@@ -0,0 +1,238 @@
+//
+// execution/executor.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_EXECUTION_EXECUTOR_HPP
+#define ASIO_EXECUTION_EXECUTOR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/type_traits.hpp"
+#include "asio/execution/execute.hpp"
+#include "asio/execution/invocable_archetype.hpp"
+#include "asio/traits/equality_comparable.hpp"
+
+#if defined(ASIO_HAS_DEDUCED_EXECUTE_FREE_TRAIT) \
+  && defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT) \
+  && defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)
+# define ASIO_HAS_DEDUCED_EXECUTION_IS_EXECUTOR_TRAIT 1
+#endif // defined(ASIO_HAS_DEDUCED_EXECUTE_FREE_TRAIT)
+       //   && defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)
+       //   && defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace execution {
+namespace detail {
+
+template <typename T, typename F>
+struct is_executor_of_impl_base :
+  integral_constant<bool,
+    conditional<true, true_type,
+        typename result_of<typename decay<F>::type&()>::type
+      >::type::value
+      && is_constructible<typename decay<F>::type, F>::value
+      && is_move_constructible<typename decay<F>::type>::value
+#if defined(ASIO_HAS_NOEXCEPT)
+      && is_nothrow_copy_constructible<T>::value
+      && is_nothrow_destructible<T>::value
+#else // defined(ASIO_HAS_NOEXCEPT)
+      && is_copy_constructible<T>::value
+      && is_destructible<T>::value
+#endif // defined(ASIO_HAS_NOEXCEPT)
+      && traits::equality_comparable<T>::is_valid
+      && traits::equality_comparable<T>::is_noexcept
+  >
+{
+};
+
+template <typename T, typename F>
+struct is_executor_of_impl :
+  conditional<
+    can_execute<T, F>::value,
+    is_executor_of_impl_base<T, F>,
+    false_type
+  >::type
+{
+};
+
+template <typename T, typename = void>
+struct executor_shape
+{
+  typedef std::size_t type;
+};
+
+template <typename T>
+struct executor_shape<T,
+    typename void_type<
+      typename T::shape_type
+    >::type>
+{
+  typedef typename T::shape_type type;
+};
+
+template <typename T, typename Default, typename = void>
+struct executor_index
+{
+  typedef Default type;
+};
+
+template <typename T, typename Default>
+struct executor_index<T, Default,
+    typename void_type<
+      typename T::index_type
+    >::type>
+{
+  typedef typename T::index_type type;
+};
+
+} // namespace detail
+
+/// The is_executor trait detects whether a type T satisfies the
+/// execution::executor concept.
+/**
+ * Class template @c is_executor is a UnaryTypeTrait that is derived from @c
+ * true_type if the type @c T meets the concept definition for an executor,
+ * otherwise @c false_type.
+ */
+template <typename T>
+struct is_executor :
+#if defined(GENERATING_DOCUMENTATION)
+  integral_constant<bool, automatically_determined>
+#else // defined(GENERATING_DOCUMENTATION)
+  detail::is_executor_of_impl<T, invocable_archetype>
+#endif // defined(GENERATING_DOCUMENTATION)
+{
+};
+
+#if defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+template <typename T>
+ASIO_CONSTEXPR const bool is_executor_v = is_executor<T>::value;
+
+#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+#if defined(ASIO_HAS_CONCEPTS)
+
+template <typename T>
+ASIO_CONCEPT executor = is_executor<T>::value;
+
+#define ASIO_EXECUTION_EXECUTOR ::asio::execution::executor
+
+#else // defined(ASIO_HAS_CONCEPTS)
+
+#define ASIO_EXECUTION_EXECUTOR typename
+
+#endif // defined(ASIO_HAS_CONCEPTS)
+
+/// The is_executor_of trait detects whether a type T satisfies the
+/// execution::executor_of concept for some set of value arguments.
+/**
+ * Class template @c is_executor_of is a type trait that is derived from @c
+ * true_type if the type @c T meets the concept definition for an executor
+ * that is invocable with a function object of type @c F, otherwise @c
+ * false_type.
+ */
+template <typename T, typename F>
+struct is_executor_of :
+#if defined(GENERATING_DOCUMENTATION)
+  integral_constant<bool, automatically_determined>
+#else // defined(GENERATING_DOCUMENTATION)
+  integral_constant<bool,
+    is_executor<T>::value && detail::is_executor_of_impl<T, F>::value
+  >
+#endif // defined(GENERATING_DOCUMENTATION)
+{
+};
+
+#if defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+template <typename T, typename F>
+ASIO_CONSTEXPR const bool is_executor_of_v =
+  is_executor_of<T, F>::value;
+
+#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+#if defined(ASIO_HAS_CONCEPTS)
+
+template <typename T, typename F>
+ASIO_CONCEPT executor_of = is_executor_of<T, F>::value;
+
+#define ASIO_EXECUTION_EXECUTOR_OF(f) \
+  ::asio::execution::executor_of<f>
+
+#else // defined(ASIO_HAS_CONCEPTS)
+
+#define ASIO_EXECUTION_EXECUTOR_OF typename
+
+#endif // defined(ASIO_HAS_CONCEPTS)
+
+/// The executor_shape trait detects the type used by an executor to represent
+/// the shape of a bulk operation.
+/**
+ * Class template @c executor_shape is a type trait with a nested type alias
+ * @c type whose type is @c T::shape_type if @c T::shape_type is valid,
+ * otherwise @c std::size_t.
+ */
+template <typename T>
+struct executor_shape
+#if !defined(GENERATING_DOCUMENTATION)
+  : detail::executor_shape<T>
+#endif // !defined(GENERATING_DOCUMENTATION)
+{
+#if defined(GENERATING_DOCUMENTATION)
+ /// @c T::shape_type if @c T::shape_type is valid, otherwise @c std::size_t.
+ typedef automatically_determined type;
+#endif // defined(GENERATING_DOCUMENTATION)
+};
+
+#if defined(ASIO_HAS_ALIAS_TEMPLATES)
+
+template <typename T>
+using executor_shape_t = typename executor_shape<T>::type;
+
+#endif // defined(ASIO_HAS_ALIAS_TEMPLATES)
+
+/// The executor_index trait detects the type used by an executor to represent
+/// an index within a bulk operation.
+/**
+ * Class template @c executor_index is a type trait with a nested type alias
+ * @c type whose type is @c T::index_type if @c T::index_type is valid,
+ * otherwise @c executor_shape_t<T>.
+ */
+template <typename T>
+struct executor_index
+#if !defined(GENERATING_DOCUMENTATION)
+  : detail::executor_index<T, typename executor_shape<T>::type>
+#endif // !defined(GENERATING_DOCUMENTATION)
+{
+#if defined(GENERATING_DOCUMENTATION)
+ /// @c T::index_type if @c T::index_type is valid, otherwise
+ /// @c executor_shape_t<T>.
+ typedef automatically_determined type;
+#endif // defined(GENERATING_DOCUMENTATION)
+};
+
+#if defined(ASIO_HAS_ALIAS_TEMPLATES)
+
+template <typename T>
+using executor_index_t = typename executor_index<T>::type;
+
+#endif // defined(ASIO_HAS_ALIAS_TEMPLATES)
+
+} // namespace execution
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_EXECUTION_EXECUTOR_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/execution/impl/bad_executor.ipp b/link/modules/asio-standalone/asio/include/asio/execution/impl/bad_executor.ipp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/execution/impl/bad_executor.ipp
@@ -0,0 +1,40 @@
+//
+// exection/impl/bad_executor.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_EXECUTION_IMPL_BAD_EXECUTOR_IPP
+#define ASIO_EXECUTION_IMPL_BAD_EXECUTOR_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/execution/bad_executor.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace execution {
+
+bad_executor::bad_executor() ASIO_NOEXCEPT
+{
+}
+
+const char* bad_executor::what() const ASIO_NOEXCEPT_OR_NOTHROW
+{
+  return "bad executor";
+}
+
+} // namespace execution
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_EXECUTION_IMPL_BAD_EXECUTOR_IPP
diff --git a/link/modules/asio-standalone/asio/include/asio/execution/impl/receiver_invocation_error.ipp b/link/modules/asio-standalone/asio/include/asio/execution/impl/receiver_invocation_error.ipp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/execution/impl/receiver_invocation_error.ipp
@@ -0,0 +1,36 @@
+//
+// exection/impl/receiver_invocation_error.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_EXECUTION_IMPL_RECEIVER_INVOCATION_ERROR_IPP
+#define ASIO_EXECUTION_IMPL_RECEIVER_INVOCATION_ERROR_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/execution/receiver_invocation_error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace execution {
+
+receiver_invocation_error::receiver_invocation_error()
+  : std::runtime_error("receiver invocation error")
+{
+}
+
+} // namespace execution
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_EXECUTION_IMPL_RECEIVER_INVOCATION_ERROR_IPP
diff --git a/link/modules/asio-standalone/asio/include/asio/execution/invocable_archetype.hpp b/link/modules/asio-standalone/asio/include/asio/execution/invocable_archetype.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/execution/invocable_archetype.hpp
@@ -0,0 +1,71 @@
+//
+// execution/invocable_archetype.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_EXECUTION_INVOCABLE_ARCHETYPE_HPP
+#define ASIO_EXECUTION_INVOCABLE_ARCHETYPE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/type_traits.hpp"
+#include "asio/detail/variadic_templates.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace execution {
+
+/// An archetypal function object used for determining adherence to the
+/// execution::executor concept.
+struct invocable_archetype
+{
+#if !defined(GENERATING_DOCUMENTATION)
+  // Necessary for compatibility with a C++03 implementation of result_of.
+  typedef void result_type;
+#endif // !defined(GENERATING_DOCUMENTATION)
+
+#if defined(ASIO_HAS_VARIADIC_TEMPLATES) \
+  || defined(GENERATING_DOCUMENTATION)
+
+  /// Function call operator.
+  template <typename... Args>
+  void operator()(ASIO_MOVE_ARG(Args)...)
+  {
+  }
+
+#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+      //   || defined(GENERATING_DOCUMENTATION)
+
+  void operator()()
+  {
+  }
+
+#define ASIO_PRIVATE_INVOCABLE_ARCHETYPE_CALL_DEF(n) \
+  template <ASIO_VARIADIC_TPARAMS(n)> \
+  void operator()(ASIO_VARIADIC_UNNAMED_MOVE_PARAMS(n)) \
+  { \
+  } \
+  /**/
+  ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_INVOCABLE_ARCHETYPE_CALL_DEF)
+#undef ASIO_PRIVATE_INVOCABLE_ARCHETYPE_CALL_DEF
+
+#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+       //   || defined(GENERATING_DOCUMENTATION)
+};
+
+} // namespace execution
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_EXECUTION_INVOCABLE_ARCHETYPE_HPP
+
diff --git a/link/modules/asio-standalone/asio/include/asio/execution/mapping.hpp b/link/modules/asio-standalone/asio/include/asio/execution/mapping.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/execution/mapping.hpp
@@ -0,0 +1,917 @@
+//
+// execution/mapping.hpp
+// ~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_EXECUTION_MAPPING_HPP
+#define ASIO_EXECUTION_MAPPING_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/type_traits.hpp"
+#include "asio/execution/executor.hpp"
+#include "asio/execution/scheduler.hpp"
+#include "asio/execution/sender.hpp"
+#include "asio/is_applicable_property.hpp"
+#include "asio/query.hpp"
+#include "asio/traits/query_free.hpp"
+#include "asio/traits/query_member.hpp"
+#include "asio/traits/query_static_constexpr_member.hpp"
+#include "asio/traits/static_query.hpp"
+#include "asio/traits/static_require.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+#if defined(GENERATING_DOCUMENTATION)
+
+namespace execution {
+
+/// A property to describe what guarantees an executor makes about the mapping
+/// of execution agents on to threads of execution.
+struct mapping_t
+{
+  /// The mapping_t property applies to executors, senders, and schedulers.
+  template <typename T>
+  static constexpr bool is_applicable_property_v =
+    is_executor_v<T> || is_sender_v<T> || is_scheduler_v<T>;
+
+  /// The top-level mapping_t property cannot be required.
+  static constexpr bool is_requirable = false;
+
+  /// The top-level mapping_t property cannot be preferred.
+  static constexpr bool is_preferable = false;
+
+  /// The type returned by queries against an @c any_executor.
+  typedef mapping_t polymorphic_query_result_type;
+
+  /// A sub-property that indicates that execution agents are mapped on to
+  /// threads of execution.
+  struct thread_t
+  {
+    /// The mapping_t::thread_t property applies to executors, senders, and
+    /// schedulers.
+    template <typename T>
+    static constexpr bool is_applicable_property_v =
+      is_executor_v<T> || is_sender_v<T> || is_scheduler_v<T>;
+
+    /// The mapping_t::thread_t property can be required.
+    static constexpr bool is_requirable = true;
+
+    /// The mapping_t::thread_t property can be preferred.
+    static constexpr bool is_preferable = true;
+
+    /// The type returned by queries against an @c any_executor.
+    typedef mapping_t polymorphic_query_result_type;
+
+    /// Default constructor.
+    constexpr thread_t();
+
+    /// Get the value associated with a property object.
+    /**
+     * @returns thread_t();
+     */
+    static constexpr mapping_t value();
+  };
+
+  /// A sub-property that indicates that execution agents are mapped on to
+  /// new threads of execution.
+  struct new_thread_t
+  {
+    /// The mapping_t::new_thread_t property applies to executors, senders, and
+    /// schedulers.
+    template <typename T>
+    static constexpr bool is_applicable_property_v =
+      is_executor_v<T> || is_sender_v<T> || is_scheduler_v<T>;
+
+    /// The mapping_t::new_thread_t property can be required.
+    static constexpr bool is_requirable = true;
+
+    /// The mapping_t::new_thread_t property can be preferred.
+    static constexpr bool is_preferable = true;
+
+    /// The type returned by queries against an @c any_executor.
+    typedef mapping_t polymorphic_query_result_type;
+
+    /// Default constructor.
+    constexpr new_thread_t();
+
+    /// Get the value associated with a property object.
+    /**
+     * @returns new_thread_t();
+     */
+    static constexpr mapping_t value();
+  };
+
+  /// A sub-property that indicates that the mapping of execution agents is
+  /// implementation-defined.
+  struct other_t
+  {
+    /// The mapping_t::other_t property applies to executors, senders, and
+    /// schedulers.
+    template <typename T>
+    static constexpr bool is_applicable_property_v =
+      is_executor_v<T> || is_sender_v<T> || is_scheduler_v<T>;
+
+    /// The mapping_t::other_t property can be required.
+    static constexpr bool is_requirable = true;
+
+    /// The mapping_t::other_t property can be preferred.
+    static constexpr bool is_preferable = true;
+
+    /// The type returned by queries against an @c any_executor.
+    typedef mapping_t polymorphic_query_result_type;
+
+    /// Default constructor.
+    constexpr other_t();
+
+    /// Get the value associated with a property object.
+    /**
+     * @returns other_t();
+     */
+    static constexpr mapping_t value();
+  };
+
+  /// A special value used for accessing the mapping_t::thread_t property.
+  static constexpr thread_t thread;
+
+  /// A special value used for accessing the mapping_t::new_thread_t property.
+  static constexpr new_thread_t new_thread;
+
+  /// A special value used for accessing the mapping_t::other_t property.
+  static constexpr other_t other;
+
+  /// Default constructor.
+  constexpr mapping_t();
+
+  /// Construct from a sub-property value.
+  constexpr mapping_t(thread_t);
+
+  /// Construct from a sub-property value.
+  constexpr mapping_t(new_thread_t);
+
+  /// Construct from a sub-property value.
+  constexpr mapping_t(other_t);
+
+  /// Compare property values for equality.
+  friend constexpr bool operator==(
+      const mapping_t& a, const mapping_t& b) noexcept;
+
+  /// Compare property values for inequality.
+  friend constexpr bool operator!=(
+      const mapping_t& a, const mapping_t& b) noexcept;
+};
+
+/// A special value used for accessing the mapping_t property.
+constexpr mapping_t mapping;
+
+} // namespace execution
+
+#else // defined(GENERATING_DOCUMENTATION)
+
+namespace execution {
+namespace detail {
+namespace mapping {
+
+template <int I> struct thread_t;
+template <int I> struct new_thread_t;
+template <int I> struct other_t;
+
+} // namespace mapping
+
+template <int I = 0>
+struct mapping_t
+{
+#if defined(ASIO_HAS_VARIABLE_TEMPLATES)
+  template <typename T>
+  ASIO_STATIC_CONSTEXPR(bool,
+    is_applicable_property_v = is_executor<T>::value
+      || is_sender<T>::value || is_scheduler<T>::value);
+#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+  ASIO_STATIC_CONSTEXPR(bool, is_requirable = false);
+  ASIO_STATIC_CONSTEXPR(bool, is_preferable = false);
+  typedef mapping_t polymorphic_query_result_type;
+
+  typedef detail::mapping::thread_t<I> thread_t;
+  typedef detail::mapping::new_thread_t<I> new_thread_t;
+  typedef detail::mapping::other_t<I> other_t;
+
+  ASIO_CONSTEXPR mapping_t()
+    : value_(-1)
+  {
+  }
+
+  ASIO_CONSTEXPR mapping_t(thread_t)
+    : value_(0)
+  {
+  }
+
+  ASIO_CONSTEXPR mapping_t(new_thread_t)
+    : value_(1)
+  {
+  }
+
+  ASIO_CONSTEXPR mapping_t(other_t)
+    : value_(2)
+  {
+  }
+
+#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \
+  && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+  template <typename T>
+  static ASIO_CONSTEXPR
+  typename traits::query_static_constexpr_member<T, mapping_t>::result_type
+  static_query()
+    ASIO_NOEXCEPT_IF((
+      traits::query_static_constexpr_member<T, mapping_t>::is_noexcept))
+  {
+    return traits::query_static_constexpr_member<T, mapping_t>::value();
+  }
+
+  template <typename T>
+  static ASIO_CONSTEXPR
+  typename traits::static_query<T, thread_t>::result_type
+  static_query(
+      typename enable_if<
+        !traits::query_static_constexpr_member<T, mapping_t>::is_valid
+          && !traits::query_member<T, mapping_t>::is_valid
+          && traits::static_query<T, thread_t>::is_valid
+      >::type* = 0) ASIO_NOEXCEPT
+  {
+    return traits::static_query<T, thread_t>::value();
+  }
+
+  template <typename T>
+  static ASIO_CONSTEXPR
+  typename traits::static_query<T, new_thread_t>::result_type
+  static_query(
+      typename enable_if<
+        !traits::query_static_constexpr_member<T, mapping_t>::is_valid
+          && !traits::query_member<T, mapping_t>::is_valid
+          && !traits::static_query<T, thread_t>::is_valid
+          && traits::static_query<T, new_thread_t>::is_valid
+      >::type* = 0) ASIO_NOEXCEPT
+  {
+    return traits::static_query<T, new_thread_t>::value();
+  }
+
+  template <typename T>
+  static ASIO_CONSTEXPR
+  typename traits::static_query<T, other_t>::result_type
+  static_query(
+      typename enable_if<
+        !traits::query_static_constexpr_member<T, mapping_t>::is_valid
+          && !traits::query_member<T, mapping_t>::is_valid
+          && !traits::static_query<T, thread_t>::is_valid
+          && !traits::static_query<T, new_thread_t>::is_valid
+          && traits::static_query<T, other_t>::is_valid
+      >::type* = 0) ASIO_NOEXCEPT
+  {
+    return traits::static_query<T, other_t>::value();
+  }
+
+  template <typename E, typename T = decltype(mapping_t::static_query<E>())>
+  static ASIO_CONSTEXPR const T static_query_v
+    = mapping_t::static_query<E>();
+#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)
+       //   && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+
+  friend ASIO_CONSTEXPR bool operator==(
+      const mapping_t& a, const mapping_t& b)
+  {
+    return a.value_ == b.value_;
+  }
+
+  friend ASIO_CONSTEXPR bool operator!=(
+      const mapping_t& a, const mapping_t& b)
+  {
+    return a.value_ != b.value_;
+  }
+
+  struct convertible_from_mapping_t
+  {
+    ASIO_CONSTEXPR convertible_from_mapping_t(mapping_t) {}
+  };
+
+  template <typename Executor>
+  friend ASIO_CONSTEXPR mapping_t query(
+      const Executor& ex, convertible_from_mapping_t,
+      typename enable_if<
+        can_query<const Executor&, thread_t>::value
+      >::type* = 0)
+#if !defined(__clang__) // Clang crashes if noexcept is used here.
+#if defined(ASIO_MSVC) // Visual C++ wants the type to be qualified.
+    ASIO_NOEXCEPT_IF((
+      is_nothrow_query<const Executor&, mapping_t<>::thread_t>::value))
+#else // defined(ASIO_MSVC)
+    ASIO_NOEXCEPT_IF((
+      is_nothrow_query<const Executor&, thread_t>::value))
+#endif // defined(ASIO_MSVC)
+#endif // !defined(__clang__)
+  {
+    return asio::query(ex, thread_t());
+  }
+
+  template <typename Executor>
+  friend ASIO_CONSTEXPR mapping_t query(
+      const Executor& ex, convertible_from_mapping_t,
+      typename enable_if<
+        !can_query<const Executor&, thread_t>::value
+          && can_query<const Executor&, new_thread_t>::value
+      >::type* = 0)
+#if !defined(__clang__) // Clang crashes if noexcept is used here.
+#if defined(ASIO_MSVC) // Visual C++ wants the type to be qualified.
+    ASIO_NOEXCEPT_IF((
+      is_nothrow_query<const Executor&, mapping_t<>::new_thread_t>::value))
+#else // defined(ASIO_MSVC)
+    ASIO_NOEXCEPT_IF((
+      is_nothrow_query<const Executor&, new_thread_t>::value))
+#endif // defined(ASIO_MSVC)
+#endif // !defined(__clang__)
+  {
+    return asio::query(ex, new_thread_t());
+  }
+
+  template <typename Executor>
+  friend ASIO_CONSTEXPR mapping_t query(
+      const Executor& ex, convertible_from_mapping_t,
+      typename enable_if<
+        !can_query<const Executor&, thread_t>::value
+          && !can_query<const Executor&, new_thread_t>::value
+          && can_query<const Executor&, other_t>::value
+      >::type* = 0)
+#if !defined(__clang__) // Clang crashes if noexcept is used here.
+#if defined(ASIO_MSVC) // Visual C++ wants the type to be qualified.
+    ASIO_NOEXCEPT_IF((
+      is_nothrow_query<const Executor&, mapping_t<>::other_t>::value))
+#else // defined(ASIO_MSVC)
+    ASIO_NOEXCEPT_IF((
+      is_nothrow_query<const Executor&, other_t>::value))
+#endif // defined(ASIO_MSVC)
+#endif // !defined(__clang__)
+  {
+    return asio::query(ex, other_t());
+  }
+
+  ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(thread_t, thread);
+  ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(new_thread_t, new_thread);
+  ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(other_t, other);
+
+#if !defined(ASIO_HAS_CONSTEXPR)
+  static const mapping_t instance;
+#endif // !defined(ASIO_HAS_CONSTEXPR)
+
+private:
+  int value_;
+};
+
+#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \
+  && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+template <int I> template <typename E, typename T>
+const T mapping_t<I>::static_query_v;
+#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)
+       //   && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+
+#if !defined(ASIO_HAS_CONSTEXPR)
+template <int I>
+const mapping_t<I> mapping_t<I>::instance;
+#endif
+
+template <int I>
+const typename mapping_t<I>::thread_t mapping_t<I>::thread;
+
+template <int I>
+const typename mapping_t<I>::new_thread_t mapping_t<I>::new_thread;
+
+template <int I>
+const typename mapping_t<I>::other_t mapping_t<I>::other;
+
+namespace mapping {
+
+template <int I = 0>
+struct thread_t
+{
+#if defined(ASIO_HAS_VARIABLE_TEMPLATES)
+  template <typename T>
+  ASIO_STATIC_CONSTEXPR(bool,
+    is_applicable_property_v = is_executor<T>::value
+      || is_sender<T>::value || is_scheduler<T>::value);
+#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+  ASIO_STATIC_CONSTEXPR(bool, is_requirable = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_preferable = true);
+  typedef mapping_t<I> polymorphic_query_result_type;
+
+  ASIO_CONSTEXPR thread_t()
+  {
+  }
+
+#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \
+  && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+  template <typename T>
+  static ASIO_CONSTEXPR
+  typename traits::query_static_constexpr_member<T, thread_t>::result_type
+  static_query()
+    ASIO_NOEXCEPT_IF((
+      traits::query_static_constexpr_member<T, thread_t>::is_noexcept))
+  {
+    return traits::query_static_constexpr_member<T, thread_t>::value();
+  }
+
+  template <typename T>
+  static ASIO_CONSTEXPR thread_t static_query(
+      typename enable_if<
+        !traits::query_static_constexpr_member<T, thread_t>::is_valid
+          && !traits::query_member<T, thread_t>::is_valid
+          && !traits::query_free<T, thread_t>::is_valid
+          && !can_query<T, new_thread_t<I> >::value
+          && !can_query<T, other_t<I> >::value
+      >::type* = 0) ASIO_NOEXCEPT
+  {
+    return thread_t();
+  }
+
+  template <typename E, typename T = decltype(thread_t::static_query<E>())>
+  static ASIO_CONSTEXPR const T static_query_v
+    = thread_t::static_query<E>();
+#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)
+       //   && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+
+  static ASIO_CONSTEXPR mapping_t<I> value()
+  {
+    return thread_t();
+  }
+
+  friend ASIO_CONSTEXPR bool operator==(
+      const thread_t&, const thread_t&)
+  {
+    return true;
+  }
+
+  friend ASIO_CONSTEXPR bool operator!=(
+      const thread_t&, const thread_t&)
+  {
+    return false;
+  }
+};
+
+#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \
+  && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+template <int I> template <typename E, typename T>
+const T thread_t<I>::static_query_v;
+#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)
+       //   && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+
+template <int I = 0>
+struct new_thread_t
+{
+#if defined(ASIO_HAS_VARIABLE_TEMPLATES)
+  template <typename T>
+  ASIO_STATIC_CONSTEXPR(bool,
+    is_applicable_property_v = is_executor<T>::value
+      || is_sender<T>::value || is_scheduler<T>::value);
+#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+  ASIO_STATIC_CONSTEXPR(bool, is_requirable = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_preferable = true);
+  typedef mapping_t<I> polymorphic_query_result_type;
+
+  ASIO_CONSTEXPR new_thread_t()
+  {
+  }
+
+#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \
+  && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+  template <typename T>
+  static ASIO_CONSTEXPR
+  typename traits::query_static_constexpr_member<T, new_thread_t>::result_type
+  static_query()
+    ASIO_NOEXCEPT_IF((
+      traits::query_static_constexpr_member<T, new_thread_t>::is_noexcept))
+  {
+    return traits::query_static_constexpr_member<T, new_thread_t>::value();
+  }
+
+  template <typename E, typename T = decltype(new_thread_t::static_query<E>())>
+  static ASIO_CONSTEXPR const T static_query_v
+    = new_thread_t::static_query<E>();
+#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)
+       //   && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+
+  static ASIO_CONSTEXPR mapping_t<I> value()
+  {
+    return new_thread_t();
+  }
+
+  friend ASIO_CONSTEXPR bool operator==(
+      const new_thread_t&, const new_thread_t&)
+  {
+    return true;
+  }
+
+  friend ASIO_CONSTEXPR bool operator!=(
+      const new_thread_t&, const new_thread_t&)
+  {
+    return false;
+  }
+};
+
+#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \
+  && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+template <int I> template <typename E, typename T>
+const T new_thread_t<I>::static_query_v;
+#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)
+       //   && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+
+template <int I>
+struct other_t
+{
+#if defined(ASIO_HAS_VARIABLE_TEMPLATES)
+  template <typename T>
+  ASIO_STATIC_CONSTEXPR(bool,
+    is_applicable_property_v = is_executor<T>::value
+      || is_sender<T>::value || is_scheduler<T>::value);
+#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+  ASIO_STATIC_CONSTEXPR(bool, is_requirable = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_preferable = true);
+  typedef mapping_t<I> polymorphic_query_result_type;
+
+  ASIO_CONSTEXPR other_t()
+  {
+  }
+
+#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \
+  && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+  template <typename T>
+  static ASIO_CONSTEXPR
+  typename traits::query_static_constexpr_member<T, other_t>::result_type
+  static_query()
+    ASIO_NOEXCEPT_IF((
+      traits::query_static_constexpr_member<T, other_t>::is_noexcept))
+  {
+    return traits::query_static_constexpr_member<T, other_t>::value();
+  }
+
+  template <typename E, typename T = decltype(other_t::static_query<E>())>
+  static ASIO_CONSTEXPR const T static_query_v
+    = other_t::static_query<E>();
+#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)
+       //   && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+
+  static ASIO_CONSTEXPR mapping_t<I> value()
+  {
+    return other_t();
+  }
+
+  friend ASIO_CONSTEXPR bool operator==(
+      const other_t&, const other_t&)
+  {
+    return true;
+  }
+
+  friend ASIO_CONSTEXPR bool operator!=(
+      const other_t&, const other_t&)
+  {
+    return false;
+  }
+};
+
+#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \
+  && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+template <int I> template <typename E, typename T>
+const T other_t<I>::static_query_v;
+#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)
+       //   && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+
+} // namespace mapping
+} // namespace detail
+
+typedef detail::mapping_t<> mapping_t;
+
+#if defined(ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION)
+constexpr mapping_t mapping;
+#else // defined(ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION)
+namespace { static const mapping_t& mapping = mapping_t::instance; }
+#endif
+
+} // namespace execution
+
+#if !defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+template <typename T>
+struct is_applicable_property<T, execution::mapping_t>
+  : integral_constant<bool,
+      execution::is_executor<T>::value
+        || execution::is_sender<T>::value
+        || execution::is_scheduler<T>::value>
+{
+};
+
+template <typename T>
+struct is_applicable_property<T, execution::mapping_t::thread_t>
+  : integral_constant<bool,
+      execution::is_executor<T>::value
+        || execution::is_sender<T>::value
+        || execution::is_scheduler<T>::value>
+{
+};
+
+template <typename T>
+struct is_applicable_property<T, execution::mapping_t::new_thread_t>
+  : integral_constant<bool,
+      execution::is_executor<T>::value
+        || execution::is_sender<T>::value
+        || execution::is_scheduler<T>::value>
+{
+};
+
+template <typename T>
+struct is_applicable_property<T, execution::mapping_t::other_t>
+  : integral_constant<bool,
+      execution::is_executor<T>::value
+        || execution::is_sender<T>::value
+        || execution::is_scheduler<T>::value>
+{
+};
+
+#endif // !defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+namespace traits {
+
+#if !defined(ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT)
+
+template <typename T>
+struct query_free_default<T, execution::mapping_t,
+  typename enable_if<
+    can_query<T, execution::mapping_t::thread_t>::value
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept =
+    (is_nothrow_query<T, execution::mapping_t::thread_t>::value));
+
+  typedef execution::mapping_t result_type;
+};
+
+template <typename T>
+struct query_free_default<T, execution::mapping_t,
+  typename enable_if<
+    !can_query<T, execution::mapping_t::thread_t>::value
+      && can_query<T, execution::mapping_t::new_thread_t>::value
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept =
+    (is_nothrow_query<T, execution::mapping_t::new_thread_t>::value));
+
+  typedef execution::mapping_t result_type;
+};
+
+template <typename T>
+struct query_free_default<T, execution::mapping_t,
+  typename enable_if<
+    !can_query<T, execution::mapping_t::thread_t>::value
+      && !can_query<T, execution::mapping_t::new_thread_t>::value
+      && can_query<T, execution::mapping_t::other_t>::value
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept =
+    (is_nothrow_query<T, execution::mapping_t::other_t>::value));
+
+  typedef execution::mapping_t result_type;
+};
+
+#endif // !defined(ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT)
+
+#if !defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \
+  || !defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+
+template <typename T>
+struct static_query<T, execution::mapping_t,
+  typename enable_if<
+    traits::query_static_constexpr_member<T,
+      execution::mapping_t>::is_valid
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
+
+  typedef typename traits::query_static_constexpr_member<T,
+    execution::mapping_t>::result_type result_type;
+
+  static ASIO_CONSTEXPR result_type value()
+  {
+    return traits::query_static_constexpr_member<T,
+      execution::mapping_t>::value();
+  }
+};
+
+template <typename T>
+struct static_query<T, execution::mapping_t,
+  typename enable_if<
+    !traits::query_static_constexpr_member<T, execution::mapping_t>::is_valid
+      && !traits::query_member<T, execution::mapping_t>::is_valid
+      && traits::static_query<T, execution::mapping_t::thread_t>::is_valid
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
+
+  typedef typename traits::static_query<T,
+    execution::mapping_t::thread_t>::result_type result_type;
+
+  static ASIO_CONSTEXPR result_type value()
+  {
+    return traits::static_query<T, execution::mapping_t::thread_t>::value();
+  }
+};
+
+template <typename T>
+struct static_query<T, execution::mapping_t,
+  typename enable_if<
+    !traits::query_static_constexpr_member<T, execution::mapping_t>::is_valid
+      && !traits::query_member<T, execution::mapping_t>::is_valid
+      && !traits::static_query<T, execution::mapping_t::thread_t>::is_valid
+      && traits::static_query<T, execution::mapping_t::new_thread_t>::is_valid
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
+
+  typedef typename traits::static_query<T,
+    execution::mapping_t::new_thread_t>::result_type result_type;
+
+  static ASIO_CONSTEXPR result_type value()
+  {
+    return traits::static_query<T, execution::mapping_t::new_thread_t>::value();
+  }
+};
+
+template <typename T>
+struct static_query<T, execution::mapping_t,
+  typename enable_if<
+    !traits::query_static_constexpr_member<T, execution::mapping_t>::is_valid
+      && !traits::query_member<T, execution::mapping_t>::is_valid
+      && !traits::static_query<T, execution::mapping_t::thread_t>::is_valid
+      && !traits::static_query<T, execution::mapping_t::new_thread_t>::is_valid
+      && traits::static_query<T, execution::mapping_t::other_t>::is_valid
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
+
+  typedef typename traits::static_query<T,
+    execution::mapping_t::other_t>::result_type result_type;
+
+  static ASIO_CONSTEXPR result_type value()
+  {
+    return traits::static_query<T, execution::mapping_t::other_t>::value();
+  }
+};
+
+template <typename T>
+struct static_query<T, execution::mapping_t::thread_t,
+  typename enable_if<
+    traits::query_static_constexpr_member<T,
+      execution::mapping_t::thread_t>::is_valid
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
+
+  typedef typename traits::query_static_constexpr_member<T,
+    execution::mapping_t::thread_t>::result_type result_type;
+
+  static ASIO_CONSTEXPR result_type value()
+  {
+    return traits::query_static_constexpr_member<T,
+      execution::mapping_t::thread_t>::value();
+  }
+};
+
+template <typename T>
+struct static_query<T, execution::mapping_t::thread_t,
+  typename enable_if<
+    !traits::query_static_constexpr_member<T,
+      execution::mapping_t::thread_t>::is_valid
+      && !traits::query_member<T, execution::mapping_t::thread_t>::is_valid
+      && !traits::query_free<T, execution::mapping_t::thread_t>::is_valid
+      && !can_query<T, execution::mapping_t::new_thread_t>::value
+      && !can_query<T, execution::mapping_t::other_t>::value
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
+
+  typedef execution::mapping_t::thread_t result_type;
+
+  static ASIO_CONSTEXPR result_type value()
+  {
+    return result_type();
+  }
+};
+
+template <typename T>
+struct static_query<T, execution::mapping_t::new_thread_t,
+  typename enable_if<
+    traits::query_static_constexpr_member<T,
+      execution::mapping_t::new_thread_t>::is_valid
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
+
+  typedef typename traits::query_static_constexpr_member<T,
+    execution::mapping_t::new_thread_t>::result_type result_type;
+
+  static ASIO_CONSTEXPR result_type value()
+  {
+    return traits::query_static_constexpr_member<T,
+      execution::mapping_t::new_thread_t>::value();
+  }
+};
+
+template <typename T>
+struct static_query<T, execution::mapping_t::other_t,
+  typename enable_if<
+    traits::query_static_constexpr_member<T,
+      execution::mapping_t::other_t>::is_valid
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
+
+  typedef typename traits::query_static_constexpr_member<T,
+    execution::mapping_t::other_t>::result_type result_type;
+
+  static ASIO_CONSTEXPR result_type value()
+  {
+    return traits::query_static_constexpr_member<T,
+      execution::mapping_t::other_t>::value();
+  }
+};
+
+#endif // !defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)
+       //   || !defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+
+#if !defined(ASIO_HAS_DEDUCED_STATIC_REQUIRE_TRAIT)
+
+template <typename T>
+struct static_require<T, execution::mapping_t::thread_t,
+  typename enable_if<
+    static_query<T, execution::mapping_t::thread_t>::is_valid
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid =
+    (is_same<typename static_query<T,
+      execution::mapping_t::thread_t>::result_type,
+        execution::mapping_t::thread_t>::value));
+};
+
+template <typename T>
+struct static_require<T, execution::mapping_t::new_thread_t,
+  typename enable_if<
+    static_query<T, execution::mapping_t::new_thread_t>::is_valid
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid =
+    (is_same<typename static_query<T,
+      execution::mapping_t::new_thread_t>::result_type,
+        execution::mapping_t::new_thread_t>::value));
+};
+
+template <typename T>
+struct static_require<T, execution::mapping_t::other_t,
+  typename enable_if<
+    static_query<T, execution::mapping_t::other_t>::is_valid
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid =
+    (is_same<typename static_query<T,
+      execution::mapping_t::other_t>::result_type,
+        execution::mapping_t::other_t>::value));
+};
+
+#endif // !defined(ASIO_HAS_DEDUCED_STATIC_REQUIRE_TRAIT)
+
+} // namespace traits
+
+#endif // defined(GENERATING_DOCUMENTATION)
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_EXECUTION_MAPPING_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/execution/occupancy.hpp b/link/modules/asio-standalone/asio/include/asio/execution/occupancy.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/execution/occupancy.hpp
@@ -0,0 +1,178 @@
+//
+// execution/occupancy.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_EXECUTION_OCCUPANCY_HPP
+#define ASIO_EXECUTION_OCCUPANCY_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/type_traits.hpp"
+#include "asio/execution/executor.hpp"
+#include "asio/execution/scheduler.hpp"
+#include "asio/execution/sender.hpp"
+#include "asio/is_applicable_property.hpp"
+#include "asio/traits/query_static_constexpr_member.hpp"
+#include "asio/traits/static_query.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+#if defined(GENERATING_DOCUMENTATION)
+
+namespace execution {
+
+/// A property that gives an estimate of the number of execution agents that
+/// should occupy the associated execution context.
+struct occupancy_t
+{
+  /// The occupancy_t property applies to executors, senders, and schedulers.
+  template <typename T>
+  static constexpr bool is_applicable_property_v =
+    is_executor_v<T> || is_sender_v<T> || is_scheduler_v<T>;
+
+  /// The occupancy_t property cannot be required.
+  static constexpr bool is_requirable = false;
+
+  /// The occupancy_t property cannot be preferred.
+  static constexpr bool is_preferable = false;
+
+  /// The type returned by queries against an @c any_executor.
+  typedef std::size_t polymorphic_query_result_type;
+};
+
+/// A special value used for accessing the occupancy_t property.
+constexpr occupancy_t occupancy;
+
+} // namespace execution
+
+#else // defined(GENERATING_DOCUMENTATION)
+
+namespace execution {
+namespace detail {
+
+template <int I = 0>
+struct occupancy_t
+{
+#if defined(ASIO_HAS_VARIABLE_TEMPLATES)
+  template <typename T>
+  ASIO_STATIC_CONSTEXPR(bool,
+    is_applicable_property_v = is_executor<T>::value
+      || is_sender<T>::value || is_scheduler<T>::value);
+#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+  ASIO_STATIC_CONSTEXPR(bool, is_requirable = false);
+  ASIO_STATIC_CONSTEXPR(bool, is_preferable = false);
+  typedef std::size_t polymorphic_query_result_type;
+
+  ASIO_CONSTEXPR occupancy_t()
+  {
+  }
+
+#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \
+  && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+  template <typename T>
+  static ASIO_CONSTEXPR
+  typename traits::query_static_constexpr_member<T, occupancy_t>::result_type
+  static_query()
+    ASIO_NOEXCEPT_IF((
+      traits::query_static_constexpr_member<T, occupancy_t>::is_noexcept))
+  {
+    return traits::query_static_constexpr_member<T, occupancy_t>::value();
+  }
+
+  template <typename E, typename T = decltype(occupancy_t::static_query<E>())>
+  static ASIO_CONSTEXPR const T static_query_v
+    = occupancy_t::static_query<E>();
+#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)
+       //   && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+
+#if !defined(ASIO_HAS_CONSTEXPR)
+  static const occupancy_t instance;
+#endif // !defined(ASIO_HAS_CONSTEXPR)
+};
+
+#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \
+  && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+template <int I> template <typename E, typename T>
+const T occupancy_t<I>::static_query_v;
+#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)
+       //   && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+
+#if !defined(ASIO_HAS_CONSTEXPR)
+template <int I>
+const occupancy_t<I> occupancy_t<I>::instance;
+#endif
+
+} // namespace detail
+
+typedef detail::occupancy_t<> occupancy_t;
+
+#if defined(ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION)
+constexpr occupancy_t occupancy;
+#else // defined(ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION)
+namespace { static const occupancy_t& occupancy = occupancy_t::instance; }
+#endif
+
+} // namespace execution
+
+#if !defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+template <typename T>
+struct is_applicable_property<T, execution::occupancy_t>
+  : integral_constant<bool,
+      execution::is_executor<T>::value
+        || execution::is_sender<T>::value
+        || execution::is_scheduler<T>::value>
+{
+};
+
+#endif // !defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+namespace traits {
+
+#if !defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \
+  || !defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+
+template <typename T>
+struct static_query<T, execution::occupancy_t,
+  typename enable_if<
+    traits::query_static_constexpr_member<T,
+      execution::occupancy_t>::is_valid
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
+
+  typedef typename traits::query_static_constexpr_member<T,
+    execution::occupancy_t>::result_type result_type;
+
+  static ASIO_CONSTEXPR result_type value()
+  {
+    return traits::query_static_constexpr_member<T,
+      execution::occupancy_t>::value();
+  }
+};
+
+#endif // !defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)
+       //   || !defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+
+} // namespace traits
+
+#endif // defined(GENERATING_DOCUMENTATION)
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_EXECUTION_OCCUPANCY_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/execution/operation_state.hpp b/link/modules/asio-standalone/asio/include/asio/execution/operation_state.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/execution/operation_state.hpp
@@ -0,0 +1,94 @@
+//
+// execution/operation_state.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_EXECUTION_OPERATION_STATE_HPP
+#define ASIO_EXECUTION_OPERATION_STATE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/type_traits.hpp"
+#include "asio/execution/start.hpp"
+
+#if defined(ASIO_HAS_DEDUCED_START_FREE_TRAIT) \
+  && defined(ASIO_HAS_DEDUCED_START_MEMBER_TRAIT)
+# define ASIO_HAS_DEDUCED_EXECUTION_IS_OPERATION_STATE_TRAIT 1
+#endif // defined(ASIO_HAS_DEDUCED_START_FREE_TRAIT)
+       //   && defined(ASIO_HAS_DEDUCED_START_MEMBER_TRAIT)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace execution {
+namespace detail {
+
+template <typename T>
+struct is_operation_state_base :
+  integral_constant<bool,
+    is_destructible<T>::value
+      && is_object<T>::value
+  >
+{
+};
+
+} // namespace detail
+
+/// The is_operation_state trait detects whether a type T satisfies the
+/// execution::operation_state concept.
+/**
+ * Class template @c is_operation_state is a type trait that is derived from
+ * @c true_type if the type @c T meets the concept definition for an
+ * @c operation_state, otherwise @c false_type.
+ */
+template <typename T>
+struct is_operation_state :
+#if defined(GENERATING_DOCUMENTATION)
+  integral_constant<bool, automatically_determined>
+#else // defined(GENERATING_DOCUMENTATION)
+  conditional<
+    can_start<typename add_lvalue_reference<T>::type>::value
+      && is_nothrow_start<typename add_lvalue_reference<T>::type>::value,
+    detail::is_operation_state_base<T>,
+    false_type
+  >::type
+#endif // defined(GENERATING_DOCUMENTATION)
+{
+};
+
+#if defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+template <typename T>
+ASIO_CONSTEXPR const bool is_operation_state_v =
+  is_operation_state<T>::value;
+
+#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+#if defined(ASIO_HAS_CONCEPTS)
+
+template <typename T>
+ASIO_CONCEPT operation_state = is_operation_state<T>::value;
+
+#define ASIO_EXECUTION_OPERATION_STATE \
+  ::asio::execution::operation_state
+
+#else // defined(ASIO_HAS_CONCEPTS)
+
+#define ASIO_EXECUTION_OPERATION_STATE typename
+
+#endif // defined(ASIO_HAS_CONCEPTS)
+
+} // namespace execution
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_EXECUTION_OPERATION_STATE_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/execution/outstanding_work.hpp b/link/modules/asio-standalone/asio/include/asio/execution/outstanding_work.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/execution/outstanding_work.hpp
@@ -0,0 +1,721 @@
+//
+// execution/outstanding_work.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_EXECUTION_OUTSTANDING_WORK_HPP
+#define ASIO_EXECUTION_OUTSTANDING_WORK_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/type_traits.hpp"
+#include "asio/execution/executor.hpp"
+#include "asio/execution/scheduler.hpp"
+#include "asio/execution/sender.hpp"
+#include "asio/is_applicable_property.hpp"
+#include "asio/query.hpp"
+#include "asio/traits/query_free.hpp"
+#include "asio/traits/query_member.hpp"
+#include "asio/traits/query_static_constexpr_member.hpp"
+#include "asio/traits/static_query.hpp"
+#include "asio/traits/static_require.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+#if defined(GENERATING_DOCUMENTATION)
+
+namespace execution {
+
+/// A property to describe whether task submission is likely in the future.
+struct outstanding_work_t
+{
+  /// The outstanding_work_t property applies to executors, senders, and
+  /// schedulers.
+  template <typename T>
+  static constexpr bool is_applicable_property_v =
+    is_executor_v<T> || is_sender_v<T> || is_scheduler_v<T>;
+
+  /// The top-level outstanding_work_t property cannot be required.
+  static constexpr bool is_requirable = false;
+
+  /// The top-level outstanding_work_t property cannot be preferred.
+  static constexpr bool is_preferable = false;
+
+  /// The type returned by queries against an @c any_executor.
+  typedef outstanding_work_t polymorphic_query_result_type;
+
+  /// A sub-property that indicates that the executor does not represent likely
+  /// future submission of a function object.
+  struct untracked_t
+  {
+    /// The outstanding_work_t::untracked_t property applies to executors,
+    /// senders, and schedulers.
+    template <typename T>
+    static constexpr bool is_applicable_property_v =
+      is_executor_v<T> || is_sender_v<T> || is_scheduler_v<T>;
+
+    /// The outstanding_work_t::untracked_t property can be required.
+    static constexpr bool is_requirable = true;
+
+    /// The outstanding_work_t::untracked_t property can be preferred.
+    static constexpr bool is_preferable = true;
+
+    /// The type returned by queries against an @c any_executor.
+    typedef outstanding_work_t polymorphic_query_result_type;
+
+    /// Default constructor.
+    constexpr untracked_t();
+
+    /// Get the value associated with a property object.
+    /**
+     * @returns untracked_t();
+     */
+    static constexpr outstanding_work_t value();
+  };
+
+  /// A sub-property that indicates that the executor represents likely
+  /// future submission of a function object.
+  struct tracked_t
+  {
+    /// The outstanding_work_t::untracked_t property applies to executors,
+    /// senders, and schedulers.
+    template <typename T>
+    static constexpr bool is_applicable_property_v =
+      is_executor_v<T> || is_sender_v<T> || is_scheduler_v<T>;
+
+    /// The outstanding_work_t::tracked_t property can be required.
+    static constexpr bool is_requirable = true;
+
+    /// The outstanding_work_t::tracked_t property can be preferred.
+    static constexpr bool is_preferable = true;
+
+    /// The type returned by queries against an @c any_executor.
+    typedef outstanding_work_t polymorphic_query_result_type;
+
+    /// Default constructor.
+    constexpr tracked_t();
+
+    /// Get the value associated with a property object.
+    /**
+     * @returns tracked_t();
+     */
+    static constexpr outstanding_work_t value();
+  };
+
+  /// A special value used for accessing the outstanding_work_t::untracked_t
+  /// property.
+  static constexpr untracked_t untracked;
+
+  /// A special value used for accessing the outstanding_work_t::tracked_t
+  /// property.
+  static constexpr tracked_t tracked;
+
+  /// Default constructor.
+  constexpr outstanding_work_t();
+
+  /// Construct from a sub-property value.
+  constexpr outstanding_work_t(untracked_t);
+
+  /// Construct from a sub-property value.
+  constexpr outstanding_work_t(tracked_t);
+
+  /// Compare property values for equality.
+  friend constexpr bool operator==(
+      const outstanding_work_t& a, const outstanding_work_t& b) noexcept;
+
+  /// Compare property values for inequality.
+  friend constexpr bool operator!=(
+      const outstanding_work_t& a, const outstanding_work_t& b) noexcept;
+};
+
+/// A special value used for accessing the outstanding_work_t property.
+constexpr outstanding_work_t outstanding_work;
+
+} // namespace execution
+
+#else // defined(GENERATING_DOCUMENTATION)
+
+namespace execution {
+namespace detail {
+namespace outstanding_work {
+
+template <int I> struct untracked_t;
+template <int I> struct tracked_t;
+
+} // namespace outstanding_work
+
+template <int I = 0>
+struct outstanding_work_t
+{
+#if defined(ASIO_HAS_VARIABLE_TEMPLATES)
+  template <typename T>
+  ASIO_STATIC_CONSTEXPR(bool,
+    is_applicable_property_v = is_executor<T>::value
+      || is_sender<T>::value || is_scheduler<T>::value);
+#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+  ASIO_STATIC_CONSTEXPR(bool, is_requirable = false);
+  ASIO_STATIC_CONSTEXPR(bool, is_preferable = false);
+  typedef outstanding_work_t polymorphic_query_result_type;
+
+  typedef detail::outstanding_work::untracked_t<I> untracked_t;
+  typedef detail::outstanding_work::tracked_t<I> tracked_t;
+
+  ASIO_CONSTEXPR outstanding_work_t()
+    : value_(-1)
+  {
+  }
+
+  ASIO_CONSTEXPR outstanding_work_t(untracked_t)
+    : value_(0)
+  {
+  }
+
+  ASIO_CONSTEXPR outstanding_work_t(tracked_t)
+    : value_(1)
+  {
+  }
+
+#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \
+  && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+  template <typename T>
+  static ASIO_CONSTEXPR
+  typename traits::query_static_constexpr_member<
+      T, outstanding_work_t>::result_type
+  static_query()
+    ASIO_NOEXCEPT_IF((
+      traits::query_static_constexpr_member<
+        T, outstanding_work_t
+      >::is_noexcept))
+  {
+    return traits::query_static_constexpr_member<
+        T, outstanding_work_t>::value();
+  }
+
+  template <typename T>
+  static ASIO_CONSTEXPR
+  typename traits::static_query<T, untracked_t>::result_type
+  static_query(
+      typename enable_if<
+        !traits::query_static_constexpr_member<
+            T, outstanding_work_t>::is_valid
+          && !traits::query_member<T, outstanding_work_t>::is_valid
+          && traits::static_query<T, untracked_t>::is_valid
+      >::type* = 0) ASIO_NOEXCEPT
+  {
+    return traits::static_query<T, untracked_t>::value();
+  }
+
+  template <typename T>
+  static ASIO_CONSTEXPR
+  typename traits::static_query<T, tracked_t>::result_type
+  static_query(
+      typename enable_if<
+        !traits::query_static_constexpr_member<
+            T, outstanding_work_t>::is_valid
+          && !traits::query_member<T, outstanding_work_t>::is_valid
+          && !traits::static_query<T, untracked_t>::is_valid
+          && traits::static_query<T, tracked_t>::is_valid
+      >::type* = 0) ASIO_NOEXCEPT
+  {
+    return traits::static_query<T, tracked_t>::value();
+  }
+
+  template <typename E,
+      typename T = decltype(outstanding_work_t::static_query<E>())>
+  static ASIO_CONSTEXPR const T static_query_v
+    = outstanding_work_t::static_query<E>();
+#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)
+       //   && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+
+  friend ASIO_CONSTEXPR bool operator==(
+      const outstanding_work_t& a, const outstanding_work_t& b)
+  {
+    return a.value_ == b.value_;
+  }
+
+  friend ASIO_CONSTEXPR bool operator!=(
+      const outstanding_work_t& a, const outstanding_work_t& b)
+  {
+    return a.value_ != b.value_;
+  }
+
+  struct convertible_from_outstanding_work_t
+  {
+    ASIO_CONSTEXPR convertible_from_outstanding_work_t(outstanding_work_t)
+    {
+    }
+  };
+
+  template <typename Executor>
+  friend ASIO_CONSTEXPR outstanding_work_t query(
+      const Executor& ex, convertible_from_outstanding_work_t,
+      typename enable_if<
+        can_query<const Executor&, untracked_t>::value
+      >::type* = 0)
+#if !defined(__clang__) // Clang crashes if noexcept is used here.
+#if defined(ASIO_MSVC) // Visual C++ wants the type to be qualified.
+    ASIO_NOEXCEPT_IF((
+      is_nothrow_query<const Executor&,
+        outstanding_work_t<>::untracked_t>::value))
+#else // defined(ASIO_MSVC)
+    ASIO_NOEXCEPT_IF((
+      is_nothrow_query<const Executor&, untracked_t>::value))
+#endif // defined(ASIO_MSVC)
+#endif // !defined(__clang__)
+  {
+    return asio::query(ex, untracked_t());
+  }
+
+  template <typename Executor>
+  friend ASIO_CONSTEXPR outstanding_work_t query(
+      const Executor& ex, convertible_from_outstanding_work_t,
+      typename enable_if<
+        !can_query<const Executor&, untracked_t>::value
+          && can_query<const Executor&, tracked_t>::value
+      >::type* = 0)
+#if !defined(__clang__) // Clang crashes if noexcept is used here.
+#if defined(ASIO_MSVC) // Visual C++ wants the type to be qualified.
+    ASIO_NOEXCEPT_IF((
+      is_nothrow_query<const Executor&,
+        outstanding_work_t<>::tracked_t>::value))
+#else // defined(ASIO_MSVC)
+    ASIO_NOEXCEPT_IF((
+      is_nothrow_query<const Executor&, tracked_t>::value))
+#endif // defined(ASIO_MSVC)
+#endif // !defined(__clang__)
+  {
+    return asio::query(ex, tracked_t());
+  }
+
+  ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(untracked_t, untracked);
+  ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(tracked_t, tracked);
+
+#if !defined(ASIO_HAS_CONSTEXPR)
+  static const outstanding_work_t instance;
+#endif // !defined(ASIO_HAS_CONSTEXPR)
+
+private:
+  int value_;
+};
+
+#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \
+  && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+template <int I> template <typename E, typename T>
+const T outstanding_work_t<I>::static_query_v;
+#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)
+       //   && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+
+#if !defined(ASIO_HAS_CONSTEXPR)
+template <int I>
+const outstanding_work_t<I> outstanding_work_t<I>::instance;
+#endif
+
+template <int I>
+const typename outstanding_work_t<I>::untracked_t
+outstanding_work_t<I>::untracked;
+
+template <int I>
+const typename outstanding_work_t<I>::tracked_t
+outstanding_work_t<I>::tracked;
+
+namespace outstanding_work {
+
+template <int I = 0>
+struct untracked_t
+{
+#if defined(ASIO_HAS_VARIABLE_TEMPLATES)
+  template <typename T>
+  ASIO_STATIC_CONSTEXPR(bool,
+    is_applicable_property_v = is_executor<T>::value
+      || is_sender<T>::value || is_scheduler<T>::value);
+#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+  ASIO_STATIC_CONSTEXPR(bool, is_requirable = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_preferable = true);
+  typedef outstanding_work_t<I> polymorphic_query_result_type;
+
+  ASIO_CONSTEXPR untracked_t()
+  {
+  }
+
+#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \
+  && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+  template <typename T>
+  static ASIO_CONSTEXPR
+  typename traits::query_static_constexpr_member<T, untracked_t>::result_type
+  static_query()
+    ASIO_NOEXCEPT_IF((
+      traits::query_static_constexpr_member<T, untracked_t>::is_noexcept))
+  {
+    return traits::query_static_constexpr_member<T, untracked_t>::value();
+  }
+
+  template <typename T>
+  static ASIO_CONSTEXPR untracked_t static_query(
+      typename enable_if<
+        !traits::query_static_constexpr_member<T, untracked_t>::is_valid
+          && !traits::query_member<T, untracked_t>::is_valid
+          && !traits::query_free<T, untracked_t>::is_valid
+          && !can_query<T, tracked_t<I> >::value
+      >::type* = 0) ASIO_NOEXCEPT
+  {
+    return untracked_t();
+  }
+
+  template <typename E, typename T = decltype(untracked_t::static_query<E>())>
+  static ASIO_CONSTEXPR const T static_query_v
+    = untracked_t::static_query<E>();
+#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)
+       //   && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+
+  static ASIO_CONSTEXPR outstanding_work_t<I> value()
+  {
+    return untracked_t();
+  }
+
+  friend ASIO_CONSTEXPR bool operator==(
+      const untracked_t&, const untracked_t&)
+  {
+    return true;
+  }
+
+  friend ASIO_CONSTEXPR bool operator!=(
+      const untracked_t&, const untracked_t&)
+  {
+    return false;
+  }
+};
+
+#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \
+  && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+template <int I> template <typename E, typename T>
+const T untracked_t<I>::static_query_v;
+#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)
+       //   && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+
+template <int I = 0>
+struct tracked_t
+{
+#if defined(ASIO_HAS_VARIABLE_TEMPLATES)
+  template <typename T>
+  ASIO_STATIC_CONSTEXPR(bool,
+    is_applicable_property_v = is_executor<T>::value
+      || is_sender<T>::value || is_scheduler<T>::value);
+#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+  ASIO_STATIC_CONSTEXPR(bool, is_requirable = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_preferable = true);
+  typedef outstanding_work_t<I> polymorphic_query_result_type;
+
+  ASIO_CONSTEXPR tracked_t()
+  {
+  }
+
+#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \
+  && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+  template <typename T>
+  static ASIO_CONSTEXPR
+  typename traits::query_static_constexpr_member<T, tracked_t>::result_type
+  static_query()
+    ASIO_NOEXCEPT_IF((
+      traits::query_static_constexpr_member<T, tracked_t>::is_noexcept))
+  {
+    return traits::query_static_constexpr_member<T, tracked_t>::value();
+  }
+
+  template <typename E, typename T = decltype(tracked_t::static_query<E>())>
+  static ASIO_CONSTEXPR const T static_query_v
+    = tracked_t::static_query<E>();
+#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)
+       //   && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+
+  static ASIO_CONSTEXPR outstanding_work_t<I> value()
+  {
+    return tracked_t();
+  }
+
+  friend ASIO_CONSTEXPR bool operator==(
+      const tracked_t&, const tracked_t&)
+  {
+    return true;
+  }
+
+  friend ASIO_CONSTEXPR bool operator!=(
+      const tracked_t&, const tracked_t&)
+  {
+    return false;
+  }
+};
+
+#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \
+  && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+template <int I> template <typename E, typename T>
+const T tracked_t<I>::static_query_v;
+#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)
+       //   && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+
+} // namespace outstanding_work
+} // namespace detail
+
+typedef detail::outstanding_work_t<> outstanding_work_t;
+
+#if defined(ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION)
+constexpr outstanding_work_t outstanding_work;
+#else // defined(ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION)
+namespace { static const outstanding_work_t&
+  outstanding_work = outstanding_work_t::instance; }
+#endif
+
+} // namespace execution
+
+#if !defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+template <typename T>
+struct is_applicable_property<T, execution::outstanding_work_t>
+  : integral_constant<bool,
+      execution::is_executor<T>::value
+        || execution::is_sender<T>::value
+        || execution::is_scheduler<T>::value>
+{
+};
+
+template <typename T>
+struct is_applicable_property<T, execution::outstanding_work_t::untracked_t>
+  : integral_constant<bool,
+      execution::is_executor<T>::value
+        || execution::is_sender<T>::value
+        || execution::is_scheduler<T>::value>
+{
+};
+
+template <typename T>
+struct is_applicable_property<T, execution::outstanding_work_t::tracked_t>
+  : integral_constant<bool,
+      execution::is_executor<T>::value
+        || execution::is_sender<T>::value
+        || execution::is_scheduler<T>::value>
+{
+};
+
+#endif // !defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+namespace traits {
+
+#if !defined(ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT)
+
+template <typename T>
+struct query_free_default<T, execution::outstanding_work_t,
+  typename enable_if<
+    can_query<T, execution::outstanding_work_t::untracked_t>::value
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept =
+    (is_nothrow_query<T, execution::outstanding_work_t::untracked_t>::value));
+
+  typedef execution::outstanding_work_t result_type;
+};
+
+template <typename T>
+struct query_free_default<T, execution::outstanding_work_t,
+  typename enable_if<
+    !can_query<T, execution::outstanding_work_t::untracked_t>::value
+      && can_query<T, execution::outstanding_work_t::tracked_t>::value
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept =
+    (is_nothrow_query<T, execution::outstanding_work_t::tracked_t>::value));
+
+  typedef execution::outstanding_work_t result_type;
+};
+
+#endif // !defined(ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT)
+
+#if !defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \
+  || !defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+
+template <typename T>
+struct static_query<T, execution::outstanding_work_t,
+  typename enable_if<
+    traits::query_static_constexpr_member<T,
+      execution::outstanding_work_t>::is_valid
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
+
+  typedef typename traits::query_static_constexpr_member<T,
+    execution::outstanding_work_t>::result_type result_type;
+
+  static ASIO_CONSTEXPR result_type value()
+  {
+    return traits::query_static_constexpr_member<T,
+      execution::outstanding_work_t>::value();
+  }
+};
+
+template <typename T>
+struct static_query<T, execution::outstanding_work_t,
+  typename enable_if<
+    !traits::query_static_constexpr_member<T,
+        execution::outstanding_work_t>::is_valid
+      && !traits::query_member<T,
+        execution::outstanding_work_t>::is_valid
+      && traits::static_query<T,
+        execution::outstanding_work_t::untracked_t>::is_valid
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
+
+  typedef typename traits::static_query<T,
+    execution::outstanding_work_t::untracked_t>::result_type result_type;
+
+  static ASIO_CONSTEXPR result_type value()
+  {
+    return traits::static_query<T,
+        execution::outstanding_work_t::untracked_t>::value();
+  }
+};
+
+template <typename T>
+struct static_query<T, execution::outstanding_work_t,
+  typename enable_if<
+    !traits::query_static_constexpr_member<T,
+        execution::outstanding_work_t>::is_valid
+      && !traits::query_member<T,
+        execution::outstanding_work_t>::is_valid
+      && !traits::static_query<T,
+        execution::outstanding_work_t::untracked_t>::is_valid
+      && traits::static_query<T,
+        execution::outstanding_work_t::tracked_t>::is_valid
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
+
+  typedef typename traits::static_query<T,
+    execution::outstanding_work_t::tracked_t>::result_type result_type;
+
+  static ASIO_CONSTEXPR result_type value()
+  {
+    return traits::static_query<T,
+        execution::outstanding_work_t::tracked_t>::value();
+  }
+};
+
+template <typename T>
+struct static_query<T, execution::outstanding_work_t::untracked_t,
+  typename enable_if<
+    traits::query_static_constexpr_member<T,
+      execution::outstanding_work_t::untracked_t>::is_valid
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
+
+  typedef typename traits::query_static_constexpr_member<T,
+    execution::outstanding_work_t::untracked_t>::result_type result_type;
+
+  static ASIO_CONSTEXPR result_type value()
+  {
+    return traits::query_static_constexpr_member<T,
+      execution::outstanding_work_t::untracked_t>::value();
+  }
+};
+
+template <typename T>
+struct static_query<T, execution::outstanding_work_t::untracked_t,
+  typename enable_if<
+    !traits::query_static_constexpr_member<T,
+        execution::outstanding_work_t::untracked_t>::is_valid
+      && !traits::query_member<T,
+        execution::outstanding_work_t::untracked_t>::is_valid
+      && !traits::query_free<T,
+        execution::outstanding_work_t::untracked_t>::is_valid
+      && !can_query<T, execution::outstanding_work_t::tracked_t>::value
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
+
+  typedef execution::outstanding_work_t::untracked_t result_type;
+
+  static ASIO_CONSTEXPR result_type value()
+  {
+    return result_type();
+  }
+};
+
+template <typename T>
+struct static_query<T, execution::outstanding_work_t::tracked_t,
+  typename enable_if<
+    traits::query_static_constexpr_member<T,
+      execution::outstanding_work_t::tracked_t>::is_valid
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
+
+  typedef typename traits::query_static_constexpr_member<T,
+    execution::outstanding_work_t::tracked_t>::result_type result_type;
+
+  static ASIO_CONSTEXPR result_type value()
+  {
+    return traits::query_static_constexpr_member<T,
+      execution::outstanding_work_t::tracked_t>::value();
+  }
+};
+
+#endif // !defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)
+       //   || !defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+
+#if !defined(ASIO_HAS_DEDUCED_STATIC_REQUIRE_TRAIT)
+
+template <typename T>
+struct static_require<T, execution::outstanding_work_t::untracked_t,
+  typename enable_if<
+    static_query<T, execution::outstanding_work_t::untracked_t>::is_valid
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid =
+    (is_same<typename static_query<T,
+      execution::outstanding_work_t::untracked_t>::result_type,
+        execution::outstanding_work_t::untracked_t>::value));
+};
+
+template <typename T>
+struct static_require<T, execution::outstanding_work_t::tracked_t,
+  typename enable_if<
+    static_query<T, execution::outstanding_work_t::tracked_t>::is_valid
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid =
+    (is_same<typename static_query<T,
+      execution::outstanding_work_t::tracked_t>::result_type,
+        execution::outstanding_work_t::tracked_t>::value));
+};
+
+#endif // !defined(ASIO_HAS_DEDUCED_STATIC_REQUIRE_TRAIT)
+
+} // namespace traits
+
+#endif // defined(GENERATING_DOCUMENTATION)
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_EXECUTION_OUTSTANDING_WORK_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/execution/prefer_only.hpp b/link/modules/asio-standalone/asio/include/asio/execution/prefer_only.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/execution/prefer_only.hpp
@@ -0,0 +1,327 @@
+//
+// execution/prefer_only.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_EXECUTION_PREFER_ONLY_HPP
+#define ASIO_EXECUTION_PREFER_ONLY_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/type_traits.hpp"
+#include "asio/is_applicable_property.hpp"
+#include "asio/prefer.hpp"
+#include "asio/query.hpp"
+#include "asio/traits/static_query.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+#if defined(GENERATING_DOCUMENTATION)
+
+namespace execution {
+
+/// A property adapter that is used with the polymorphic executor wrapper
+/// to mark properties as preferable, but not requirable.
+template <typename Property>
+struct prefer_only
+{
+  /// The prefer_only adapter applies to the same types as the nested property.
+  template <typename T>
+  static constexpr bool is_applicable_property_v =
+    is_applicable_property<T, Property>::value;
+
+  /// The context_t property cannot be required.
+  static constexpr bool is_requirable = false;
+
+  /// The context_t property can be preferred, it the underlying property can
+  /// be preferred.
+  /**
+   * @c true if @c Property::is_preferable is @c true, otherwise @c false.
+   */
+  static constexpr bool is_preferable = automatically_determined;
+
+  /// The type returned by queries against an @c any_executor.
+  typedef typename Property::polymorphic_query_result_type
+    polymorphic_query_result_type;
+};
+
+} // namespace execution
+
+#else // defined(GENERATING_DOCUMENTATION)
+
+namespace execution {
+namespace detail {
+
+template <typename InnerProperty, typename = void>
+struct prefer_only_is_preferable
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_preferable = false);
+};
+
+template <typename InnerProperty>
+struct prefer_only_is_preferable<InnerProperty,
+    typename enable_if<
+      InnerProperty::is_preferable
+    >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_preferable = true);
+};
+
+template <typename InnerProperty, typename = void>
+struct prefer_only_polymorphic_query_result_type
+{
+};
+
+template <typename InnerProperty>
+struct prefer_only_polymorphic_query_result_type<InnerProperty,
+    typename void_type<
+      typename InnerProperty::polymorphic_query_result_type
+    >::type>
+{
+  typedef typename InnerProperty::polymorphic_query_result_type
+    polymorphic_query_result_type;
+};
+
+template <typename InnerProperty, typename = void>
+struct prefer_only_property
+{
+  InnerProperty property;
+
+  prefer_only_property(const InnerProperty& p)
+    : property(p)
+  {
+  }
+};
+
+#if defined(ASIO_HAS_DECLTYPE) \
+  && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)
+
+template <typename InnerProperty>
+struct prefer_only_property<InnerProperty,
+    typename void_type<
+      decltype(asio::declval<const InnerProperty>().value())
+    >::type>
+{
+  InnerProperty property;
+
+  prefer_only_property(const InnerProperty& p)
+    : property(p)
+  {
+  }
+
+  ASIO_CONSTEXPR auto value() const
+    ASIO_NOEXCEPT_IF((
+      noexcept(asio::declval<const InnerProperty>().value())))
+    -> decltype(asio::declval<const InnerProperty>().value())
+  {
+    return property.value();
+  }
+};
+
+#else // defined(ASIO_HAS_DECLTYPE)
+      //   && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)
+
+struct prefer_only_memfns_base
+{
+  void value();
+};
+
+template <typename T>
+struct prefer_only_memfns_derived
+  : T, prefer_only_memfns_base
+{
+};
+
+template <typename T, T>
+struct prefer_only_memfns_check
+{
+};
+
+template <typename>
+char (&prefer_only_value_memfn_helper(...))[2];
+
+template <typename T>
+char prefer_only_value_memfn_helper(
+    prefer_only_memfns_check<
+      void (prefer_only_memfns_base::*)(),
+      &prefer_only_memfns_derived<T>::value>*);
+
+template <typename InnerProperty>
+struct prefer_only_property<InnerProperty,
+    typename enable_if<
+      sizeof(prefer_only_value_memfn_helper<InnerProperty>(0)) != 1
+        && !is_same<typename InnerProperty::polymorphic_query_result_type,
+          void>::value
+    >::type>
+{
+  InnerProperty property;
+
+  prefer_only_property(const InnerProperty& p)
+    : property(p)
+  {
+  }
+
+  ASIO_CONSTEXPR typename InnerProperty::polymorphic_query_result_type
+  value() const
+  {
+    return property.value();
+  }
+};
+
+#endif // defined(ASIO_HAS_DECLTYPE)
+       //   && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)
+
+} // namespace detail
+
+template <typename InnerProperty>
+struct prefer_only :
+  detail::prefer_only_is_preferable<InnerProperty>,
+  detail::prefer_only_polymorphic_query_result_type<InnerProperty>,
+  detail::prefer_only_property<InnerProperty>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_requirable = false);
+
+  ASIO_CONSTEXPR prefer_only(const InnerProperty& p)
+    : detail::prefer_only_property<InnerProperty>(p)
+  {
+  }
+
+#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \
+  && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+  template <typename T>
+  static ASIO_CONSTEXPR
+  typename traits::static_query<T, InnerProperty>::result_type
+  static_query()
+    ASIO_NOEXCEPT_IF((
+      traits::static_query<T, InnerProperty>::is_noexcept))
+  {
+    return traits::static_query<T, InnerProperty>::value();
+  }
+
+  template <typename E, typename T = decltype(prefer_only::static_query<E>())>
+  static ASIO_CONSTEXPR const T static_query_v
+    = prefer_only::static_query<E>();
+#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)
+       //   && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+
+  template <typename Executor, typename Property>
+  friend ASIO_CONSTEXPR
+  typename prefer_result<const Executor&, const InnerProperty&>::type
+  prefer(const Executor& ex, const prefer_only<Property>& p,
+      typename enable_if<
+        is_same<Property, InnerProperty>::value
+          && can_prefer<const Executor&, const InnerProperty&>::value
+      >::type* = 0)
+#if !defined(ASIO_MSVC) \
+  && !defined(__clang__) // Clang crashes if noexcept is used here.
+    ASIO_NOEXCEPT_IF((
+      is_nothrow_prefer<const Executor&, const InnerProperty&>::value))
+#endif // !defined(ASIO_MSVC)
+       //   && !defined(__clang__)
+  {
+    return asio::prefer(ex, p.property);
+  }
+
+  template <typename Executor, typename Property>
+  friend ASIO_CONSTEXPR
+  typename query_result<const Executor&, const InnerProperty&>::type
+  query(const Executor& ex, const prefer_only<Property>& p,
+      typename enable_if<
+        is_same<Property, InnerProperty>::value
+          && can_query<const Executor&, const InnerProperty&>::value
+      >::type* = 0)
+#if !defined(ASIO_MSVC) \
+  && !defined(__clang__) // Clang crashes if noexcept is used here.
+    ASIO_NOEXCEPT_IF((
+      is_nothrow_query<const Executor&, const InnerProperty&>::value))
+#endif // !defined(ASIO_MSVC)
+       //   && !defined(__clang__)
+  {
+    return asio::query(ex, p.property);
+  }
+};
+
+#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \
+  && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+template <typename InnerProperty> template <typename E, typename T>
+const T prefer_only<InnerProperty>::static_query_v;
+#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)
+       //   && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+
+} // namespace execution
+
+template <typename T, typename InnerProperty>
+struct is_applicable_property<T, execution::prefer_only<InnerProperty> >
+  : is_applicable_property<T, InnerProperty>
+{
+};
+
+namespace traits {
+
+#if !defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \
+  || !defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+
+template <typename T, typename InnerProperty>
+struct static_query<T, execution::prefer_only<InnerProperty> > :
+  static_query<T, const InnerProperty&>
+{
+};
+
+#endif // !defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)
+       //   || !defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+
+#if !defined(ASIO_HAS_DEDUCED_PREFER_FREE_TRAIT)
+
+template <typename T, typename InnerProperty>
+struct prefer_free_default<T, execution::prefer_only<InnerProperty>,
+    typename enable_if<
+      can_prefer<const T&, const InnerProperty&>::value
+    >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept =
+    (is_nothrow_prefer<const T&, const InnerProperty&>::value));
+
+  typedef typename prefer_result<const T&,
+      const InnerProperty&>::type result_type;
+};
+
+#endif // !defined(ASIO_HAS_DEDUCED_PREFER_FREE_TRAIT)
+
+#if !defined(ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT)
+
+template <typename T, typename InnerProperty>
+struct query_free<T, execution::prefer_only<InnerProperty>,
+    typename enable_if<
+      can_query<const T&, const InnerProperty&>::value
+    >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept =
+    (is_nothrow_query<const T&, const InnerProperty&>::value));
+
+  typedef typename query_result<const T&,
+      const InnerProperty&>::type result_type;
+};
+
+#endif // !defined(ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT)
+
+} // namespace traits
+
+#endif // defined(GENERATING_DOCUMENTATION)
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_EXECUTION_PREFER_ONLY_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/execution/receiver.hpp b/link/modules/asio-standalone/asio/include/asio/execution/receiver.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/execution/receiver.hpp
@@ -0,0 +1,280 @@
+//
+// execution/receiver.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_EXECUTION_RECEIVER_HPP
+#define ASIO_EXECUTION_RECEIVER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/type_traits.hpp"
+#include "asio/detail/variadic_templates.hpp"
+#include "asio/execution/set_done.hpp"
+#include "asio/execution/set_error.hpp"
+#include "asio/execution/set_value.hpp"
+
+#if defined(ASIO_HAS_STD_EXCEPTION_PTR)
+# include <exception>
+#else // defined(ASIO_HAS_STD_EXCEPTION_PTR)
+# include "asio/error_code.hpp"
+#endif // defined(ASIO_HAS_STD_EXCEPTION_PTR)
+
+#if defined(ASIO_HAS_DEDUCED_SET_DONE_FREE_TRAIT) \
+  && defined(ASIO_HAS_DEDUCED_SET_DONE_MEMBER_TRAIT) \
+  && defined(ASIO_HAS_DEDUCED_SET_ERROR_FREE_TRAIT) \
+  && defined(ASIO_HAS_DEDUCED_SET_ERROR_MEMBER_TRAIT) \
+  && defined(ASIO_HAS_DEDUCED_SET_VALUE_FREE_TRAIT) \
+  && defined(ASIO_HAS_DEDUCED_SET_VALUE_MEMBER_TRAIT) \
+  && defined(ASIO_HAS_DEDUCED_RECEIVER_OF_FREE_TRAIT) \
+  && defined(ASIO_HAS_DEDUCED_RECEIVER_OF_MEMBER_TRAIT)
+# define ASIO_HAS_DEDUCED_EXECUTION_IS_RECEIVER_TRAIT 1
+#endif // defined(ASIO_HAS_DEDUCED_SET_DONE_FREE_TRAIT)
+       //   && defined(ASIO_HAS_DEDUCED_SET_DONE_MEMBER_TRAIT)
+       //   && defined(ASIO_HAS_DEDUCED_SET_ERROR_FREE_TRAIT)
+       //   && defined(ASIO_HAS_DEDUCED_SET_ERROR_MEMBER_TRAIT)
+       //   && defined(ASIO_HAS_DEDUCED_SET_VALUE_FREE_TRAIT)
+       //   && defined(ASIO_HAS_DEDUCED_SET_VALUE_MEMBER_TRAIT)
+       //   && defined(ASIO_HAS_DEDUCED_RECEIVER_OF_FREE_TRAIT)
+       //   && defined(ASIO_HAS_DEDUCED_RECEIVER_OF_MEMBER_TRAIT)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace execution {
+namespace detail {
+
+template <typename T, typename E>
+struct is_receiver_base :
+  integral_constant<bool,
+    is_move_constructible<typename remove_cvref<T>::type>::value
+      && is_constructible<typename remove_cvref<T>::type, T>::value
+  >
+{
+};
+
+} // namespace detail
+
+#if defined(ASIO_HAS_STD_EXCEPTION_PTR)
+# define ASIO_EXECUTION_RECEIVER_ERROR_DEFAULT = std::exception_ptr
+#else // defined(ASIO_HAS_STD_EXCEPTION_PTR)
+# define ASIO_EXECUTION_RECEIVER_ERROR_DEFAULT \
+  = ::asio::error_code
+#endif // defined(ASIO_HAS_STD_EXCEPTION_PTR)
+
+/// The is_receiver trait detects whether a type T satisfies the
+/// execution::receiver concept.
+/**
+ * Class template @c is_receiver is a type trait that is derived from @c
+ * true_type if the type @c T meets the concept definition for a receiver for
+ * error type @c E, otherwise @c false_type.
+ */
+template <typename T, typename E ASIO_EXECUTION_RECEIVER_ERROR_DEFAULT>
+struct is_receiver :
+#if defined(GENERATING_DOCUMENTATION)
+  integral_constant<bool, automatically_determined>
+#else // defined(GENERATING_DOCUMENTATION)
+  conditional<
+    can_set_done<typename remove_cvref<T>::type>::value
+      && is_nothrow_set_done<typename remove_cvref<T>::type>::value
+      && can_set_error<typename remove_cvref<T>::type, E>::value
+      && is_nothrow_set_error<typename remove_cvref<T>::type, E>::value,
+    detail::is_receiver_base<T, E>,
+    false_type
+  >::type
+#endif // defined(GENERATING_DOCUMENTATION)
+{
+};
+
+#if defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+template <typename T, typename E ASIO_EXECUTION_RECEIVER_ERROR_DEFAULT>
+ASIO_CONSTEXPR const bool is_receiver_v = is_receiver<T, E>::value;
+
+#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+#if defined(ASIO_HAS_CONCEPTS)
+
+template <typename T, typename E ASIO_EXECUTION_RECEIVER_ERROR_DEFAULT>
+ASIO_CONCEPT receiver = is_receiver<T, E>::value;
+
+#define ASIO_EXECUTION_RECEIVER ::asio::execution::receiver
+
+#else // defined(ASIO_HAS_CONCEPTS)
+
+#define ASIO_EXECUTION_RECEIVER typename
+
+#endif // defined(ASIO_HAS_CONCEPTS)
+
+#if defined(ASIO_HAS_VARIADIC_TEMPLATES) \
+  || defined(GENERATING_DOCUMENTATION)
+
+/// The is_receiver_of trait detects whether a type T satisfies the
+/// execution::receiver_of concept for some set of value arguments.
+/**
+ * Class template @c is_receiver_of is a type trait that is derived from @c
+ * true_type if the type @c T meets the concept definition for a receiver for
+ * value arguments @c Vs, otherwise @c false_type.
+ */
+template <typename T, typename... Vs>
+struct is_receiver_of :
+#if defined(GENERATING_DOCUMENTATION)
+  integral_constant<bool, automatically_determined>
+#else // defined(GENERATING_DOCUMENTATION)
+  conditional<
+    is_receiver<T>::value,
+    can_set_value<typename remove_cvref<T>::type, Vs...>,
+    false_type
+  >::type
+#endif // defined(GENERATING_DOCUMENTATION)
+{
+};
+
+#if defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+template <typename T, typename... Vs>
+ASIO_CONSTEXPR const bool is_receiver_of_v =
+  is_receiver_of<T, Vs...>::value;
+
+#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+#if defined(ASIO_HAS_CONCEPTS)
+
+template <typename T, typename... Vs>
+ASIO_CONCEPT receiver_of = is_receiver_of<T, Vs...>::value;
+
+#define ASIO_EXECUTION_RECEIVER_OF_0 \
+  ::asio::execution::receiver_of
+
+#define ASIO_EXECUTION_RECEIVER_OF_1(v) \
+  ::asio::execution::receiver_of<v>
+
+#else // defined(ASIO_HAS_CONCEPTS)
+
+#define ASIO_EXECUTION_RECEIVER_OF_0 typename
+#define ASIO_EXECUTION_RECEIVER_OF_1(v) typename
+
+#endif // defined(ASIO_HAS_CONCEPTS)
+
+#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+      //   || defined(GENERATING_DOCUMENTATION)
+
+template <typename T, typename = void,
+    typename = void, typename = void, typename = void, typename = void,
+    typename = void, typename = void, typename = void, typename = void>
+struct is_receiver_of;
+
+template <typename T>
+struct is_receiver_of<T> :
+  conditional<
+    is_receiver<T>::value,
+    can_set_value<typename remove_cvref<T>::type>,
+    false_type
+  >::type
+{
+};
+
+#define ASIO_PRIVATE_RECEIVER_OF_TRAITS_DEF(n) \
+  template <typename T, ASIO_VARIADIC_TPARAMS(n)> \
+  struct is_receiver_of<T, ASIO_VARIADIC_TARGS(n)> : \
+    conditional< \
+      conditional<true, is_receiver<T>, void>::type::value, \
+      can_set_value< \
+        typename remove_cvref<T>::type, \
+        ASIO_VARIADIC_TARGS(n)>, \
+      false_type \
+    >::type \
+  { \
+  }; \
+  /**/
+ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_RECEIVER_OF_TRAITS_DEF)
+#undef ASIO_PRIVATE_RECEIVER_OF_TRAITS_DEF
+
+#define ASIO_EXECUTION_RECEIVER_OF_0 typename
+#define ASIO_EXECUTION_RECEIVER_OF_1(v) typename
+
+#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+       //   || defined(GENERATING_DOCUMENTATION)
+
+#if defined(ASIO_HAS_VARIADIC_TEMPLATES) \
+  || defined(GENERATING_DOCUMENTATION)
+
+/// The is_nothrow_receiver_of trait detects whether a type T satisfies the
+/// execution::receiver_of concept for some set of value arguments, with a
+/// noexcept @c set_value operation.
+/**
+ * Class template @c is_nothrow_receiver_of is a type trait that is derived
+ * from @c true_type if the type @c T meets the concept definition for a
+ * receiver for value arguments @c Vs, and the expression
+ * <tt>execution::set_value(declval<T>(), declval<Ts>()...)</tt> is noexcept,
+ * otherwise @c false_type.
+ */
+template <typename T, typename... Vs>
+struct is_nothrow_receiver_of :
+#if defined(GENERATING_DOCUMENTATION)
+  integral_constant<bool, automatically_determined>
+#else // defined(GENERATING_DOCUMENTATION)
+  integral_constant<bool,
+    is_receiver_of<T, Vs...>::value
+      && is_nothrow_set_value<typename remove_cvref<T>::type, Vs...>::value
+  >
+#endif // defined(GENERATING_DOCUMENTATION)
+{
+};
+
+#if defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+template <typename T, typename... Vs>
+ASIO_CONSTEXPR const bool is_nothrow_receiver_of_v =
+  is_nothrow_receiver_of<T, Vs...>::value;
+
+#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+      //   || defined(GENERATING_DOCUMENTATION)
+
+template <typename T, typename = void,
+    typename = void, typename = void, typename = void, typename = void,
+    typename = void, typename = void, typename = void, typename = void>
+struct is_nothrow_receiver_of;
+
+template <typename T>
+struct is_nothrow_receiver_of<T> :
+  integral_constant<bool,
+    is_receiver_of<T>::value
+      && is_nothrow_set_value<typename remove_cvref<T>::type>::value
+  >
+{
+};
+
+#define ASIO_PRIVATE_NOTHROW_RECEIVER_OF_TRAITS_DEF(n) \
+  template <typename T, ASIO_VARIADIC_TPARAMS(n)> \
+  struct is_nothrow_receiver_of<T, ASIO_VARIADIC_TARGS(n)> : \
+    integral_constant<bool, \
+      is_receiver_of<T, ASIO_VARIADIC_TARGS(n)>::value \
+        && is_nothrow_set_value<typename remove_cvref<T>::type, \
+          ASIO_VARIADIC_TARGS(n)>::value \
+    > \
+  { \
+  }; \
+  /**/
+ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_NOTHROW_RECEIVER_OF_TRAITS_DEF)
+#undef ASIO_PRIVATE_NOTHROW_RECEIVER_OF_TRAITS_DEF
+
+#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+       //   || defined(GENERATING_DOCUMENTATION)
+
+} // namespace execution
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_EXECUTION_RECEIVER_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/execution/receiver_invocation_error.hpp b/link/modules/asio-standalone/asio/include/asio/execution/receiver_invocation_error.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/execution/receiver_invocation_error.hpp
@@ -0,0 +1,48 @@
+//
+// execution/receiver_invocation_error.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_EXECUTION_RECEIVER_INVOCATION_ERROR_HPP
+#define ASIO_EXECUTION_RECEIVER_INVOCATION_ERROR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <stdexcept>
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace execution {
+
+/// Exception reported via @c set_error when an exception escapes from
+/// @c set_value.
+class receiver_invocation_error
+  : public std::runtime_error
+#if defined(ASIO_HAS_STD_NESTED_EXCEPTION)
+  , public std::nested_exception
+#endif // defined(ASIO_HAS_STD_NESTED_EXCEPTION)
+{
+public:
+  /// Constructor.
+  ASIO_DECL receiver_invocation_error();
+};
+
+} // namespace execution
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/execution/impl/receiver_invocation_error.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // ASIO_EXECUTION_RECEIVER_INVOCATION_ERROR_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/execution/relationship.hpp b/link/modules/asio-standalone/asio/include/asio/execution/relationship.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/execution/relationship.hpp
@@ -0,0 +1,720 @@
+//
+// execution/relationship.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_EXECUTION_RELATIONSHIP_HPP
+#define ASIO_EXECUTION_RELATIONSHIP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/type_traits.hpp"
+#include "asio/execution/executor.hpp"
+#include "asio/execution/scheduler.hpp"
+#include "asio/execution/sender.hpp"
+#include "asio/is_applicable_property.hpp"
+#include "asio/query.hpp"
+#include "asio/traits/query_free.hpp"
+#include "asio/traits/query_member.hpp"
+#include "asio/traits/query_static_constexpr_member.hpp"
+#include "asio/traits/static_query.hpp"
+#include "asio/traits/static_require.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+#if defined(GENERATING_DOCUMENTATION)
+
+namespace execution {
+
+/// A property to describe whether submitted tasks represent continuations of
+/// the calling context.
+struct relationship_t
+{
+  /// The relationship_t property applies to executors, senders, and schedulers.
+  template <typename T>
+  static constexpr bool is_applicable_property_v =
+    is_executor_v<T> || is_sender_v<T> || is_scheduler_v<T>;
+
+  /// The top-level relationship_t property cannot be required.
+  static constexpr bool is_requirable = false;
+
+  /// The top-level relationship_t property cannot be preferred.
+  static constexpr bool is_preferable = false;
+
+  /// The type returned by queries against an @c any_executor.
+  typedef relationship_t polymorphic_query_result_type;
+
+  /// A sub-property that indicates that the executor does not represent a
+  /// continuation of the calling context.
+  struct fork_t
+  {
+    /// The relationship_t::fork_t property applies to executors, senders, and
+    /// schedulers.
+    template <typename T>
+    static constexpr bool is_applicable_property_v =
+      is_executor_v<T> || is_sender_v<T> || is_scheduler_v<T>;
+
+    /// The relationship_t::fork_t property can be required.
+    static constexpr bool is_requirable = true;
+
+    /// The relationship_t::fork_t property can be preferred.
+    static constexpr bool is_preferable = true;
+
+    /// The type returned by queries against an @c any_executor.
+    typedef relationship_t polymorphic_query_result_type;
+
+    /// Default constructor.
+    constexpr fork_t();
+
+    /// Get the value associated with a property object.
+    /**
+     * @returns fork_t();
+     */
+    static constexpr relationship_t value();
+  };
+
+  /// A sub-property that indicates that the executor represents a continuation
+  /// of the calling context.
+  struct continuation_t
+  {
+    /// The relationship_t::continuation_t property applies to executors,
+    /// senders, and schedulers.
+    template <typename T>
+    static constexpr bool is_applicable_property_v =
+      is_executor_v<T> || is_sender_v<T> || is_scheduler_v<T>;
+
+    /// The relationship_t::continuation_t property can be required.
+    static constexpr bool is_requirable = true;
+
+    /// The relationship_t::continuation_t property can be preferred.
+    static constexpr bool is_preferable = true;
+
+    /// The type returned by queries against an @c any_executor.
+    typedef relationship_t polymorphic_query_result_type;
+
+    /// Default constructor.
+    constexpr continuation_t();
+
+    /// Get the value associated with a property object.
+    /**
+     * @returns continuation_t();
+     */
+    static constexpr relationship_t value();
+  };
+
+  /// A special value used for accessing the relationship_t::fork_t property.
+  static constexpr fork_t fork;
+
+  /// A special value used for accessing the relationship_t::continuation_t
+  /// property.
+  static constexpr continuation_t continuation;
+
+  /// Default constructor.
+  constexpr relationship_t();
+
+  /// Construct from a sub-property value.
+  constexpr relationship_t(fork_t);
+
+  /// Construct from a sub-property value.
+  constexpr relationship_t(continuation_t);
+
+  /// Compare property values for equality.
+  friend constexpr bool operator==(
+      const relationship_t& a, const relationship_t& b) noexcept;
+
+  /// Compare property values for inequality.
+  friend constexpr bool operator!=(
+      const relationship_t& a, const relationship_t& b) noexcept;
+};
+
+/// A special value used for accessing the relationship_t property.
+constexpr relationship_t relationship;
+
+} // namespace execution
+
+#else // defined(GENERATING_DOCUMENTATION)
+
+namespace execution {
+namespace detail {
+namespace relationship {
+
+template <int I> struct fork_t;
+template <int I> struct continuation_t;
+
+} // namespace relationship
+
+template <int I = 0>
+struct relationship_t
+{
+#if defined(ASIO_HAS_VARIABLE_TEMPLATES)
+  template <typename T>
+  ASIO_STATIC_CONSTEXPR(bool,
+    is_applicable_property_v = is_executor<T>::value
+      || is_sender<T>::value || is_scheduler<T>::value);
+#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+  ASIO_STATIC_CONSTEXPR(bool, is_requirable = false);
+  ASIO_STATIC_CONSTEXPR(bool, is_preferable = false);
+  typedef relationship_t polymorphic_query_result_type;
+
+  typedef detail::relationship::fork_t<I> fork_t;
+  typedef detail::relationship::continuation_t<I> continuation_t;
+
+  ASIO_CONSTEXPR relationship_t()
+    : value_(-1)
+  {
+  }
+
+  ASIO_CONSTEXPR relationship_t(fork_t)
+    : value_(0)
+  {
+  }
+
+  ASIO_CONSTEXPR relationship_t(continuation_t)
+    : value_(1)
+  {
+  }
+
+#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \
+  && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+  template <typename T>
+  static ASIO_CONSTEXPR
+  typename traits::query_static_constexpr_member<
+      T, relationship_t>::result_type
+  static_query()
+    ASIO_NOEXCEPT_IF((
+      traits::query_static_constexpr_member<
+        T, relationship_t
+      >::is_noexcept))
+  {
+    return traits::query_static_constexpr_member<
+        T, relationship_t>::value();
+  }
+
+  template <typename T>
+  static ASIO_CONSTEXPR
+  typename traits::static_query<T, fork_t>::result_type
+  static_query(
+      typename enable_if<
+        !traits::query_static_constexpr_member<
+            T, relationship_t>::is_valid
+          && !traits::query_member<T, relationship_t>::is_valid
+          && traits::static_query<T, fork_t>::is_valid
+      >::type* = 0) ASIO_NOEXCEPT
+  {
+    return traits::static_query<T, fork_t>::value();
+  }
+
+  template <typename T>
+  static ASIO_CONSTEXPR
+  typename traits::static_query<T, continuation_t>::result_type
+  static_query(
+      typename enable_if<
+        !traits::query_static_constexpr_member<
+            T, relationship_t>::is_valid
+          && !traits::query_member<T, relationship_t>::is_valid
+          && !traits::static_query<T, fork_t>::is_valid
+          && traits::static_query<T, continuation_t>::is_valid
+      >::type* = 0) ASIO_NOEXCEPT
+  {
+    return traits::static_query<T, continuation_t>::value();
+  }
+
+  template <typename E,
+      typename T = decltype(relationship_t::static_query<E>())>
+  static ASIO_CONSTEXPR const T static_query_v
+    = relationship_t::static_query<E>();
+#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)
+       //   && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+
+  friend ASIO_CONSTEXPR bool operator==(
+      const relationship_t& a, const relationship_t& b)
+  {
+    return a.value_ == b.value_;
+  }
+
+  friend ASIO_CONSTEXPR bool operator!=(
+      const relationship_t& a, const relationship_t& b)
+  {
+    return a.value_ != b.value_;
+  }
+
+  struct convertible_from_relationship_t
+  {
+    ASIO_CONSTEXPR convertible_from_relationship_t(relationship_t)
+    {
+    }
+  };
+
+  template <typename Executor>
+  friend ASIO_CONSTEXPR relationship_t query(
+      const Executor& ex, convertible_from_relationship_t,
+      typename enable_if<
+        can_query<const Executor&, fork_t>::value
+      >::type* = 0)
+#if !defined(__clang__) // Clang crashes if noexcept is used here.
+#if defined(ASIO_MSVC) // Visual C++ wants the type to be qualified.
+    ASIO_NOEXCEPT_IF((
+      is_nothrow_query<const Executor&, relationship_t<>::fork_t>::value))
+#else // defined(ASIO_MSVC)
+    ASIO_NOEXCEPT_IF((
+      is_nothrow_query<const Executor&, fork_t>::value))
+#endif // defined(ASIO_MSVC)
+#endif // !defined(__clang__)
+  {
+    return asio::query(ex, fork_t());
+  }
+
+  template <typename Executor>
+  friend ASIO_CONSTEXPR relationship_t query(
+      const Executor& ex, convertible_from_relationship_t,
+      typename enable_if<
+        !can_query<const Executor&, fork_t>::value
+          && can_query<const Executor&, continuation_t>::value
+      >::type* = 0)
+#if !defined(__clang__) // Clang crashes if noexcept is used here.
+#if defined(ASIO_MSVC) // Visual C++ wants the type to be qualified.
+    ASIO_NOEXCEPT_IF((
+      is_nothrow_query<const Executor&,
+        relationship_t<>::continuation_t>::value))
+#else // defined(ASIO_MSVC)
+    ASIO_NOEXCEPT_IF((
+      is_nothrow_query<const Executor&, continuation_t>::value))
+#endif // defined(ASIO_MSVC)
+#endif // !defined(__clang__)
+  {
+    return asio::query(ex, continuation_t());
+  }
+
+  ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(fork_t, fork);
+  ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(continuation_t, continuation);
+
+#if !defined(ASIO_HAS_CONSTEXPR)
+  static const relationship_t instance;
+#endif // !defined(ASIO_HAS_CONSTEXPR)
+
+private:
+  int value_;
+};
+
+#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \
+  && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+template <int I> template <typename E, typename T>
+const T relationship_t<I>::static_query_v;
+#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)
+       //   && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+
+#if !defined(ASIO_HAS_CONSTEXPR)
+template <int I>
+const relationship_t<I> relationship_t<I>::instance;
+#endif
+
+template <int I>
+const typename relationship_t<I>::fork_t
+relationship_t<I>::fork;
+
+template <int I>
+const typename relationship_t<I>::continuation_t
+relationship_t<I>::continuation;
+
+namespace relationship {
+
+template <int I = 0>
+struct fork_t
+{
+#if defined(ASIO_HAS_VARIABLE_TEMPLATES)
+  template <typename T>
+  ASIO_STATIC_CONSTEXPR(bool,
+    is_applicable_property_v = is_executor<T>::value
+      || is_sender<T>::value || is_scheduler<T>::value);
+#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+  ASIO_STATIC_CONSTEXPR(bool, is_requirable = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_preferable = true);
+  typedef relationship_t<I> polymorphic_query_result_type;
+
+  ASIO_CONSTEXPR fork_t()
+  {
+  }
+
+#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \
+  && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+  template <typename T>
+  static ASIO_CONSTEXPR
+  typename traits::query_static_constexpr_member<T, fork_t>::result_type
+  static_query()
+    ASIO_NOEXCEPT_IF((
+      traits::query_static_constexpr_member<T, fork_t>::is_noexcept))
+  {
+    return traits::query_static_constexpr_member<T, fork_t>::value();
+  }
+
+  template <typename T>
+  static ASIO_CONSTEXPR fork_t static_query(
+      typename enable_if<
+        !traits::query_static_constexpr_member<T, fork_t>::is_valid
+          && !traits::query_member<T, fork_t>::is_valid
+          && !traits::query_free<T, fork_t>::is_valid
+          && !can_query<T, continuation_t<I> >::value
+      >::type* = 0) ASIO_NOEXCEPT
+  {
+    return fork_t();
+  }
+
+  template <typename E, typename T = decltype(fork_t::static_query<E>())>
+  static ASIO_CONSTEXPR const T static_query_v
+    = fork_t::static_query<E>();
+#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)
+       //   && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+
+  static ASIO_CONSTEXPR relationship_t<I> value()
+  {
+    return fork_t();
+  }
+
+  friend ASIO_CONSTEXPR bool operator==(
+      const fork_t&, const fork_t&)
+  {
+    return true;
+  }
+
+  friend ASIO_CONSTEXPR bool operator!=(
+      const fork_t&, const fork_t&)
+  {
+    return false;
+  }
+};
+
+#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \
+  && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+template <int I> template <typename E, typename T>
+const T fork_t<I>::static_query_v;
+#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)
+       //   && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+
+template <int I = 0>
+struct continuation_t
+{
+#if defined(ASIO_HAS_VARIABLE_TEMPLATES)
+  template <typename T>
+  ASIO_STATIC_CONSTEXPR(bool,
+    is_applicable_property_v = is_executor<T>::value
+      || is_sender<T>::value || is_scheduler<T>::value);
+#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+  ASIO_STATIC_CONSTEXPR(bool, is_requirable = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_preferable = true);
+  typedef relationship_t<I> polymorphic_query_result_type;
+
+  ASIO_CONSTEXPR continuation_t()
+  {
+  }
+
+#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \
+  && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+  template <typename T>
+  static ASIO_CONSTEXPR
+  typename traits::query_static_constexpr_member<T, continuation_t>::result_type
+  static_query()
+    ASIO_NOEXCEPT_IF((
+      traits::query_static_constexpr_member<T, continuation_t>::is_noexcept))
+  {
+    return traits::query_static_constexpr_member<T, continuation_t>::value();
+  }
+
+  template <typename E,
+      typename T = decltype(continuation_t::static_query<E>())>
+  static ASIO_CONSTEXPR const T static_query_v
+    = continuation_t::static_query<E>();
+#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)
+       //   && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+
+  static ASIO_CONSTEXPR relationship_t<I> value()
+  {
+    return continuation_t();
+  }
+
+  friend ASIO_CONSTEXPR bool operator==(
+      const continuation_t&, const continuation_t&)
+  {
+    return true;
+  }
+
+  friend ASIO_CONSTEXPR bool operator!=(
+      const continuation_t&, const continuation_t&)
+  {
+    return false;
+  }
+};
+
+#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \
+  && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+template <int I> template <typename E, typename T>
+const T continuation_t<I>::static_query_v;
+#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)
+       //   && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+
+} // namespace relationship
+} // namespace detail
+
+typedef detail::relationship_t<> relationship_t;
+
+#if defined(ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION)
+constexpr relationship_t relationship;
+#else // defined(ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION)
+namespace { static const relationship_t&
+  relationship = relationship_t::instance; }
+#endif
+
+} // namespace execution
+
+#if !defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+template <typename T>
+struct is_applicable_property<T, execution::relationship_t>
+  : integral_constant<bool,
+      execution::is_executor<T>::value
+        || execution::is_sender<T>::value
+        || execution::is_scheduler<T>::value>
+{
+};
+
+template <typename T>
+struct is_applicable_property<T, execution::relationship_t::fork_t>
+  : integral_constant<bool,
+      execution::is_executor<T>::value
+        || execution::is_sender<T>::value
+        || execution::is_scheduler<T>::value>
+{
+};
+
+template <typename T>
+struct is_applicable_property<T, execution::relationship_t::continuation_t>
+  : integral_constant<bool,
+      execution::is_executor<T>::value
+        || execution::is_sender<T>::value
+        || execution::is_scheduler<T>::value>
+{
+};
+
+#endif // !defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+namespace traits {
+
+#if !defined(ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT)
+
+template <typename T>
+struct query_free_default<T, execution::relationship_t,
+  typename enable_if<
+    can_query<T, execution::relationship_t::fork_t>::value
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept =
+    (is_nothrow_query<T, execution::relationship_t::fork_t>::value));
+
+  typedef execution::relationship_t result_type;
+};
+
+template <typename T>
+struct query_free_default<T, execution::relationship_t,
+  typename enable_if<
+    !can_query<T, execution::relationship_t::fork_t>::value
+      && can_query<T, execution::relationship_t::continuation_t>::value
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept =
+    (is_nothrow_query<T, execution::relationship_t::continuation_t>::value));
+
+  typedef execution::relationship_t result_type;
+};
+
+#endif // !defined(ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT)
+
+#if !defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \
+  || !defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+
+template <typename T>
+struct static_query<T, execution::relationship_t,
+  typename enable_if<
+    traits::query_static_constexpr_member<T,
+      execution::relationship_t>::is_valid
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
+
+  typedef typename traits::query_static_constexpr_member<T,
+    execution::relationship_t>::result_type result_type;
+
+  static ASIO_CONSTEXPR result_type value()
+  {
+    return traits::query_static_constexpr_member<T,
+      execution::relationship_t>::value();
+  }
+};
+
+template <typename T>
+struct static_query<T, execution::relationship_t,
+  typename enable_if<
+    !traits::query_static_constexpr_member<T,
+        execution::relationship_t>::is_valid
+      && !traits::query_member<T,
+        execution::relationship_t>::is_valid
+      && traits::static_query<T,
+        execution::relationship_t::fork_t>::is_valid
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
+
+  typedef typename traits::static_query<T,
+    execution::relationship_t::fork_t>::result_type result_type;
+
+  static ASIO_CONSTEXPR result_type value()
+  {
+    return traits::static_query<T,
+        execution::relationship_t::fork_t>::value();
+  }
+};
+
+template <typename T>
+struct static_query<T, execution::relationship_t,
+  typename enable_if<
+    !traits::query_static_constexpr_member<T,
+        execution::relationship_t>::is_valid
+      && !traits::query_member<T,
+        execution::relationship_t>::is_valid
+      && !traits::static_query<T,
+        execution::relationship_t::fork_t>::is_valid
+      && traits::static_query<T,
+        execution::relationship_t::continuation_t>::is_valid
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
+
+  typedef typename traits::static_query<T,
+    execution::relationship_t::continuation_t>::result_type result_type;
+
+  static ASIO_CONSTEXPR result_type value()
+  {
+    return traits::static_query<T,
+        execution::relationship_t::continuation_t>::value();
+  }
+};
+
+template <typename T>
+struct static_query<T, execution::relationship_t::fork_t,
+  typename enable_if<
+    traits::query_static_constexpr_member<T,
+      execution::relationship_t::fork_t>::is_valid
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
+
+  typedef typename traits::query_static_constexpr_member<T,
+    execution::relationship_t::fork_t>::result_type result_type;
+
+  static ASIO_CONSTEXPR result_type value()
+  {
+    return traits::query_static_constexpr_member<T,
+      execution::relationship_t::fork_t>::value();
+  }
+};
+
+template <typename T>
+struct static_query<T, execution::relationship_t::fork_t,
+  typename enable_if<
+    !traits::query_static_constexpr_member<T,
+        execution::relationship_t::fork_t>::is_valid
+      && !traits::query_member<T,
+        execution::relationship_t::fork_t>::is_valid
+      && !traits::query_free<T,
+        execution::relationship_t::fork_t>::is_valid
+      && !can_query<T, execution::relationship_t::continuation_t>::value
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
+
+  typedef execution::relationship_t::fork_t result_type;
+
+  static ASIO_CONSTEXPR result_type value()
+  {
+    return result_type();
+  }
+};
+
+template <typename T>
+struct static_query<T, execution::relationship_t::continuation_t,
+  typename enable_if<
+    traits::query_static_constexpr_member<T,
+      execution::relationship_t::continuation_t>::is_valid
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
+
+  typedef typename traits::query_static_constexpr_member<T,
+    execution::relationship_t::continuation_t>::result_type result_type;
+
+  static ASIO_CONSTEXPR result_type value()
+  {
+    return traits::query_static_constexpr_member<T,
+      execution::relationship_t::continuation_t>::value();
+  }
+};
+
+#endif // !defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)
+       //   || !defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
+
+#if !defined(ASIO_HAS_DEDUCED_STATIC_REQUIRE_TRAIT)
+
+template <typename T>
+struct static_require<T, execution::relationship_t::fork_t,
+  typename enable_if<
+    static_query<T, execution::relationship_t::fork_t>::is_valid
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid =
+    (is_same<typename static_query<T,
+      execution::relationship_t::fork_t>::result_type,
+        execution::relationship_t::fork_t>::value));
+};
+
+template <typename T>
+struct static_require<T, execution::relationship_t::continuation_t,
+  typename enable_if<
+    static_query<T, execution::relationship_t::continuation_t>::is_valid
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid =
+    (is_same<typename static_query<T,
+      execution::relationship_t::continuation_t>::result_type,
+        execution::relationship_t::continuation_t>::value));
+};
+
+#endif // !defined(ASIO_HAS_DEDUCED_STATIC_REQUIRE_TRAIT)
+
+} // namespace traits
+
+#endif // defined(GENERATING_DOCUMENTATION)
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_EXECUTION_RELATIONSHIP_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/execution/schedule.hpp b/link/modules/asio-standalone/asio/include/asio/execution/schedule.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/execution/schedule.hpp
@@ -0,0 +1,290 @@
+//
+// execution/schedule.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_EXECUTION_SCHEDULE_HPP
+#define ASIO_EXECUTION_SCHEDULE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/type_traits.hpp"
+#include "asio/execution/executor.hpp"
+#include "asio/traits/schedule_member.hpp"
+#include "asio/traits/schedule_free.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+#if defined(GENERATING_DOCUMENTATION)
+
+namespace asio {
+namespace execution {
+
+/// A customisation point that is used to obtain a sender from a scheduler.
+/**
+ * The name <tt>execution::schedule</tt> denotes a customisation point object.
+ * For some subexpression <tt>s</tt>, let <tt>S</tt> be a type such that
+ * <tt>decltype((s))</tt> is <tt>S</tt>. The expression
+ * <tt>execution::schedule(s)</tt> is expression-equivalent to:
+ *
+ * @li <tt>s.schedule()</tt>, if that expression is valid and its type models
+ *   <tt>sender</tt>.
+ *
+ * @li Otherwise, <tt>schedule(s)</tt>, if that expression is valid and its
+ *   type models <tt>sender</tt> with overload resolution performed in a context
+ *   that includes the declaration <tt>void schedule();</tt> and that does not
+ *   include a declaration of <tt>execution::schedule</tt>.
+ *
+ * @li Otherwise, <tt>S</tt> if <tt>S</tt> satisfies <tt>executor</tt>.
+ *
+ * @li Otherwise, <tt>execution::schedule(s)</tt> is ill-formed.
+ */
+inline constexpr unspecified schedule = unspecified;
+
+/// A type trait that determines whether a @c schedule expression is
+/// well-formed.
+/**
+ * Class template @c can_schedule is a trait that is derived from @c true_type
+ * if the expression <tt>execution::schedule(std::declval<S>())</tt> is well
+ * formed; otherwise @c false_type.
+ */
+template <typename S>
+struct can_schedule :
+  integral_constant<bool, automatically_determined>
+{
+};
+
+} // namespace execution
+} // namespace asio
+
+#else // defined(GENERATING_DOCUMENTATION)
+
+namespace asio_execution_schedule_fn {
+
+using asio::decay;
+using asio::declval;
+using asio::enable_if;
+using asio::execution::is_executor;
+using asio::traits::schedule_free;
+using asio::traits::schedule_member;
+
+void schedule();
+
+enum overload_type
+{
+  identity,
+  call_member,
+  call_free,
+  ill_formed
+};
+
+template <typename S, typename = void>
+struct call_traits
+{
+  ASIO_STATIC_CONSTEXPR(overload_type, overload = ill_formed);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
+  typedef void result_type;
+};
+
+template <typename S>
+struct call_traits<S,
+  typename enable_if<
+    (
+      schedule_member<S>::is_valid
+    )
+  >::type> :
+  schedule_member<S>
+{
+  ASIO_STATIC_CONSTEXPR(overload_type, overload = call_member);
+};
+
+template <typename S>
+struct call_traits<S,
+  typename enable_if<
+    (
+      !schedule_member<S>::is_valid
+      &&
+      schedule_free<S>::is_valid
+    )
+  >::type> :
+  schedule_free<S>
+{
+  ASIO_STATIC_CONSTEXPR(overload_type, overload = call_free);
+};
+
+template <typename S>
+struct call_traits<S,
+  typename enable_if<
+    (
+      !schedule_member<S>::is_valid
+      &&
+      !schedule_free<S>::is_valid
+      &&
+      is_executor<typename decay<S>::type>::value
+    )
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(overload_type, overload = identity);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
+
+#if defined(ASIO_HAS_MOVE)
+  typedef ASIO_MOVE_ARG(S) result_type;
+#else // defined(ASIO_HAS_MOVE)
+  typedef ASIO_MOVE_ARG(typename decay<S>::type) result_type;
+#endif // defined(ASIO_HAS_MOVE)
+};
+
+struct impl
+{
+  template <typename S>
+  ASIO_CONSTEXPR typename enable_if<
+    call_traits<S>::overload == identity,
+    typename call_traits<S>::result_type
+  >::type
+  operator()(ASIO_MOVE_ARG(S) s) const
+    ASIO_NOEXCEPT_IF((
+      call_traits<S>::is_noexcept))
+  {
+    return ASIO_MOVE_CAST(S)(s);
+  }
+
+#if defined(ASIO_HAS_MOVE)
+  template <typename S>
+  ASIO_CONSTEXPR typename enable_if<
+    call_traits<S>::overload == call_member,
+    typename call_traits<S>::result_type
+  >::type
+  operator()(S&& s) const
+    ASIO_NOEXCEPT_IF((
+      call_traits<S>::is_noexcept))
+  {
+    return ASIO_MOVE_CAST(S)(s).schedule();
+  }
+
+  template <typename S>
+  ASIO_CONSTEXPR typename enable_if<
+    call_traits<S>::overload == call_free,
+    typename call_traits<S>::result_type
+  >::type
+  operator()(S&& s) const
+    ASIO_NOEXCEPT_IF((
+      call_traits<S>::is_noexcept))
+  {
+    return schedule(ASIO_MOVE_CAST(S)(s));
+  }
+#else // defined(ASIO_HAS_MOVE)
+  template <typename S>
+  ASIO_CONSTEXPR typename enable_if<
+    call_traits<S&>::overload == call_member,
+    typename call_traits<S&>::result_type
+  >::type
+  operator()(S& s) const
+    ASIO_NOEXCEPT_IF((
+      call_traits<S&>::is_noexcept))
+  {
+    return s.schedule();
+  }
+
+  template <typename S>
+  ASIO_CONSTEXPR typename enable_if<
+    call_traits<const S&>::overload == call_member,
+    typename call_traits<const S&>::result_type
+  >::type
+  operator()(const S& s) const
+    ASIO_NOEXCEPT_IF((
+      call_traits<const S&>::is_noexcept))
+  {
+    return s.schedule();
+  }
+
+  template <typename S>
+  ASIO_CONSTEXPR typename enable_if<
+    call_traits<S&>::overload == call_free,
+    typename call_traits<S&>::result_type
+  >::type
+  operator()(S& s) const
+    ASIO_NOEXCEPT_IF((
+      call_traits<S&>::is_noexcept))
+  {
+    return schedule(s);
+  }
+
+  template <typename S>
+  ASIO_CONSTEXPR typename enable_if<
+    call_traits<const S&>::overload == call_free,
+    typename call_traits<const S&>::result_type
+  >::type
+  operator()(const S& s) const
+    ASIO_NOEXCEPT_IF((
+      call_traits<const S&>::is_noexcept))
+  {
+    return schedule(s);
+  }
+#endif // defined(ASIO_HAS_MOVE)
+};
+
+template <typename T = impl>
+struct static_instance
+{
+  static const T instance;
+};
+
+template <typename T>
+const T static_instance<T>::instance = {};
+
+} // namespace asio_execution_schedule_fn
+namespace asio {
+namespace execution {
+namespace {
+
+static ASIO_CONSTEXPR const asio_execution_schedule_fn::impl&
+  schedule = asio_execution_schedule_fn::static_instance<>::instance;
+
+} // namespace
+
+template <typename S>
+struct can_schedule :
+  integral_constant<bool,
+    asio_execution_schedule_fn::call_traits<S>::overload !=
+      asio_execution_schedule_fn::ill_formed>
+{
+};
+
+#if defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+template <typename S>
+constexpr bool can_schedule_v = can_schedule<S>::value;
+
+#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+template <typename S>
+struct is_nothrow_schedule :
+  integral_constant<bool,
+    asio_execution_schedule_fn::call_traits<S>::is_noexcept>
+{
+};
+
+#if defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+template <typename S>
+constexpr bool is_nothrow_schedule_v
+  = is_nothrow_schedule<S>::value;
+
+#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+} // namespace execution
+} // namespace asio
+
+#endif // defined(GENERATING_DOCUMENTATION)
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_EXECUTION_SCHEDULE_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/execution/scheduler.hpp b/link/modules/asio-standalone/asio/include/asio/execution/scheduler.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/execution/scheduler.hpp
@@ -0,0 +1,86 @@
+//
+// execution/scheduler.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_EXECUTION_SCHEDULER_HPP
+#define ASIO_EXECUTION_SCHEDULER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/type_traits.hpp"
+#include "asio/execution/schedule.hpp"
+#include "asio/traits/equality_comparable.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace execution {
+namespace detail {
+
+template <typename T>
+struct is_scheduler_base :
+  integral_constant<bool,
+    is_copy_constructible<typename remove_cvref<T>::type>::value
+      && traits::equality_comparable<typename remove_cvref<T>::type>::is_valid
+  >
+{
+};
+
+} // namespace detail
+
+/// The is_scheduler trait detects whether a type T satisfies the
+/// execution::scheduler concept.
+/**
+ * Class template @c is_scheduler is a type trait that is derived from @c
+ * true_type if the type @c T meets the concept definition for a scheduler for
+ * error type @c E, otherwise @c false_type.
+ */
+template <typename T>
+struct is_scheduler :
+#if defined(GENERATING_DOCUMENTATION)
+  integral_constant<bool, automatically_determined>
+#else // defined(GENERATING_DOCUMENTATION)
+  conditional<
+    can_schedule<T>::value,
+    detail::is_scheduler_base<T>,
+    false_type
+  >::type
+#endif // defined(GENERATING_DOCUMENTATION)
+{
+};
+
+#if defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+template <typename T>
+ASIO_CONSTEXPR const bool is_scheduler_v = is_scheduler<T>::value;
+
+#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+#if defined(ASIO_HAS_CONCEPTS)
+
+template <typename T>
+ASIO_CONCEPT scheduler = is_scheduler<T>::value;
+
+#define ASIO_EXECUTION_SCHEDULER ::asio::execution::scheduler
+
+#else // defined(ASIO_HAS_CONCEPTS)
+
+#define ASIO_EXECUTION_SCHEDULER typename
+
+#endif // defined(ASIO_HAS_CONCEPTS)
+
+} // namespace execution
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_EXECUTION_SCHEDULER_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/execution/sender.hpp b/link/modules/asio-standalone/asio/include/asio/execution/sender.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/execution/sender.hpp
@@ -0,0 +1,311 @@
+//
+// execution/sender.hpp
+// ~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_EXECUTION_SENDER_HPP
+#define ASIO_EXECUTION_SENDER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/type_traits.hpp"
+#include "asio/execution/detail/as_invocable.hpp"
+#include "asio/execution/detail/void_receiver.hpp"
+#include "asio/execution/executor.hpp"
+#include "asio/execution/receiver.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+#if defined(ASIO_HAS_ALIAS_TEMPLATES) \
+  && defined(ASIO_HAS_VARIADIC_TEMPLATES) \
+  && defined(ASIO_HAS_DECLTYPE) \
+  && !defined(ASIO_MSVC) || (_MSC_VER >= 1910)
+# define ASIO_HAS_DEDUCED_EXECUTION_IS_TYPED_SENDER_TRAIT 1
+#endif // defined(ASIO_HAS_ALIAS_TEMPLATES)
+       //   && defined(ASIO_HAS_VARIADIC_TEMPLATES)
+       //   && defined(ASIO_HAS_DECLTYPE)
+       //   && !defined(ASIO_MSVC) || (_MSC_VER >= 1910)
+
+namespace asio {
+namespace execution {
+namespace detail {
+
+namespace sender_base_ns { struct sender_base {}; }
+
+template <typename S, typename = void>
+struct sender_traits_base
+{
+  typedef void asio_execution_sender_traits_base_is_unspecialised;
+};
+
+template <typename S>
+struct sender_traits_base<S,
+    typename enable_if<
+      is_base_of<sender_base_ns::sender_base, S>::value
+    >::type>
+{
+};
+
+template <typename S, typename = void, typename = void, typename = void>
+struct has_sender_types : false_type
+{
+};
+
+#if defined(ASIO_HAS_DEDUCED_EXECUTION_IS_TYPED_SENDER_TRAIT)
+
+template <
+    template <
+      template <typename...> class Tuple,
+      template <typename...> class Variant
+    > class>
+struct has_value_types
+{
+  typedef void type;
+};
+
+template <
+  template <
+    template <typename...> class Variant
+  > class>
+struct has_error_types
+{
+  typedef void type;
+};
+
+template <typename S>
+struct has_sender_types<S,
+    typename has_value_types<S::template value_types>::type,
+    typename has_error_types<S::template error_types>::type,
+    typename conditional<S::sends_done, void, void>::type> : true_type
+{
+};
+
+template <typename S>
+struct sender_traits_base<S,
+    typename enable_if<
+      has_sender_types<S>::value
+    >::type>
+{
+  template <
+      template <typename...> class Tuple,
+      template <typename...> class Variant>
+  using value_types = typename S::template value_types<Tuple, Variant>;
+
+  template <template <typename...> class Variant>
+  using error_types = typename S::template error_types<Variant>;
+
+  ASIO_STATIC_CONSTEXPR(bool, sends_done = S::sends_done);
+};
+
+#endif // defined(ASIO_HAS_DEDUCED_EXECUTION_IS_TYPED_SENDER_TRAIT)
+
+template <typename S>
+struct sender_traits_base<S,
+    typename enable_if<
+      !has_sender_types<S>::value
+        && detail::is_executor_of_impl<S,
+          as_invocable<void_receiver, S> >::value
+    >::type>
+{
+#if defined(ASIO_HAS_DEDUCED_EXECUTION_IS_TYPED_SENDER_TRAIT) \
+  && defined(ASIO_HAS_STD_EXCEPTION_PTR)
+
+  template <
+      template <typename...> class Tuple,
+      template <typename...> class Variant>
+  using value_types = Variant<Tuple<>>;
+
+  template <template <typename...> class Variant>
+  using error_types = Variant<std::exception_ptr>;
+
+  ASIO_STATIC_CONSTEXPR(bool, sends_done = true);
+
+#endif // defined(ASIO_HAS_DEDUCED_EXECUTION_IS_TYPED_SENDER_TRAIT)
+       //   && defined(ASIO_HAS_STD_EXCEPTION_PTR)
+};
+
+} // namespace detail
+
+/// Base class used for tagging senders.
+#if defined(GENERATING_DOCUMENTATION)
+typedef unspecified sender_base;
+#else // defined(GENERATING_DOCUMENTATION)
+typedef detail::sender_base_ns::sender_base sender_base;
+#endif // defined(GENERATING_DOCUMENTATION)
+
+/// Traits for senders.
+template <typename S>
+struct sender_traits
+#if !defined(GENERATING_DOCUMENTATION)
+  : detail::sender_traits_base<S>
+#endif // !defined(GENERATING_DOCUMENTATION)
+{
+};
+
+namespace detail {
+
+template <typename S, typename = void>
+struct has_sender_traits : true_type
+{
+};
+
+template <typename S>
+struct has_sender_traits<S,
+    typename enable_if<
+      is_same<
+        typename asio::execution::sender_traits<
+          S>::asio_execution_sender_traits_base_is_unspecialised,
+        void
+      >::value
+    >::type> : false_type
+{
+};
+
+} // namespace detail
+
+/// The is_sender trait detects whether a type T satisfies the
+/// execution::sender concept.
+
+/**
+ * Class template @c is_sender is a type trait that is derived from @c
+ * true_type if the type @c T meets the concept definition for a sender,
+ * otherwise @c false_type.
+ */
+template <typename T>
+struct is_sender :
+#if defined(GENERATING_DOCUMENTATION)
+  integral_constant<bool, automatically_determined>
+#else // defined(GENERATING_DOCUMENTATION)
+  conditional<
+    detail::has_sender_traits<typename remove_cvref<T>::type>::value,
+    is_move_constructible<typename remove_cvref<T>::type>,
+    false_type
+  >::type
+#endif // defined(GENERATING_DOCUMENTATION)
+{
+};
+
+#if defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+template <typename T>
+ASIO_CONSTEXPR const bool is_sender_v = is_sender<T>::value;
+
+#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+#if defined(ASIO_HAS_CONCEPTS)
+
+template <typename T>
+ASIO_CONCEPT sender = is_sender<T>::value;
+
+#define ASIO_EXECUTION_SENDER ::asio::execution::sender
+
+#else // defined(ASIO_HAS_CONCEPTS)
+
+#define ASIO_EXECUTION_SENDER typename
+
+#endif // defined(ASIO_HAS_CONCEPTS)
+
+template <typename S, typename R>
+struct can_connect;
+
+/// The is_sender_to trait detects whether a type T satisfies the
+/// execution::sender_to concept for some receiver.
+/**
+ * Class template @c is_sender_to is a type trait that is derived from @c
+ * true_type if the type @c T meets the concept definition for a sender
+ * for some receiver type R, otherwise @c false.
+ */
+template <typename T, typename R>
+struct is_sender_to :
+#if defined(GENERATING_DOCUMENTATION)
+  integral_constant<bool, automatically_determined>
+#else // defined(GENERATING_DOCUMENTATION)
+  integral_constant<bool,
+    is_sender<T>::value
+      && is_receiver<R>::value
+      && can_connect<T, R>::value
+  >
+#endif // defined(GENERATING_DOCUMENTATION)
+{
+};
+
+#if defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+template <typename T, typename R>
+ASIO_CONSTEXPR const bool is_sender_to_v =
+  is_sender_to<T, R>::value;
+
+#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+#if defined(ASIO_HAS_CONCEPTS)
+
+template <typename T, typename R>
+ASIO_CONCEPT sender_to = is_sender_to<T, R>::value;
+
+#define ASIO_EXECUTION_SENDER_TO(r) \
+  ::asio::execution::sender_to<r>
+
+#else // defined(ASIO_HAS_CONCEPTS)
+
+#define ASIO_EXECUTION_SENDER_TO(r) typename
+
+#endif // defined(ASIO_HAS_CONCEPTS)
+
+/// The is_typed_sender trait detects whether a type T satisfies the
+/// execution::typed_sender concept.
+/**
+ * Class template @c is_typed_sender is a type trait that is derived from @c
+ * true_type if the type @c T meets the concept definition for a typed sender,
+ * otherwise @c false.
+ */
+template <typename T>
+struct is_typed_sender :
+#if defined(GENERATING_DOCUMENTATION)
+  integral_constant<bool, automatically_determined>
+#else // defined(GENERATING_DOCUMENTATION)
+  integral_constant<bool,
+    is_sender<T>::value
+      && detail::has_sender_types<
+        sender_traits<typename remove_cvref<T>::type> >::value
+  >
+#endif // defined(GENERATING_DOCUMENTATION)
+{
+};
+
+#if defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+template <typename T>
+ASIO_CONSTEXPR const bool is_typed_sender_v = is_typed_sender<T>::value;
+
+#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+#if defined(ASIO_HAS_CONCEPTS)
+
+template <typename T>
+ASIO_CONCEPT typed_sender = is_typed_sender<T>::value;
+
+#define ASIO_EXECUTION_TYPED_SENDER \
+  ::asio::execution::typed_sender
+
+#else // defined(ASIO_HAS_CONCEPTS)
+
+#define ASIO_EXECUTION_TYPED_SENDER typename
+
+#endif // defined(ASIO_HAS_CONCEPTS)
+
+} // namespace execution
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/execution/connect.hpp"
+
+#endif // ASIO_EXECUTION_SENDER_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/execution/set_done.hpp b/link/modules/asio-standalone/asio/include/asio/execution/set_done.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/execution/set_done.hpp
@@ -0,0 +1,253 @@
+//
+// execution/set_done.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_EXECUTION_SET_DONE_HPP
+#define ASIO_EXECUTION_SET_DONE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/type_traits.hpp"
+#include "asio/traits/set_done_member.hpp"
+#include "asio/traits/set_done_free.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+#if defined(GENERATING_DOCUMENTATION)
+
+namespace asio {
+namespace execution {
+
+/// A customisation point that delivers a done notification to a receiver.
+/**
+ * The name <tt>execution::set_done</tt> denotes a customisation point object.
+ * The expression <tt>execution::set_done(R)</tt> for some subexpression
+ * <tt>R</tt> is expression-equivalent to:
+ *
+ * @li <tt>R.set_done()</tt>, if that expression is valid. If the function
+ *   selected does not signal the receiver <tt>R</tt>'s done channel, the
+ *   program is ill-formed with no diagnostic required.
+ *
+ * @li Otherwise, <tt>set_done(R)</tt>, if that expression is valid, with
+ * overload resolution performed in a context that includes the declaration
+ * <tt>void set_done();</tt> and that does not include a declaration of
+ * <tt>execution::set_done</tt>. If the function selected by overload
+ * resolution does not signal the receiver <tt>R</tt>'s done channel, the
+ * program is ill-formed with no diagnostic required.
+ *
+ * @li Otherwise, <tt>execution::set_done(R)</tt> is ill-formed.
+ */
+inline constexpr unspecified set_done = unspecified;
+
+/// A type trait that determines whether a @c set_done expression is
+/// well-formed.
+/**
+ * Class template @c can_set_done is a trait that is derived from
+ * @c true_type if the expression <tt>execution::set_done(std::declval<R>(),
+ * std::declval<E>())</tt> is well formed; otherwise @c false_type.
+ */
+template <typename R>
+struct can_set_done :
+  integral_constant<bool, automatically_determined>
+{
+};
+
+} // namespace execution
+} // namespace asio
+
+#else // defined(GENERATING_DOCUMENTATION)
+
+namespace asio_execution_set_done_fn {
+
+using asio::decay;
+using asio::declval;
+using asio::enable_if;
+using asio::traits::set_done_free;
+using asio::traits::set_done_member;
+
+void set_done();
+
+enum overload_type
+{
+  call_member,
+  call_free,
+  ill_formed
+};
+
+template <typename R, typename = void>
+struct call_traits
+{
+  ASIO_STATIC_CONSTEXPR(overload_type, overload = ill_formed);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
+  typedef void result_type;
+};
+
+template <typename R>
+struct call_traits<R,
+  typename enable_if<
+    (
+      set_done_member<R>::is_valid
+    )
+  >::type> :
+  set_done_member<R>
+{
+  ASIO_STATIC_CONSTEXPR(overload_type, overload = call_member);
+};
+
+template <typename R>
+struct call_traits<R,
+  typename enable_if<
+    (
+      !set_done_member<R>::is_valid
+      &&
+      set_done_free<R>::is_valid
+    )
+  >::type> :
+  set_done_free<R>
+{
+  ASIO_STATIC_CONSTEXPR(overload_type, overload = call_free);
+};
+
+struct impl
+{
+#if defined(ASIO_HAS_MOVE)
+  template <typename R>
+  ASIO_CONSTEXPR typename enable_if<
+    call_traits<R>::overload == call_member,
+    typename call_traits<R>::result_type
+  >::type
+  operator()(R&& r) const
+    ASIO_NOEXCEPT_IF((
+      call_traits<R>::is_noexcept))
+  {
+    return ASIO_MOVE_CAST(R)(r).set_done();
+  }
+
+  template <typename R>
+  ASIO_CONSTEXPR typename enable_if<
+    call_traits<R>::overload == call_free,
+    typename call_traits<R>::result_type
+  >::type
+  operator()(R&& r) const
+    ASIO_NOEXCEPT_IF((
+      call_traits<R>::is_noexcept))
+  {
+    return set_done(ASIO_MOVE_CAST(R)(r));
+  }
+#else // defined(ASIO_HAS_MOVE)
+  template <typename R>
+  ASIO_CONSTEXPR typename enable_if<
+    call_traits<R&>::overload == call_member,
+    typename call_traits<R&>::result_type
+  >::type
+  operator()(R& r) const
+    ASIO_NOEXCEPT_IF((
+      call_traits<R&>::is_noexcept))
+  {
+    return r.set_done();
+  }
+
+  template <typename R>
+  ASIO_CONSTEXPR typename enable_if<
+    call_traits<const R&>::overload == call_member,
+    typename call_traits<const R&>::result_type
+  >::type
+  operator()(const R& r) const
+    ASIO_NOEXCEPT_IF((
+      call_traits<const R&>::is_noexcept))
+  {
+    return r.set_done();
+  }
+
+  template <typename R>
+  ASIO_CONSTEXPR typename enable_if<
+    call_traits<R&>::overload == call_free,
+    typename call_traits<R&>::result_type
+  >::type
+  operator()(R& r) const
+    ASIO_NOEXCEPT_IF((
+      call_traits<R&>::is_noexcept))
+  {
+    return set_done(r);
+  }
+
+  template <typename R>
+  ASIO_CONSTEXPR typename enable_if<
+    call_traits<const R&>::overload == call_free,
+    typename call_traits<const R&>::result_type
+  >::type
+  operator()(const R& r) const
+    ASIO_NOEXCEPT_IF((
+      call_traits<const R&>::is_noexcept))
+  {
+    return set_done(r);
+  }
+#endif // defined(ASIO_HAS_MOVE)
+};
+
+template <typename T = impl>
+struct static_instance
+{
+  static const T instance;
+};
+
+template <typename T>
+const T static_instance<T>::instance = {};
+
+} // namespace asio_execution_set_done_fn
+namespace asio {
+namespace execution {
+namespace {
+
+static ASIO_CONSTEXPR const asio_execution_set_done_fn::impl&
+  set_done = asio_execution_set_done_fn::static_instance<>::instance;
+
+} // namespace
+
+template <typename R>
+struct can_set_done :
+  integral_constant<bool,
+    asio_execution_set_done_fn::call_traits<R>::overload !=
+      asio_execution_set_done_fn::ill_formed>
+{
+};
+
+#if defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+template <typename R>
+constexpr bool can_set_done_v = can_set_done<R>::value;
+
+#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+template <typename R>
+struct is_nothrow_set_done :
+  integral_constant<bool,
+    asio_execution_set_done_fn::call_traits<R>::is_noexcept>
+{
+};
+
+#if defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+template <typename R>
+constexpr bool is_nothrow_set_done_v
+  = is_nothrow_set_done<R>::value;
+
+#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+} // namespace execution
+} // namespace asio
+
+#endif // defined(GENERATING_DOCUMENTATION)
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_EXECUTION_SET_DONE_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/execution/set_error.hpp b/link/modules/asio-standalone/asio/include/asio/execution/set_error.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/execution/set_error.hpp
@@ -0,0 +1,253 @@
+//
+// execution/set_error.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_EXECUTION_SET_ERROR_HPP
+#define ASIO_EXECUTION_SET_ERROR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/type_traits.hpp"
+#include "asio/traits/set_error_member.hpp"
+#include "asio/traits/set_error_free.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+#if defined(GENERATING_DOCUMENTATION)
+
+namespace asio {
+namespace execution {
+
+/// A customisation point that delivers an error notification to a receiver.
+/**
+ * The name <tt>execution::set_error</tt> denotes a customisation point object.
+ * The expression <tt>execution::set_error(R, E)</tt> for some subexpressions
+ * <tt>R</tt> and <tt>E</tt> are expression-equivalent to:
+ *
+ * @li <tt>R.set_error(E)</tt>, if that expression is valid. If the function
+ *   selected does not send the error <tt>E</tt> to the receiver <tt>R</tt>'s
+ *   error channel, the program is ill-formed with no diagnostic required.
+ *
+ * @li Otherwise, <tt>set_error(R, E)</tt>, if that expression is valid, with
+ *   overload resolution performed in a context that includes the declaration
+ *   <tt>void set_error();</tt> and that does not include a declaration of
+ *   <tt>execution::set_error</tt>. If the function selected by overload
+ *   resolution does not send the error <tt>E</tt> to the receiver <tt>R</tt>'s
+ *   error channel, the program is ill-formed with no diagnostic required.
+ *
+ * @li Otherwise, <tt>execution::set_error(R, E)</tt> is ill-formed.
+ */
+inline constexpr unspecified set_error = unspecified;
+
+/// A type trait that determines whether a @c set_error expression is
+/// well-formed.
+/**
+ * Class template @c can_set_error is a trait that is derived from
+ * @c true_type if the expression <tt>execution::set_error(std::declval<R>(),
+ * std::declval<E>())</tt> is well formed; otherwise @c false_type.
+ */
+template <typename R, typename E>
+struct can_set_error :
+  integral_constant<bool, automatically_determined>
+{
+};
+
+} // namespace execution
+} // namespace asio
+
+#else // defined(GENERATING_DOCUMENTATION)
+
+namespace asio_execution_set_error_fn {
+
+using asio::decay;
+using asio::declval;
+using asio::enable_if;
+using asio::traits::set_error_free;
+using asio::traits::set_error_member;
+
+void set_error();
+
+enum overload_type
+{
+  call_member,
+  call_free,
+  ill_formed
+};
+
+template <typename R, typename E, typename = void>
+struct call_traits
+{
+  ASIO_STATIC_CONSTEXPR(overload_type, overload = ill_formed);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
+  typedef void result_type;
+};
+
+template <typename R, typename E>
+struct call_traits<R, void(E),
+  typename enable_if<
+    (
+      set_error_member<R, E>::is_valid
+    )
+  >::type> :
+  set_error_member<R, E>
+{
+  ASIO_STATIC_CONSTEXPR(overload_type, overload = call_member);
+};
+
+template <typename R, typename E>
+struct call_traits<R, void(E),
+  typename enable_if<
+    (
+      !set_error_member<R, E>::is_valid
+      &&
+      set_error_free<R, E>::is_valid
+    )
+  >::type> :
+  set_error_free<R, E>
+{
+  ASIO_STATIC_CONSTEXPR(overload_type, overload = call_free);
+};
+
+struct impl
+{
+#if defined(ASIO_HAS_MOVE)
+  template <typename R, typename E>
+  ASIO_CONSTEXPR typename enable_if<
+    call_traits<R, void(E)>::overload == call_member,
+    typename call_traits<R, void(E)>::result_type
+  >::type
+  operator()(R&& r, E&& e) const
+    ASIO_NOEXCEPT_IF((
+      call_traits<R, void(E)>::is_noexcept))
+  {
+    return ASIO_MOVE_CAST(R)(r).set_error(ASIO_MOVE_CAST(E)(e));
+  }
+
+  template <typename R, typename E>
+  ASIO_CONSTEXPR typename enable_if<
+    call_traits<R, void(E)>::overload == call_free,
+    typename call_traits<R, void(E)>::result_type
+  >::type
+  operator()(R&& r, E&& e) const
+    ASIO_NOEXCEPT_IF((
+      call_traits<R, void(E)>::is_noexcept))
+  {
+    return set_error(ASIO_MOVE_CAST(R)(r), ASIO_MOVE_CAST(E)(e));
+  }
+#else // defined(ASIO_HAS_MOVE)
+  template <typename R, typename E>
+  ASIO_CONSTEXPR typename enable_if<
+    call_traits<R&, void(const E&)>::overload == call_member,
+    typename call_traits<R&, void(const E&)>::result_type
+  >::type
+  operator()(R& r, const E& e) const
+    ASIO_NOEXCEPT_IF((
+      call_traits<R&, void(const E&)>::is_noexcept))
+  {
+    return r.set_error(e);
+  }
+
+  template <typename R, typename E>
+  ASIO_CONSTEXPR typename enable_if<
+    call_traits<const R&, void(const E&)>::overload == call_member,
+    typename call_traits<const R&, void(const E&)>::result_type
+  >::type
+  operator()(const R& r, const E& e) const
+    ASIO_NOEXCEPT_IF((
+      call_traits<const R&, void(const E&)>::is_noexcept))
+  {
+    return r.set_error(e);
+  }
+
+  template <typename R, typename E>
+  ASIO_CONSTEXPR typename enable_if<
+    call_traits<R&, void(const E&)>::overload == call_free,
+    typename call_traits<R&, void(const E&)>::result_type
+  >::type
+  operator()(R& r, const E& e) const
+    ASIO_NOEXCEPT_IF((
+      call_traits<R&, void(const E&)>::is_noexcept))
+  {
+    return set_error(r, e);
+  }
+
+  template <typename R, typename E>
+  ASIO_CONSTEXPR typename enable_if<
+    call_traits<const R&, void(const E&)>::overload == call_free,
+    typename call_traits<const R&, void(const E&)>::result_type
+  >::type
+  operator()(const R& r, const E& e) const
+    ASIO_NOEXCEPT_IF((
+      call_traits<const R&, void(const E&)>::is_noexcept))
+  {
+    return set_error(r, e);
+  }
+#endif // defined(ASIO_HAS_MOVE)
+};
+
+template <typename T = impl>
+struct static_instance
+{
+  static const T instance;
+};
+
+template <typename T>
+const T static_instance<T>::instance = {};
+
+} // namespace asio_execution_set_error_fn
+namespace asio {
+namespace execution {
+namespace {
+
+static ASIO_CONSTEXPR const asio_execution_set_error_fn::impl&
+  set_error = asio_execution_set_error_fn::static_instance<>::instance;
+
+} // namespace
+
+template <typename R, typename E>
+struct can_set_error :
+  integral_constant<bool,
+    asio_execution_set_error_fn::call_traits<R, void(E)>::overload !=
+      asio_execution_set_error_fn::ill_formed>
+{
+};
+
+#if defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+template <typename R, typename E>
+constexpr bool can_set_error_v = can_set_error<R, E>::value;
+
+#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+template <typename R, typename E>
+struct is_nothrow_set_error :
+  integral_constant<bool,
+    asio_execution_set_error_fn::call_traits<R, void(E)>::is_noexcept>
+{
+};
+
+#if defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+template <typename R, typename E>
+constexpr bool is_nothrow_set_error_v
+  = is_nothrow_set_error<R, E>::value;
+
+#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+} // namespace execution
+} // namespace asio
+
+#endif // defined(GENERATING_DOCUMENTATION)
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_EXECUTION_SET_ERROR_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/execution/set_value.hpp b/link/modules/asio-standalone/asio/include/asio/execution/set_value.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/execution/set_value.hpp
@@ -0,0 +1,486 @@
+//
+// execution/set_value.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_EXECUTION_SET_VALUE_HPP
+#define ASIO_EXECUTION_SET_VALUE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/type_traits.hpp"
+#include "asio/detail/variadic_templates.hpp"
+#include "asio/traits/set_value_member.hpp"
+#include "asio/traits/set_value_free.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+#if defined(GENERATING_DOCUMENTATION)
+
+namespace asio {
+namespace execution {
+
+/// A customisation point that delivers a value to a receiver.
+/**
+ * The name <tt>execution::set_value</tt> denotes a customisation point object.
+ * The expression <tt>execution::set_value(R, Vs...)</tt> for some
+ * subexpressions <tt>R</tt> and <tt>Vs...</tt> is expression-equivalent to:
+ *
+ * @li <tt>R.set_value(Vs...)</tt>, if that expression is valid. If the
+ *   function selected does not send the value(s) <tt>Vs...</tt> to the receiver
+ *   <tt>R</tt>'s value channel, the program is ill-formed with no diagnostic
+ *   required.
+ *
+ * @li Otherwise, <tt>set_value(R, Vs...)</tt>, if that expression is valid,
+ *   with overload resolution performed in a context that includes the
+ *   declaration <tt>void set_value();</tt> and that does not include a
+ *   declaration of <tt>execution::set_value</tt>. If the function selected by
+ *   overload resolution does not send the value(s) <tt>Vs...</tt> to the
+ *   receiver <tt>R</tt>'s value channel, the program is ill-formed with no
+ *   diagnostic required.
+ *
+ * @li Otherwise, <tt>execution::set_value(R, Vs...)</tt> is ill-formed.
+ */
+inline constexpr unspecified set_value = unspecified;
+
+/// A type trait that determines whether a @c set_value expression is
+/// well-formed.
+/**
+ * Class template @c can_set_value is a trait that is derived from
+ * @c true_type if the expression <tt>execution::set_value(std::declval<R>(),
+ * std::declval<Vs>()...)</tt> is well formed; otherwise @c false_type.
+ */
+template <typename R, typename... Vs>
+struct can_set_value :
+  integral_constant<bool, automatically_determined>
+{
+};
+
+} // namespace execution
+} // namespace asio
+
+#else // defined(GENERATING_DOCUMENTATION)
+
+namespace asio_execution_set_value_fn {
+
+using asio::decay;
+using asio::declval;
+using asio::enable_if;
+using asio::traits::set_value_free;
+using asio::traits::set_value_member;
+
+void set_value();
+
+enum overload_type
+{
+  call_member,
+  call_free,
+  ill_formed
+};
+
+template <typename R, typename Vs, typename = void>
+struct call_traits
+{
+  ASIO_STATIC_CONSTEXPR(overload_type, overload = ill_formed);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
+  typedef void result_type;
+};
+
+template <typename R, typename Vs>
+struct call_traits<R, Vs,
+  typename enable_if<
+    (
+      set_value_member<R, Vs>::is_valid
+    )
+  >::type> :
+  set_value_member<R, Vs>
+{
+  ASIO_STATIC_CONSTEXPR(overload_type, overload = call_member);
+};
+
+template <typename R, typename Vs>
+struct call_traits<R, Vs,
+  typename enable_if<
+    (
+      !set_value_member<R, Vs>::is_valid
+      &&
+      set_value_free<R, Vs>::is_valid
+    )
+  >::type> :
+  set_value_free<R, Vs>
+{
+  ASIO_STATIC_CONSTEXPR(overload_type, overload = call_free);
+};
+
+struct impl
+{
+#if defined(ASIO_HAS_MOVE)
+
+#if defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+  template <typename R, typename... Vs>
+  ASIO_CONSTEXPR typename enable_if<
+    call_traits<R, void(Vs...)>::overload == call_member,
+    typename call_traits<R, void(Vs...)>::result_type
+  >::type
+  operator()(R&& r, Vs&&... v) const
+    ASIO_NOEXCEPT_IF((
+      call_traits<R, void(Vs...)>::is_noexcept))
+  {
+    return ASIO_MOVE_CAST(R)(r).set_value(ASIO_MOVE_CAST(Vs)(v)...);
+  }
+
+  template <typename R, typename... Vs>
+  ASIO_CONSTEXPR typename enable_if<
+    call_traits<R, void(Vs...)>::overload == call_free,
+    typename call_traits<R, void(Vs...)>::result_type
+  >::type
+  operator()(R&& r, Vs&&... v) const
+    ASIO_NOEXCEPT_IF((
+      call_traits<R, void(Vs...)>::is_noexcept))
+  {
+    return set_value(ASIO_MOVE_CAST(R)(r),
+        ASIO_MOVE_CAST(Vs)(v)...);
+  }
+
+#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+  template <typename R>
+  ASIO_CONSTEXPR typename enable_if<
+    call_traits<R, void()>::overload == call_member,
+    typename call_traits<R, void()>::result_type
+  >::type
+  operator()(R&& r) const
+    ASIO_NOEXCEPT_IF((
+      call_traits<R, void()>::is_noexcept))
+  {
+    return ASIO_MOVE_CAST(R)(r).set_value();
+  }
+
+  template <typename R>
+  ASIO_CONSTEXPR typename enable_if<
+    call_traits<R, void()>::overload == call_free,
+    typename call_traits<R, void()>::result_type
+  >::type
+  operator()(R&& r) const
+    ASIO_NOEXCEPT_IF((
+      call_traits<R, void()>::is_noexcept))
+  {
+    return set_value(ASIO_MOVE_CAST(R)(r));
+  }
+
+#define ASIO_PRIVATE_SET_VALUE_CALL_DEF(n) \
+  template <typename R, ASIO_VARIADIC_TPARAMS(n)> \
+  ASIO_CONSTEXPR typename enable_if< \
+    call_traits<R, \
+      void(ASIO_VARIADIC_TARGS(n))>::overload == call_member, \
+    typename call_traits<R, void(ASIO_VARIADIC_TARGS(n))>::result_type \
+  >::type \
+  operator()(R&& r, ASIO_VARIADIC_MOVE_PARAMS(n)) const \
+    ASIO_NOEXCEPT_IF(( \
+      call_traits<R, void(ASIO_VARIADIC_TARGS(n))>::is_noexcept)) \
+  { \
+    return ASIO_MOVE_CAST(R)(r).set_value( \
+        ASIO_VARIADIC_MOVE_ARGS(n)); \
+  } \
+  \
+  template <typename R, ASIO_VARIADIC_TPARAMS(n)> \
+  ASIO_CONSTEXPR typename enable_if< \
+    call_traits<R, void(ASIO_VARIADIC_TARGS(n))>::overload == call_free, \
+    typename call_traits<R, void(ASIO_VARIADIC_TARGS(n))>::result_type \
+  >::type \
+  operator()(R&& r, ASIO_VARIADIC_MOVE_PARAMS(n)) const \
+    ASIO_NOEXCEPT_IF(( \
+      call_traits<R, void(ASIO_VARIADIC_TARGS(n))>::is_noexcept)) \
+  { \
+    return set_value(ASIO_MOVE_CAST(R)(r), \
+        ASIO_VARIADIC_MOVE_ARGS(n)); \
+  } \
+  /**/
+ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_SET_VALUE_CALL_DEF)
+#undef ASIO_PRIVATE_SET_VALUE_CALL_DEF
+
+#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+#else // defined(ASIO_HAS_MOVE)
+
+#if defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+  template <typename R, typename... Vs>
+  ASIO_CONSTEXPR typename enable_if<
+    call_traits<R&, void(const Vs&...)>::overload == call_member,
+    typename call_traits<R&, void(const Vs&...)>::result_type
+  >::type
+  operator()(R& r, const Vs&... v) const
+    ASIO_NOEXCEPT_IF((
+      call_traits<R&, void(const Vs&...)>::is_noexcept))
+  {
+    return r.set_value(v...);
+  }
+
+  template <typename R, typename... Vs>
+  ASIO_CONSTEXPR typename enable_if<
+    call_traits<const R&, void(const Vs&...)>::overload == call_member,
+    typename call_traits<const R&, void(const Vs&...)>::result_type
+  >::type
+  operator()(const R& r, const Vs&... v) const
+    ASIO_NOEXCEPT_IF((
+      call_traits<const R&, void(const Vs&...)>::is_noexcept))
+  {
+    return r.set_value(v...);
+  }
+
+  template <typename R, typename... Vs>
+  ASIO_CONSTEXPR typename enable_if<
+    call_traits<R&, void(const Vs&...)>::overload == call_free,
+    typename call_traits<R&, void(const Vs&...)>::result_type
+  >::type
+  operator()(R& r, const Vs&... v) const
+    ASIO_NOEXCEPT_IF((
+      call_traits<R&, void(const Vs&...)>::is_noexcept))
+  {
+    return set_value(r, v...);
+  }
+
+  template <typename R, typename... Vs>
+  ASIO_CONSTEXPR typename enable_if<
+    call_traits<const R&, void(const Vs&...)>::overload == call_free,
+    typename call_traits<const R&, void(const Vs&...)>::result_type
+  >::type
+  operator()(const R& r, const Vs&... v) const
+    ASIO_NOEXCEPT_IF((
+      call_traits<const R&, void(const Vs&...)>::is_noexcept))
+  {
+    return set_value(r, v...);
+  }
+
+#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+  template <typename R>
+  ASIO_CONSTEXPR typename enable_if<
+    call_traits<R&, void()>::overload == call_member,
+    typename call_traits<R&, void()>::result_type
+  >::type
+  operator()(R& r) const
+    ASIO_NOEXCEPT_IF((
+      call_traits<R&, void()>::is_noexcept))
+  {
+    return r.set_value();
+  }
+
+  template <typename R>
+  ASIO_CONSTEXPR typename enable_if<
+    call_traits<const R&, void()>::overload == call_member,
+    typename call_traits<const R&, void()>::result_type
+  >::type
+  operator()(const R& r) const
+    ASIO_NOEXCEPT_IF((
+      call_traits<const R&, void()>::is_noexcept))
+  {
+    return r.set_value();
+  }
+
+  template <typename R>
+  ASIO_CONSTEXPR typename enable_if<
+    call_traits<R&, void()>::overload == call_free,
+    typename call_traits<R&, void()>::result_type
+  >::type
+  operator()(R& r) const
+    ASIO_NOEXCEPT_IF((
+      call_traits<R&, void()>::is_noexcept))
+  {
+    return set_value(r);
+  }
+
+  template <typename R>
+  ASIO_CONSTEXPR typename enable_if<
+    call_traits<const R&, void()>::overload == call_free,
+    typename call_traits<const R&, void()>::result_type
+  >::type
+  operator()(const R& r) const
+    ASIO_NOEXCEPT_IF((
+      call_traits<const R&, void()>::is_noexcept))
+  {
+    return set_value(r);
+  }
+
+#define ASIO_PRIVATE_SET_VALUE_CALL_DEF(n) \
+  template <typename R, ASIO_VARIADIC_TPARAMS(n)> \
+  ASIO_CONSTEXPR typename enable_if< \
+    call_traits<R&, \
+      void(ASIO_VARIADIC_TARGS(n))>::overload == call_member, \
+    typename call_traits<R&, void(ASIO_VARIADIC_TARGS(n))>::result_type \
+  >::type \
+  operator()(R& r, ASIO_VARIADIC_MOVE_PARAMS(n)) const \
+    ASIO_NOEXCEPT_IF(( \
+      call_traits<R&, void(ASIO_VARIADIC_TARGS(n))>::is_noexcept)) \
+  { \
+    return r.set_value(ASIO_VARIADIC_MOVE_ARGS(n)); \
+  } \
+  \
+  template <typename R, ASIO_VARIADIC_TPARAMS(n)> \
+  ASIO_CONSTEXPR typename enable_if< \
+    call_traits<const R&, \
+      void(ASIO_VARIADIC_TARGS(n))>::overload == call_member, \
+    typename call_traits<const R&, \
+      void(ASIO_VARIADIC_TARGS(n))>::result_type \
+  >::type \
+  operator()(const R& r, ASIO_VARIADIC_MOVE_PARAMS(n)) const \
+    ASIO_NOEXCEPT_IF(( \
+      call_traits<const R&, void(ASIO_VARIADIC_TARGS(n))>::is_noexcept)) \
+  { \
+    return r.set_value(ASIO_VARIADIC_MOVE_ARGS(n)); \
+  } \
+  \
+  template <typename R, ASIO_VARIADIC_TPARAMS(n)> \
+  ASIO_CONSTEXPR typename enable_if< \
+    call_traits<R&, \
+      void(ASIO_VARIADIC_TARGS(n))>::overload == call_free, \
+    typename call_traits<R&, void(ASIO_VARIADIC_TARGS(n))>::result_type \
+  >::type \
+  operator()(R& r, ASIO_VARIADIC_MOVE_PARAMS(n)) const \
+    ASIO_NOEXCEPT_IF(( \
+      call_traits<R&, void(ASIO_VARIADIC_TARGS(n))>::is_noexcept)) \
+  { \
+    return set_value(r, ASIO_VARIADIC_MOVE_ARGS(n)); \
+  } \
+  \
+  template <typename R, ASIO_VARIADIC_TPARAMS(n)> \
+  ASIO_CONSTEXPR typename enable_if< \
+    call_traits<const R&, \
+      void(ASIO_VARIADIC_TARGS(n))>::overload == call_free, \
+    typename call_traits<const R&, \
+      void(ASIO_VARIADIC_TARGS(n))>::result_type \
+  >::type \
+  operator()(const R& r, ASIO_VARIADIC_MOVE_PARAMS(n)) const \
+    ASIO_NOEXCEPT_IF(( \
+      call_traits<const R&, void(ASIO_VARIADIC_TARGS(n))>::is_noexcept)) \
+  { \
+    return set_value(r, ASIO_VARIADIC_MOVE_ARGS(n)); \
+  } \
+  /**/
+ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_SET_VALUE_CALL_DEF)
+#undef ASIO_PRIVATE_SET_VALUE_CALL_DEF
+
+#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+#endif // defined(ASIO_HAS_MOVE)
+};
+
+template <typename T = impl>
+struct static_instance
+{
+  static const T instance;
+};
+
+template <typename T>
+const T static_instance<T>::instance = {};
+
+} // namespace asio_execution_set_value_fn
+namespace asio {
+namespace execution {
+namespace {
+
+static ASIO_CONSTEXPR const asio_execution_set_value_fn::impl&
+  set_value = asio_execution_set_value_fn::static_instance<>::instance;
+
+} // namespace
+
+#if defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+template <typename R, typename... Vs>
+struct can_set_value :
+  integral_constant<bool,
+    asio_execution_set_value_fn::call_traits<R, void(Vs...)>::overload !=
+      asio_execution_set_value_fn::ill_formed>
+{
+};
+
+#if defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+template <typename R, typename... Vs>
+constexpr bool can_set_value_v = can_set_value<R, Vs...>::value;
+
+#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+template <typename R, typename... Vs>
+struct is_nothrow_set_value :
+  integral_constant<bool,
+    asio_execution_set_value_fn::call_traits<R, void(Vs...)>::is_noexcept>
+{
+};
+
+#if defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+template <typename R, typename... Vs>
+constexpr bool is_nothrow_set_value_v
+  = is_nothrow_set_value<R, Vs...>::value;
+
+#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+template <typename R, typename = void,
+    typename = void, typename = void, typename = void, typename = void,
+    typename = void, typename = void, typename = void, typename = void>
+struct can_set_value;
+
+template <typename R, typename = void,
+    typename = void, typename = void, typename = void, typename = void,
+    typename = void, typename = void, typename = void, typename = void>
+struct is_nothrow_set_value;
+
+template <typename R>
+struct can_set_value<R> :
+  integral_constant<bool,
+    asio_execution_set_value_fn::call_traits<R, void()>::overload !=
+      asio_execution_set_value_fn::ill_formed>
+{
+};
+
+template <typename R>
+struct is_nothrow_set_value<R> :
+  integral_constant<bool,
+    asio_execution_set_value_fn::call_traits<R, void()>::is_noexcept>
+{
+};
+
+#define ASIO_PRIVATE_SET_VALUE_TRAITS_DEF(n) \
+  template <typename R, ASIO_VARIADIC_TPARAMS(n)> \
+  struct can_set_value<R, ASIO_VARIADIC_TARGS(n)> : \
+    integral_constant<bool, \
+      asio_execution_set_value_fn::call_traits<R, \
+        void(ASIO_VARIADIC_TARGS(n))>::overload != \
+          asio_execution_set_value_fn::ill_formed> \
+  { \
+  }; \
+  \
+  template <typename R, ASIO_VARIADIC_TPARAMS(n)> \
+  struct is_nothrow_set_value<R, ASIO_VARIADIC_TARGS(n)> : \
+    integral_constant<bool, \
+      asio_execution_set_value_fn::call_traits<R, \
+        void(ASIO_VARIADIC_TARGS(n))>::is_noexcept> \
+  { \
+  }; \
+  /**/
+ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_SET_VALUE_TRAITS_DEF)
+#undef ASIO_PRIVATE_SET_VALUE_TRAITS_DEF
+
+#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+} // namespace execution
+} // namespace asio
+
+#endif // defined(GENERATING_DOCUMENTATION)
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_EXECUTION_SET_VALUE_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/execution/start.hpp b/link/modules/asio-standalone/asio/include/asio/execution/start.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/execution/start.hpp
@@ -0,0 +1,250 @@
+//
+// execution/start.hpp
+// ~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_EXECUTION_START_HPP
+#define ASIO_EXECUTION_START_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/type_traits.hpp"
+#include "asio/traits/start_member.hpp"
+#include "asio/traits/start_free.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+#if defined(GENERATING_DOCUMENTATION)
+
+namespace asio {
+namespace execution {
+
+/// A customisation point that notifies an operation state object to start
+/// its associated operation.
+/**
+ * The name <tt>execution::start</tt> denotes a customisation point object.
+ * The expression <tt>execution::start(R)</tt> for some subexpression
+ * <tt>R</tt> is expression-equivalent to:
+ *
+ * @li <tt>R.start()</tt>, if that expression is valid.
+ *
+ * @li Otherwise, <tt>start(R)</tt>, if that expression is valid, with
+ * overload resolution performed in a context that includes the declaration
+ * <tt>void start();</tt> and that does not include a declaration of
+ * <tt>execution::start</tt>.
+ *
+ * @li Otherwise, <tt>execution::start(R)</tt> is ill-formed.
+ */
+inline constexpr unspecified start = unspecified;
+
+/// A type trait that determines whether a @c start expression is
+/// well-formed.
+/**
+ * Class template @c can_start is a trait that is derived from
+ * @c true_type if the expression <tt>execution::start(std::declval<R>(),
+ * std::declval<E>())</tt> is well formed; otherwise @c false_type.
+ */
+template <typename R>
+struct can_start :
+  integral_constant<bool, automatically_determined>
+{
+};
+
+} // namespace execution
+} // namespace asio
+
+#else // defined(GENERATING_DOCUMENTATION)
+
+namespace asio_execution_start_fn {
+
+using asio::decay;
+using asio::declval;
+using asio::enable_if;
+using asio::traits::start_free;
+using asio::traits::start_member;
+
+void start();
+
+enum overload_type
+{
+  call_member,
+  call_free,
+  ill_formed
+};
+
+template <typename R, typename = void>
+struct call_traits
+{
+  ASIO_STATIC_CONSTEXPR(overload_type, overload = ill_formed);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
+  typedef void result_type;
+};
+
+template <typename R>
+struct call_traits<R,
+  typename enable_if<
+    (
+      start_member<R>::is_valid
+    )
+  >::type> :
+  start_member<R>
+{
+  ASIO_STATIC_CONSTEXPR(overload_type, overload = call_member);
+};
+
+template <typename R>
+struct call_traits<R,
+  typename enable_if<
+    (
+      !start_member<R>::is_valid
+      &&
+      start_free<R>::is_valid
+    )
+  >::type> :
+  start_free<R>
+{
+  ASIO_STATIC_CONSTEXPR(overload_type, overload = call_free);
+};
+
+struct impl
+{
+#if defined(ASIO_HAS_MOVE)
+  template <typename R>
+  ASIO_CONSTEXPR typename enable_if<
+    call_traits<R>::overload == call_member,
+    typename call_traits<R>::result_type
+  >::type
+  operator()(R&& r) const
+    ASIO_NOEXCEPT_IF((
+      call_traits<R>::is_noexcept))
+  {
+    return ASIO_MOVE_CAST(R)(r).start();
+  }
+
+  template <typename R>
+  ASIO_CONSTEXPR typename enable_if<
+    call_traits<R>::overload == call_free,
+    typename call_traits<R>::result_type
+  >::type
+  operator()(R&& r) const
+    ASIO_NOEXCEPT_IF((
+      call_traits<R>::is_noexcept))
+  {
+    return start(ASIO_MOVE_CAST(R)(r));
+  }
+#else // defined(ASIO_HAS_MOVE)
+  template <typename R>
+  ASIO_CONSTEXPR typename enable_if<
+    call_traits<R&>::overload == call_member,
+    typename call_traits<R&>::result_type
+  >::type
+  operator()(R& r) const
+    ASIO_NOEXCEPT_IF((
+      call_traits<R&>::is_noexcept))
+  {
+    return r.start();
+  }
+
+  template <typename R>
+  ASIO_CONSTEXPR typename enable_if<
+    call_traits<const R&>::overload == call_member,
+    typename call_traits<const R&>::result_type
+  >::type
+  operator()(const R& r) const
+    ASIO_NOEXCEPT_IF((
+      call_traits<const R&>::is_noexcept))
+  {
+    return r.start();
+  }
+
+  template <typename R>
+  ASIO_CONSTEXPR typename enable_if<
+    call_traits<R&>::overload == call_free,
+    typename call_traits<R&>::result_type
+  >::type
+  operator()(R& r) const
+    ASIO_NOEXCEPT_IF((
+      call_traits<R&>::is_noexcept))
+  {
+    return start(r);
+  }
+
+  template <typename R>
+  ASIO_CONSTEXPR typename enable_if<
+    call_traits<const R&>::overload == call_free,
+    typename call_traits<const R&>::result_type
+  >::type
+  operator()(const R& r) const
+    ASIO_NOEXCEPT_IF((
+      call_traits<const R&>::is_noexcept))
+  {
+    return start(r);
+  }
+#endif // defined(ASIO_HAS_MOVE)
+};
+
+template <typename T = impl>
+struct static_instance
+{
+  static const T instance;
+};
+
+template <typename T>
+const T static_instance<T>::instance = {};
+
+} // namespace asio_execution_start_fn
+namespace asio {
+namespace execution {
+namespace {
+
+static ASIO_CONSTEXPR const asio_execution_start_fn::impl&
+  start = asio_execution_start_fn::static_instance<>::instance;
+
+} // namespace
+
+template <typename R>
+struct can_start :
+  integral_constant<bool,
+    asio_execution_start_fn::call_traits<R>::overload !=
+      asio_execution_start_fn::ill_formed>
+{
+};
+
+#if defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+template <typename R>
+constexpr bool can_start_v = can_start<R>::value;
+
+#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+template <typename R>
+struct is_nothrow_start :
+  integral_constant<bool,
+    asio_execution_start_fn::call_traits<R>::is_noexcept>
+{
+};
+
+#if defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+template <typename R>
+constexpr bool is_nothrow_start_v
+  = is_nothrow_start<R>::value;
+
+#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+} // namespace execution
+} // namespace asio
+
+#endif // defined(GENERATING_DOCUMENTATION)
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_EXECUTION_START_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/execution/submit.hpp b/link/modules/asio-standalone/asio/include/asio/execution/submit.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/execution/submit.hpp
@@ -0,0 +1,450 @@
+//
+// execution/submit.hpp
+// ~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_EXECUTION_SUBMIT_HPP
+#define ASIO_EXECUTION_SUBMIT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/type_traits.hpp"
+#include "asio/execution/detail/submit_receiver.hpp"
+#include "asio/execution/executor.hpp"
+#include "asio/execution/receiver.hpp"
+#include "asio/execution/sender.hpp"
+#include "asio/execution/start.hpp"
+#include "asio/traits/submit_member.hpp"
+#include "asio/traits/submit_free.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+#if defined(GENERATING_DOCUMENTATION)
+
+namespace asio {
+namespace execution {
+
+/// A customisation point that submits a sender to a receiver.
+/**
+ * The name <tt>execution::submit</tt> denotes a customisation point object. For
+ * some subexpressions <tt>s</tt> and <tt>r</tt>, let <tt>S</tt> be a type such
+ * that <tt>decltype((s))</tt> is <tt>S</tt> and let <tt>R</tt> be a type such
+ * that <tt>decltype((r))</tt> is <tt>R</tt>. The expression
+ * <tt>execution::submit(s, r)</tt> is ill-formed if <tt>sender_to<S, R></tt> is
+ * not <tt>true</tt>. Otherwise, it is expression-equivalent to:
+ *
+ * @li <tt>s.submit(r)</tt>, if that expression is valid and <tt>S</tt> models
+ *   <tt>sender</tt>. If the function selected does not submit the receiver
+ *   object <tt>r</tt> via the sender <tt>s</tt>, the program is ill-formed with
+ *   no diagnostic required.
+ *
+ * @li Otherwise, <tt>submit(s, r)</tt>, if that expression is valid and
+ *   <tt>S</tt> models <tt>sender</tt>, with overload resolution performed in a
+ *   context that includes the declaration <tt>void submit();</tt> and that does
+ *   not include a declaration of <tt>execution::submit</tt>. If the function
+ *   selected by overload resolution does not submit the receiver object
+ *   <tt>r</tt> via the sender <tt>s</tt>, the program is ill-formed with no
+ *   diagnostic required.
+ *
+ * @li Otherwise, <tt>execution::start((new submit_receiver<S,
+ *   R>{s,r})->state_)</tt>, where <tt>submit_receiver</tt> is an
+ *   implementation-defined class template equivalent to:
+ *   @code template<class S, class R>
+ *   struct submit_receiver {
+ *     struct wrap {
+ *       submit_receiver * p_;
+ *       template<class...As>
+ *         requires receiver_of<R, As...>
+ *       void set_value(As&&... as) &&
+ *         noexcept(is_nothrow_receiver_of_v<R, As...>) {
+ *         execution::set_value(std::move(p_->r_), (As&&) as...);
+ *         delete p_;
+ *       }
+ *       template<class E>
+ *         requires receiver<R, E>
+ *       void set_error(E&& e) && noexcept {
+ *         execution::set_error(std::move(p_->r_), (E&&) e);
+ *         delete p_;
+ *       }
+ *       void set_done() && noexcept {
+ *         execution::set_done(std::move(p_->r_));
+ *         delete p_;
+ *       }
+ *     };
+ *     remove_cvref_t<R> r_;
+ *     connect_result_t<S, wrap> state_;
+ *     submit_receiver(S&& s, R&& r)
+ *       : r_((R&&) r)
+ *       , state_(execution::connect((S&&) s, wrap{this})) {}
+ *   };
+ *   @endcode
+ */
+inline constexpr unspecified submit = unspecified;
+
+/// A type trait that determines whether a @c submit expression is
+/// well-formed.
+/**
+ * Class template @c can_submit is a trait that is derived from
+ * @c true_type if the expression <tt>execution::submit(std::declval<R>(),
+ * std::declval<E>())</tt> is well formed; otherwise @c false_type.
+ */
+template <typename S, typename R>
+struct can_submit :
+  integral_constant<bool, automatically_determined>
+{
+};
+
+} // namespace execution
+} // namespace asio
+
+#else // defined(GENERATING_DOCUMENTATION)
+
+namespace asio_execution_submit_fn {
+
+using asio::declval;
+using asio::enable_if;
+using asio::execution::is_sender_to;
+using asio::traits::submit_free;
+using asio::traits::submit_member;
+
+void submit();
+
+enum overload_type
+{
+  call_member,
+  call_free,
+  adapter,
+  ill_formed
+};
+
+template <typename S, typename R, typename = void>
+struct call_traits
+{
+  ASIO_STATIC_CONSTEXPR(overload_type, overload = ill_formed);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
+  typedef void result_type;
+};
+
+template <typename S, typename R>
+struct call_traits<S, void(R),
+  typename enable_if<
+    (
+      submit_member<S, R>::is_valid
+      &&
+      is_sender_to<S, R>::value
+    )
+  >::type> :
+  submit_member<S, R>
+{
+  ASIO_STATIC_CONSTEXPR(overload_type, overload = call_member);
+};
+
+template <typename S, typename R>
+struct call_traits<S, void(R),
+  typename enable_if<
+    (
+      !submit_member<S, R>::is_valid
+      &&
+      submit_free<S, R>::is_valid
+      &&
+      is_sender_to<S, R>::value
+    )
+  >::type> :
+  submit_free<S, R>
+{
+  ASIO_STATIC_CONSTEXPR(overload_type, overload = call_free);
+};
+
+template <typename S, typename R>
+struct call_traits<S, void(R),
+  typename enable_if<
+    (
+      !submit_member<S, R>::is_valid
+      &&
+      !submit_free<S, R>::is_valid
+      &&
+      is_sender_to<S, R>::value
+    )
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(overload_type, overload = adapter);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
+  typedef void result_type;
+};
+
+struct impl
+{
+#if defined(ASIO_HAS_MOVE)
+  template <typename S, typename R>
+  ASIO_CONSTEXPR typename enable_if<
+    call_traits<S, void(R)>::overload == call_member,
+    typename call_traits<S, void(R)>::result_type
+  >::type
+  operator()(S&& s, R&& r) const
+    ASIO_NOEXCEPT_IF((
+      call_traits<S, void(R)>::is_noexcept))
+  {
+    return ASIO_MOVE_CAST(S)(s).submit(ASIO_MOVE_CAST(R)(r));
+  }
+
+  template <typename S, typename R>
+  ASIO_CONSTEXPR typename enable_if<
+    call_traits<S, void(R)>::overload == call_free,
+    typename call_traits<S, void(R)>::result_type
+  >::type
+  operator()(S&& s, R&& r) const
+    ASIO_NOEXCEPT_IF((
+      call_traits<S, void(R)>::is_noexcept))
+  {
+    return submit(ASIO_MOVE_CAST(S)(s), ASIO_MOVE_CAST(R)(r));
+  }
+
+  template <typename S, typename R>
+  ASIO_CONSTEXPR typename enable_if<
+    call_traits<S, void(R)>::overload == adapter,
+    typename call_traits<S, void(R)>::result_type
+  >::type
+  operator()(S&& s, R&& r) const
+    ASIO_NOEXCEPT_IF((
+      call_traits<S, void(R)>::is_noexcept))
+  {
+    return asio::execution::start(
+        (new asio::execution::detail::submit_receiver<S, R>(
+          ASIO_MOVE_CAST(S)(s), ASIO_MOVE_CAST(R)(r)))->state_);
+  }
+#else // defined(ASIO_HAS_MOVE)
+  template <typename S, typename R>
+  ASIO_CONSTEXPR typename enable_if<
+    call_traits<S&, void(R&)>::overload == call_member,
+    typename call_traits<S&, void(R&)>::result_type
+  >::type
+  operator()(S& s, R& r) const
+    ASIO_NOEXCEPT_IF((
+      call_traits<S&, void(R&)>::is_noexcept))
+  {
+    return s.submit(r);
+  }
+
+  template <typename S, typename R>
+  ASIO_CONSTEXPR typename enable_if<
+    call_traits<const S&, void(R&)>::overload == call_member,
+    typename call_traits<const S&, void(R&)>::result_type
+  >::type
+  operator()(const S& s, R& r) const
+    ASIO_NOEXCEPT_IF((
+      call_traits<const S&, void(R&)>::is_noexcept))
+  {
+    return s.submit(r);
+  }
+
+  template <typename S, typename R>
+  ASIO_CONSTEXPR typename enable_if<
+    call_traits<S&, void(R&)>::overload == call_free,
+    typename call_traits<S&, void(R&)>::result_type
+  >::type
+  operator()(S& s, R& r) const
+    ASIO_NOEXCEPT_IF((
+      call_traits<S&, void(R&)>::is_noexcept))
+  {
+    return submit(s, r);
+  }
+
+  template <typename S, typename R>
+  ASIO_CONSTEXPR typename enable_if<
+    call_traits<const S&, void(R&)>::overload == call_free,
+    typename call_traits<const S&, void(R&)>::result_type
+  >::type
+  operator()(const S& s, R& r) const
+    ASIO_NOEXCEPT_IF((
+      call_traits<const S&, void(R&)>::is_noexcept))
+  {
+    return submit(s, r);
+  }
+
+  template <typename S, typename R>
+  ASIO_CONSTEXPR typename enable_if<
+    call_traits<S&, void(R&)>::overload == adapter,
+    typename call_traits<S&, void(R&)>::result_type
+  >::type
+  operator()(S& s, R& r) const
+    ASIO_NOEXCEPT_IF((
+      call_traits<S&, void(R&)>::is_noexcept))
+  {
+    return asio::execution::start(
+        (new asio::execution::detail::submit_receiver<
+          S&, R&>(s, r))->state_);
+  }
+
+  template <typename S, typename R>
+  ASIO_CONSTEXPR typename enable_if<
+    call_traits<const S&, void(R&)>::overload == adapter,
+    typename call_traits<const S&, void(R&)>::result_type
+  >::type
+  operator()(const S& s, R& r) const
+    ASIO_NOEXCEPT_IF((
+      call_traits<const S&, void(R&)>::is_noexcept))
+  {
+    asio::execution::start(
+        (new asio::execution::detail::submit_receiver<
+          const S&, R&>(s, r))->state_);
+  }
+
+  template <typename S, typename R>
+  ASIO_CONSTEXPR typename enable_if<
+    call_traits<S&, void(const R&)>::overload == call_member,
+    typename call_traits<S&, void(const R&)>::result_type
+  >::type
+  operator()(S& s, const R& r) const
+    ASIO_NOEXCEPT_IF((
+      call_traits<S&, void(const R&)>::is_noexcept))
+  {
+    return s.submit(r);
+  }
+
+  template <typename S, typename R>
+  ASIO_CONSTEXPR typename enable_if<
+    call_traits<const S&, void(const R&)>::overload == call_member,
+    typename call_traits<const S&, void(const R&)>::result_type
+  >::type
+  operator()(const S& s, const R& r) const
+    ASIO_NOEXCEPT_IF((
+      call_traits<const S&, void(const R&)>::is_noexcept))
+  {
+    return s.submit(r);
+  }
+
+  template <typename S, typename R>
+  ASIO_CONSTEXPR typename enable_if<
+    call_traits<S&, void(const R&)>::overload == call_free,
+    typename call_traits<S&, void(const R&)>::result_type
+  >::type
+  operator()(S& s, const R& r) const
+    ASIO_NOEXCEPT_IF((
+      call_traits<S&, void(const R&)>::is_noexcept))
+  {
+    return submit(s, r);
+  }
+
+  template <typename S, typename R>
+  ASIO_CONSTEXPR typename enable_if<
+    call_traits<const S&, void(const R&)>::overload == call_free,
+    typename call_traits<const S&, void(const R&)>::result_type
+  >::type
+  operator()(const S& s, const R& r) const
+    ASIO_NOEXCEPT_IF((
+      call_traits<const S&, void(const R&)>::is_noexcept))
+  {
+    return submit(s, r);
+  }
+
+  template <typename S, typename R>
+  ASIO_CONSTEXPR typename enable_if<
+    call_traits<S&, void(const R&)>::overload == adapter,
+    typename call_traits<S&, void(const R&)>::result_type
+  >::type
+  operator()(S& s, const R& r) const
+    ASIO_NOEXCEPT_IF((
+      call_traits<S&, void(const R&)>::is_noexcept))
+  {
+    asio::execution::start(
+        (new asio::execution::detail::submit_receiver<
+          S&, const R&>(s, r))->state_);
+  }
+
+  template <typename S, typename R>
+  ASIO_CONSTEXPR typename enable_if<
+    call_traits<const S&, void(const R&)>::overload == adapter,
+    typename call_traits<const S&, void(const R&)>::result_type
+  >::type
+  operator()(const S& s, const R& r) const
+    ASIO_NOEXCEPT_IF((
+      call_traits<const S&, void(const R&)>::is_noexcept))
+  {
+    asio::execution::start(
+        (new asio::execution::detail::submit_receiver<
+          const S&, const R&>(s, r))->state_);
+  }
+#endif // defined(ASIO_HAS_MOVE)
+};
+
+template <typename T = impl>
+struct static_instance
+{
+  static const T instance;
+};
+
+template <typename T>
+const T static_instance<T>::instance = {};
+
+} // namespace asio_execution_submit_fn
+namespace asio {
+namespace execution {
+namespace {
+
+static ASIO_CONSTEXPR const asio_execution_submit_fn::impl&
+  submit = asio_execution_submit_fn::static_instance<>::instance;
+
+} // namespace
+
+template <typename S, typename R>
+struct can_submit :
+  integral_constant<bool,
+    asio_execution_submit_fn::call_traits<S, void(R)>::overload !=
+      asio_execution_submit_fn::ill_formed>
+{
+};
+
+#if defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+template <typename S, typename R>
+constexpr bool can_submit_v = can_submit<S, R>::value;
+
+#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+template <typename S, typename R>
+struct is_nothrow_submit :
+  integral_constant<bool,
+    asio_execution_submit_fn::call_traits<S, void(R)>::is_noexcept>
+{
+};
+
+#if defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+template <typename S, typename R>
+constexpr bool is_nothrow_submit_v
+  = is_nothrow_submit<S, R>::value;
+
+#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+template <typename S, typename R>
+struct submit_result
+{
+  typedef typename asio_execution_submit_fn::call_traits<
+      S, void(R)>::result_type type;
+};
+
+namespace detail {
+
+template <typename S, typename R>
+void submit_helper(ASIO_MOVE_ARG(S) s, ASIO_MOVE_ARG(R) r)
+{
+  execution::submit(ASIO_MOVE_CAST(S)(s), ASIO_MOVE_CAST(R)(r));
+}
+
+} // namespace detail
+} // namespace execution
+} // namespace asio
+
+#endif // defined(GENERATING_DOCUMENTATION)
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_EXECUTION_SUBMIT_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/execution_context.hpp b/link/modules/asio-standalone/asio/include/asio/execution_context.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/execution_context.hpp
@@ -0,0 +1,412 @@
+//
+// execution_context.hpp
+// ~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_EXECUTION_CONTEXT_HPP
+#define ASIO_EXECUTION_CONTEXT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <cstddef>
+#include <stdexcept>
+#include <typeinfo>
+#include "asio/detail/noncopyable.hpp"
+#include "asio/detail/variadic_templates.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+class execution_context;
+class io_context;
+
+#if !defined(GENERATING_DOCUMENTATION)
+template <typename Service> Service& use_service(execution_context&);
+template <typename Service> Service& use_service(io_context&);
+template <typename Service> void add_service(execution_context&, Service*);
+template <typename Service> bool has_service(execution_context&);
+#endif // !defined(GENERATING_DOCUMENTATION)
+
+namespace detail { class service_registry; }
+
+/// A context for function object execution.
+/**
+ * An execution context represents a place where function objects will be
+ * executed. An @c io_context is an example of an execution context.
+ *
+ * @par The execution_context class and services
+ *
+ * Class execution_context implements an extensible, type-safe, polymorphic set
+ * of services, indexed by service type.
+ *
+ * Services exist to manage the resources that are shared across an execution
+ * context. For example, timers may be implemented in terms of a single timer
+ * queue, and this queue would be stored in a service.
+ *
+ * Access to the services of an execution_context is via three function
+ * templates, use_service(), add_service() and has_service().
+ *
+ * In a call to @c use_service<Service>(), the type argument chooses a service,
+ * making available all members of the named type. If @c Service is not present
+ * in an execution_context, an object of type @c Service is created and added
+ * to the execution_context. A C++ program can check if an execution_context
+ * implements a particular service with the function template @c
+ * has_service<Service>().
+ *
+ * Service objects may be explicitly added to an execution_context using the
+ * function template @c add_service<Service>(). If the @c Service is already
+ * present, the service_already_exists exception is thrown. If the owner of the
+ * service is not the same object as the execution_context parameter, the
+ * invalid_service_owner exception is thrown.
+ *
+ * Once a service reference is obtained from an execution_context object by
+ * calling use_service(), that reference remains usable as long as the owning
+ * execution_context object exists.
+ *
+ * All service implementations have execution_context::service as a public base
+ * class. Custom services may be implemented by deriving from this class and
+ * then added to an execution_context using the facilities described above.
+ *
+ * @par The execution_context as a base class
+ *
+ * Class execution_context may be used only as a base class for concrete
+ * execution context types. The @c io_context is an example of such a derived
+ * type.
+ *
+ * On destruction, a class that is derived from execution_context must perform
+ * <tt>execution_context::shutdown()</tt> followed by
+ * <tt>execution_context::destroy()</tt>.
+ *
+ * This destruction sequence permits programs to simplify their resource
+ * management by using @c shared_ptr<>. Where an object's lifetime is tied to
+ * the lifetime of a connection (or some other sequence of asynchronous
+ * operations), a @c shared_ptr to the object would be bound into the handlers
+ * for all asynchronous operations associated with it. This works as follows:
+ *
+ * @li When a single connection ends, all associated asynchronous operations
+ * complete. The corresponding handler objects are destroyed, and all @c
+ * shared_ptr references to the objects are destroyed.
+ *
+ * @li To shut down the whole program, the io_context function stop() is called
+ * to terminate any run() calls as soon as possible. The io_context destructor
+ * calls @c shutdown() and @c destroy() to destroy all pending handlers,
+ * causing all @c shared_ptr references to all connection objects to be
+ * destroyed.
+ */
+class execution_context
+  : private noncopyable
+{
+public:
+  class id;
+  class service;
+
+public:
+  /// Constructor.
+  ASIO_DECL execution_context();
+
+  /// Destructor.
+  ASIO_DECL ~execution_context();
+
+protected:
+  /// Shuts down all services in the context.
+  /**
+   * This function is implemented as follows:
+   *
+   * @li For each service object @c svc in the execution_context set, in
+   * reverse order of the beginning of service object lifetime, performs @c
+   * svc->shutdown().
+   */
+  ASIO_DECL void shutdown();
+
+  /// Destroys all services in the context.
+  /**
+   * This function is implemented as follows:
+   *
+   * @li For each service object @c svc in the execution_context set, in
+   * reverse order * of the beginning of service object lifetime, performs
+   * <tt>delete static_cast<execution_context::service*>(svc)</tt>.
+   */
+  ASIO_DECL void destroy();
+
+public:
+  /// Fork-related event notifications.
+  enum fork_event
+  {
+    /// Notify the context that the process is about to fork.
+    fork_prepare,
+
+    /// Notify the context that the process has forked and is the parent.
+    fork_parent,
+
+    /// Notify the context that the process has forked and is the child.
+    fork_child
+  };
+
+  /// Notify the execution_context of a fork-related event.
+  /**
+   * This function is used to inform the execution_context that the process is
+   * about to fork, or has just forked. This allows the execution_context, and
+   * the services it contains, to perform any necessary housekeeping to ensure
+   * correct operation following a fork.
+   *
+   * This function must not be called while any other execution_context
+   * function, or any function associated with the execution_context's derived
+   * class, is being called in another thread. It is, however, safe to call
+   * this function from within a completion handler, provided no other thread
+   * is accessing the execution_context or its derived class.
+   *
+   * @param event A fork-related event.
+   *
+   * @throws asio::system_error Thrown on failure. If the notification
+   * fails the execution_context object should no longer be used and should be
+   * destroyed.
+   *
+   * @par Example
+   * The following code illustrates how to incorporate the notify_fork()
+   * function:
+   * @code my_execution_context.notify_fork(execution_context::fork_prepare);
+   * if (fork() == 0)
+   * {
+   *   // This is the child process.
+   *   my_execution_context.notify_fork(execution_context::fork_child);
+   * }
+   * else
+   * {
+   *   // This is the parent process.
+   *   my_execution_context.notify_fork(execution_context::fork_parent);
+   * } @endcode
+   *
+   * @note For each service object @c svc in the execution_context set,
+   * performs <tt>svc->notify_fork();</tt>. When processing the fork_prepare
+   * event, services are visited in reverse order of the beginning of service
+   * object lifetime. Otherwise, services are visited in order of the beginning
+   * of service object lifetime.
+   */
+  ASIO_DECL void notify_fork(fork_event event);
+
+  /// Obtain the service object corresponding to the given type.
+  /**
+   * This function is used to locate a service object that corresponds to the
+   * given service type. If there is no existing implementation of the service,
+   * then the execution_context will create a new instance of the service.
+   *
+   * @param e The execution_context object that owns the service.
+   *
+   * @return The service interface implementing the specified service type.
+   * Ownership of the service interface is not transferred to the caller.
+   */
+  template <typename Service>
+  friend Service& use_service(execution_context& e);
+
+  /// Obtain the service object corresponding to the given type.
+  /**
+   * This function is used to locate a service object that corresponds to the
+   * given service type. If there is no existing implementation of the service,
+   * then the io_context will create a new instance of the service.
+   *
+   * @param ioc The io_context object that owns the service.
+   *
+   * @return The service interface implementing the specified service type.
+   * Ownership of the service interface is not transferred to the caller.
+   *
+   * @note This overload is preserved for backwards compatibility with services
+   * that inherit from io_context::service.
+   */
+  template <typename Service>
+  friend Service& use_service(io_context& ioc);
+
+#if defined(GENERATING_DOCUMENTATION)
+
+  /// Creates a service object and adds it to the execution_context.
+  /**
+   * This function is used to add a service to the execution_context.
+   *
+   * @param e The execution_context object that owns the service.
+   *
+   * @param args Zero or more arguments to be passed to the service
+   * constructor.
+   *
+   * @throws asio::service_already_exists Thrown if a service of the
+   * given type is already present in the execution_context.
+   */
+  template <typename Service, typename... Args>
+  friend Service& make_service(execution_context& e, Args&&... args);
+
+#elif defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+  template <typename Service, typename... Args>
+  friend Service& make_service(execution_context& e,
+      ASIO_MOVE_ARG(Args)... args);
+
+#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+  template <typename Service>
+  friend Service& make_service(execution_context& e);
+
+#define ASIO_PRIVATE_MAKE_SERVICE_DEF(n) \
+  template <typename Service, ASIO_VARIADIC_TPARAMS(n)> \
+  friend Service& make_service(execution_context& e, \
+      ASIO_VARIADIC_MOVE_PARAMS(n)); \
+  /**/
+  ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_MAKE_SERVICE_DEF)
+#undef ASIO_PRIVATE_MAKE_SERVICE_DEF
+
+#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+  /// (Deprecated: Use make_service().) Add a service object to the
+  /// execution_context.
+  /**
+   * This function is used to add a service to the execution_context.
+   *
+   * @param e The execution_context object that owns the service.
+   *
+   * @param svc The service object. On success, ownership of the service object
+   * is transferred to the execution_context. When the execution_context object
+   * is destroyed, it will destroy the service object by performing: @code
+   * delete static_cast<execution_context::service*>(svc) @endcode
+   *
+   * @throws asio::service_already_exists Thrown if a service of the
+   * given type is already present in the execution_context.
+   *
+   * @throws asio::invalid_service_owner Thrown if the service's owning
+   * execution_context is not the execution_context object specified by the
+   * @c e parameter.
+   */
+  template <typename Service>
+  friend void add_service(execution_context& e, Service* svc);
+
+  /// Determine if an execution_context contains a specified service type.
+  /**
+   * This function is used to determine whether the execution_context contains a
+   * service object corresponding to the given service type.
+   *
+   * @param e The execution_context object that owns the service.
+   *
+   * @return A boolean indicating whether the execution_context contains the
+   * service.
+   */
+  template <typename Service>
+  friend bool has_service(execution_context& e);
+
+private:
+  // The service registry.
+  asio::detail::service_registry* service_registry_;
+};
+
+/// Class used to uniquely identify a service.
+class execution_context::id
+  : private noncopyable
+{
+public:
+  /// Constructor.
+  id() {}
+};
+
+/// Base class for all io_context services.
+class execution_context::service
+  : private noncopyable
+{
+public:
+  /// Get the context object that owns the service.
+  execution_context& context();
+
+protected:
+  /// Constructor.
+  /**
+   * @param owner The execution_context object that owns the service.
+   */
+  ASIO_DECL service(execution_context& owner);
+
+  /// Destructor.
+  ASIO_DECL virtual ~service();
+
+private:
+  /// Destroy all user-defined handler objects owned by the service.
+  virtual void shutdown() = 0;
+
+  /// Handle notification of a fork-related event to perform any necessary
+  /// housekeeping.
+  /**
+   * This function is not a pure virtual so that services only have to
+   * implement it if necessary. The default implementation does nothing.
+   */
+  ASIO_DECL virtual void notify_fork(
+      execution_context::fork_event event);
+
+  friend class asio::detail::service_registry;
+  struct key
+  {
+    key() : type_info_(0), id_(0) {}
+    const std::type_info* type_info_;
+    const execution_context::id* id_;
+  } key_;
+
+  execution_context& owner_;
+  service* next_;
+};
+
+/// Exception thrown when trying to add a duplicate service to an
+/// execution_context.
+class service_already_exists
+  : public std::logic_error
+{
+public:
+  ASIO_DECL service_already_exists();
+};
+
+/// Exception thrown when trying to add a service object to an
+/// execution_context where the service has a different owner.
+class invalid_service_owner
+  : public std::logic_error
+{
+public:
+  ASIO_DECL invalid_service_owner();
+};
+
+namespace detail {
+
+// Special derived service id type to keep classes header-file only.
+template <typename Type>
+class service_id
+  : public execution_context::id
+{
+};
+
+// Special service base class to keep classes header-file only.
+template <typename Type>
+class execution_context_service_base
+  : public execution_context::service
+{
+public:
+  static service_id<Type> id;
+
+  // Constructor.
+  execution_context_service_base(execution_context& e)
+    : execution_context::service(e)
+  {
+  }
+};
+
+template <typename Type>
+service_id<Type> execution_context_service_base<Type>::id;
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/impl/execution_context.hpp"
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/impl/execution_context.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // ASIO_EXECUTION_CONTEXT_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/executor.hpp b/link/modules/asio-standalone/asio/include/asio/executor.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/executor.hpp
@@ -0,0 +1,347 @@
+//
+// executor.hpp
+// ~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_EXECUTOR_HPP
+#define ASIO_EXECUTOR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if !defined(ASIO_NO_TS_EXECUTORS)
+
+#include <typeinfo>
+#include "asio/detail/cstddef.hpp"
+#include "asio/detail/executor_function.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/detail/throw_exception.hpp"
+#include "asio/execution_context.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+/// Exception thrown when trying to access an empty polymorphic executor.
+class bad_executor
+  : public std::exception
+{
+public:
+  /// Constructor.
+  ASIO_DECL bad_executor() ASIO_NOEXCEPT;
+
+  /// Obtain message associated with exception.
+  ASIO_DECL virtual const char* what() const
+    ASIO_NOEXCEPT_OR_NOTHROW;
+};
+
+/// Polymorphic wrapper for executors.
+class executor
+{
+public:
+  /// Default constructor.
+  executor() ASIO_NOEXCEPT
+    : impl_(0)
+  {
+  }
+
+  /// Construct from nullptr.
+  executor(nullptr_t) ASIO_NOEXCEPT
+    : impl_(0)
+  {
+  }
+
+  /// Copy constructor.
+  executor(const executor& other) ASIO_NOEXCEPT
+    : impl_(other.clone())
+  {
+  }
+
+#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+  /// Move constructor.
+  executor(executor&& other) ASIO_NOEXCEPT
+    : impl_(other.impl_)
+  {
+    other.impl_ = 0;
+  }
+#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+
+  /// Construct a polymorphic wrapper for the specified executor.
+  template <typename Executor>
+  executor(Executor e);
+
+  /// Allocator-aware constructor to create a polymorphic wrapper for the
+  /// specified executor.
+  template <typename Executor, typename Allocator>
+  executor(allocator_arg_t, const Allocator& a, Executor e);
+
+  /// Destructor.
+  ~executor()
+  {
+    destroy();
+  }
+
+  /// Assignment operator.
+  executor& operator=(const executor& other) ASIO_NOEXCEPT
+  {
+    destroy();
+    impl_ = other.clone();
+    return *this;
+  }
+
+#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+  // Move assignment operator.
+  executor& operator=(executor&& other) ASIO_NOEXCEPT
+  {
+    destroy();
+    impl_ = other.impl_;
+    other.impl_ = 0;
+    return *this;
+  }
+#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+
+  /// Assignment operator for nullptr_t.
+  executor& operator=(nullptr_t) ASIO_NOEXCEPT
+  {
+    destroy();
+    impl_ = 0;
+    return *this;
+  }
+
+  /// Assignment operator to create a polymorphic wrapper for the specified
+  /// executor.
+  template <typename Executor>
+  executor& operator=(ASIO_MOVE_ARG(Executor) e) ASIO_NOEXCEPT
+  {
+    executor tmp(ASIO_MOVE_CAST(Executor)(e));
+    destroy();
+    impl_ = tmp.impl_;
+    tmp.impl_ = 0;
+    return *this;
+  }
+
+  /// Obtain the underlying execution context.
+  execution_context& context() const ASIO_NOEXCEPT
+  {
+    return get_impl()->context();
+  }
+
+  /// Inform the executor that it has some outstanding work to do.
+  void on_work_started() const ASIO_NOEXCEPT
+  {
+    get_impl()->on_work_started();
+  }
+
+  /// Inform the executor that some work is no longer outstanding.
+  void on_work_finished() const ASIO_NOEXCEPT
+  {
+    get_impl()->on_work_finished();
+  }
+
+  /// Request the executor to invoke the given function object.
+  /**
+   * This function is used to ask the executor to execute the given function
+   * object. The function object is executed according to the rules of the
+   * target executor object.
+   *
+   * @param f The function object to be called. The executor will make a copy
+   * of the handler object as required. The function signature of the function
+   * object must be: @code void function(); @endcode
+   *
+   * @param a An allocator that may be used by the executor to allocate the
+   * internal storage needed for function invocation.
+   */
+  template <typename Function, typename Allocator>
+  void dispatch(ASIO_MOVE_ARG(Function) f, const Allocator& a) const;
+
+  /// Request the executor to invoke the given function object.
+  /**
+   * This function is used to ask the executor to execute the given function
+   * object. The function object is executed according to the rules of the
+   * target executor object.
+   *
+   * @param f The function object to be called. The executor will make
+   * a copy of the handler object as required. The function signature of the
+   * function object must be: @code void function(); @endcode
+   *
+   * @param a An allocator that may be used by the executor to allocate the
+   * internal storage needed for function invocation.
+   */
+  template <typename Function, typename Allocator>
+  void post(ASIO_MOVE_ARG(Function) f, const Allocator& a) const;
+
+  /// Request the executor to invoke the given function object.
+  /**
+   * This function is used to ask the executor to execute the given function
+   * object. The function object is executed according to the rules of the
+   * target executor object.
+   *
+   * @param f The function object to be called. The executor will make
+   * a copy of the handler object as required. The function signature of the
+   * function object must be: @code void function(); @endcode
+   *
+   * @param a An allocator that may be used by the executor to allocate the
+   * internal storage needed for function invocation.
+   */
+  template <typename Function, typename Allocator>
+  void defer(ASIO_MOVE_ARG(Function) f, const Allocator& a) const;
+
+  struct unspecified_bool_type_t {};
+  typedef void (*unspecified_bool_type)(unspecified_bool_type_t);
+  static void unspecified_bool_true(unspecified_bool_type_t) {}
+
+  /// Operator to test if the executor contains a valid target.
+  operator unspecified_bool_type() const ASIO_NOEXCEPT
+  {
+    return impl_ ? &executor::unspecified_bool_true : 0;
+  }
+
+  /// Obtain type information for the target executor object.
+  /**
+   * @returns If @c *this has a target type of type @c T, <tt>typeid(T)</tt>;
+   * otherwise, <tt>typeid(void)</tt>.
+   */
+#if !defined(ASIO_NO_TYPEID) || defined(GENERATING_DOCUMENTATION)
+  const std::type_info& target_type() const ASIO_NOEXCEPT
+  {
+    return impl_ ? impl_->target_type() : typeid(void);
+  }
+#else // !defined(ASIO_NO_TYPEID) || defined(GENERATING_DOCUMENTATION)
+  const void* target_type() const ASIO_NOEXCEPT
+  {
+    return impl_ ? impl_->target_type() : 0;
+  }
+#endif // !defined(ASIO_NO_TYPEID) || defined(GENERATING_DOCUMENTATION)
+
+  /// Obtain a pointer to the target executor object.
+  /**
+   * @returns If <tt>target_type() == typeid(T)</tt>, a pointer to the stored
+   * executor target; otherwise, a null pointer.
+   */
+  template <typename Executor>
+  Executor* target() ASIO_NOEXCEPT;
+
+  /// Obtain a pointer to the target executor object.
+  /**
+   * @returns If <tt>target_type() == typeid(T)</tt>, a pointer to the stored
+   * executor target; otherwise, a null pointer.
+   */
+  template <typename Executor>
+  const Executor* target() const ASIO_NOEXCEPT;
+
+  /// Compare two executors for equality.
+  friend bool operator==(const executor& a,
+      const executor& b) ASIO_NOEXCEPT
+  {
+    if (a.impl_ == b.impl_)
+      return true;
+    if (!a.impl_ || !b.impl_)
+      return false;
+    return a.impl_->equals(b.impl_);
+  }
+
+  /// Compare two executors for inequality.
+  friend bool operator!=(const executor& a,
+      const executor& b) ASIO_NOEXCEPT
+  {
+    return !(a == b);
+  }
+
+private:
+#if !defined(GENERATING_DOCUMENTATION)
+  typedef detail::executor_function function;
+  template <typename, typename> class impl;
+
+#if !defined(ASIO_NO_TYPEID)
+  typedef const std::type_info& type_id_result_type;
+#else // !defined(ASIO_NO_TYPEID)
+  typedef const void* type_id_result_type;
+#endif // !defined(ASIO_NO_TYPEID)
+
+  template <typename T>
+  static type_id_result_type type_id()
+  {
+#if !defined(ASIO_NO_TYPEID)
+    return typeid(T);
+#else // !defined(ASIO_NO_TYPEID)
+    static int unique_id;
+    return &unique_id;
+#endif // !defined(ASIO_NO_TYPEID)
+  }
+
+  // Base class for all polymorphic executor implementations.
+  class impl_base
+  {
+  public:
+    virtual impl_base* clone() const ASIO_NOEXCEPT = 0;
+    virtual void destroy() ASIO_NOEXCEPT = 0;
+    virtual execution_context& context() ASIO_NOEXCEPT = 0;
+    virtual void on_work_started() ASIO_NOEXCEPT = 0;
+    virtual void on_work_finished() ASIO_NOEXCEPT = 0;
+    virtual void dispatch(ASIO_MOVE_ARG(function)) = 0;
+    virtual void post(ASIO_MOVE_ARG(function)) = 0;
+    virtual void defer(ASIO_MOVE_ARG(function)) = 0;
+    virtual type_id_result_type target_type() const ASIO_NOEXCEPT = 0;
+    virtual void* target() ASIO_NOEXCEPT = 0;
+    virtual const void* target() const ASIO_NOEXCEPT = 0;
+    virtual bool equals(const impl_base* e) const ASIO_NOEXCEPT = 0;
+
+  protected:
+    impl_base(bool fast_dispatch) : fast_dispatch_(fast_dispatch) {}
+    virtual ~impl_base() {}
+
+  private:
+    friend class executor;
+    const bool fast_dispatch_;
+  };
+
+  // Helper function to check and return the implementation pointer.
+  impl_base* get_impl() const
+  {
+    if (!impl_)
+    {
+      bad_executor ex;
+      asio::detail::throw_exception(ex);
+    }
+    return impl_;
+  }
+
+  // Helper function to clone another implementation.
+  impl_base* clone() const ASIO_NOEXCEPT
+  {
+    return impl_ ? impl_->clone() : 0;
+  }
+
+  // Helper function to destroy an implementation.
+  void destroy() ASIO_NOEXCEPT
+  {
+    if (impl_)
+      impl_->destroy();
+  }
+
+  impl_base* impl_;
+#endif // !defined(GENERATING_DOCUMENTATION)
+};
+
+} // namespace asio
+
+ASIO_USES_ALLOCATOR(asio::executor)
+
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/impl/executor.hpp"
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/impl/executor.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // !defined(ASIO_NO_TS_EXECUTORS)
+
+#endif // ASIO_EXECUTOR_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/executor_work_guard.hpp b/link/modules/asio-standalone/asio/include/asio/executor_work_guard.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/executor_work_guard.hpp
@@ -0,0 +1,287 @@
+//
+// executor_work_guard.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_EXECUTOR_WORK_GUARD_HPP
+#define ASIO_EXECUTOR_WORK_GUARD_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if !defined(ASIO_NO_TS_EXECUTORS)
+
+#include "asio/associated_executor.hpp"
+#include "asio/detail/type_traits.hpp"
+#include "asio/execution.hpp"
+#include "asio/is_executor.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+#if !defined(ASIO_EXECUTOR_WORK_GUARD_DECL)
+#define ASIO_EXECUTOR_WORK_GUARD_DECL
+
+template <typename Executor, typename = void>
+class executor_work_guard;
+
+#endif // !defined(ASIO_EXECUTOR_WORK_GUARD_DECL)
+
+/// An object of type @c executor_work_guard controls ownership of executor work
+/// within a scope.
+#if defined(GENERATING_DOCUMENTATION)
+template <typename Executor>
+#else // defined(GENERATING_DOCUMENTATION)
+template <typename Executor, typename>
+#endif // defined(GENERATING_DOCUMENTATION)
+class executor_work_guard
+{
+public:
+  /// The underlying executor type.
+  typedef Executor executor_type;
+
+  /// Constructs a @c executor_work_guard object for the specified executor.
+  /**
+   * Stores a copy of @c e and calls <tt>on_work_started()</tt> on it.
+   */
+  explicit executor_work_guard(const executor_type& e) ASIO_NOEXCEPT
+    : executor_(e),
+      owns_(true)
+  {
+    executor_.on_work_started();
+  }
+
+  /// Copy constructor.
+  executor_work_guard(const executor_work_guard& other) ASIO_NOEXCEPT
+    : executor_(other.executor_),
+      owns_(other.owns_)
+  {
+    if (owns_)
+      executor_.on_work_started();
+  }
+
+#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+  /// Move constructor.
+  executor_work_guard(executor_work_guard&& other) ASIO_NOEXCEPT
+    : executor_(ASIO_MOVE_CAST(Executor)(other.executor_)),
+      owns_(other.owns_)
+  {
+    other.owns_ = false;
+  }
+#endif //  defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+
+  /// Destructor.
+  /**
+   * Unless the object has already been reset, or is in a moved-from state,
+   * calls <tt>on_work_finished()</tt> on the stored executor.
+   */
+  ~executor_work_guard()
+  {
+    if (owns_)
+      executor_.on_work_finished();
+  }
+
+  /// Obtain the associated executor.
+  executor_type get_executor() const ASIO_NOEXCEPT
+  {
+    return executor_;
+  }
+
+  /// Whether the executor_work_guard object owns some outstanding work.
+  bool owns_work() const ASIO_NOEXCEPT
+  {
+    return owns_;
+  }
+
+  /// Indicate that the work is no longer outstanding.
+  /**
+   * Unless the object has already been reset, or is in a moved-from state,
+   * calls <tt>on_work_finished()</tt> on the stored executor.
+   */
+  void reset() ASIO_NOEXCEPT
+  {
+    if (owns_)
+    {
+      executor_.on_work_finished();
+      owns_ = false;
+    }
+  }
+
+private:
+  // Disallow assignment.
+  executor_work_guard& operator=(const executor_work_guard&);
+
+  executor_type executor_;
+  bool owns_;
+};
+
+#if !defined(GENERATING_DOCUMENTATION)
+
+template <typename Executor>
+class executor_work_guard<Executor,
+    typename enable_if<
+      !is_executor<Executor>::value && execution::is_executor<Executor>::value
+    >::type>
+{
+public:
+  typedef Executor executor_type;
+
+  explicit executor_work_guard(const executor_type& e) ASIO_NOEXCEPT
+    : executor_(e),
+      owns_(true)
+  {
+    new (&work_) work_type(asio::prefer(executor_,
+          execution::outstanding_work.tracked));
+  }
+
+  executor_work_guard(const executor_work_guard& other) ASIO_NOEXCEPT
+    : executor_(other.executor_),
+      owns_(other.owns_)
+  {
+    if (owns_)
+    {
+      new (&work_) work_type(asio::prefer(executor_,
+            execution::outstanding_work.tracked));
+    }
+  }
+
+#if defined(ASIO_HAS_MOVE)
+  executor_work_guard(executor_work_guard&& other) ASIO_NOEXCEPT
+    : executor_(ASIO_MOVE_CAST(Executor)(other.executor_)),
+      owns_(other.owns_)
+  {
+    if (owns_)
+    {
+      new (&work_) work_type(
+          ASIO_MOVE_CAST(work_type)(
+            *static_cast<work_type*>(
+              static_cast<void*>(&other.work_))));
+      other.owns_ = false;
+    }
+  }
+#endif //  defined(ASIO_HAS_MOVE)
+
+  ~executor_work_guard()
+  {
+    if (owns_)
+      static_cast<work_type*>(static_cast<void*>(&work_))->~work_type();
+  }
+
+  executor_type get_executor() const ASIO_NOEXCEPT
+  {
+    return executor_;
+  }
+
+  bool owns_work() const ASIO_NOEXCEPT
+  {
+    return owns_;
+  }
+
+  void reset() ASIO_NOEXCEPT
+  {
+    if (owns_)
+    {
+      static_cast<work_type*>(static_cast<void*>(&work_))->~work_type();
+      owns_ = false;
+    }
+  }
+
+private:
+  // Disallow assignment.
+  executor_work_guard& operator=(const executor_work_guard&);
+
+  typedef typename decay<
+      typename prefer_result<
+        const executor_type&,
+        execution::outstanding_work_t::tracked_t
+      >::type
+    >::type work_type;
+
+  executor_type executor_;
+  typename aligned_storage<sizeof(work_type),
+      alignment_of<work_type>::value>::type work_;
+  bool owns_;
+};
+
+#endif // !defined(GENERATING_DOCUMENTATION)
+
+/// Create an @ref executor_work_guard object.
+template <typename Executor>
+inline executor_work_guard<Executor> make_work_guard(const Executor& ex,
+    typename enable_if<
+      is_executor<Executor>::value || execution::is_executor<Executor>::value
+    >::type* = 0)
+{
+  return executor_work_guard<Executor>(ex);
+}
+
+/// Create an @ref executor_work_guard object.
+template <typename ExecutionContext>
+inline executor_work_guard<typename ExecutionContext::executor_type>
+make_work_guard(ExecutionContext& ctx,
+    typename enable_if<
+      is_convertible<ExecutionContext&, execution_context&>::value
+    >::type* = 0)
+{
+  return executor_work_guard<typename ExecutionContext::executor_type>(
+      ctx.get_executor());
+}
+
+/// Create an @ref executor_work_guard object.
+template <typename T>
+inline executor_work_guard<typename associated_executor<T>::type>
+make_work_guard(const T& t,
+    typename enable_if<
+      !is_executor<T>::value && !execution::is_executor<T>::value
+        && !is_convertible<T&, execution_context&
+    >::value>::type* = 0)
+{
+  return executor_work_guard<typename associated_executor<T>::type>(
+      associated_executor<T>::get(t));
+}
+
+/// Create an @ref executor_work_guard object.
+template <typename T, typename Executor>
+inline executor_work_guard<typename associated_executor<T, Executor>::type>
+make_work_guard(const T& t, const Executor& ex,
+    typename enable_if<
+      is_executor<Executor>::value || execution::is_executor<Executor>::value
+    >::type* = 0)
+{
+  return executor_work_guard<typename associated_executor<T, Executor>::type>(
+      associated_executor<T, Executor>::get(t, ex));
+}
+
+/// Create an @ref executor_work_guard object.
+template <typename T, typename ExecutionContext>
+inline executor_work_guard<typename associated_executor<T,
+  typename ExecutionContext::executor_type>::type>
+make_work_guard(const T& t, ExecutionContext& ctx,
+    typename enable_if<
+      !is_executor<T>::value && !execution::is_executor<T>::value
+        && !is_convertible<T&, execution_context&>::value
+        && is_convertible<ExecutionContext&, execution_context&>::value
+    >::type* = 0)
+{
+  return executor_work_guard<typename associated_executor<T,
+    typename ExecutionContext::executor_type>::type>(
+      associated_executor<T, typename ExecutionContext::executor_type>::get(
+        t, ctx.get_executor()));
+}
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // !defined(ASIO_NO_TS_EXECUTORS)
+
+#endif // ASIO_EXECUTOR_WORK_GUARD_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/generic/basic_endpoint.hpp b/link/modules/asio-standalone/asio/include/asio/generic/basic_endpoint.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/generic/basic_endpoint.hpp
@@ -0,0 +1,193 @@
+//
+// generic/basic_endpoint.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_GENERIC_BASIC_ENDPOINT_HPP
+#define ASIO_GENERIC_BASIC_ENDPOINT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/generic/detail/endpoint.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace generic {
+
+/// Describes an endpoint for any socket type.
+/**
+ * The asio::generic::basic_endpoint class template describes an endpoint
+ * that may be associated with any socket type.
+ *
+ * @note The socket types sockaddr type must be able to fit into a
+ * @c sockaddr_storage structure.
+ *
+ * @par Thread Safety
+ * @e Distinct @e objects: Safe.@n
+ * @e Shared @e objects: Unsafe.
+ *
+ * @par Concepts:
+ * Endpoint.
+ */
+template <typename Protocol>
+class basic_endpoint
+{
+public:
+  /// The protocol type associated with the endpoint.
+  typedef Protocol protocol_type;
+
+  /// The type of the endpoint structure. This type is dependent on the
+  /// underlying implementation of the socket layer.
+#if defined(GENERATING_DOCUMENTATION)
+  typedef implementation_defined data_type;
+#else
+  typedef asio::detail::socket_addr_type data_type;
+#endif
+
+  /// Default constructor.
+  basic_endpoint() ASIO_NOEXCEPT
+  {
+  }
+
+  /// Construct an endpoint from the specified socket address.
+  basic_endpoint(const void* socket_address,
+      std::size_t socket_address_size, int socket_protocol = 0)
+    : impl_(socket_address, socket_address_size, socket_protocol)
+  {
+  }
+
+  /// Construct an endpoint from the specific endpoint type.
+  template <typename Endpoint>
+  basic_endpoint(const Endpoint& endpoint)
+    : impl_(endpoint.data(), endpoint.size(), endpoint.protocol().protocol())
+  {
+  }
+
+  /// Copy constructor.
+  basic_endpoint(const basic_endpoint& other)
+    : impl_(other.impl_)
+  {
+  }
+
+#if defined(ASIO_HAS_MOVE)
+  /// Move constructor.
+  basic_endpoint(basic_endpoint&& other)
+    : impl_(other.impl_)
+  {
+  }
+#endif // defined(ASIO_HAS_MOVE)
+
+  /// Assign from another endpoint.
+  basic_endpoint& operator=(const basic_endpoint& other)
+  {
+    impl_ = other.impl_;
+    return *this;
+  }
+
+#if defined(ASIO_HAS_MOVE)
+  /// Move-assign from another endpoint.
+  basic_endpoint& operator=(basic_endpoint&& other)
+  {
+    impl_ = other.impl_;
+    return *this;
+  }
+#endif // defined(ASIO_HAS_MOVE)
+
+  /// The protocol associated with the endpoint.
+  protocol_type protocol() const
+  {
+    return protocol_type(impl_.family(), impl_.protocol());
+  }
+
+  /// Get the underlying endpoint in the native type.
+  data_type* data()
+  {
+    return impl_.data();
+  }
+
+  /// Get the underlying endpoint in the native type.
+  const data_type* data() const
+  {
+    return impl_.data();
+  }
+
+  /// Get the underlying size of the endpoint in the native type.
+  std::size_t size() const
+  {
+    return impl_.size();
+  }
+
+  /// Set the underlying size of the endpoint in the native type.
+  void resize(std::size_t new_size)
+  {
+    impl_.resize(new_size);
+  }
+
+  /// Get the capacity of the endpoint in the native type.
+  std::size_t capacity() const
+  {
+    return impl_.capacity();
+  }
+
+  /// Compare two endpoints for equality.
+  friend bool operator==(const basic_endpoint<Protocol>& e1,
+      const basic_endpoint<Protocol>& e2)
+  {
+    return e1.impl_ == e2.impl_;
+  }
+
+  /// Compare two endpoints for inequality.
+  friend bool operator!=(const basic_endpoint<Protocol>& e1,
+      const basic_endpoint<Protocol>& e2)
+  {
+    return !(e1.impl_ == e2.impl_);
+  }
+
+  /// Compare endpoints for ordering.
+  friend bool operator<(const basic_endpoint<Protocol>& e1,
+      const basic_endpoint<Protocol>& e2)
+  {
+    return e1.impl_ < e2.impl_;
+  }
+
+  /// Compare endpoints for ordering.
+  friend bool operator>(const basic_endpoint<Protocol>& e1,
+      const basic_endpoint<Protocol>& e2)
+  {
+    return e2.impl_ < e1.impl_;
+  }
+
+  /// Compare endpoints for ordering.
+  friend bool operator<=(const basic_endpoint<Protocol>& e1,
+      const basic_endpoint<Protocol>& e2)
+  {
+    return !(e2 < e1);
+  }
+
+  /// Compare endpoints for ordering.
+  friend bool operator>=(const basic_endpoint<Protocol>& e1,
+      const basic_endpoint<Protocol>& e2)
+  {
+    return !(e1 < e2);
+  }
+
+private:
+  // The underlying generic endpoint.
+  asio::generic::detail::endpoint impl_;
+};
+
+} // namespace generic
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_GENERIC_BASIC_ENDPOINT_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/generic/datagram_protocol.hpp b/link/modules/asio-standalone/asio/include/asio/generic/datagram_protocol.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/generic/datagram_protocol.hpp
@@ -0,0 +1,123 @@
+//
+// generic/datagram_protocol.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_GENERIC_DATAGRAM_PROTOCOL_HPP
+#define ASIO_GENERIC_DATAGRAM_PROTOCOL_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#include <typeinfo>
+#include "asio/basic_datagram_socket.hpp"
+#include "asio/detail/socket_types.hpp"
+#include "asio/detail/throw_exception.hpp"
+#include "asio/generic/basic_endpoint.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace generic {
+
+/// Encapsulates the flags needed for a generic datagram-oriented socket.
+/**
+ * The asio::generic::datagram_protocol class contains flags necessary
+ * for datagram-oriented sockets of any address family and protocol.
+ *
+ * @par Examples
+ * Constructing using a native address family and socket protocol:
+ * @code datagram_protocol p(AF_INET, IPPROTO_UDP); @endcode
+ * Constructing from a specific protocol type:
+ * @code datagram_protocol p(asio::ip::udp::v4()); @endcode
+ *
+ * @par Thread Safety
+ * @e Distinct @e objects: Safe.@n
+ * @e Shared @e objects: Safe.
+ *
+ * @par Concepts:
+ * Protocol.
+ */
+class datagram_protocol
+{
+public:
+  /// Construct a protocol object for a specific address family and protocol.
+  datagram_protocol(int address_family, int socket_protocol)
+    : family_(address_family),
+      protocol_(socket_protocol)
+  {
+  }
+
+  /// Construct a generic protocol object from a specific protocol.
+  /**
+   * @throws @c bad_cast Thrown if the source protocol is not datagram-oriented.
+   */
+  template <typename Protocol>
+  datagram_protocol(const Protocol& source_protocol)
+    : family_(source_protocol.family()),
+      protocol_(source_protocol.protocol())
+  {
+    if (source_protocol.type() != type())
+    {
+      std::bad_cast ex;
+      asio::detail::throw_exception(ex);
+    }
+  }
+
+  /// Obtain an identifier for the type of the protocol.
+  int type() const ASIO_NOEXCEPT
+  {
+    return ASIO_OS_DEF(SOCK_DGRAM);
+  }
+
+  /// Obtain an identifier for the protocol.
+  int protocol() const ASIO_NOEXCEPT
+  {
+    return protocol_;
+  }
+
+  /// Obtain an identifier for the protocol family.
+  int family() const ASIO_NOEXCEPT
+  {
+    return family_;
+  }
+
+  /// Compare two protocols for equality.
+  friend bool operator==(const datagram_protocol& p1,
+      const datagram_protocol& p2)
+  {
+    return p1.family_ == p2.family_ && p1.protocol_ == p2.protocol_;
+  }
+
+  /// Compare two protocols for inequality.
+  friend bool operator!=(const datagram_protocol& p1,
+      const datagram_protocol& p2)
+  {
+    return !(p1 == p2);
+  }
+
+  /// The type of an endpoint.
+  typedef basic_endpoint<datagram_protocol> endpoint;
+
+  /// The generic socket type.
+  typedef basic_datagram_socket<datagram_protocol> socket;
+
+private:
+  int family_;
+  int protocol_;
+};
+
+} // namespace generic
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_GENERIC_DATAGRAM_PROTOCOL_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/generic/detail/endpoint.hpp b/link/modules/asio-standalone/asio/include/asio/generic/detail/endpoint.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/generic/detail/endpoint.hpp
@@ -0,0 +1,133 @@
+//
+// generic/detail/endpoint.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_GENERIC_DETAIL_ENDPOINT_HPP
+#define ASIO_GENERIC_DETAIL_ENDPOINT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#include <cstddef>
+#include "asio/detail/socket_types.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace generic {
+namespace detail {
+
+// Helper class for implementing a generic socket endpoint.
+class endpoint
+{
+public:
+  // Default constructor.
+  ASIO_DECL endpoint();
+
+  // Construct an endpoint from the specified raw bytes.
+  ASIO_DECL endpoint(const void* sock_addr,
+      std::size_t sock_addr_size, int sock_protocol);
+
+  // Copy constructor.
+  endpoint(const endpoint& other)
+    : data_(other.data_),
+      size_(other.size_),
+      protocol_(other.protocol_)
+  {
+  }
+
+  // Assign from another endpoint.
+  endpoint& operator=(const endpoint& other)
+  {
+    data_ = other.data_;
+    size_ = other.size_;
+    protocol_ = other.protocol_;
+    return *this;
+  }
+
+  // Get the address family associated with the endpoint.
+  int family() const
+  {
+    return data_.base.sa_family;
+  }
+
+  // Get the socket protocol associated with the endpoint.
+  int protocol() const
+  {
+    return protocol_;
+  }
+
+  // Get the underlying endpoint in the native type.
+  asio::detail::socket_addr_type* data()
+  {
+    return &data_.base;
+  }
+
+  // Get the underlying endpoint in the native type.
+  const asio::detail::socket_addr_type* data() const
+  {
+    return &data_.base;
+  }
+
+  // Get the underlying size of the endpoint in the native type.
+  std::size_t size() const
+  {
+    return size_;
+  }
+
+  // Set the underlying size of the endpoint in the native type.
+  ASIO_DECL void resize(std::size_t size);
+
+  // Get the capacity of the endpoint in the native type.
+  std::size_t capacity() const
+  {
+    return sizeof(asio::detail::sockaddr_storage_type);
+  }
+
+  // Compare two endpoints for equality.
+  ASIO_DECL friend bool operator==(
+      const endpoint& e1, const endpoint& e2);
+
+  // Compare endpoints for ordering.
+  ASIO_DECL friend bool operator<(
+      const endpoint& e1, const endpoint& e2);
+
+private:
+  // The underlying socket address.
+  union data_union
+  {
+    asio::detail::socket_addr_type base;
+    asio::detail::sockaddr_storage_type generic;
+  } data_;
+
+  // The length of the socket address stored in the endpoint.
+  std::size_t size_;
+
+  // The socket protocol associated with the endpoint.
+  int protocol_;
+
+  // Initialise with a specified memory.
+  ASIO_DECL void init(const void* sock_addr,
+      std::size_t sock_addr_size, int sock_protocol);
+};
+
+} // namespace detail
+} // namespace generic
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/generic/detail/impl/endpoint.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // ASIO_GENERIC_DETAIL_ENDPOINT_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/generic/detail/impl/endpoint.ipp b/link/modules/asio-standalone/asio/include/asio/generic/detail/impl/endpoint.ipp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/generic/detail/impl/endpoint.ipp
@@ -0,0 +1,110 @@
+//
+// generic/detail/impl/endpoint.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_GENERIC_DETAIL_IMPL_ENDPOINT_IPP
+#define ASIO_GENERIC_DETAIL_IMPL_ENDPOINT_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#include <cstring>
+#include <typeinfo>
+#include "asio/detail/socket_ops.hpp"
+#include "asio/detail/throw_error.hpp"
+#include "asio/detail/throw_exception.hpp"
+#include "asio/error.hpp"
+#include "asio/generic/detail/endpoint.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace generic {
+namespace detail {
+
+endpoint::endpoint()
+{
+  init(0, 0, 0);
+}
+
+endpoint::endpoint(const void* sock_addr,
+    std::size_t sock_addr_size, int sock_protocol)
+{
+  init(sock_addr, sock_addr_size, sock_protocol);
+}
+
+void endpoint::resize(std::size_t new_size)
+{
+  if (new_size > sizeof(asio::detail::sockaddr_storage_type))
+  {
+    asio::error_code ec(asio::error::invalid_argument);
+    asio::detail::throw_error(ec);
+  }
+  else
+  {
+    size_ = new_size;
+    protocol_ = 0;
+  }
+}
+
+bool operator==(const endpoint& e1, const endpoint& e2)
+{
+  using namespace std; // For memcmp.
+  return e1.size() == e2.size() && memcmp(e1.data(), e2.data(), e1.size()) == 0;
+}
+
+bool operator<(const endpoint& e1, const endpoint& e2)
+{
+  if (e1.protocol() < e2.protocol())
+    return true;
+
+  if (e1.protocol() > e2.protocol())
+    return false;
+
+  using namespace std; // For memcmp.
+  std::size_t compare_size = e1.size() < e2.size() ? e1.size() : e2.size();
+  int compare_result = memcmp(e1.data(), e2.data(), compare_size);
+
+  if (compare_result < 0)
+    return true;
+
+  if (compare_result > 0)
+    return false;
+
+  return e1.size() < e2.size();
+}
+
+void endpoint::init(const void* sock_addr,
+    std::size_t sock_addr_size, int sock_protocol)
+{
+  if (sock_addr_size > sizeof(asio::detail::sockaddr_storage_type))
+  {
+    asio::error_code ec(asio::error::invalid_argument);
+    asio::detail::throw_error(ec);
+  }
+
+  using namespace std; // For memset and memcpy.
+  memset(&data_.generic, 0, sizeof(asio::detail::sockaddr_storage_type));
+  if (sock_addr_size > 0)
+    memcpy(&data_.generic, sock_addr, sock_addr_size);
+
+  size_ = sock_addr_size;
+  protocol_ = sock_protocol;
+}
+
+} // namespace detail
+} // namespace generic
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_GENERIC_DETAIL_IMPL_ENDPOINT_IPP
diff --git a/link/modules/asio-standalone/asio/include/asio/generic/raw_protocol.hpp b/link/modules/asio-standalone/asio/include/asio/generic/raw_protocol.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/generic/raw_protocol.hpp
@@ -0,0 +1,121 @@
+//
+// generic/raw_protocol.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_GENERIC_RAW_PROTOCOL_HPP
+#define ASIO_GENERIC_RAW_PROTOCOL_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#include <typeinfo>
+#include "asio/basic_raw_socket.hpp"
+#include "asio/detail/socket_types.hpp"
+#include "asio/detail/throw_exception.hpp"
+#include "asio/generic/basic_endpoint.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace generic {
+
+/// Encapsulates the flags needed for a generic raw socket.
+/**
+ * The asio::generic::raw_protocol class contains flags necessary for
+ * raw sockets of any address family and protocol.
+ *
+ * @par Examples
+ * Constructing using a native address family and socket protocol:
+ * @code raw_protocol p(AF_INET, IPPROTO_ICMP); @endcode
+ * Constructing from a specific protocol type:
+ * @code raw_protocol p(asio::ip::icmp::v4()); @endcode
+ *
+ * @par Thread Safety
+ * @e Distinct @e objects: Safe.@n
+ * @e Shared @e objects: Safe.
+ *
+ * @par Concepts:
+ * Protocol.
+ */
+class raw_protocol
+{
+public:
+  /// Construct a protocol object for a specific address family and protocol.
+  raw_protocol(int address_family, int socket_protocol)
+    : family_(address_family),
+      protocol_(socket_protocol)
+  {
+  }
+
+  /// Construct a generic protocol object from a specific protocol.
+  /**
+   * @throws @c bad_cast Thrown if the source protocol is not raw-oriented.
+   */
+  template <typename Protocol>
+  raw_protocol(const Protocol& source_protocol)
+    : family_(source_protocol.family()),
+      protocol_(source_protocol.protocol())
+  {
+    if (source_protocol.type() != type())
+    {
+      std::bad_cast ex;
+      asio::detail::throw_exception(ex);
+    }
+  }
+
+  /// Obtain an identifier for the type of the protocol.
+  int type() const ASIO_NOEXCEPT
+  {
+    return ASIO_OS_DEF(SOCK_RAW);
+  }
+
+  /// Obtain an identifier for the protocol.
+  int protocol() const ASIO_NOEXCEPT
+  {
+    return protocol_;
+  }
+
+  /// Obtain an identifier for the protocol family.
+  int family() const ASIO_NOEXCEPT
+  {
+    return family_;
+  }
+
+  /// Compare two protocols for equality.
+  friend bool operator==(const raw_protocol& p1, const raw_protocol& p2)
+  {
+    return p1.family_ == p2.family_ && p1.protocol_ == p2.protocol_;
+  }
+
+  /// Compare two protocols for inequality.
+  friend bool operator!=(const raw_protocol& p1, const raw_protocol& p2)
+  {
+    return !(p1 == p2);
+  }
+
+  /// The type of an endpoint.
+  typedef basic_endpoint<raw_protocol> endpoint;
+
+  /// The generic socket type.
+  typedef basic_raw_socket<raw_protocol> socket;
+
+private:
+  int family_;
+  int protocol_;
+};
+
+} // namespace generic
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_GENERIC_RAW_PROTOCOL_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/generic/seq_packet_protocol.hpp b/link/modules/asio-standalone/asio/include/asio/generic/seq_packet_protocol.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/generic/seq_packet_protocol.hpp
@@ -0,0 +1,122 @@
+//
+// generic/seq_packet_protocol.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_GENERIC_SEQ_PACKET_PROTOCOL_HPP
+#define ASIO_GENERIC_SEQ_PACKET_PROTOCOL_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#include <typeinfo>
+#include "asio/basic_seq_packet_socket.hpp"
+#include "asio/detail/socket_types.hpp"
+#include "asio/detail/throw_exception.hpp"
+#include "asio/generic/basic_endpoint.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace generic {
+
+/// Encapsulates the flags needed for a generic sequenced packet socket.
+/**
+ * The asio::generic::seq_packet_protocol class contains flags necessary
+ * for seq_packet-oriented sockets of any address family and protocol.
+ *
+ * @par Examples
+ * Constructing using a native address family and socket protocol:
+ * @code seq_packet_protocol p(AF_INET, IPPROTO_SCTP); @endcode
+ *
+ * @par Thread Safety
+ * @e Distinct @e objects: Safe.@n
+ * @e Shared @e objects: Safe.
+ *
+ * @par Concepts:
+ * Protocol.
+ */
+class seq_packet_protocol
+{
+public:
+  /// Construct a protocol object for a specific address family and protocol.
+  seq_packet_protocol(int address_family, int socket_protocol)
+    : family_(address_family),
+      protocol_(socket_protocol)
+  {
+  }
+
+  /// Construct a generic protocol object from a specific protocol.
+  /**
+   * @throws @c bad_cast Thrown if the source protocol is not based around
+   * sequenced packets.
+   */
+  template <typename Protocol>
+  seq_packet_protocol(const Protocol& source_protocol)
+    : family_(source_protocol.family()),
+      protocol_(source_protocol.protocol())
+  {
+    if (source_protocol.type() != type())
+    {
+      std::bad_cast ex;
+      asio::detail::throw_exception(ex);
+    }
+  }
+
+  /// Obtain an identifier for the type of the protocol.
+  int type() const ASIO_NOEXCEPT
+  {
+    return ASIO_OS_DEF(SOCK_SEQPACKET);
+  }
+
+  /// Obtain an identifier for the protocol.
+  int protocol() const ASIO_NOEXCEPT
+  {
+    return protocol_;
+  }
+
+  /// Obtain an identifier for the protocol family.
+  int family() const ASIO_NOEXCEPT
+  {
+    return family_;
+  }
+
+  /// Compare two protocols for equality.
+  friend bool operator==(const seq_packet_protocol& p1,
+      const seq_packet_protocol& p2)
+  {
+    return p1.family_ == p2.family_ && p1.protocol_ == p2.protocol_;
+  }
+
+  /// Compare two protocols for inequality.
+  friend bool operator!=(const seq_packet_protocol& p1,
+      const seq_packet_protocol& p2)
+  {
+    return !(p1 == p2);
+  }
+
+  /// The type of an endpoint.
+  typedef basic_endpoint<seq_packet_protocol> endpoint;
+
+  /// The generic socket type.
+  typedef basic_seq_packet_socket<seq_packet_protocol> socket;
+
+private:
+  int family_;
+  int protocol_;
+};
+
+} // namespace generic
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_GENERIC_SEQ_PACKET_PROTOCOL_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/generic/stream_protocol.hpp b/link/modules/asio-standalone/asio/include/asio/generic/stream_protocol.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/generic/stream_protocol.hpp
@@ -0,0 +1,127 @@
+//
+// generic/stream_protocol.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_GENERIC_STREAM_PROTOCOL_HPP
+#define ASIO_GENERIC_STREAM_PROTOCOL_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#include <typeinfo>
+#include "asio/basic_socket_iostream.hpp"
+#include "asio/basic_stream_socket.hpp"
+#include "asio/detail/socket_types.hpp"
+#include "asio/detail/throw_exception.hpp"
+#include "asio/generic/basic_endpoint.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace generic {
+
+/// Encapsulates the flags needed for a generic stream-oriented socket.
+/**
+ * The asio::generic::stream_protocol class contains flags necessary for
+ * stream-oriented sockets of any address family and protocol.
+ *
+ * @par Examples
+ * Constructing using a native address family and socket protocol:
+ * @code stream_protocol p(AF_INET, IPPROTO_TCP); @endcode
+ * Constructing from a specific protocol type:
+ * @code stream_protocol p(asio::ip::tcp::v4()); @endcode
+ *
+ * @par Thread Safety
+ * @e Distinct @e objects: Safe.@n
+ * @e Shared @e objects: Safe.
+ *
+ * @par Concepts:
+ * Protocol.
+ */
+class stream_protocol
+{
+public:
+  /// Construct a protocol object for a specific address family and protocol.
+  stream_protocol(int address_family, int socket_protocol)
+    : family_(address_family),
+      protocol_(socket_protocol)
+  {
+  }
+
+  /// Construct a generic protocol object from a specific protocol.
+  /**
+   * @throws @c bad_cast Thrown if the source protocol is not stream-oriented.
+   */
+  template <typename Protocol>
+  stream_protocol(const Protocol& source_protocol)
+    : family_(source_protocol.family()),
+      protocol_(source_protocol.protocol())
+  {
+    if (source_protocol.type() != type())
+    {
+      std::bad_cast ex;
+      asio::detail::throw_exception(ex);
+    }
+  }
+
+  /// Obtain an identifier for the type of the protocol.
+  int type() const ASIO_NOEXCEPT
+  {
+    return ASIO_OS_DEF(SOCK_STREAM);
+  }
+
+  /// Obtain an identifier for the protocol.
+  int protocol() const ASIO_NOEXCEPT
+  {
+    return protocol_;
+  }
+
+  /// Obtain an identifier for the protocol family.
+  int family() const ASIO_NOEXCEPT
+  {
+    return family_;
+  }
+
+  /// Compare two protocols for equality.
+  friend bool operator==(const stream_protocol& p1, const stream_protocol& p2)
+  {
+    return p1.family_ == p2.family_ && p1.protocol_ == p2.protocol_;
+  }
+
+  /// Compare two protocols for inequality.
+  friend bool operator!=(const stream_protocol& p1, const stream_protocol& p2)
+  {
+    return !(p1 == p2);
+  }
+
+  /// The type of an endpoint.
+  typedef basic_endpoint<stream_protocol> endpoint;
+
+  /// The generic socket type.
+  typedef basic_stream_socket<stream_protocol> socket;
+
+#if !defined(ASIO_NO_IOSTREAM)
+  /// The generic socket iostream type.
+  typedef basic_socket_iostream<stream_protocol> iostream;
+#endif // !defined(ASIO_NO_IOSTREAM)
+
+private:
+  int family_;
+  int protocol_;
+};
+
+} // namespace generic
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_GENERIC_STREAM_PROTOCOL_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/handler_alloc_hook.hpp b/link/modules/asio-standalone/asio/include/asio/handler_alloc_hook.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/handler_alloc_hook.hpp
@@ -0,0 +1,104 @@
+//
+// handler_alloc_hook.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_HANDLER_ALLOC_HOOK_HPP
+#define ASIO_HANDLER_ALLOC_HOOK_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <cstddef>
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+#if defined(ASIO_NO_DEPRECATED)
+
+// Places in asio that would have previously called the allocate or deallocate
+// hooks to manage memory, now call them only to check whether the result types
+// are these types. If the result is not the correct type, it indicates that
+// the user code still has the old hooks in place, and if so we want to trigger
+// a compile error.
+enum asio_handler_allocate_is_no_longer_used {};
+enum asio_handler_deallocate_is_no_longer_used {};
+
+typedef asio_handler_allocate_is_no_longer_used
+  asio_handler_allocate_is_deprecated;
+typedef asio_handler_deallocate_is_no_longer_used
+  asio_handler_deallocate_is_deprecated;
+
+#else // defined(ASIO_NO_DEPRECATED)
+
+typedef void* asio_handler_allocate_is_deprecated;
+typedef void asio_handler_deallocate_is_deprecated;
+
+#endif // defined(ASIO_NO_DEPRECATED)
+
+/// (Deprecated: Use the associated_allocator trait.) Default allocation
+/// function for handlers.
+/**
+ * Asynchronous operations may need to allocate temporary objects. Since
+ * asynchronous operations have a handler function object, these temporary
+ * objects can be said to be associated with the handler.
+ *
+ * Implement asio_handler_allocate and asio_handler_deallocate for your own
+ * handlers to provide custom allocation for these temporary objects.
+ *
+ * The default implementation of these allocation hooks uses <tt>::operator
+ * new</tt> and <tt>::operator delete</tt>.
+ *
+ * @note All temporary objects associated with a handler will be deallocated
+ * before the upcall to the handler is performed. This allows the same memory to
+ * be reused for a subsequent asynchronous operation initiated by the handler.
+ *
+ * @par Example
+ * @code
+ * class my_handler;
+ *
+ * void* asio_handler_allocate(std::size_t size, my_handler* context)
+ * {
+ *   return ::operator new(size);
+ * }
+ *
+ * void asio_handler_deallocate(void* pointer, std::size_t size,
+ *     my_handler* context)
+ * {
+ *   ::operator delete(pointer);
+ * }
+ * @endcode
+ */
+ASIO_DECL asio_handler_allocate_is_deprecated
+asio_handler_allocate(std::size_t size, ...);
+
+/// Default deallocation function for handlers.
+/**
+ * Implement asio_handler_allocate and asio_handler_deallocate for your own
+ * handlers to provide custom allocation for the associated temporary objects.
+ *
+ * The default implementation of these allocation hooks uses <tt>::operator
+ * new</tt> and <tt>::operator delete</tt>.
+ *
+ * @sa asio_handler_allocate.
+ */
+ASIO_DECL asio_handler_deallocate_is_deprecated
+asio_handler_deallocate(void* pointer, std::size_t size, ...);
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/impl/handler_alloc_hook.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // ASIO_HANDLER_ALLOC_HOOK_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/handler_continuation_hook.hpp b/link/modules/asio-standalone/asio/include/asio/handler_continuation_hook.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/handler_continuation_hook.hpp
@@ -0,0 +1,54 @@
+//
+// handler_continuation_hook.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_HANDLER_CONTINUATION_HOOK_HPP
+#define ASIO_HANDLER_CONTINUATION_HOOK_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+/// Default continuation function for handlers.
+/**
+ * Asynchronous operations may represent a continuation of the asynchronous
+ * control flow associated with the current handler. The implementation can use
+ * this knowledge to optimise scheduling of the handler.
+ *
+ * Implement asio_handler_is_continuation for your own handlers to indicate
+ * when a handler represents a continuation.
+ *
+ * The default implementation of the continuation hook returns <tt>false</tt>.
+ *
+ * @par Example
+ * @code
+ * class my_handler;
+ *
+ * bool asio_handler_is_continuation(my_handler* context)
+ * {
+ *   return true;
+ * }
+ * @endcode
+ */
+inline bool asio_handler_is_continuation(...)
+{
+  return false;
+}
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_HANDLER_CONTINUATION_HOOK_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/handler_invoke_hook.hpp b/link/modules/asio-standalone/asio/include/asio/handler_invoke_hook.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/handler_invoke_hook.hpp
@@ -0,0 +1,111 @@
+//
+// handler_invoke_hook.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_HANDLER_INVOKE_HOOK_HPP
+#define ASIO_HANDLER_INVOKE_HOOK_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+/** @defgroup asio_handler_invoke asio::asio_handler_invoke
+ *
+ * @brief (Deprecated: Use the associated_executor trait.) Default invoke
+ * function for handlers.
+ *
+ * Completion handlers for asynchronous operations are invoked by the
+ * io_context associated with the corresponding object (e.g. a socket or
+ * deadline_timer). Certain guarantees are made on when the handler may be
+ * invoked, in particular that a handler can only be invoked from a thread that
+ * is currently calling @c run() on the corresponding io_context object.
+ * Handlers may subsequently be invoked through other objects (such as
+ * io_context::strand objects) that provide additional guarantees.
+ *
+ * When asynchronous operations are composed from other asynchronous
+ * operations, all intermediate handlers should be invoked using the same
+ * method as the final handler. This is required to ensure that user-defined
+ * objects are not accessed in a way that may violate the guarantees. This
+ * hooking function ensures that the invoked method used for the final handler
+ * is accessible at each intermediate step.
+ *
+ * Implement asio_handler_invoke for your own handlers to specify a custom
+ * invocation strategy.
+ *
+ * This default implementation invokes the function object like so:
+ * @code function(); @endcode
+ * If necessary, the default implementation makes a copy of the function object
+ * so that the non-const operator() can be used.
+ *
+ * @par Example
+ * @code
+ * class my_handler;
+ *
+ * template <typename Function>
+ * void asio_handler_invoke(Function function, my_handler* context)
+ * {
+ *   context->strand_.dispatch(function);
+ * }
+ * @endcode
+ */
+/*@{*/
+
+#if defined(ASIO_NO_DEPRECATED)
+
+// Places in asio that would have previously called the invocation hook to
+// execute a handler, now call it only to check whether the result type is this
+// type. If the result is not this type, it indicates that the user code still
+// has the old hooks in place, and if so we want to trigger a compile error.
+enum asio_handler_invoke_is_no_longer_used {};
+
+typedef asio_handler_invoke_is_no_longer_used
+  asio_handler_invoke_is_deprecated;
+
+#else // defined(ASIO_NO_DEPRECATED)
+
+typedef void asio_handler_invoke_is_deprecated;
+
+#endif // defined(ASIO_NO_DEPRECATED)
+
+/// Default handler invocation hook used for non-const function objects.
+template <typename Function>
+inline asio_handler_invoke_is_deprecated
+asio_handler_invoke(Function& function, ...)
+{
+  function();
+#if defined(ASIO_NO_DEPRECATED)
+  return asio_handler_invoke_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+}
+
+/// Default handler invocation hook used for const function objects.
+template <typename Function>
+inline asio_handler_invoke_is_deprecated
+asio_handler_invoke(const Function& function, ...)
+{
+  Function tmp(function);
+  tmp();
+#if defined(ASIO_NO_DEPRECATED)
+  return asio_handler_invoke_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+}
+
+/*@}*/
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_HANDLER_INVOKE_HOOK_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/high_resolution_timer.hpp b/link/modules/asio-standalone/asio/include/asio/high_resolution_timer.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/high_resolution_timer.hpp
@@ -0,0 +1,44 @@
+//
+// high_resolution_timer.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_HIGH_RESOLUTION_TIMER_HPP
+#define ASIO_HIGH_RESOLUTION_TIMER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_CHRONO) || defined(GENERATING_DOCUMENTATION)
+
+#include "asio/basic_waitable_timer.hpp"
+#include "asio/detail/chrono.hpp"
+
+namespace asio {
+
+/// Typedef for a timer based on the high resolution clock.
+/**
+ * This typedef uses the C++11 @c &lt;chrono&gt; standard library facility, if
+ * available. Otherwise, it may use the Boost.Chrono library. To explicitly
+ * utilise Boost.Chrono, use the basic_waitable_timer template directly:
+ * @code
+ * typedef basic_waitable_timer<boost::chrono::high_resolution_clock> timer;
+ * @endcode
+ */
+typedef basic_waitable_timer<
+    chrono::high_resolution_clock>
+  high_resolution_timer;
+
+} // namespace asio
+
+#endif // defined(ASIO_HAS_CHRONO) || defined(GENERATING_DOCUMENTATION)
+
+#endif // ASIO_HIGH_RESOLUTION_TIMER_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/impl/awaitable.hpp b/link/modules/asio-standalone/asio/include/asio/impl/awaitable.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/impl/awaitable.hpp
@@ -0,0 +1,436 @@
+//
+// impl/awaitable.hpp
+// ~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_IMPL_AWAITABLE_HPP
+#define ASIO_IMPL_AWAITABLE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <exception>
+#include <new>
+#include <tuple>
+#include <utility>
+#include "asio/detail/thread_context.hpp"
+#include "asio/detail/thread_info_base.hpp"
+#include "asio/detail/type_traits.hpp"
+#include "asio/post.hpp"
+#include "asio/system_error.hpp"
+#include "asio/this_coro.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+// An awaitable_thread represents a thread-of-execution that is composed of one
+// or more "stack frames", with each frame represented by an awaitable_frame.
+// All execution occurs in the context of the awaitable_thread's executor. An
+// awaitable_thread continues to "pump" the stack frames by repeatedly resuming
+// the top stack frame until the stack is empty, or until ownership of the
+// stack is transferred to another awaitable_thread object.
+//
+//                +------------------------------------+
+//                | top_of_stack_                      |
+//                |                                    V
+// +--------------+---+                            +-----------------+
+// |                  |                            |                 |
+// | awaitable_thread |<---------------------------+ awaitable_frame |
+// |                  |           attached_thread_ |                 |
+// +--------------+---+           (Set only when   +---+-------------+
+//                |               frames are being     |
+//                |               actively pumped      | caller_
+//                |               by a thread, and     |
+//                |               then only for        V
+//                |               the top frame.)  +-----------------+
+//                |                                |                 |
+//                |                                | awaitable_frame |
+//                |                                |                 |
+//                |                                +---+-------------+
+//                |                                    |
+//                |                                    | caller_
+//                |                                    :
+//                |                                    :
+//                |                                    |
+//                |                                    V
+//                |                                +-----------------+
+//                | bottom_of_stack_               |                 |
+//                +------------------------------->| awaitable_frame |
+//                                                 |                 |
+//                                                 +-----------------+
+
+template <typename Executor>
+class awaitable_frame_base
+{
+public:
+#if !defined(ASIO_DISABLE_AWAITABLE_FRAME_RECYCLING)
+  void* operator new(std::size_t size)
+  {
+    return asio::detail::thread_info_base::allocate(
+        asio::detail::thread_info_base::awaitable_frame_tag(),
+        asio::detail::thread_context::thread_call_stack::top(),
+        size);
+  }
+
+  void operator delete(void* pointer, std::size_t size)
+  {
+    asio::detail::thread_info_base::deallocate(
+        asio::detail::thread_info_base::awaitable_frame_tag(),
+        asio::detail::thread_context::thread_call_stack::top(),
+        pointer, size);
+  }
+#endif // !defined(ASIO_DISABLE_AWAITABLE_FRAME_RECYCLING)
+
+  // The frame starts in a suspended state until the awaitable_thread object
+  // pumps the stack.
+  auto initial_suspend() noexcept
+  {
+    return suspend_always();
+  }
+
+  // On final suspension the frame is popped from the top of the stack.
+  auto final_suspend() noexcept
+  {
+    struct result
+    {
+      awaitable_frame_base* this_;
+
+      bool await_ready() const noexcept
+      {
+        return false;
+      }
+
+      void await_suspend(coroutine_handle<void>) noexcept
+      {
+        this_->pop_frame();
+      }
+
+      void await_resume() const noexcept
+      {
+      }
+    };
+
+    return result{this};
+  }
+
+  void set_except(std::exception_ptr e) noexcept
+  {
+    pending_exception_ = e;
+  }
+
+  void set_error(const asio::error_code& ec)
+  {
+    this->set_except(std::make_exception_ptr(asio::system_error(ec)));
+  }
+
+  void unhandled_exception()
+  {
+    set_except(std::current_exception());
+  }
+
+  void rethrow_exception()
+  {
+    if (pending_exception_)
+    {
+      std::exception_ptr ex = std::exchange(pending_exception_, nullptr);
+      std::rethrow_exception(ex);
+    }
+  }
+
+  template <typename T>
+  auto await_transform(awaitable<T, Executor> a) const
+  {
+    return a;
+  }
+
+  // This await transformation obtains the associated executor of the thread of
+  // execution.
+  auto await_transform(this_coro::executor_t) noexcept
+  {
+    struct result
+    {
+      awaitable_frame_base* this_;
+
+      bool await_ready() const noexcept
+      {
+        return true;
+      }
+
+      void await_suspend(coroutine_handle<void>) noexcept
+      {
+      }
+
+      auto await_resume() const noexcept
+      {
+        return this_->attached_thread_->get_executor();
+      }
+    };
+
+    return result{this};
+  }
+
+  // This await transformation is used to run an async operation's initiation
+  // function object after the coroutine has been suspended. This ensures that
+  // immediate resumption of the coroutine in another thread does not cause a
+  // race condition.
+  template <typename Function>
+  auto await_transform(Function f,
+      typename enable_if<
+        is_convertible<
+          typename result_of<Function(awaitable_frame_base*)>::type,
+          awaitable_thread<Executor>*
+        >::value
+      >::type* = 0)
+  {
+    struct result
+    {
+      Function function_;
+      awaitable_frame_base* this_;
+
+      bool await_ready() const noexcept
+      {
+        return false;
+      }
+
+      void await_suspend(coroutine_handle<void>) noexcept
+      {
+        function_(this_);
+      }
+
+      void await_resume() const noexcept
+      {
+      }
+    };
+
+    return result{std::move(f), this};
+  }
+
+  void attach_thread(awaitable_thread<Executor>* handler) noexcept
+  {
+    attached_thread_ = handler;
+  }
+
+  awaitable_thread<Executor>* detach_thread() noexcept
+  {
+    return std::exchange(attached_thread_, nullptr);
+  }
+
+  void push_frame(awaitable_frame_base<Executor>* caller) noexcept
+  {
+    caller_ = caller;
+    attached_thread_ = caller_->attached_thread_;
+    attached_thread_->top_of_stack_ = this;
+    caller_->attached_thread_ = nullptr;
+  }
+
+  void pop_frame() noexcept
+  {
+    if (caller_)
+      caller_->attached_thread_ = attached_thread_;
+    attached_thread_->top_of_stack_ = caller_;
+    attached_thread_ = nullptr;
+    caller_ = nullptr;
+  }
+
+  void resume()
+  {
+    coro_.resume();
+  }
+
+  void destroy()
+  {
+    coro_.destroy();
+  }
+
+protected:
+  coroutine_handle<void> coro_ = nullptr;
+  awaitable_thread<Executor>* attached_thread_ = nullptr;
+  awaitable_frame_base<Executor>* caller_ = nullptr;
+  std::exception_ptr pending_exception_ = nullptr;
+};
+
+template <typename T, typename Executor>
+class awaitable_frame
+  : public awaitable_frame_base<Executor>
+{
+public:
+  awaitable_frame() noexcept
+  {
+  }
+
+  awaitable_frame(awaitable_frame&& other) noexcept
+    : awaitable_frame_base<Executor>(std::move(other))
+  {
+  }
+
+  ~awaitable_frame()
+  {
+    if (has_result_)
+      static_cast<T*>(static_cast<void*>(result_))->~T();
+  }
+
+  awaitable<T, Executor> get_return_object() noexcept
+  {
+    this->coro_ = coroutine_handle<awaitable_frame>::from_promise(*this);
+    return awaitable<T, Executor>(this);
+  };
+
+  template <typename U>
+  void return_value(U&& u)
+  {
+    new (&result_) T(std::forward<U>(u));
+    has_result_ = true;
+  }
+
+  template <typename... Us>
+  void return_values(Us&&... us)
+  {
+    this->return_value(std::forward_as_tuple(std::forward<Us>(us)...));
+  }
+
+  T get()
+  {
+    this->caller_ = nullptr;
+    this->rethrow_exception();
+    return std::move(*static_cast<T*>(static_cast<void*>(result_)));
+  }
+
+private:
+  alignas(T) unsigned char result_[sizeof(T)];
+  bool has_result_ = false;
+};
+
+template <typename Executor>
+class awaitable_frame<void, Executor>
+  : public awaitable_frame_base<Executor>
+{
+public:
+  awaitable<void, Executor> get_return_object()
+  {
+    this->coro_ = coroutine_handle<awaitable_frame>::from_promise(*this);
+    return awaitable<void, Executor>(this);
+  };
+
+  void return_void()
+  {
+  }
+
+  void get()
+  {
+    this->caller_ = nullptr;
+    this->rethrow_exception();
+  }
+};
+
+template <typename Executor>
+class awaitable_thread
+{
+public:
+  typedef Executor executor_type;
+
+  // Construct from the entry point of a new thread of execution.
+  awaitable_thread(awaitable<void, Executor> p, const Executor& ex)
+    : bottom_of_stack_(std::move(p)),
+      top_of_stack_(bottom_of_stack_.frame_),
+      executor_(ex)
+  {
+  }
+
+  // Transfer ownership from another awaitable_thread.
+  awaitable_thread(awaitable_thread&& other) noexcept
+    : bottom_of_stack_(std::move(other.bottom_of_stack_)),
+      top_of_stack_(std::exchange(other.top_of_stack_, nullptr)),
+      executor_(std::move(other.executor_))
+  {
+  }
+
+  // Clean up with a last ditch effort to ensure the thread is unwound within
+  // the context of the executor.
+  ~awaitable_thread()
+  {
+    if (bottom_of_stack_.valid())
+    {
+      // Coroutine "stack unwinding" must be performed through the executor.
+      (post)(executor_,
+          [a = std::move(bottom_of_stack_)]() mutable
+          {
+            awaitable<void, Executor>(std::move(a));
+          });
+    }
+  }
+
+  executor_type get_executor() const noexcept
+  {
+    return executor_;
+  }
+
+  // Launch a new thread of execution.
+  void launch()
+  {
+    top_of_stack_->attach_thread(this);
+    pump();
+  }
+
+protected:
+  template <typename> friend class awaitable_frame_base;
+
+  // Repeatedly resume the top stack frame until the stack is empty or until it
+  // has been transferred to another resumable_thread object.
+  void pump()
+  {
+    do top_of_stack_->resume(); while (top_of_stack_);
+    if (bottom_of_stack_.valid())
+    {
+      awaitable<void, Executor> a(std::move(bottom_of_stack_));
+      a.frame_->rethrow_exception();
+    }
+  }
+
+  awaitable<void, Executor> bottom_of_stack_;
+  awaitable_frame_base<Executor>* top_of_stack_;
+  executor_type executor_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#if !defined(GENERATING_DOCUMENTATION)
+# if defined(ASIO_HAS_STD_COROUTINE)
+
+namespace std {
+
+template <typename T, typename Executor, typename... Args>
+struct coroutine_traits<asio::awaitable<T, Executor>, Args...>
+{
+  typedef asio::detail::awaitable_frame<T, Executor> promise_type;
+};
+
+} // namespace std
+
+# else // defined(ASIO_HAS_STD_COROUTINE)
+
+namespace std { namespace experimental {
+
+template <typename T, typename Executor, typename... Args>
+struct coroutine_traits<asio::awaitable<T, Executor>, Args...>
+{
+  typedef asio::detail::awaitable_frame<T, Executor> promise_type;
+};
+
+}} // namespace std::experimental
+
+# endif // defined(ASIO_HAS_STD_COROUTINE)
+#endif // !defined(GENERATING_DOCUMENTATION)
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IMPL_AWAITABLE_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/impl/buffered_read_stream.hpp b/link/modules/asio-standalone/asio/include/asio/impl/buffered_read_stream.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/impl/buffered_read_stream.hpp
@@ -0,0 +1,527 @@
+//
+// impl/buffered_read_stream.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_IMPL_BUFFERED_READ_STREAM_HPP
+#define ASIO_IMPL_BUFFERED_READ_STREAM_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/associated_allocator.hpp"
+#include "asio/associated_executor.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_cont_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/handler_type_requirements.hpp"
+#include "asio/detail/non_const_lvalue.hpp"
+#include "asio/detail/type_traits.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+template <typename Stream>
+std::size_t buffered_read_stream<Stream>::fill()
+{
+  detail::buffer_resize_guard<detail::buffered_stream_storage>
+    resize_guard(storage_);
+  std::size_t previous_size = storage_.size();
+  storage_.resize(storage_.capacity());
+  storage_.resize(previous_size + next_layer_.read_some(buffer(
+          storage_.data() + previous_size,
+          storage_.size() - previous_size)));
+  resize_guard.commit();
+  return storage_.size() - previous_size;
+}
+
+template <typename Stream>
+std::size_t buffered_read_stream<Stream>::fill(asio::error_code& ec)
+{
+  detail::buffer_resize_guard<detail::buffered_stream_storage>
+    resize_guard(storage_);
+  std::size_t previous_size = storage_.size();
+  storage_.resize(storage_.capacity());
+  storage_.resize(previous_size + next_layer_.read_some(buffer(
+          storage_.data() + previous_size,
+          storage_.size() - previous_size),
+        ec));
+  resize_guard.commit();
+  return storage_.size() - previous_size;
+}
+
+namespace detail
+{
+  template <typename ReadHandler>
+  class buffered_fill_handler
+  {
+  public:
+    buffered_fill_handler(detail::buffered_stream_storage& storage,
+        std::size_t previous_size, ReadHandler& handler)
+      : storage_(storage),
+        previous_size_(previous_size),
+        handler_(ASIO_MOVE_CAST(ReadHandler)(handler))
+    {
+    }
+
+#if defined(ASIO_HAS_MOVE)
+    buffered_fill_handler(const buffered_fill_handler& other)
+      : storage_(other.storage_),
+        previous_size_(other.previous_size_),
+        handler_(other.handler_)
+    {
+    }
+
+    buffered_fill_handler(buffered_fill_handler&& other)
+      : storage_(other.storage_),
+        previous_size_(other.previous_size_),
+        handler_(ASIO_MOVE_CAST(ReadHandler)(other.handler_))
+    {
+    }
+#endif // defined(ASIO_HAS_MOVE)
+
+    void operator()(const asio::error_code& ec,
+        const std::size_t bytes_transferred)
+    {
+      storage_.resize(previous_size_ + bytes_transferred);
+      handler_(ec, bytes_transferred);
+    }
+
+  //private:
+    detail::buffered_stream_storage& storage_;
+    std::size_t previous_size_;
+    ReadHandler handler_;
+  };
+
+  template <typename ReadHandler>
+  inline asio_handler_allocate_is_deprecated
+  asio_handler_allocate(std::size_t size,
+      buffered_fill_handler<ReadHandler>* this_handler)
+  {
+#if defined(ASIO_NO_DEPRECATED)
+    asio_handler_alloc_helpers::allocate(size, this_handler->handler_);
+    return asio_handler_allocate_is_no_longer_used();
+#else // defined(ASIO_NO_DEPRECATED)
+    return asio_handler_alloc_helpers::allocate(
+        size, this_handler->handler_);
+#endif // defined(ASIO_NO_DEPRECATED)
+  }
+
+  template <typename ReadHandler>
+  inline asio_handler_deallocate_is_deprecated
+  asio_handler_deallocate(void* pointer, std::size_t size,
+      buffered_fill_handler<ReadHandler>* this_handler)
+  {
+    asio_handler_alloc_helpers::deallocate(
+        pointer, size, this_handler->handler_);
+#if defined(ASIO_NO_DEPRECATED)
+    return asio_handler_deallocate_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+  }
+
+  template <typename ReadHandler>
+  inline bool asio_handler_is_continuation(
+      buffered_fill_handler<ReadHandler>* this_handler)
+  {
+    return asio_handler_cont_helpers::is_continuation(
+          this_handler->handler_);
+  }
+
+  template <typename Function, typename ReadHandler>
+  inline asio_handler_invoke_is_deprecated
+  asio_handler_invoke(Function& function,
+      buffered_fill_handler<ReadHandler>* this_handler)
+  {
+    asio_handler_invoke_helpers::invoke(
+        function, this_handler->handler_);
+#if defined(ASIO_NO_DEPRECATED)
+    return asio_handler_invoke_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+  }
+
+  template <typename Function, typename ReadHandler>
+  inline asio_handler_invoke_is_deprecated
+  asio_handler_invoke(const Function& function,
+      buffered_fill_handler<ReadHandler>* this_handler)
+  {
+    asio_handler_invoke_helpers::invoke(
+        function, this_handler->handler_);
+#if defined(ASIO_NO_DEPRECATED)
+    return asio_handler_invoke_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+  }
+
+  template <typename Stream>
+  class initiate_async_buffered_fill
+  {
+  public:
+    typedef typename remove_reference<
+      Stream>::type::lowest_layer_type::executor_type executor_type;
+
+    explicit initiate_async_buffered_fill(
+        typename remove_reference<Stream>::type& next_layer)
+      : next_layer_(next_layer)
+    {
+    }
+
+    executor_type get_executor() const ASIO_NOEXCEPT
+    {
+      return next_layer_.lowest_layer().get_executor();
+    }
+
+    template <typename ReadHandler>
+    void operator()(ASIO_MOVE_ARG(ReadHandler) handler,
+        buffered_stream_storage* storage) const
+    {
+      // If you get an error on the following line it means that your handler
+      // does not meet the documented type requirements for a ReadHandler.
+      ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
+
+      non_const_lvalue<ReadHandler> handler2(handler);
+      std::size_t previous_size = storage->size();
+      storage->resize(storage->capacity());
+      next_layer_.async_read_some(
+          buffer(
+            storage->data() + previous_size,
+            storage->size() - previous_size),
+          buffered_fill_handler<typename decay<ReadHandler>::type>(
+            *storage, previous_size, handler2.value));
+    }
+
+  private:
+    typename remove_reference<Stream>::type& next_layer_;
+  };
+} // namespace detail
+
+#if !defined(GENERATING_DOCUMENTATION)
+
+template <typename ReadHandler, typename Allocator>
+struct associated_allocator<
+    detail::buffered_fill_handler<ReadHandler>, Allocator>
+{
+  typedef typename associated_allocator<ReadHandler, Allocator>::type type;
+
+  static type get(const detail::buffered_fill_handler<ReadHandler>& h,
+      const Allocator& a = Allocator()) ASIO_NOEXCEPT
+  {
+    return associated_allocator<ReadHandler, Allocator>::get(h.handler_, a);
+  }
+};
+
+template <typename ReadHandler, typename Executor>
+struct associated_executor<
+    detail::buffered_fill_handler<ReadHandler>, Executor>
+{
+  typedef typename associated_executor<ReadHandler, Executor>::type type;
+
+  static type get(const detail::buffered_fill_handler<ReadHandler>& h,
+      const Executor& ex = Executor()) ASIO_NOEXCEPT
+  {
+    return associated_executor<ReadHandler, Executor>::get(h.handler_, ex);
+  }
+};
+
+#endif // !defined(GENERATING_DOCUMENTATION)
+
+template <typename Stream>
+template <
+    ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+      std::size_t)) ReadHandler>
+ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,
+    void (asio::error_code, std::size_t))
+buffered_read_stream<Stream>::async_fill(
+    ASIO_MOVE_ARG(ReadHandler) handler)
+{
+  return async_initiate<ReadHandler,
+    void (asio::error_code, std::size_t)>(
+      detail::initiate_async_buffered_fill<Stream>(next_layer_),
+      handler, &storage_);
+}
+
+template <typename Stream>
+template <typename MutableBufferSequence>
+std::size_t buffered_read_stream<Stream>::read_some(
+    const MutableBufferSequence& buffers)
+{
+  using asio::buffer_size;
+  if (buffer_size(buffers) == 0)
+    return 0;
+
+  if (storage_.empty())
+    this->fill();
+
+  return this->copy(buffers);
+}
+
+template <typename Stream>
+template <typename MutableBufferSequence>
+std::size_t buffered_read_stream<Stream>::read_some(
+    const MutableBufferSequence& buffers, asio::error_code& ec)
+{
+  ec = asio::error_code();
+
+  using asio::buffer_size;
+  if (buffer_size(buffers) == 0)
+    return 0;
+
+  if (storage_.empty() && !this->fill(ec))
+    return 0;
+
+  return this->copy(buffers);
+}
+
+namespace detail
+{
+  template <typename MutableBufferSequence, typename ReadHandler>
+  class buffered_read_some_handler
+  {
+  public:
+    buffered_read_some_handler(detail::buffered_stream_storage& storage,
+        const MutableBufferSequence& buffers, ReadHandler& handler)
+      : storage_(storage),
+        buffers_(buffers),
+        handler_(ASIO_MOVE_CAST(ReadHandler)(handler))
+    {
+    }
+
+#if defined(ASIO_HAS_MOVE)
+      buffered_read_some_handler(const buffered_read_some_handler& other)
+        : storage_(other.storage_),
+          buffers_(other.buffers_),
+          handler_(other.handler_)
+      {
+      }
+
+      buffered_read_some_handler(buffered_read_some_handler&& other)
+        : storage_(other.storage_),
+          buffers_(other.buffers_),
+          handler_(ASIO_MOVE_CAST(ReadHandler)(other.handler_))
+      {
+      }
+#endif // defined(ASIO_HAS_MOVE)
+
+    void operator()(const asio::error_code& ec, std::size_t)
+    {
+      if (ec || storage_.empty())
+      {
+        const std::size_t length = 0;
+        handler_(ec, length);
+      }
+      else
+      {
+        const std::size_t bytes_copied = asio::buffer_copy(
+            buffers_, storage_.data(), storage_.size());
+        storage_.consume(bytes_copied);
+        handler_(ec, bytes_copied);
+      }
+    }
+
+  //private:
+    detail::buffered_stream_storage& storage_;
+    MutableBufferSequence buffers_;
+    ReadHandler handler_;
+  };
+
+  template <typename MutableBufferSequence, typename ReadHandler>
+  inline asio_handler_allocate_is_deprecated
+  asio_handler_allocate(std::size_t size,
+      buffered_read_some_handler<
+        MutableBufferSequence, ReadHandler>* this_handler)
+  {
+#if defined(ASIO_NO_DEPRECATED)
+    asio_handler_alloc_helpers::allocate(size, this_handler->handler_);
+    return asio_handler_allocate_is_no_longer_used();
+#else // defined(ASIO_NO_DEPRECATED)
+    return asio_handler_alloc_helpers::allocate(
+        size, this_handler->handler_);
+#endif // defined(ASIO_NO_DEPRECATED)
+  }
+
+  template <typename MutableBufferSequence, typename ReadHandler>
+  inline asio_handler_deallocate_is_deprecated
+  asio_handler_deallocate(void* pointer, std::size_t size,
+      buffered_read_some_handler<
+        MutableBufferSequence, ReadHandler>* this_handler)
+  {
+    asio_handler_alloc_helpers::deallocate(
+        pointer, size, this_handler->handler_);
+#if defined(ASIO_NO_DEPRECATED)
+    return asio_handler_deallocate_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+  }
+
+  template <typename MutableBufferSequence, typename ReadHandler>
+  inline bool asio_handler_is_continuation(
+      buffered_read_some_handler<
+        MutableBufferSequence, ReadHandler>* this_handler)
+  {
+    return asio_handler_cont_helpers::is_continuation(
+          this_handler->handler_);
+  }
+
+  template <typename Function, typename MutableBufferSequence,
+      typename ReadHandler>
+  inline asio_handler_invoke_is_deprecated
+  asio_handler_invoke(Function& function,
+      buffered_read_some_handler<
+        MutableBufferSequence, ReadHandler>* this_handler)
+  {
+    asio_handler_invoke_helpers::invoke(
+        function, this_handler->handler_);
+#if defined(ASIO_NO_DEPRECATED)
+    return asio_handler_invoke_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+  }
+
+  template <typename Function, typename MutableBufferSequence,
+      typename ReadHandler>
+  inline asio_handler_invoke_is_deprecated
+  asio_handler_invoke(const Function& function,
+      buffered_read_some_handler<
+        MutableBufferSequence, ReadHandler>* this_handler)
+  {
+    asio_handler_invoke_helpers::invoke(
+        function, this_handler->handler_);
+#if defined(ASIO_NO_DEPRECATED)
+    return asio_handler_invoke_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+  }
+
+  template <typename Stream>
+  class initiate_async_buffered_read_some
+  {
+  public:
+    typedef typename remove_reference<
+      Stream>::type::lowest_layer_type::executor_type executor_type;
+
+    explicit initiate_async_buffered_read_some(
+        typename remove_reference<Stream>::type& next_layer)
+      : next_layer_(next_layer)
+    {
+    }
+
+    executor_type get_executor() const ASIO_NOEXCEPT
+    {
+      return next_layer_.lowest_layer().get_executor();
+    }
+
+    template <typename ReadHandler, typename MutableBufferSequence>
+    void operator()(ASIO_MOVE_ARG(ReadHandler) handler,
+        buffered_stream_storage* storage,
+        const MutableBufferSequence& buffers) const
+    {
+      // If you get an error on the following line it means that your handler
+      // does not meet the documented type requirements for a ReadHandler.
+      ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
+
+      using asio::buffer_size;
+      non_const_lvalue<ReadHandler> handler2(handler);
+      if (buffer_size(buffers) == 0 || !storage->empty())
+      {
+        next_layer_.async_read_some(ASIO_MUTABLE_BUFFER(0, 0),
+            buffered_read_some_handler<MutableBufferSequence,
+              typename decay<ReadHandler>::type>(
+                *storage, buffers, handler2.value));
+      }
+      else
+      {
+        initiate_async_buffered_fill<Stream>(this->next_layer_)(
+            buffered_read_some_handler<MutableBufferSequence,
+              typename decay<ReadHandler>::type>(
+                *storage, buffers, handler2.value),
+            storage);
+      }
+    }
+
+  private:
+    typename remove_reference<Stream>::type& next_layer_;
+  };
+} // namespace detail
+
+#if !defined(GENERATING_DOCUMENTATION)
+
+template <typename MutableBufferSequence,
+    typename ReadHandler, typename Allocator>
+struct associated_allocator<
+    detail::buffered_read_some_handler<MutableBufferSequence, ReadHandler>,
+    Allocator>
+{
+  typedef typename associated_allocator<ReadHandler, Allocator>::type type;
+
+  static type get(
+      const detail::buffered_read_some_handler<
+        MutableBufferSequence, ReadHandler>& h,
+      const Allocator& a = Allocator()) ASIO_NOEXCEPT
+  {
+    return associated_allocator<ReadHandler, Allocator>::get(h.handler_, a);
+  }
+};
+
+template <typename MutableBufferSequence,
+    typename ReadHandler, typename Executor>
+struct associated_executor<
+    detail::buffered_read_some_handler<MutableBufferSequence, ReadHandler>,
+    Executor>
+{
+  typedef typename associated_executor<ReadHandler, Executor>::type type;
+
+  static type get(
+      const detail::buffered_read_some_handler<
+        MutableBufferSequence, ReadHandler>& h,
+      const Executor& ex = Executor()) ASIO_NOEXCEPT
+  {
+    return associated_executor<ReadHandler, Executor>::get(h.handler_, ex);
+  }
+};
+
+#endif // !defined(GENERATING_DOCUMENTATION)
+
+template <typename Stream>
+template <typename MutableBufferSequence,
+    ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+      std::size_t)) ReadHandler>
+ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,
+    void (asio::error_code, std::size_t))
+buffered_read_stream<Stream>::async_read_some(
+    const MutableBufferSequence& buffers,
+    ASIO_MOVE_ARG(ReadHandler) handler)
+{
+  return async_initiate<ReadHandler,
+    void (asio::error_code, std::size_t)>(
+      detail::initiate_async_buffered_read_some<Stream>(next_layer_),
+      handler, &storage_, buffers);
+}
+
+template <typename Stream>
+template <typename MutableBufferSequence>
+std::size_t buffered_read_stream<Stream>::peek(
+    const MutableBufferSequence& buffers)
+{
+  if (storage_.empty())
+    this->fill();
+  return this->peek_copy(buffers);
+}
+
+template <typename Stream>
+template <typename MutableBufferSequence>
+std::size_t buffered_read_stream<Stream>::peek(
+    const MutableBufferSequence& buffers, asio::error_code& ec)
+{
+  ec = asio::error_code();
+  if (storage_.empty() && !this->fill(ec))
+    return 0;
+  return this->peek_copy(buffers);
+}
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IMPL_BUFFERED_READ_STREAM_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/impl/buffered_write_stream.hpp b/link/modules/asio-standalone/asio/include/asio/impl/buffered_write_stream.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/impl/buffered_write_stream.hpp
@@ -0,0 +1,507 @@
+//
+// impl/buffered_write_stream.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_IMPL_BUFFERED_WRITE_STREAM_HPP
+#define ASIO_IMPL_BUFFERED_WRITE_STREAM_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/associated_allocator.hpp"
+#include "asio/associated_executor.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_cont_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/handler_type_requirements.hpp"
+#include "asio/detail/non_const_lvalue.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+template <typename Stream>
+std::size_t buffered_write_stream<Stream>::flush()
+{
+  std::size_t bytes_written = write(next_layer_,
+      buffer(storage_.data(), storage_.size()));
+  storage_.consume(bytes_written);
+  return bytes_written;
+}
+
+template <typename Stream>
+std::size_t buffered_write_stream<Stream>::flush(asio::error_code& ec)
+{
+  std::size_t bytes_written = write(next_layer_,
+      buffer(storage_.data(), storage_.size()),
+      transfer_all(), ec);
+  storage_.consume(bytes_written);
+  return bytes_written;
+}
+
+namespace detail
+{
+  template <typename WriteHandler>
+  class buffered_flush_handler
+  {
+  public:
+    buffered_flush_handler(detail::buffered_stream_storage& storage,
+        WriteHandler& handler)
+      : storage_(storage),
+        handler_(ASIO_MOVE_CAST(WriteHandler)(handler))
+    {
+    }
+
+#if defined(ASIO_HAS_MOVE)
+    buffered_flush_handler(const buffered_flush_handler& other)
+      : storage_(other.storage_),
+        handler_(other.handler_)
+    {
+    }
+
+    buffered_flush_handler(buffered_flush_handler&& other)
+      : storage_(other.storage_),
+        handler_(ASIO_MOVE_CAST(WriteHandler)(other.handler_))
+    {
+    }
+#endif // defined(ASIO_HAS_MOVE)
+
+    void operator()(const asio::error_code& ec,
+        const std::size_t bytes_written)
+    {
+      storage_.consume(bytes_written);
+      handler_(ec, bytes_written);
+    }
+
+  //private:
+    detail::buffered_stream_storage& storage_;
+    WriteHandler handler_;
+  };
+
+  template <typename WriteHandler>
+  inline asio_handler_allocate_is_deprecated
+  asio_handler_allocate(std::size_t size,
+      buffered_flush_handler<WriteHandler>* this_handler)
+  {
+#if defined(ASIO_NO_DEPRECATED)
+    asio_handler_alloc_helpers::allocate(size, this_handler->handler_);
+    return asio_handler_allocate_is_no_longer_used();
+#else // defined(ASIO_NO_DEPRECATED)
+    return asio_handler_alloc_helpers::allocate(
+        size, this_handler->handler_);
+#endif // defined(ASIO_NO_DEPRECATED)
+  }
+
+  template <typename WriteHandler>
+  inline asio_handler_deallocate_is_deprecated
+  asio_handler_deallocate(void* pointer, std::size_t size,
+      buffered_flush_handler<WriteHandler>* this_handler)
+  {
+    asio_handler_alloc_helpers::deallocate(
+        pointer, size, this_handler->handler_);
+#if defined(ASIO_NO_DEPRECATED)
+    return asio_handler_deallocate_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+  }
+
+  template <typename WriteHandler>
+  inline bool asio_handler_is_continuation(
+      buffered_flush_handler<WriteHandler>* this_handler)
+  {
+    return asio_handler_cont_helpers::is_continuation(
+          this_handler->handler_);
+  }
+
+  template <typename Function, typename WriteHandler>
+  inline asio_handler_invoke_is_deprecated
+  asio_handler_invoke(Function& function,
+      buffered_flush_handler<WriteHandler>* this_handler)
+  {
+    asio_handler_invoke_helpers::invoke(
+        function, this_handler->handler_);
+#if defined(ASIO_NO_DEPRECATED)
+    return asio_handler_invoke_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+  }
+
+  template <typename Function, typename WriteHandler>
+  inline asio_handler_invoke_is_deprecated
+  asio_handler_invoke(const Function& function,
+      buffered_flush_handler<WriteHandler>* this_handler)
+  {
+    asio_handler_invoke_helpers::invoke(
+        function, this_handler->handler_);
+#if defined(ASIO_NO_DEPRECATED)
+    return asio_handler_invoke_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+  }
+
+  template <typename Stream>
+  class initiate_async_buffered_flush
+  {
+  public:
+    typedef typename remove_reference<
+      Stream>::type::lowest_layer_type::executor_type executor_type;
+
+    explicit initiate_async_buffered_flush(
+        typename remove_reference<Stream>::type& next_layer)
+      : next_layer_(next_layer)
+    {
+    }
+
+    executor_type get_executor() const ASIO_NOEXCEPT
+    {
+      return next_layer_.lowest_layer().get_executor();
+    }
+
+    template <typename WriteHandler>
+    void operator()(ASIO_MOVE_ARG(WriteHandler) handler,
+        buffered_stream_storage* storage) const
+    {
+      // If you get an error on the following line it means that your handler
+      // does not meet the documented type requirements for a WriteHandler.
+      ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check;
+
+      non_const_lvalue<WriteHandler> handler2(handler);
+      async_write(next_layer_, buffer(storage->data(), storage->size()),
+          buffered_flush_handler<typename decay<WriteHandler>::type>(
+            *storage, handler2.value));
+    }
+
+  private:
+    typename remove_reference<Stream>::type& next_layer_;
+  };
+} // namespace detail
+
+#if !defined(GENERATING_DOCUMENTATION)
+
+template <typename WriteHandler, typename Allocator>
+struct associated_allocator<
+    detail::buffered_flush_handler<WriteHandler>, Allocator>
+{
+  typedef typename associated_allocator<WriteHandler, Allocator>::type type;
+
+  static type get(const detail::buffered_flush_handler<WriteHandler>& h,
+      const Allocator& a = Allocator()) ASIO_NOEXCEPT
+  {
+    return associated_allocator<WriteHandler, Allocator>::get(h.handler_, a);
+  }
+};
+
+template <typename WriteHandler, typename Executor>
+struct associated_executor<
+    detail::buffered_flush_handler<WriteHandler>, Executor>
+{
+  typedef typename associated_executor<WriteHandler, Executor>::type type;
+
+  static type get(const detail::buffered_flush_handler<WriteHandler>& h,
+      const Executor& ex = Executor()) ASIO_NOEXCEPT
+  {
+    return associated_executor<WriteHandler, Executor>::get(h.handler_, ex);
+  }
+};
+
+#endif // !defined(GENERATING_DOCUMENTATION)
+
+template <typename Stream>
+template <
+    ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+      std::size_t)) WriteHandler>
+ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,
+    void (asio::error_code, std::size_t))
+buffered_write_stream<Stream>::async_flush(
+    ASIO_MOVE_ARG(WriteHandler) handler)
+{
+  return async_initiate<WriteHandler,
+    void (asio::error_code, std::size_t)>(
+      detail::initiate_async_buffered_flush<Stream>(next_layer_),
+      handler, &storage_);
+}
+
+template <typename Stream>
+template <typename ConstBufferSequence>
+std::size_t buffered_write_stream<Stream>::write_some(
+    const ConstBufferSequence& buffers)
+{
+  using asio::buffer_size;
+  if (buffer_size(buffers) == 0)
+    return 0;
+
+  if (storage_.size() == storage_.capacity())
+    this->flush();
+
+  return this->copy(buffers);
+}
+
+template <typename Stream>
+template <typename ConstBufferSequence>
+std::size_t buffered_write_stream<Stream>::write_some(
+    const ConstBufferSequence& buffers, asio::error_code& ec)
+{
+  ec = asio::error_code();
+
+  using asio::buffer_size;
+  if (buffer_size(buffers) == 0)
+    return 0;
+
+  if (storage_.size() == storage_.capacity() && !flush(ec))
+    return 0;
+
+  return this->copy(buffers);
+}
+
+namespace detail
+{
+  template <typename ConstBufferSequence, typename WriteHandler>
+  class buffered_write_some_handler
+  {
+  public:
+    buffered_write_some_handler(detail::buffered_stream_storage& storage,
+        const ConstBufferSequence& buffers, WriteHandler& handler)
+      : storage_(storage),
+        buffers_(buffers),
+        handler_(ASIO_MOVE_CAST(WriteHandler)(handler))
+    {
+    }
+
+#if defined(ASIO_HAS_MOVE)
+      buffered_write_some_handler(const buffered_write_some_handler& other)
+        : storage_(other.storage_),
+          buffers_(other.buffers_),
+          handler_(other.handler_)
+      {
+      }
+
+      buffered_write_some_handler(buffered_write_some_handler&& other)
+        : storage_(other.storage_),
+          buffers_(other.buffers_),
+          handler_(ASIO_MOVE_CAST(WriteHandler)(other.handler_))
+      {
+      }
+#endif // defined(ASIO_HAS_MOVE)
+
+    void operator()(const asio::error_code& ec, std::size_t)
+    {
+      if (ec)
+      {
+        const std::size_t length = 0;
+        handler_(ec, length);
+      }
+      else
+      {
+        using asio::buffer_size;
+        std::size_t orig_size = storage_.size();
+        std::size_t space_avail = storage_.capacity() - orig_size;
+        std::size_t bytes_avail = buffer_size(buffers_);
+        std::size_t length = bytes_avail < space_avail
+          ? bytes_avail : space_avail;
+        storage_.resize(orig_size + length);
+        const std::size_t bytes_copied = asio::buffer_copy(
+            storage_.data() + orig_size, buffers_, length);
+        handler_(ec, bytes_copied);
+      }
+    }
+
+  //private:
+    detail::buffered_stream_storage& storage_;
+    ConstBufferSequence buffers_;
+    WriteHandler handler_;
+  };
+
+  template <typename ConstBufferSequence, typename WriteHandler>
+  inline asio_handler_allocate_is_deprecated
+  asio_handler_allocate(std::size_t size,
+      buffered_write_some_handler<
+        ConstBufferSequence, WriteHandler>* this_handler)
+  {
+#if defined(ASIO_NO_DEPRECATED)
+    asio_handler_alloc_helpers::allocate(size, this_handler->handler_);
+    return asio_handler_allocate_is_no_longer_used();
+#else // defined(ASIO_NO_DEPRECATED)
+    return asio_handler_alloc_helpers::allocate(
+        size, this_handler->handler_);
+#endif // defined(ASIO_NO_DEPRECATED)
+  }
+
+  template <typename ConstBufferSequence, typename WriteHandler>
+  inline asio_handler_deallocate_is_deprecated
+  asio_handler_deallocate(void* pointer, std::size_t size,
+      buffered_write_some_handler<
+        ConstBufferSequence, WriteHandler>* this_handler)
+  {
+    asio_handler_alloc_helpers::deallocate(
+        pointer, size, this_handler->handler_);
+#if defined(ASIO_NO_DEPRECATED)
+    return asio_handler_deallocate_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+  }
+
+  template <typename ConstBufferSequence, typename WriteHandler>
+  inline bool asio_handler_is_continuation(
+      buffered_write_some_handler<
+        ConstBufferSequence, WriteHandler>* this_handler)
+  {
+    return asio_handler_cont_helpers::is_continuation(
+          this_handler->handler_);
+  }
+
+  template <typename Function, typename ConstBufferSequence,
+      typename WriteHandler>
+  inline asio_handler_invoke_is_deprecated
+  asio_handler_invoke(Function& function,
+      buffered_write_some_handler<
+        ConstBufferSequence, WriteHandler>* this_handler)
+  {
+    asio_handler_invoke_helpers::invoke(
+        function, this_handler->handler_);
+#if defined(ASIO_NO_DEPRECATED)
+    return asio_handler_invoke_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+  }
+
+  template <typename Function, typename ConstBufferSequence,
+      typename WriteHandler>
+  inline asio_handler_invoke_is_deprecated
+  asio_handler_invoke(const Function& function,
+      buffered_write_some_handler<
+        ConstBufferSequence, WriteHandler>* this_handler)
+  {
+    asio_handler_invoke_helpers::invoke(
+        function, this_handler->handler_);
+#if defined(ASIO_NO_DEPRECATED)
+    return asio_handler_invoke_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+  }
+
+  template <typename Stream>
+  class initiate_async_buffered_write_some
+  {
+  public:
+    typedef typename remove_reference<
+      Stream>::type::lowest_layer_type::executor_type executor_type;
+
+    explicit initiate_async_buffered_write_some(
+        typename remove_reference<Stream>::type& next_layer)
+      : next_layer_(next_layer)
+    {
+    }
+
+    executor_type get_executor() const ASIO_NOEXCEPT
+    {
+      return next_layer_.lowest_layer().get_executor();
+    }
+
+    template <typename WriteHandler, typename ConstBufferSequence>
+    void operator()(ASIO_MOVE_ARG(WriteHandler) handler,
+        buffered_stream_storage* storage,
+        const ConstBufferSequence& buffers) const
+    {
+      // If you get an error on the following line it means that your handler
+      // does not meet the documented type requirements for a WriteHandler.
+      ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check;
+
+      using asio::buffer_size;
+      non_const_lvalue<WriteHandler> handler2(handler);
+      if (buffer_size(buffers) == 0 || storage->size() < storage->capacity())
+      {
+        next_layer_.async_write_some(ASIO_CONST_BUFFER(0, 0),
+            buffered_write_some_handler<ConstBufferSequence,
+              typename decay<WriteHandler>::type>(
+                *storage, buffers, handler2.value));
+      }
+      else
+      {
+        initiate_async_buffered_flush<Stream>(this->next_layer_)(
+            buffered_write_some_handler<ConstBufferSequence,
+              typename decay<WriteHandler>::type>(
+                *storage, buffers, handler2.value),
+            storage);
+      }
+    }
+
+  private:
+    typename remove_reference<Stream>::type& next_layer_;
+  };
+} // namespace detail
+
+#if !defined(GENERATING_DOCUMENTATION)
+
+template <typename ConstBufferSequence,
+    typename WriteHandler, typename Allocator>
+struct associated_allocator<
+    detail::buffered_write_some_handler<ConstBufferSequence, WriteHandler>,
+    Allocator>
+{
+  typedef typename associated_allocator<WriteHandler, Allocator>::type type;
+
+  static type get(
+      const detail::buffered_write_some_handler<
+        ConstBufferSequence, WriteHandler>& h,
+      const Allocator& a = Allocator()) ASIO_NOEXCEPT
+  {
+    return associated_allocator<WriteHandler, Allocator>::get(h.handler_, a);
+  }
+};
+
+template <typename ConstBufferSequence,
+    typename WriteHandler, typename Executor>
+struct associated_executor<
+    detail::buffered_write_some_handler<ConstBufferSequence, WriteHandler>,
+    Executor>
+{
+  typedef typename associated_executor<WriteHandler, Executor>::type type;
+
+  static type get(
+      const detail::buffered_write_some_handler<
+        ConstBufferSequence, WriteHandler>& h,
+      const Executor& ex = Executor()) ASIO_NOEXCEPT
+  {
+    return associated_executor<WriteHandler, Executor>::get(h.handler_, ex);
+  }
+};
+
+#endif // !defined(GENERATING_DOCUMENTATION)
+
+template <typename Stream>
+template <typename ConstBufferSequence,
+    ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+      std::size_t)) WriteHandler>
+ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,
+    void (asio::error_code, std::size_t))
+buffered_write_stream<Stream>::async_write_some(
+    const ConstBufferSequence& buffers,
+    ASIO_MOVE_ARG(WriteHandler) handler)
+{
+  return async_initiate<WriteHandler,
+    void (asio::error_code, std::size_t)>(
+      detail::initiate_async_buffered_write_some<Stream>(next_layer_),
+      handler, &storage_, buffers);
+}
+
+template <typename Stream>
+template <typename ConstBufferSequence>
+std::size_t buffered_write_stream<Stream>::copy(
+    const ConstBufferSequence& buffers)
+{
+  using asio::buffer_size;
+  std::size_t orig_size = storage_.size();
+  std::size_t space_avail = storage_.capacity() - orig_size;
+  std::size_t bytes_avail = buffer_size(buffers);
+  std::size_t length = bytes_avail < space_avail ? bytes_avail : space_avail;
+  storage_.resize(orig_size + length);
+  return asio::buffer_copy(
+      storage_.data() + orig_size, buffers, length);
+}
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IMPL_BUFFERED_WRITE_STREAM_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/impl/co_spawn.hpp b/link/modules/asio-standalone/asio/include/asio/impl/co_spawn.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/impl/co_spawn.hpp
@@ -0,0 +1,298 @@
+//
+// impl/co_spawn.hpp
+// ~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_IMPL_CO_SPAWN_HPP
+#define ASIO_IMPL_CO_SPAWN_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/awaitable.hpp"
+#include "asio/dispatch.hpp"
+#include "asio/execution/outstanding_work.hpp"
+#include "asio/post.hpp"
+#include "asio/prefer.hpp"
+#include "asio/use_awaitable.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Executor, typename = void>
+class co_spawn_work_guard
+{
+public:
+  typedef typename decay<
+      typename prefer_result<Executor,
+        execution::outstanding_work_t::tracked_t
+      >::type
+    >::type executor_type;
+
+  co_spawn_work_guard(const Executor& ex)
+    : executor_(asio::prefer(ex, execution::outstanding_work.tracked))
+  {
+  }
+
+  executor_type get_executor() const ASIO_NOEXCEPT
+  {
+    return executor_;
+  }
+
+private:
+  executor_type executor_;
+};
+
+#if !defined(ASIO_NO_TS_EXECUTORS)
+
+template <typename Executor>
+struct co_spawn_work_guard<Executor,
+    typename enable_if<
+      !execution::is_executor<Executor>::value
+    >::type> : executor_work_guard<Executor>
+{
+  co_spawn_work_guard(const Executor& ex)
+    : executor_work_guard<Executor>(ex)
+  {
+  }
+};
+
+#endif // !defined(ASIO_NO_TS_EXECUTORS)
+
+template <typename Executor>
+inline co_spawn_work_guard<Executor>
+make_co_spawn_work_guard(const Executor& ex)
+{
+  return co_spawn_work_guard<Executor>(ex);
+}
+
+template <typename T, typename Executor, typename F, typename Handler>
+awaitable<void, Executor> co_spawn_entry_point(
+    awaitable<T, Executor>*, Executor ex, F f, Handler handler)
+{
+  auto spawn_work = make_co_spawn_work_guard(ex);
+  auto handler_work = make_co_spawn_work_guard(
+      asio::get_associated_executor(handler, ex));
+
+  (void) co_await (post)(spawn_work.get_executor(),
+      use_awaitable_t<Executor>{});
+
+  bool done = false;
+  try
+  {
+    T t = co_await f();
+
+    done = true;
+
+    (dispatch)(handler_work.get_executor(),
+        [handler = std::move(handler), t = std::move(t)]() mutable
+        {
+          handler(std::exception_ptr(), std::move(t));
+        });
+  }
+  catch (...)
+  {
+    if (done)
+      throw;
+
+    (dispatch)(handler_work.get_executor(),
+        [handler = std::move(handler), e = std::current_exception()]() mutable
+        {
+          handler(e, T());
+        });
+  }
+}
+
+template <typename Executor, typename F, typename Handler>
+awaitable<void, Executor> co_spawn_entry_point(
+    awaitable<void, Executor>*, Executor ex, F f, Handler handler)
+{
+  auto spawn_work = make_co_spawn_work_guard(ex);
+  auto handler_work = make_co_spawn_work_guard(
+      asio::get_associated_executor(handler, ex));
+
+  (void) co_await (post)(spawn_work.get_executor(),
+      use_awaitable_t<Executor>{__FILE__, __LINE__, "co_spawn_entry_point"});
+
+  std::exception_ptr e = nullptr;
+  try
+  {
+    co_await f();
+  }
+  catch (...)
+  {
+    e = std::current_exception();
+  }
+
+  (dispatch)(handler_work.get_executor(),
+      [handler = std::move(handler), e]() mutable
+      {
+        handler(e);
+      });
+}
+
+template <typename T, typename Executor>
+class awaitable_as_function
+{
+public:
+  explicit awaitable_as_function(awaitable<T, Executor>&& a)
+    : awaitable_(std::move(a))
+  {
+  }
+
+  awaitable<T, Executor> operator()()
+  {
+    return std::move(awaitable_);
+  }
+
+private:
+  awaitable<T, Executor> awaitable_;
+};
+
+template <typename Executor>
+class initiate_co_spawn
+{
+public:
+  typedef Executor executor_type;
+
+  template <typename OtherExecutor>
+  explicit initiate_co_spawn(const OtherExecutor& ex)
+    : ex_(ex)
+  {
+  }
+
+  executor_type get_executor() const ASIO_NOEXCEPT
+  {
+    return ex_;
+  }
+
+  template <typename Handler, typename F>
+  void operator()(Handler&& handler, F&& f) const
+  {
+    typedef typename result_of<F()>::type awaitable_type;
+
+    auto a = (co_spawn_entry_point)(static_cast<awaitable_type*>(nullptr),
+        ex_, std::forward<F>(f), std::forward<Handler>(handler));
+    awaitable_handler<executor_type, void>(std::move(a), ex_).launch();
+  }
+
+private:
+  Executor ex_;
+};
+
+} // namespace detail
+
+template <typename Executor, typename T, typename AwaitableExecutor,
+    ASIO_COMPLETION_TOKEN_FOR(
+      void(std::exception_ptr, T)) CompletionToken>
+inline ASIO_INITFN_AUTO_RESULT_TYPE(
+    CompletionToken, void(std::exception_ptr, T))
+co_spawn(const Executor& ex,
+    awaitable<T, AwaitableExecutor> a, CompletionToken&& token,
+    typename enable_if<
+      (is_executor<Executor>::value || execution::is_executor<Executor>::value)
+        && is_convertible<Executor, AwaitableExecutor>::value
+    >::type*)
+{
+  return async_initiate<CompletionToken, void(std::exception_ptr, T)>(
+      detail::initiate_co_spawn<AwaitableExecutor>(AwaitableExecutor(ex)),
+      token, detail::awaitable_as_function<T, AwaitableExecutor>(std::move(a)));
+}
+
+template <typename Executor, typename AwaitableExecutor,
+    ASIO_COMPLETION_TOKEN_FOR(
+      void(std::exception_ptr)) CompletionToken>
+inline ASIO_INITFN_AUTO_RESULT_TYPE(
+    CompletionToken, void(std::exception_ptr))
+co_spawn(const Executor& ex,
+    awaitable<void, AwaitableExecutor> a, CompletionToken&& token,
+    typename enable_if<
+      (is_executor<Executor>::value || execution::is_executor<Executor>::value)
+        && is_convertible<Executor, AwaitableExecutor>::value
+    >::type*)
+{
+  return async_initiate<CompletionToken, void(std::exception_ptr)>(
+      detail::initiate_co_spawn<AwaitableExecutor>(AwaitableExecutor(ex)),
+      token, detail::awaitable_as_function<
+        void, AwaitableExecutor>(std::move(a)));
+}
+
+template <typename ExecutionContext, typename T, typename AwaitableExecutor,
+    ASIO_COMPLETION_TOKEN_FOR(
+      void(std::exception_ptr, T)) CompletionToken>
+inline ASIO_INITFN_AUTO_RESULT_TYPE(
+    CompletionToken, void(std::exception_ptr, T))
+co_spawn(ExecutionContext& ctx,
+    awaitable<T, AwaitableExecutor> a, CompletionToken&& token,
+    typename enable_if<
+      is_convertible<ExecutionContext&, execution_context&>::value
+        && is_convertible<typename ExecutionContext::executor_type,
+          AwaitableExecutor>::value
+    >::type*)
+{
+  return (co_spawn)(ctx.get_executor(), std::move(a),
+      std::forward<CompletionToken>(token));
+}
+
+template <typename ExecutionContext, typename AwaitableExecutor,
+    ASIO_COMPLETION_TOKEN_FOR(
+      void(std::exception_ptr)) CompletionToken>
+inline ASIO_INITFN_AUTO_RESULT_TYPE(
+    CompletionToken, void(std::exception_ptr))
+co_spawn(ExecutionContext& ctx,
+    awaitable<void, AwaitableExecutor> a, CompletionToken&& token,
+    typename enable_if<
+      is_convertible<ExecutionContext&, execution_context&>::value
+        && is_convertible<typename ExecutionContext::executor_type,
+          AwaitableExecutor>::value
+    >::type*)
+{
+  return (co_spawn)(ctx.get_executor(), std::move(a),
+      std::forward<CompletionToken>(token));
+}
+
+template <typename Executor, typename F,
+    ASIO_COMPLETION_TOKEN_FOR(typename detail::awaitable_signature<
+      typename result_of<F()>::type>::type) CompletionToken>
+inline ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken,
+    typename detail::awaitable_signature<typename result_of<F()>::type>::type)
+co_spawn(const Executor& ex, F&& f, CompletionToken&& token,
+    typename enable_if<
+      is_executor<Executor>::value || execution::is_executor<Executor>::value
+    >::type*)
+{
+  return async_initiate<CompletionToken,
+    typename detail::awaitable_signature<typename result_of<F()>::type>::type>(
+      detail::initiate_co_spawn<
+        typename result_of<F()>::type::executor_type>(ex),
+      token, std::forward<F>(f));
+}
+
+template <typename ExecutionContext, typename F,
+    ASIO_COMPLETION_TOKEN_FOR(typename detail::awaitable_signature<
+      typename result_of<F()>::type>::type) CompletionToken>
+inline ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken,
+    typename detail::awaitable_signature<typename result_of<F()>::type>::type)
+co_spawn(ExecutionContext& ctx, F&& f, CompletionToken&& token,
+    typename enable_if<
+      is_convertible<ExecutionContext&, execution_context&>::value
+    >::type*)
+{
+  return (co_spawn)(ctx.get_executor(), std::forward<F>(f),
+      std::forward<CompletionToken>(token));
+}
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IMPL_CO_SPAWN_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/impl/compose.hpp b/link/modules/asio-standalone/asio/include/asio/impl/compose.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/impl/compose.hpp
@@ -0,0 +1,635 @@
+//
+// impl/compose.hpp
+// ~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_IMPL_COMPOSE_HPP
+#define ASIO_IMPL_COMPOSE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/associated_executor.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_cont_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/type_traits.hpp"
+#include "asio/detail/variadic_templates.hpp"
+#include "asio/execution/executor.hpp"
+#include "asio/execution/outstanding_work.hpp"
+#include "asio/executor_work_guard.hpp"
+#include "asio/is_executor.hpp"
+#include "asio/system_executor.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+namespace detail
+{
+  template <typename Executor, typename = void>
+  class composed_work_guard
+  {
+  public:
+    typedef typename decay<
+        typename prefer_result<Executor,
+          execution::outstanding_work_t::tracked_t
+        >::type
+      >::type executor_type;
+
+    composed_work_guard(const Executor& ex)
+      : executor_(asio::prefer(ex, execution::outstanding_work.tracked))
+    {
+    }
+
+    void reset()
+    {
+    }
+
+    executor_type get_executor() const ASIO_NOEXCEPT
+    {
+      return executor_;
+    }
+
+  private:
+    executor_type executor_;
+  };
+
+#if !defined(ASIO_NO_TS_EXECUTORS)
+
+  template <typename Executor>
+  struct composed_work_guard<Executor,
+      typename enable_if<
+        !execution::is_executor<Executor>::value
+      >::type> : executor_work_guard<Executor>
+  {
+    composed_work_guard(const Executor& ex)
+      : executor_work_guard<Executor>(ex)
+    {
+    }
+  };
+
+#endif // !defined(ASIO_NO_TS_EXECUTORS)
+
+  template <typename>
+  struct composed_io_executors;
+
+  template <>
+  struct composed_io_executors<void()>
+  {
+    composed_io_executors() ASIO_NOEXCEPT
+      : head_(system_executor())
+    {
+    }
+
+    typedef system_executor head_type;
+    system_executor head_;
+  };
+
+  inline composed_io_executors<void()> make_composed_io_executors()
+  {
+    return composed_io_executors<void()>();
+  }
+
+  template <typename Head>
+  struct composed_io_executors<void(Head)>
+  {
+    explicit composed_io_executors(const Head& ex) ASIO_NOEXCEPT
+      : head_(ex)
+    {
+    }
+
+    typedef Head head_type;
+    Head head_;
+  };
+
+  template <typename Head>
+  inline composed_io_executors<void(Head)>
+  make_composed_io_executors(const Head& head)
+  {
+    return composed_io_executors<void(Head)>(head);
+  }
+
+#if defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+  template <typename Head, typename... Tail>
+  struct composed_io_executors<void(Head, Tail...)>
+  {
+    explicit composed_io_executors(const Head& head,
+        const Tail&... tail) ASIO_NOEXCEPT
+      : head_(head),
+        tail_(tail...)
+    {
+    }
+
+    void reset()
+    {
+      head_.reset();
+      tail_.reset();
+    }
+
+    typedef Head head_type;
+    Head head_;
+    composed_io_executors<void(Tail...)> tail_;
+  };
+
+  template <typename Head, typename... Tail>
+  inline composed_io_executors<void(Head, Tail...)>
+  make_composed_io_executors(const Head& head, const Tail&... tail)
+  {
+    return composed_io_executors<void(Head, Tail...)>(head, tail...);
+  }
+
+#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+#define ASIO_PRIVATE_COMPOSED_IO_EXECUTORS_DEF(n) \
+  template <typename Head, ASIO_VARIADIC_TPARAMS(n)> \
+  struct composed_io_executors<void(Head, ASIO_VARIADIC_TARGS(n))> \
+  { \
+    explicit composed_io_executors(const Head& head, \
+        ASIO_VARIADIC_CONSTREF_PARAMS(n)) ASIO_NOEXCEPT \
+      : head_(head), \
+        tail_(ASIO_VARIADIC_BYVAL_ARGS(n)) \
+    { \
+    } \
+  \
+    void reset() \
+    { \
+      head_.reset(); \
+      tail_.reset(); \
+    } \
+  \
+    typedef Head head_type; \
+    Head head_; \
+    composed_io_executors<void(ASIO_VARIADIC_TARGS(n))> tail_; \
+  }; \
+  \
+  template <typename Head, ASIO_VARIADIC_TPARAMS(n)> \
+  inline composed_io_executors<void(Head, ASIO_VARIADIC_TARGS(n))> \
+  make_composed_io_executors(const Head& head, \
+      ASIO_VARIADIC_CONSTREF_PARAMS(n)) \
+  { \
+    return composed_io_executors< \
+      void(Head, ASIO_VARIADIC_TARGS(n))>( \
+        head, ASIO_VARIADIC_BYVAL_ARGS(n)); \
+  } \
+  /**/
+  ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_COMPOSED_IO_EXECUTORS_DEF)
+#undef ASIO_PRIVATE_COMPOSED_IO_EXECUTORS_DEF
+
+#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+  template <typename>
+  struct composed_work;
+
+  template <>
+  struct composed_work<void()>
+  {
+    typedef composed_io_executors<void()> executors_type;
+
+    composed_work(const executors_type&) ASIO_NOEXCEPT
+      : head_(system_executor())
+    {
+    }
+
+    void reset()
+    {
+      head_.reset();
+    }
+
+    typedef system_executor head_type;
+    composed_work_guard<system_executor> head_;
+  };
+
+  template <typename Head>
+  struct composed_work<void(Head)>
+  {
+    typedef composed_io_executors<void(Head)> executors_type;
+
+    explicit composed_work(const executors_type& ex) ASIO_NOEXCEPT
+      : head_(ex.head_)
+    {
+    }
+
+    void reset()
+    {
+      head_.reset();
+    }
+
+    typedef Head head_type;
+    composed_work_guard<Head> head_;
+  };
+
+#if defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+  template <typename Head, typename... Tail>
+  struct composed_work<void(Head, Tail...)>
+  {
+    typedef composed_io_executors<void(Head, Tail...)> executors_type;
+
+    explicit composed_work(const executors_type& ex) ASIO_NOEXCEPT
+      : head_(ex.head_),
+        tail_(ex.tail_)
+    {
+    }
+
+    void reset()
+    {
+      head_.reset();
+      tail_.reset();
+    }
+
+    typedef Head head_type;
+    composed_work_guard<Head> head_;
+    composed_work<void(Tail...)> tail_;
+  };
+
+#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+#define ASIO_PRIVATE_COMPOSED_WORK_DEF(n) \
+  template <typename Head, ASIO_VARIADIC_TPARAMS(n)> \
+  struct composed_work<void(Head, ASIO_VARIADIC_TARGS(n))> \
+  { \
+    typedef composed_io_executors<void(Head, \
+      ASIO_VARIADIC_TARGS(n))> executors_type; \
+  \
+    explicit composed_work(const executors_type& ex) ASIO_NOEXCEPT \
+      : head_(ex.head_), \
+        tail_(ex.tail_) \
+    { \
+    } \
+  \
+    void reset() \
+    { \
+      head_.reset(); \
+      tail_.reset(); \
+    } \
+  \
+    typedef Head head_type; \
+    composed_work_guard<Head> head_; \
+    composed_work<void(ASIO_VARIADIC_TARGS(n))> tail_; \
+  }; \
+  /**/
+  ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_COMPOSED_WORK_DEF)
+#undef ASIO_PRIVATE_COMPOSED_WORK_DEF
+
+#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+#if defined(ASIO_HAS_VARIADIC_TEMPLATES)
+  template <typename Impl, typename Work, typename Handler, typename Signature>
+  class composed_op;
+
+  template <typename Impl, typename Work, typename Handler,
+      typename R, typename... Args>
+  class composed_op<Impl, Work, Handler, R(Args...)>
+#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+  template <typename Impl, typename Work, typename Handler, typename Signature>
+  class composed_op
+#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+  {
+  public:
+    template <typename I, typename W, typename H>
+    composed_op(ASIO_MOVE_ARG(I) impl,
+        ASIO_MOVE_ARG(W) work,
+        ASIO_MOVE_ARG(H) handler)
+      : impl_(ASIO_MOVE_CAST(I)(impl)),
+        work_(ASIO_MOVE_CAST(W)(work)),
+        handler_(ASIO_MOVE_CAST(H)(handler)),
+        invocations_(0)
+    {
+    }
+
+#if defined(ASIO_HAS_MOVE)
+    composed_op(composed_op&& other)
+      : impl_(ASIO_MOVE_CAST(Impl)(other.impl_)),
+        work_(ASIO_MOVE_CAST(Work)(other.work_)),
+        handler_(ASIO_MOVE_CAST(Handler)(other.handler_)),
+        invocations_(other.invocations_)
+    {
+    }
+#endif // defined(ASIO_HAS_MOVE)
+
+    typedef typename associated_executor<Handler,
+        typename composed_work_guard<
+          typename Work::head_type
+        >::executor_type
+      >::type executor_type;
+
+    executor_type get_executor() const ASIO_NOEXCEPT
+    {
+      return (get_associated_executor)(handler_, work_.head_.get_executor());
+    }
+
+    typedef typename associated_allocator<Handler,
+      std::allocator<void> >::type allocator_type;
+
+    allocator_type get_allocator() const ASIO_NOEXCEPT
+    {
+      return (get_associated_allocator)(handler_, std::allocator<void>());
+    }
+
+#if defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+    template<typename... T>
+    void operator()(ASIO_MOVE_ARG(T)... t)
+    {
+      if (invocations_ < ~0u)
+        ++invocations_;
+      impl_(*this, ASIO_MOVE_CAST(T)(t)...);
+    }
+
+    void complete(Args... args)
+    {
+      this->work_.reset();
+      this->handler_(ASIO_MOVE_CAST(Args)(args)...);
+    }
+
+#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+    void operator()()
+    {
+      if (invocations_ < ~0u)
+        ++invocations_;
+      impl_(*this);
+    }
+
+    void complete()
+    {
+      this->work_.reset();
+      this->handler_();
+    }
+
+#define ASIO_PRIVATE_COMPOSED_OP_DEF(n) \
+    template<ASIO_VARIADIC_TPARAMS(n)> \
+    void operator()(ASIO_VARIADIC_MOVE_PARAMS(n)) \
+    { \
+      if (invocations_ < ~0u) \
+        ++invocations_; \
+      impl_(*this, ASIO_VARIADIC_MOVE_ARGS(n)); \
+    } \
+    \
+    template<ASIO_VARIADIC_TPARAMS(n)> \
+    void complete(ASIO_VARIADIC_MOVE_PARAMS(n)) \
+    { \
+      this->work_.reset(); \
+      this->handler_(ASIO_VARIADIC_MOVE_ARGS(n)); \
+    } \
+    /**/
+    ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_COMPOSED_OP_DEF)
+#undef ASIO_PRIVATE_COMPOSED_OP_DEF
+
+#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+  //private:
+    Impl impl_;
+    Work work_;
+    Handler handler_;
+    unsigned invocations_;
+  };
+
+  template <typename Impl, typename Work, typename Handler, typename Signature>
+  inline asio_handler_allocate_is_deprecated
+  asio_handler_allocate(std::size_t size,
+      composed_op<Impl, Work, Handler, Signature>* this_handler)
+  {
+#if defined(ASIO_NO_DEPRECATED)
+    asio_handler_alloc_helpers::allocate(size, this_handler->handler_);
+    return asio_handler_allocate_is_no_longer_used();
+#else // defined(ASIO_NO_DEPRECATED)
+    return asio_handler_alloc_helpers::allocate(
+        size, this_handler->handler_);
+#endif // defined(ASIO_NO_DEPRECATED)
+  }
+
+  template <typename Impl, typename Work, typename Handler, typename Signature>
+  inline asio_handler_deallocate_is_deprecated
+  asio_handler_deallocate(void* pointer, std::size_t size,
+      composed_op<Impl, Work, Handler, Signature>* this_handler)
+  {
+    asio_handler_alloc_helpers::deallocate(
+        pointer, size, this_handler->handler_);
+#if defined(ASIO_NO_DEPRECATED)
+    return asio_handler_deallocate_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+  }
+
+  template <typename Impl, typename Work, typename Handler, typename Signature>
+  inline bool asio_handler_is_continuation(
+      composed_op<Impl, Work, Handler, Signature>* this_handler)
+  {
+    return this_handler->invocations_ > 1 ? true
+      : asio_handler_cont_helpers::is_continuation(
+          this_handler->handler_);
+  }
+
+  template <typename Function, typename Impl,
+      typename Work, typename Handler, typename Signature>
+  inline asio_handler_invoke_is_deprecated
+  asio_handler_invoke(Function& function,
+      composed_op<Impl, Work, Handler, Signature>* this_handler)
+  {
+    asio_handler_invoke_helpers::invoke(
+        function, this_handler->handler_);
+#if defined(ASIO_NO_DEPRECATED)
+    return asio_handler_invoke_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+  }
+
+  template <typename Function, typename Impl,
+      typename Work, typename Handler, typename Signature>
+  inline asio_handler_invoke_is_deprecated
+  asio_handler_invoke(const Function& function,
+      composed_op<Impl, Work, Handler, Signature>* this_handler)
+  {
+    asio_handler_invoke_helpers::invoke(
+        function, this_handler->handler_);
+#if defined(ASIO_NO_DEPRECATED)
+    return asio_handler_invoke_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+  }
+
+  template <typename Signature, typename Executors>
+  class initiate_composed_op
+  {
+  public:
+    typedef typename composed_io_executors<Executors>::head_type executor_type;
+
+    template <typename T>
+    explicit initiate_composed_op(int, ASIO_MOVE_ARG(T) executors)
+      : executors_(ASIO_MOVE_CAST(T)(executors))
+    {
+    }
+
+    executor_type get_executor() const ASIO_NOEXCEPT
+    {
+      return executors_.head_;
+    }
+
+    template <typename Handler, typename Impl>
+    void operator()(ASIO_MOVE_ARG(Handler) handler,
+        ASIO_MOVE_ARG(Impl) impl) const
+    {
+      composed_op<typename decay<Impl>::type, composed_work<Executors>,
+        typename decay<Handler>::type, Signature>(
+          ASIO_MOVE_CAST(Impl)(impl),
+          composed_work<Executors>(executors_),
+          ASIO_MOVE_CAST(Handler)(handler))();
+    }
+
+  private:
+    composed_io_executors<Executors> executors_;
+  };
+
+  template <typename Signature, typename Executors>
+  inline initiate_composed_op<Signature, Executors> make_initiate_composed_op(
+      ASIO_MOVE_ARG(composed_io_executors<Executors>) executors)
+  {
+    return initiate_composed_op<Signature, Executors>(0,
+        ASIO_MOVE_CAST(composed_io_executors<Executors>)(executors));
+  }
+
+  template <typename IoObject>
+  inline typename IoObject::executor_type
+  get_composed_io_executor(IoObject& io_object,
+      typename enable_if<
+        !is_executor<IoObject>::value
+          && !execution::is_executor<IoObject>::value
+      >::type* = 0)
+  {
+    return io_object.get_executor();
+  }
+
+  template <typename Executor>
+  inline const Executor& get_composed_io_executor(const Executor& ex,
+      typename enable_if<
+        is_executor<Executor>::value
+          || execution::is_executor<Executor>::value
+      >::type* = 0)
+  {
+    return ex;
+  }
+} // namespace detail
+
+#if !defined(GENERATING_DOCUMENTATION)
+#if defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+template <typename CompletionToken, typename Signature,
+    typename Implementation, typename... IoObjectsOrExecutors>
+ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, Signature)
+async_compose(ASIO_MOVE_ARG(Implementation) implementation,
+    ASIO_NONDEDUCED_MOVE_ARG(CompletionToken) token,
+    ASIO_MOVE_ARG(IoObjectsOrExecutors)... io_objects_or_executors)
+{
+  return async_initiate<CompletionToken, Signature>(
+      detail::make_initiate_composed_op<Signature>(
+        detail::make_composed_io_executors(
+          detail::get_composed_io_executor(
+            ASIO_MOVE_CAST(IoObjectsOrExecutors)(
+              io_objects_or_executors))...)),
+      token, ASIO_MOVE_CAST(Implementation)(implementation));
+}
+
+#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+template <typename CompletionToken, typename Signature, typename Implementation>
+ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, Signature)
+async_compose(ASIO_MOVE_ARG(Implementation) implementation,
+    ASIO_NONDEDUCED_MOVE_ARG(CompletionToken) token)
+{
+  return async_initiate<CompletionToken, Signature>(
+      detail::make_initiate_composed_op<Signature>(
+        detail::make_composed_io_executors()),
+      token, ASIO_MOVE_CAST(Implementation)(implementation));
+}
+
+# define ASIO_PRIVATE_GET_COMPOSED_IO_EXECUTOR(n) \
+  ASIO_PRIVATE_GET_COMPOSED_IO_EXECUTOR_##n
+
+# define ASIO_PRIVATE_GET_COMPOSED_IO_EXECUTOR_1 \
+  detail::get_composed_io_executor(ASIO_MOVE_CAST(T1)(x1))
+# define ASIO_PRIVATE_GET_COMPOSED_IO_EXECUTOR_2 \
+  detail::get_composed_io_executor(ASIO_MOVE_CAST(T1)(x1)), \
+  detail::get_composed_io_executor(ASIO_MOVE_CAST(T2)(x2))
+# define ASIO_PRIVATE_GET_COMPOSED_IO_EXECUTOR_3 \
+  detail::get_composed_io_executor(ASIO_MOVE_CAST(T1)(x1)), \
+  detail::get_composed_io_executor(ASIO_MOVE_CAST(T2)(x2)), \
+  detail::get_composed_io_executor(ASIO_MOVE_CAST(T3)(x3))
+# define ASIO_PRIVATE_GET_COMPOSED_IO_EXECUTOR_4 \
+  detail::get_composed_io_executor(ASIO_MOVE_CAST(T1)(x1)), \
+  detail::get_composed_io_executor(ASIO_MOVE_CAST(T2)(x2)), \
+  detail::get_composed_io_executor(ASIO_MOVE_CAST(T3)(x3)), \
+  detail::get_composed_io_executor(ASIO_MOVE_CAST(T4)(x4))
+# define ASIO_PRIVATE_GET_COMPOSED_IO_EXECUTOR_5 \
+  detail::get_composed_io_executor(ASIO_MOVE_CAST(T1)(x1)), \
+  detail::get_composed_io_executor(ASIO_MOVE_CAST(T2)(x2)), \
+  detail::get_composed_io_executor(ASIO_MOVE_CAST(T3)(x3)), \
+  detail::get_composed_io_executor(ASIO_MOVE_CAST(T4)(x4)), \
+  detail::get_composed_io_executor(ASIO_MOVE_CAST(T5)(x5))
+# define ASIO_PRIVATE_GET_COMPOSED_IO_EXECUTOR_6 \
+  detail::get_composed_io_executor(ASIO_MOVE_CAST(T1)(x1)), \
+  detail::get_composed_io_executor(ASIO_MOVE_CAST(T2)(x2)), \
+  detail::get_composed_io_executor(ASIO_MOVE_CAST(T3)(x3)), \
+  detail::get_composed_io_executor(ASIO_MOVE_CAST(T4)(x4)), \
+  detail::get_composed_io_executor(ASIO_MOVE_CAST(T5)(x5)), \
+  detail::get_composed_io_executor(ASIO_MOVE_CAST(T6)(x6))
+# define ASIO_PRIVATE_GET_COMPOSED_IO_EXECUTOR_7 \
+  detail::get_composed_io_executor(ASIO_MOVE_CAST(T1)(x1)), \
+  detail::get_composed_io_executor(ASIO_MOVE_CAST(T2)(x2)), \
+  detail::get_composed_io_executor(ASIO_MOVE_CAST(T3)(x3)), \
+  detail::get_composed_io_executor(ASIO_MOVE_CAST(T4)(x4)), \
+  detail::get_composed_io_executor(ASIO_MOVE_CAST(T5)(x5)), \
+  detail::get_composed_io_executor(ASIO_MOVE_CAST(T6)(x6)), \
+  detail::get_composed_io_executor(ASIO_MOVE_CAST(T7)(x7))
+# define ASIO_PRIVATE_GET_COMPOSED_IO_EXECUTOR_8 \
+  detail::get_composed_io_executor(ASIO_MOVE_CAST(T1)(x1)), \
+  detail::get_composed_io_executor(ASIO_MOVE_CAST(T2)(x2)), \
+  detail::get_composed_io_executor(ASIO_MOVE_CAST(T3)(x3)), \
+  detail::get_composed_io_executor(ASIO_MOVE_CAST(T4)(x4)), \
+  detail::get_composed_io_executor(ASIO_MOVE_CAST(T5)(x5)), \
+  detail::get_composed_io_executor(ASIO_MOVE_CAST(T6)(x6)), \
+  detail::get_composed_io_executor(ASIO_MOVE_CAST(T7)(x7)), \
+  detail::get_composed_io_executor(ASIO_MOVE_CAST(T8)(x8))
+
+#define ASIO_PRIVATE_ASYNC_COMPOSE_DEF(n) \
+  template <typename CompletionToken, typename Signature, \
+      typename Implementation, ASIO_VARIADIC_TPARAMS(n)> \
+  ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, Signature) \
+  async_compose(ASIO_MOVE_ARG(Implementation) implementation, \
+      ASIO_NONDEDUCED_MOVE_ARG(CompletionToken) token, \
+      ASIO_VARIADIC_MOVE_PARAMS(n)) \
+  { \
+    return async_initiate<CompletionToken, Signature>( \
+        detail::make_initiate_composed_op<Signature>( \
+          detail::make_composed_io_executors( \
+            ASIO_PRIVATE_GET_COMPOSED_IO_EXECUTOR(n))), \
+        token, ASIO_MOVE_CAST(Implementation)(implementation)); \
+  } \
+  /**/
+  ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_ASYNC_COMPOSE_DEF)
+#undef ASIO_PRIVATE_ASYNC_COMPOSE_DEF
+
+#undef ASIO_PRIVATE_GET_COMPOSED_IO_EXECUTOR
+#undef ASIO_PRIVATE_GET_COMPOSED_IO_EXECUTOR_1
+#undef ASIO_PRIVATE_GET_COMPOSED_IO_EXECUTOR_2
+#undef ASIO_PRIVATE_GET_COMPOSED_IO_EXECUTOR_3
+#undef ASIO_PRIVATE_GET_COMPOSED_IO_EXECUTOR_4
+#undef ASIO_PRIVATE_GET_COMPOSED_IO_EXECUTOR_5
+#undef ASIO_PRIVATE_GET_COMPOSED_IO_EXECUTOR_6
+#undef ASIO_PRIVATE_GET_COMPOSED_IO_EXECUTOR_7
+#undef ASIO_PRIVATE_GET_COMPOSED_IO_EXECUTOR_8
+
+#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+#endif // !defined(GENERATING_DOCUMENTATION)
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IMPL_COMPOSE_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/impl/connect.hpp b/link/modules/asio-standalone/asio/include/asio/impl/connect.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/impl/connect.hpp
@@ -0,0 +1,916 @@
+//
+// impl/connect.hpp
+// ~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_IMPL_CONNECT_HPP
+#define ASIO_IMPL_CONNECT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <algorithm>
+#include "asio/associated_allocator.hpp"
+#include "asio/associated_executor.hpp"
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_cont_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/handler_tracking.hpp"
+#include "asio/detail/handler_type_requirements.hpp"
+#include "asio/detail/non_const_lvalue.hpp"
+#include "asio/detail/throw_error.hpp"
+#include "asio/error.hpp"
+#include "asio/post.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+namespace detail
+{
+  struct default_connect_condition
+  {
+    template <typename Endpoint>
+    bool operator()(const asio::error_code&, const Endpoint&)
+    {
+      return true;
+    }
+  };
+
+  template <typename Protocol, typename Iterator>
+  inline typename Protocol::endpoint deref_connect_result(
+      Iterator iter, asio::error_code& ec)
+  {
+    return ec ? typename Protocol::endpoint() : *iter;
+  }
+
+  template <typename T, typename Iterator>
+  struct legacy_connect_condition_helper : T
+  {
+    typedef char (*fallback_func_type)(...);
+    operator fallback_func_type() const;
+  };
+
+  template <typename R, typename Arg1, typename Arg2, typename Iterator>
+  struct legacy_connect_condition_helper<R (*)(Arg1, Arg2), Iterator>
+  {
+    R operator()(Arg1, Arg2) const;
+    char operator()(...) const;
+  };
+
+  template <typename T, typename Iterator>
+  struct is_legacy_connect_condition
+  {
+    static char asio_connect_condition_check(char);
+    static char (&asio_connect_condition_check(Iterator))[2];
+
+    static const bool value =
+      sizeof(asio_connect_condition_check(
+        (*static_cast<legacy_connect_condition_helper<T, Iterator>*>(0))(
+          *static_cast<const asio::error_code*>(0),
+          *static_cast<const Iterator*>(0)))) != 1;
+  };
+
+  template <typename ConnectCondition, typename Iterator>
+  inline Iterator call_connect_condition(ConnectCondition& connect_condition,
+      const asio::error_code& ec, Iterator next, Iterator end,
+      typename enable_if<is_legacy_connect_condition<
+        ConnectCondition, Iterator>::value>::type* = 0)
+  {
+    if (next != end)
+      return connect_condition(ec, next);
+    return end;
+  }
+
+  template <typename ConnectCondition, typename Iterator>
+  inline Iterator call_connect_condition(ConnectCondition& connect_condition,
+      const asio::error_code& ec, Iterator next, Iterator end,
+      typename enable_if<!is_legacy_connect_condition<
+        ConnectCondition, Iterator>::value>::type* = 0)
+  {
+    for (;next != end; ++next)
+      if (connect_condition(ec, *next))
+        return next;
+    return end;
+  }
+}
+
+template <typename Protocol, typename Executor, typename EndpointSequence>
+typename Protocol::endpoint connect(basic_socket<Protocol, Executor>& s,
+    const EndpointSequence& endpoints,
+    typename enable_if<is_endpoint_sequence<
+        EndpointSequence>::value>::type*)
+{
+  asio::error_code ec;
+  typename Protocol::endpoint result = connect(s, endpoints, ec);
+  asio::detail::throw_error(ec, "connect");
+  return result;
+}
+
+template <typename Protocol, typename Executor, typename EndpointSequence>
+typename Protocol::endpoint connect(basic_socket<Protocol, Executor>& s,
+    const EndpointSequence& endpoints, asio::error_code& ec,
+    typename enable_if<is_endpoint_sequence<
+        EndpointSequence>::value>::type*)
+{
+  return detail::deref_connect_result<Protocol>(
+      connect(s, endpoints.begin(), endpoints.end(),
+        detail::default_connect_condition(), ec), ec);
+}
+
+#if !defined(ASIO_NO_DEPRECATED)
+template <typename Protocol, typename Executor, typename Iterator>
+Iterator connect(basic_socket<Protocol, Executor>& s, Iterator begin,
+    typename enable_if<!is_endpoint_sequence<Iterator>::value>::type*)
+{
+  asio::error_code ec;
+  Iterator result = connect(s, begin, ec);
+  asio::detail::throw_error(ec, "connect");
+  return result;
+}
+
+template <typename Protocol, typename Executor, typename Iterator>
+inline Iterator connect(basic_socket<Protocol, Executor>& s,
+    Iterator begin, asio::error_code& ec,
+    typename enable_if<!is_endpoint_sequence<Iterator>::value>::type*)
+{
+  return connect(s, begin, Iterator(), detail::default_connect_condition(), ec);
+}
+#endif // !defined(ASIO_NO_DEPRECATED)
+
+template <typename Protocol, typename Executor, typename Iterator>
+Iterator connect(basic_socket<Protocol, Executor>& s,
+    Iterator begin, Iterator end)
+{
+  asio::error_code ec;
+  Iterator result = connect(s, begin, end, ec);
+  asio::detail::throw_error(ec, "connect");
+  return result;
+}
+
+template <typename Protocol, typename Executor, typename Iterator>
+inline Iterator connect(basic_socket<Protocol, Executor>& s,
+    Iterator begin, Iterator end, asio::error_code& ec)
+{
+  return connect(s, begin, end, detail::default_connect_condition(), ec);
+}
+
+template <typename Protocol, typename Executor,
+    typename EndpointSequence, typename ConnectCondition>
+typename Protocol::endpoint connect(basic_socket<Protocol, Executor>& s,
+    const EndpointSequence& endpoints, ConnectCondition connect_condition,
+    typename enable_if<is_endpoint_sequence<
+        EndpointSequence>::value>::type*)
+{
+  asio::error_code ec;
+  typename Protocol::endpoint result = connect(
+      s, endpoints, connect_condition, ec);
+  asio::detail::throw_error(ec, "connect");
+  return result;
+}
+
+template <typename Protocol, typename Executor,
+    typename EndpointSequence, typename ConnectCondition>
+typename Protocol::endpoint connect(basic_socket<Protocol, Executor>& s,
+    const EndpointSequence& endpoints, ConnectCondition connect_condition,
+    asio::error_code& ec,
+    typename enable_if<is_endpoint_sequence<
+        EndpointSequence>::value>::type*)
+{
+  return detail::deref_connect_result<Protocol>(
+      connect(s, endpoints.begin(), endpoints.end(),
+        connect_condition, ec), ec);
+}
+
+#if !defined(ASIO_NO_DEPRECATED)
+template <typename Protocol, typename Executor,
+    typename Iterator, typename ConnectCondition>
+Iterator connect(basic_socket<Protocol, Executor>& s,
+    Iterator begin, ConnectCondition connect_condition,
+    typename enable_if<!is_endpoint_sequence<Iterator>::value>::type*)
+{
+  asio::error_code ec;
+  Iterator result = connect(s, begin, connect_condition, ec);
+  asio::detail::throw_error(ec, "connect");
+  return result;
+}
+
+template <typename Protocol, typename Executor,
+    typename Iterator, typename ConnectCondition>
+inline Iterator connect(basic_socket<Protocol, Executor>& s,
+    Iterator begin, ConnectCondition connect_condition,
+    asio::error_code& ec,
+    typename enable_if<!is_endpoint_sequence<Iterator>::value>::type*)
+{
+  return connect(s, begin, Iterator(), connect_condition, ec);
+}
+#endif // !defined(ASIO_NO_DEPRECATED)
+
+template <typename Protocol, typename Executor,
+    typename Iterator, typename ConnectCondition>
+Iterator connect(basic_socket<Protocol, Executor>& s, Iterator begin,
+    Iterator end, ConnectCondition connect_condition)
+{
+  asio::error_code ec;
+  Iterator result = connect(s, begin, end, connect_condition, ec);
+  asio::detail::throw_error(ec, "connect");
+  return result;
+}
+
+template <typename Protocol, typename Executor,
+    typename Iterator, typename ConnectCondition>
+Iterator connect(basic_socket<Protocol, Executor>& s, Iterator begin,
+    Iterator end, ConnectCondition connect_condition,
+    asio::error_code& ec)
+{
+  ec = asio::error_code();
+
+  for (Iterator iter = begin; iter != end; ++iter)
+  {
+    iter = (detail::call_connect_condition(connect_condition, ec, iter, end));
+    if (iter != end)
+    {
+      s.close(ec);
+      s.connect(*iter, ec);
+      if (!ec)
+        return iter;
+    }
+    else
+      break;
+  }
+
+  if (!ec)
+    ec = asio::error::not_found;
+
+  return end;
+}
+
+namespace detail
+{
+  // Enable the empty base class optimisation for the connect condition.
+  template <typename ConnectCondition>
+  class base_from_connect_condition
+  {
+  protected:
+    explicit base_from_connect_condition(
+        const ConnectCondition& connect_condition)
+      : connect_condition_(connect_condition)
+    {
+    }
+
+    template <typename Iterator>
+    void check_condition(const asio::error_code& ec,
+        Iterator& iter, Iterator& end)
+    {
+      iter = detail::call_connect_condition(connect_condition_, ec, iter, end);
+    }
+
+  private:
+    ConnectCondition connect_condition_;
+  };
+
+  // The default_connect_condition implementation is essentially a no-op. This
+  // template specialisation lets us eliminate all costs associated with it.
+  template <>
+  class base_from_connect_condition<default_connect_condition>
+  {
+  protected:
+    explicit base_from_connect_condition(const default_connect_condition&)
+    {
+    }
+
+    template <typename Iterator>
+    void check_condition(const asio::error_code&, Iterator&, Iterator&)
+    {
+    }
+  };
+
+  template <typename Protocol, typename Executor, typename EndpointSequence,
+      typename ConnectCondition, typename RangeConnectHandler>
+  class range_connect_op : base_from_connect_condition<ConnectCondition>
+  {
+  public:
+    range_connect_op(basic_socket<Protocol, Executor>& sock,
+        const EndpointSequence& endpoints,
+        const ConnectCondition& connect_condition,
+        RangeConnectHandler& handler)
+      : base_from_connect_condition<ConnectCondition>(connect_condition),
+        socket_(sock),
+        endpoints_(endpoints),
+        index_(0),
+        start_(0),
+        handler_(ASIO_MOVE_CAST(RangeConnectHandler)(handler))
+    {
+    }
+
+#if defined(ASIO_HAS_MOVE)
+    range_connect_op(const range_connect_op& other)
+      : base_from_connect_condition<ConnectCondition>(other),
+        socket_(other.socket_),
+        endpoints_(other.endpoints_),
+        index_(other.index_),
+        start_(other.start_),
+        handler_(other.handler_)
+    {
+    }
+
+    range_connect_op(range_connect_op&& other)
+      : base_from_connect_condition<ConnectCondition>(other),
+        socket_(other.socket_),
+        endpoints_(other.endpoints_),
+        index_(other.index_),
+        start_(other.start_),
+        handler_(ASIO_MOVE_CAST(RangeConnectHandler)(other.handler_))
+    {
+    }
+#endif // defined(ASIO_HAS_MOVE)
+
+    void operator()(asio::error_code ec, int start = 0)
+    {
+      this->process(ec, start,
+          const_cast<const EndpointSequence&>(endpoints_).begin(),
+          const_cast<const EndpointSequence&>(endpoints_).end());
+    }
+
+  //private:
+    template <typename Iterator>
+    void process(asio::error_code ec,
+        int start, Iterator begin, Iterator end)
+    {
+      Iterator iter = begin;
+      std::advance(iter, index_);
+
+      switch (start_ = start)
+      {
+        case 1:
+        for (;;)
+        {
+          this->check_condition(ec, iter, end);
+          index_ = std::distance(begin, iter);
+
+          if (iter != end)
+          {
+            socket_.close(ec);
+            ASIO_HANDLER_LOCATION((__FILE__, __LINE__, "async_connect"));
+            socket_.async_connect(*iter,
+                ASIO_MOVE_CAST(range_connect_op)(*this));
+            return;
+          }
+
+          if (start)
+          {
+            ec = asio::error::not_found;
+            ASIO_HANDLER_LOCATION((__FILE__, __LINE__, "async_connect"));
+            asio::post(socket_.get_executor(),
+                detail::bind_handler(
+                  ASIO_MOVE_CAST(range_connect_op)(*this), ec));
+            return;
+          }
+
+          /* fall-through */ default:
+
+          if (iter == end)
+            break;
+
+          if (!socket_.is_open())
+          {
+            ec = asio::error::operation_aborted;
+            break;
+          }
+
+          if (!ec)
+            break;
+
+          ++iter;
+          ++index_;
+        }
+
+        handler_(static_cast<const asio::error_code&>(ec),
+            static_cast<const typename Protocol::endpoint&>(
+              ec || iter == end ? typename Protocol::endpoint() : *iter));
+      }
+    }
+
+    basic_socket<Protocol, Executor>& socket_;
+    EndpointSequence endpoints_;
+    std::size_t index_;
+    int start_;
+    RangeConnectHandler handler_;
+  };
+
+  template <typename Protocol, typename Executor, typename EndpointSequence,
+      typename ConnectCondition, typename RangeConnectHandler>
+  inline asio_handler_allocate_is_deprecated
+  asio_handler_allocate(std::size_t size,
+      range_connect_op<Protocol, Executor, EndpointSequence,
+        ConnectCondition, RangeConnectHandler>* this_handler)
+  {
+#if defined(ASIO_NO_DEPRECATED)
+    asio_handler_alloc_helpers::allocate(size, this_handler->handler_);
+    return asio_handler_allocate_is_no_longer_used();
+#else // defined(ASIO_NO_DEPRECATED)
+    return asio_handler_alloc_helpers::allocate(
+        size, this_handler->handler_);
+#endif // defined(ASIO_NO_DEPRECATED)
+  }
+
+  template <typename Protocol, typename Executor, typename EndpointSequence,
+      typename ConnectCondition, typename RangeConnectHandler>
+  inline asio_handler_deallocate_is_deprecated
+  asio_handler_deallocate(void* pointer, std::size_t size,
+      range_connect_op<Protocol, Executor, EndpointSequence,
+        ConnectCondition, RangeConnectHandler>* this_handler)
+  {
+    asio_handler_alloc_helpers::deallocate(
+        pointer, size, this_handler->handler_);
+#if defined(ASIO_NO_DEPRECATED)
+    return asio_handler_deallocate_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+  }
+
+  template <typename Protocol, typename Executor, typename EndpointSequence,
+      typename ConnectCondition, typename RangeConnectHandler>
+  inline bool asio_handler_is_continuation(
+      range_connect_op<Protocol, Executor, EndpointSequence,
+        ConnectCondition, RangeConnectHandler>* this_handler)
+  {
+    return asio_handler_cont_helpers::is_continuation(
+        this_handler->handler_);
+  }
+
+  template <typename Function, typename Executor, typename Protocol,
+      typename EndpointSequence, typename ConnectCondition,
+      typename RangeConnectHandler>
+  inline asio_handler_invoke_is_deprecated
+  asio_handler_invoke(Function& function,
+      range_connect_op<Protocol, Executor, EndpointSequence,
+        ConnectCondition, RangeConnectHandler>* this_handler)
+  {
+    asio_handler_invoke_helpers::invoke(
+        function, this_handler->handler_);
+#if defined(ASIO_NO_DEPRECATED)
+    return asio_handler_invoke_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+  }
+
+  template <typename Function, typename Executor, typename Protocol,
+      typename EndpointSequence, typename ConnectCondition,
+      typename RangeConnectHandler>
+  inline asio_handler_invoke_is_deprecated
+  asio_handler_invoke(const Function& function,
+      range_connect_op<Protocol, Executor, EndpointSequence,
+        ConnectCondition, RangeConnectHandler>* this_handler)
+  {
+    asio_handler_invoke_helpers::invoke(
+        function, this_handler->handler_);
+#if defined(ASIO_NO_DEPRECATED)
+    return asio_handler_invoke_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+  }
+
+  template <typename Protocol, typename Executor>
+  class initiate_async_range_connect
+  {
+  public:
+    typedef Executor executor_type;
+
+    explicit initiate_async_range_connect(basic_socket<Protocol, Executor>& s)
+      : socket_(s)
+    {
+    }
+
+    executor_type get_executor() const ASIO_NOEXCEPT
+    {
+      return socket_.get_executor();
+    }
+
+    template <typename RangeConnectHandler,
+        typename EndpointSequence, typename ConnectCondition>
+    void operator()(ASIO_MOVE_ARG(RangeConnectHandler) handler,
+        const EndpointSequence& endpoints,
+        const ConnectCondition& connect_condition) const
+    {
+      // If you get an error on the following line it means that your
+      // handler does not meet the documented type requirements for an
+      // RangeConnectHandler.
+      ASIO_RANGE_CONNECT_HANDLER_CHECK(RangeConnectHandler,
+          handler, typename Protocol::endpoint) type_check;
+
+      non_const_lvalue<RangeConnectHandler> handler2(handler);
+      range_connect_op<Protocol, Executor, EndpointSequence, ConnectCondition,
+        typename decay<RangeConnectHandler>::type>(socket_, endpoints,
+          connect_condition, handler2.value)(asio::error_code(), 1);
+    }
+
+  private:
+    basic_socket<Protocol, Executor>& socket_;
+  };
+
+  template <typename Protocol, typename Executor, typename Iterator,
+      typename ConnectCondition, typename IteratorConnectHandler>
+  class iterator_connect_op : base_from_connect_condition<ConnectCondition>
+  {
+  public:
+    iterator_connect_op(basic_socket<Protocol, Executor>& sock,
+        const Iterator& begin, const Iterator& end,
+        const ConnectCondition& connect_condition,
+        IteratorConnectHandler& handler)
+      : base_from_connect_condition<ConnectCondition>(connect_condition),
+        socket_(sock),
+        iter_(begin),
+        end_(end),
+        start_(0),
+        handler_(ASIO_MOVE_CAST(IteratorConnectHandler)(handler))
+    {
+    }
+
+#if defined(ASIO_HAS_MOVE)
+    iterator_connect_op(const iterator_connect_op& other)
+      : base_from_connect_condition<ConnectCondition>(other),
+        socket_(other.socket_),
+        iter_(other.iter_),
+        end_(other.end_),
+        start_(other.start_),
+        handler_(other.handler_)
+    {
+    }
+
+    iterator_connect_op(iterator_connect_op&& other)
+      : base_from_connect_condition<ConnectCondition>(other),
+        socket_(other.socket_),
+        iter_(other.iter_),
+        end_(other.end_),
+        start_(other.start_),
+        handler_(ASIO_MOVE_CAST(IteratorConnectHandler)(other.handler_))
+    {
+    }
+#endif // defined(ASIO_HAS_MOVE)
+
+    void operator()(asio::error_code ec, int start = 0)
+    {
+      switch (start_ = start)
+      {
+        case 1:
+        for (;;)
+        {
+          this->check_condition(ec, iter_, end_);
+
+          if (iter_ != end_)
+          {
+            socket_.close(ec);
+            ASIO_HANDLER_LOCATION((__FILE__, __LINE__, "async_connect"));
+            socket_.async_connect(*iter_,
+                ASIO_MOVE_CAST(iterator_connect_op)(*this));
+            return;
+          }
+
+          if (start)
+          {
+            ec = asio::error::not_found;
+            ASIO_HANDLER_LOCATION((__FILE__, __LINE__, "async_connect"));
+            asio::post(socket_.get_executor(),
+                detail::bind_handler(
+                  ASIO_MOVE_CAST(iterator_connect_op)(*this), ec));
+            return;
+          }
+
+          /* fall-through */ default:
+
+          if (iter_ == end_)
+            break;
+
+          if (!socket_.is_open())
+          {
+            ec = asio::error::operation_aborted;
+            break;
+          }
+
+          if (!ec)
+            break;
+
+          ++iter_;
+        }
+
+        handler_(static_cast<const asio::error_code&>(ec),
+            static_cast<const Iterator&>(iter_));
+      }
+    }
+
+  //private:
+    basic_socket<Protocol, Executor>& socket_;
+    Iterator iter_;
+    Iterator end_;
+    int start_;
+    IteratorConnectHandler handler_;
+  };
+
+  template <typename Protocol, typename Executor, typename Iterator,
+      typename ConnectCondition, typename IteratorConnectHandler>
+  inline asio_handler_allocate_is_deprecated
+  asio_handler_allocate(std::size_t size,
+      iterator_connect_op<Protocol, Executor, Iterator,
+        ConnectCondition, IteratorConnectHandler>* this_handler)
+  {
+#if defined(ASIO_NO_DEPRECATED)
+    asio_handler_alloc_helpers::allocate(size, this_handler->handler_);
+    return asio_handler_allocate_is_no_longer_used();
+#else // defined(ASIO_NO_DEPRECATED)
+    return asio_handler_alloc_helpers::allocate(
+        size, this_handler->handler_);
+#endif // defined(ASIO_NO_DEPRECATED)
+  }
+
+  template <typename Protocol, typename Executor, typename Iterator,
+      typename ConnectCondition, typename IteratorConnectHandler>
+  inline asio_handler_deallocate_is_deprecated
+  asio_handler_deallocate(void* pointer, std::size_t size,
+      iterator_connect_op<Protocol, Executor, Iterator,
+        ConnectCondition, IteratorConnectHandler>* this_handler)
+  {
+    asio_handler_alloc_helpers::deallocate(
+        pointer, size, this_handler->handler_);
+#if defined(ASIO_NO_DEPRECATED)
+    return asio_handler_deallocate_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+  }
+
+  template <typename Protocol, typename Executor, typename Iterator,
+      typename ConnectCondition, typename IteratorConnectHandler>
+  inline bool asio_handler_is_continuation(
+      iterator_connect_op<Protocol, Executor, Iterator,
+        ConnectCondition, IteratorConnectHandler>* this_handler)
+  {
+    return asio_handler_cont_helpers::is_continuation(
+        this_handler->handler_);
+  }
+
+  template <typename Function, typename Executor, typename Protocol,
+      typename Iterator, typename ConnectCondition,
+      typename IteratorConnectHandler>
+  inline asio_handler_invoke_is_deprecated
+  asio_handler_invoke(Function& function,
+      iterator_connect_op<Protocol, Executor, Iterator,
+        ConnectCondition, IteratorConnectHandler>* this_handler)
+  {
+    asio_handler_invoke_helpers::invoke(
+        function, this_handler->handler_);
+#if defined(ASIO_NO_DEPRECATED)
+    return asio_handler_invoke_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+  }
+
+  template <typename Function, typename Executor, typename Protocol,
+      typename Iterator, typename ConnectCondition,
+      typename IteratorConnectHandler>
+  inline asio_handler_invoke_is_deprecated
+  asio_handler_invoke(const Function& function,
+      iterator_connect_op<Protocol, Executor, Iterator,
+        ConnectCondition, IteratorConnectHandler>* this_handler)
+  {
+    asio_handler_invoke_helpers::invoke(
+        function, this_handler->handler_);
+#if defined(ASIO_NO_DEPRECATED)
+    return asio_handler_invoke_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+  }
+
+  template <typename Protocol, typename Executor>
+  class initiate_async_iterator_connect
+  {
+  public:
+    typedef Executor executor_type;
+
+    explicit initiate_async_iterator_connect(
+        basic_socket<Protocol, Executor>& s)
+      : socket_(s)
+    {
+    }
+
+    executor_type get_executor() const ASIO_NOEXCEPT
+    {
+      return socket_.get_executor();
+    }
+
+    template <typename IteratorConnectHandler,
+        typename Iterator, typename ConnectCondition>
+    void operator()(ASIO_MOVE_ARG(IteratorConnectHandler) handler,
+        Iterator begin, Iterator end,
+        const ConnectCondition& connect_condition) const
+    {
+      // If you get an error on the following line it means that your
+      // handler does not meet the documented type requirements for an
+      // IteratorConnectHandler.
+      ASIO_ITERATOR_CONNECT_HANDLER_CHECK(
+          IteratorConnectHandler, handler, Iterator) type_check;
+
+      non_const_lvalue<IteratorConnectHandler> handler2(handler);
+      iterator_connect_op<Protocol, Executor, Iterator, ConnectCondition,
+        typename decay<IteratorConnectHandler>::type>(socket_, begin, end,
+          connect_condition, handler2.value)(asio::error_code(), 1);
+    }
+
+  private:
+    basic_socket<Protocol, Executor>& socket_;
+  };
+} // namespace detail
+
+#if !defined(GENERATING_DOCUMENTATION)
+
+template <typename Protocol, typename Executor, typename EndpointSequence,
+    typename ConnectCondition, typename RangeConnectHandler, typename Allocator>
+struct associated_allocator<
+    detail::range_connect_op<Protocol, Executor, EndpointSequence,
+      ConnectCondition, RangeConnectHandler>, Allocator>
+{
+  typedef typename associated_allocator<
+      RangeConnectHandler, Allocator>::type type;
+
+  static type get(
+      const detail::range_connect_op<Protocol, Executor, EndpointSequence,
+        ConnectCondition, RangeConnectHandler>& h,
+      const Allocator& a = Allocator()) ASIO_NOEXCEPT
+  {
+    return associated_allocator<RangeConnectHandler,
+        Allocator>::get(h.handler_, a);
+  }
+};
+
+template <typename Protocol, typename Executor, typename EndpointSequence,
+    typename ConnectCondition, typename RangeConnectHandler, typename Executor1>
+struct associated_executor<
+    detail::range_connect_op<Protocol, Executor, EndpointSequence,
+      ConnectCondition, RangeConnectHandler>, Executor1>
+  : detail::associated_executor_forwarding_base<RangeConnectHandler, Executor1>
+{
+  typedef typename associated_executor<
+      RangeConnectHandler, Executor1>::type type;
+
+  static type get(
+      const detail::range_connect_op<Protocol, Executor, EndpointSequence,
+      ConnectCondition, RangeConnectHandler>& h,
+      const Executor1& ex = Executor1()) ASIO_NOEXCEPT
+  {
+    return associated_executor<RangeConnectHandler,
+        Executor1>::get(h.handler_, ex);
+  }
+};
+
+template <typename Protocol, typename Executor, typename Iterator,
+    typename ConnectCondition, typename IteratorConnectHandler,
+    typename Allocator>
+struct associated_allocator<
+    detail::iterator_connect_op<Protocol, Executor,
+      Iterator, ConnectCondition, IteratorConnectHandler>,
+    Allocator>
+{
+  typedef typename associated_allocator<
+      IteratorConnectHandler, Allocator>::type type;
+
+  static type get(
+      const detail::iterator_connect_op<Protocol, Executor,
+        Iterator, ConnectCondition, IteratorConnectHandler>& h,
+      const Allocator& a = Allocator()) ASIO_NOEXCEPT
+  {
+    return associated_allocator<IteratorConnectHandler,
+        Allocator>::get(h.handler_, a);
+  }
+};
+
+template <typename Protocol, typename Executor, typename Iterator,
+    typename ConnectCondition, typename IteratorConnectHandler,
+    typename Executor1>
+struct associated_executor<
+    detail::iterator_connect_op<Protocol, Executor,
+      Iterator, ConnectCondition, IteratorConnectHandler>,
+    Executor1>
+  : detail::associated_executor_forwarding_base<
+      IteratorConnectHandler, Executor1>
+{
+  typedef typename associated_executor<
+      IteratorConnectHandler, Executor1>::type type;
+
+  static type get(
+      const detail::iterator_connect_op<Protocol, Executor,
+        Iterator, ConnectCondition, IteratorConnectHandler>& h,
+      const Executor1& ex = Executor1()) ASIO_NOEXCEPT
+  {
+    return associated_executor<IteratorConnectHandler,
+        Executor1>::get(h.handler_, ex);
+  }
+};
+
+#endif // !defined(GENERATING_DOCUMENTATION)
+
+template <typename Protocol, typename Executor, typename EndpointSequence,
+    ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+      typename Protocol::endpoint)) RangeConnectHandler>
+inline ASIO_INITFN_AUTO_RESULT_TYPE(RangeConnectHandler,
+    void (asio::error_code, typename Protocol::endpoint))
+async_connect(basic_socket<Protocol, Executor>& s,
+    const EndpointSequence& endpoints,
+    ASIO_MOVE_ARG(RangeConnectHandler) handler,
+    typename enable_if<is_endpoint_sequence<
+        EndpointSequence>::value>::type*)
+{
+  return async_initiate<RangeConnectHandler,
+    void (asio::error_code, typename Protocol::endpoint)>(
+      detail::initiate_async_range_connect<Protocol, Executor>(s),
+      handler, endpoints, detail::default_connect_condition());
+}
+
+#if !defined(ASIO_NO_DEPRECATED)
+template <typename Protocol, typename Executor, typename Iterator,
+    ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+      Iterator)) IteratorConnectHandler>
+inline ASIO_INITFN_AUTO_RESULT_TYPE(IteratorConnectHandler,
+    void (asio::error_code, Iterator))
+async_connect(basic_socket<Protocol, Executor>& s, Iterator begin,
+    ASIO_MOVE_ARG(IteratorConnectHandler) handler,
+    typename enable_if<!is_endpoint_sequence<Iterator>::value>::type*)
+{
+  return async_initiate<IteratorConnectHandler,
+    void (asio::error_code, Iterator)>(
+      detail::initiate_async_iterator_connect<Protocol, Executor>(s),
+      handler, begin, Iterator(), detail::default_connect_condition());
+}
+#endif // !defined(ASIO_NO_DEPRECATED)
+
+template <typename Protocol, typename Executor, typename Iterator,
+    ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+      Iterator)) IteratorConnectHandler>
+inline ASIO_INITFN_AUTO_RESULT_TYPE(IteratorConnectHandler,
+    void (asio::error_code, Iterator))
+async_connect(basic_socket<Protocol, Executor>& s, Iterator begin, Iterator end,
+    ASIO_MOVE_ARG(IteratorConnectHandler) handler)
+{
+  return async_initiate<IteratorConnectHandler,
+    void (asio::error_code, Iterator)>(
+      detail::initiate_async_iterator_connect<Protocol, Executor>(s),
+      handler, begin, end, detail::default_connect_condition());
+}
+
+template <typename Protocol, typename Executor,
+    typename EndpointSequence, typename ConnectCondition,
+    ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+      typename Protocol::endpoint)) RangeConnectHandler>
+inline ASIO_INITFN_AUTO_RESULT_TYPE(RangeConnectHandler,
+    void (asio::error_code, typename Protocol::endpoint))
+async_connect(basic_socket<Protocol, Executor>& s,
+    const EndpointSequence& endpoints, ConnectCondition connect_condition,
+    ASIO_MOVE_ARG(RangeConnectHandler) handler,
+    typename enable_if<is_endpoint_sequence<
+        EndpointSequence>::value>::type*)
+{
+  return async_initiate<RangeConnectHandler,
+    void (asio::error_code, typename Protocol::endpoint)>(
+      detail::initiate_async_range_connect<Protocol, Executor>(s),
+      handler, endpoints, connect_condition);
+}
+
+#if !defined(ASIO_NO_DEPRECATED)
+template <typename Protocol, typename Executor,
+    typename Iterator, typename ConnectCondition,
+    ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+      Iterator)) IteratorConnectHandler>
+inline ASIO_INITFN_AUTO_RESULT_TYPE(IteratorConnectHandler,
+    void (asio::error_code, Iterator))
+async_connect(basic_socket<Protocol, Executor>& s, Iterator begin,
+    ConnectCondition connect_condition,
+    ASIO_MOVE_ARG(IteratorConnectHandler) handler,
+    typename enable_if<!is_endpoint_sequence<Iterator>::value>::type*)
+{
+  return async_initiate<IteratorConnectHandler,
+    void (asio::error_code, Iterator)>(
+      detail::initiate_async_iterator_connect<Protocol, Executor>(s),
+      handler, begin, Iterator(), connect_condition);
+}
+#endif // !defined(ASIO_NO_DEPRECATED)
+
+template <typename Protocol, typename Executor,
+    typename Iterator, typename ConnectCondition,
+    ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+      Iterator)) IteratorConnectHandler>
+inline ASIO_INITFN_AUTO_RESULT_TYPE(IteratorConnectHandler,
+    void (asio::error_code, Iterator))
+async_connect(basic_socket<Protocol, Executor>& s, Iterator begin,
+    Iterator end, ConnectCondition connect_condition,
+    ASIO_MOVE_ARG(IteratorConnectHandler) handler)
+{
+  return async_initiate<IteratorConnectHandler,
+    void (asio::error_code, Iterator)>(
+      detail::initiate_async_iterator_connect<Protocol, Executor>(s),
+      handler, begin, end, connect_condition);
+}
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IMPL_CONNECT_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/impl/defer.hpp b/link/modules/asio-standalone/asio/include/asio/impl/defer.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/impl/defer.hpp
@@ -0,0 +1,248 @@
+//
+// impl/defer.hpp
+// ~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_IMPL_DEFER_HPP
+#define ASIO_IMPL_DEFER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/associated_allocator.hpp"
+#include "asio/associated_executor.hpp"
+#include "asio/detail/work_dispatcher.hpp"
+#include "asio/execution/allocator.hpp"
+#include "asio/execution/blocking.hpp"
+#include "asio/execution/relationship.hpp"
+#include "asio/prefer.hpp"
+#include "asio/require.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class initiate_defer
+{
+public:
+  template <typename CompletionHandler>
+  void operator()(ASIO_MOVE_ARG(CompletionHandler) handler,
+      typename enable_if<
+        execution::is_executor<
+          typename associated_executor<
+            typename decay<CompletionHandler>::type
+          >::type
+        >::value
+      >::type* = 0) const
+  {
+    typedef typename decay<CompletionHandler>::type handler_t;
+
+    typename associated_executor<handler_t>::type ex(
+        (get_associated_executor)(handler));
+
+    typename associated_allocator<handler_t>::type alloc(
+        (get_associated_allocator)(handler));
+
+    execution::execute(
+        asio::prefer(
+          asio::require(ex, execution::blocking.never),
+          execution::relationship.continuation,
+          execution::allocator(alloc)),
+        ASIO_MOVE_CAST(CompletionHandler)(handler));
+  }
+
+  template <typename CompletionHandler>
+  void operator()(ASIO_MOVE_ARG(CompletionHandler) handler,
+      typename enable_if<
+        !execution::is_executor<
+          typename associated_executor<
+            typename decay<CompletionHandler>::type
+          >::type
+        >::value
+      >::type* = 0) const
+  {
+    typedef typename decay<CompletionHandler>::type handler_t;
+
+    typename associated_executor<handler_t>::type ex(
+        (get_associated_executor)(handler));
+
+    typename associated_allocator<handler_t>::type alloc(
+        (get_associated_allocator)(handler));
+
+    ex.defer(ASIO_MOVE_CAST(CompletionHandler)(handler), alloc);
+  }
+};
+
+template <typename Executor>
+class initiate_defer_with_executor
+{
+public:
+  typedef Executor executor_type;
+
+  explicit initiate_defer_with_executor(const Executor& ex)
+    : ex_(ex)
+  {
+  }
+
+  executor_type get_executor() const ASIO_NOEXCEPT
+  {
+    return ex_;
+  }
+
+  template <typename CompletionHandler>
+  void operator()(ASIO_MOVE_ARG(CompletionHandler) handler,
+      typename enable_if<
+        execution::is_executor<
+          typename conditional<true, executor_type, CompletionHandler>::type
+        >::value
+        &&
+        !detail::is_work_dispatcher_required<
+          typename decay<CompletionHandler>::type,
+          Executor
+        >::value
+      >::type* = 0) const
+  {
+    typedef typename decay<CompletionHandler>::type handler_t;
+
+    typename associated_allocator<handler_t>::type alloc(
+        (get_associated_allocator)(handler));
+
+    execution::execute(
+        asio::prefer(
+          asio::require(ex_, execution::blocking.never),
+          execution::relationship.continuation,
+          execution::allocator(alloc)),
+        ASIO_MOVE_CAST(CompletionHandler)(handler));
+  }
+
+  template <typename CompletionHandler>
+  void operator()(ASIO_MOVE_ARG(CompletionHandler) handler,
+      typename enable_if<
+        execution::is_executor<
+          typename conditional<true, executor_type, CompletionHandler>::type
+        >::value
+        &&
+        detail::is_work_dispatcher_required<
+          typename decay<CompletionHandler>::type,
+          Executor
+        >::value
+      >::type* = 0) const
+  {
+    typedef typename decay<CompletionHandler>::type handler_t;
+
+    typedef typename associated_executor<
+      handler_t, Executor>::type handler_ex_t;
+    handler_ex_t handler_ex((get_associated_executor)(handler, ex_));
+
+    typename associated_allocator<handler_t>::type alloc(
+        (get_associated_allocator)(handler));
+
+    execution::execute(
+        asio::prefer(
+          asio::require(ex_, execution::blocking.never),
+          execution::relationship.continuation,
+          execution::allocator(alloc)),
+        detail::work_dispatcher<handler_t, handler_ex_t>(
+          ASIO_MOVE_CAST(CompletionHandler)(handler), handler_ex));
+  }
+
+  template <typename CompletionHandler>
+  void operator()(ASIO_MOVE_ARG(CompletionHandler) handler,
+      typename enable_if<
+        !execution::is_executor<
+          typename conditional<true, executor_type, CompletionHandler>::type
+        >::value
+        &&
+        !detail::is_work_dispatcher_required<
+          typename decay<CompletionHandler>::type,
+          Executor
+        >::value
+      >::type* = 0) const
+  {
+    typedef typename decay<CompletionHandler>::type handler_t;
+
+    typename associated_allocator<handler_t>::type alloc(
+        (get_associated_allocator)(handler));
+
+    ex_.defer(ASIO_MOVE_CAST(CompletionHandler)(handler), alloc);
+  }
+
+  template <typename CompletionHandler>
+  void operator()(ASIO_MOVE_ARG(CompletionHandler) handler,
+      typename enable_if<
+        !execution::is_executor<
+          typename conditional<true, executor_type, CompletionHandler>::type
+        >::value
+        &&
+        detail::is_work_dispatcher_required<
+          typename decay<CompletionHandler>::type,
+          Executor
+        >::value
+      >::type* = 0) const
+  {
+    typedef typename decay<CompletionHandler>::type handler_t;
+
+    typedef typename associated_executor<
+      handler_t, Executor>::type handler_ex_t;
+    handler_ex_t handler_ex((get_associated_executor)(handler, ex_));
+
+    typename associated_allocator<handler_t>::type alloc(
+        (get_associated_allocator)(handler));
+
+    ex_.defer(detail::work_dispatcher<handler_t, handler_ex_t>(
+          ASIO_MOVE_CAST(CompletionHandler)(handler),
+          handler_ex), alloc);
+  }
+
+private:
+  Executor ex_;
+};
+
+} // namespace detail
+
+template <ASIO_COMPLETION_TOKEN_FOR(void()) CompletionToken>
+ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void()) defer(
+    ASIO_MOVE_ARG(CompletionToken) token)
+{
+  return async_initiate<CompletionToken, void()>(
+      detail::initiate_defer(), token);
+}
+
+template <typename Executor,
+    ASIO_COMPLETION_TOKEN_FOR(void()) CompletionToken>
+ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void()) defer(
+    const Executor& ex, ASIO_MOVE_ARG(CompletionToken) token,
+    typename enable_if<
+      execution::is_executor<Executor>::value || is_executor<Executor>::value
+    >::type*)
+{
+  return async_initiate<CompletionToken, void()>(
+      detail::initiate_defer_with_executor<Executor>(ex), token);
+}
+
+template <typename ExecutionContext,
+    ASIO_COMPLETION_TOKEN_FOR(void()) CompletionToken>
+inline ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void()) defer(
+    ExecutionContext& ctx, ASIO_MOVE_ARG(CompletionToken) token,
+    typename enable_if<is_convertible<
+      ExecutionContext&, execution_context&>::value>::type*)
+{
+  return async_initiate<CompletionToken, void()>(
+      detail::initiate_defer_with_executor<
+        typename ExecutionContext::executor_type>(
+          ctx.get_executor()), token);
+}
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IMPL_DEFER_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/impl/detached.hpp b/link/modules/asio-standalone/asio/include/asio/impl/detached.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/impl/detached.hpp
@@ -0,0 +1,130 @@
+//
+// impl/detached.hpp
+// ~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_IMPL_DETACHED_HPP
+#define ASIO_IMPL_DETACHED_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/async_result.hpp"
+#include "asio/detail/variadic_templates.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+  // Class to adapt a detached_t as a completion handler.
+  class detached_handler
+  {
+  public:
+    typedef void result_type;
+
+    detached_handler(detached_t)
+    {
+    }
+
+#if defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+    template <typename... Args>
+    void operator()(Args...)
+    {
+    }
+
+#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+    void operator()()
+    {
+    }
+
+#define ASIO_PRIVATE_DETACHED_DEF(n) \
+    template <ASIO_VARIADIC_TPARAMS(n)> \
+    void operator()(ASIO_VARIADIC_TARGS(n)) \
+    { \
+    } \
+    /**/
+    ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_DETACHED_DEF)
+#undef ASIO_PRIVATE_DETACHED_DEF
+
+#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+  };
+
+} // namespace detail
+
+#if !defined(GENERATING_DOCUMENTATION)
+
+template <typename Signature>
+struct async_result<detached_t, Signature>
+{
+  typedef asio::detail::detached_handler completion_handler_type;
+
+  typedef void return_type;
+
+  explicit async_result(completion_handler_type&)
+  {
+  }
+
+  void get()
+  {
+  }
+
+#if defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+  template <typename Initiation, typename RawCompletionToken, typename... Args>
+  static return_type initiate(
+      ASIO_MOVE_ARG(Initiation) initiation,
+      ASIO_MOVE_ARG(RawCompletionToken),
+      ASIO_MOVE_ARG(Args)... args)
+  {
+    ASIO_MOVE_CAST(Initiation)(initiation)(
+        detail::detached_handler(detached_t()),
+        ASIO_MOVE_CAST(Args)(args)...);
+  }
+
+#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+  template <typename Initiation, typename RawCompletionToken>
+  static return_type initiate(
+      ASIO_MOVE_ARG(Initiation) initiation,
+      ASIO_MOVE_ARG(RawCompletionToken))
+  {
+    ASIO_MOVE_CAST(Initiation)(initiation)(
+        detail::detached_handler(detached_t()));
+  }
+
+#define ASIO_PRIVATE_INITIATE_DEF(n) \
+  template <typename Initiation, typename RawCompletionToken, \
+      ASIO_VARIADIC_TPARAMS(n)> \
+  static return_type initiate( \
+      ASIO_MOVE_ARG(Initiation) initiation, \
+      ASIO_MOVE_ARG(RawCompletionToken), \
+      ASIO_VARIADIC_MOVE_PARAMS(n)) \
+  { \
+    ASIO_MOVE_CAST(Initiation)(initiation)( \
+        detail::detached_handler(detached_t()), \
+        ASIO_VARIADIC_MOVE_ARGS(n)); \
+  } \
+  /**/
+  ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_INITIATE_DEF)
+#undef ASIO_PRIVATE_INITIATE_DEF
+
+#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+};
+
+#endif // !defined(GENERATING_DOCUMENTATION)
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IMPL_DETACHED_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/impl/dispatch.hpp b/link/modules/asio-standalone/asio/include/asio/impl/dispatch.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/impl/dispatch.hpp
@@ -0,0 +1,243 @@
+//
+// impl/dispatch.hpp
+// ~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_IMPL_DISPATCH_HPP
+#define ASIO_IMPL_DISPATCH_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/associated_allocator.hpp"
+#include "asio/associated_executor.hpp"
+#include "asio/detail/work_dispatcher.hpp"
+#include "asio/execution/allocator.hpp"
+#include "asio/execution/blocking.hpp"
+#include "asio/prefer.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class initiate_dispatch
+{
+public:
+  template <typename CompletionHandler>
+  void operator()(ASIO_MOVE_ARG(CompletionHandler) handler,
+      typename enable_if<
+        execution::is_executor<
+          typename associated_executor<
+            typename decay<CompletionHandler>::type
+          >::type
+        >::value
+      >::type* = 0) const
+  {
+    typedef typename decay<CompletionHandler>::type handler_t;
+
+    typename associated_executor<handler_t>::type ex(
+        (get_associated_executor)(handler));
+
+    typename associated_allocator<handler_t>::type alloc(
+        (get_associated_allocator)(handler));
+
+    execution::execute(
+        asio::prefer(ex,
+          execution::blocking.possibly,
+          execution::allocator(alloc)),
+        ASIO_MOVE_CAST(CompletionHandler)(handler));
+  }
+
+  template <typename CompletionHandler>
+  void operator()(ASIO_MOVE_ARG(CompletionHandler) handler,
+      typename enable_if<
+        !execution::is_executor<
+          typename associated_executor<
+            typename decay<CompletionHandler>::type
+          >::type
+        >::value
+      >::type* = 0) const
+  {
+    typedef typename decay<CompletionHandler>::type handler_t;
+
+    typename associated_executor<handler_t>::type ex(
+        (get_associated_executor)(handler));
+
+    typename associated_allocator<handler_t>::type alloc(
+        (get_associated_allocator)(handler));
+
+    ex.dispatch(ASIO_MOVE_CAST(CompletionHandler)(handler), alloc);
+  }
+};
+
+template <typename Executor>
+class initiate_dispatch_with_executor
+{
+public:
+  typedef Executor executor_type;
+
+  explicit initiate_dispatch_with_executor(const Executor& ex)
+    : ex_(ex)
+  {
+  }
+
+  executor_type get_executor() const ASIO_NOEXCEPT
+  {
+    return ex_;
+  }
+
+  template <typename CompletionHandler>
+  void operator()(ASIO_MOVE_ARG(CompletionHandler) handler,
+      typename enable_if<
+        execution::is_executor<
+          typename conditional<true, executor_type, CompletionHandler>::type
+        >::value
+        &&
+        !detail::is_work_dispatcher_required<
+          typename decay<CompletionHandler>::type,
+          Executor
+        >::value
+      >::type* = 0) const
+  {
+    typedef typename decay<CompletionHandler>::type handler_t;
+
+    typename associated_allocator<handler_t>::type alloc(
+        (get_associated_allocator)(handler));
+
+    execution::execute(
+        asio::prefer(ex_,
+          execution::blocking.possibly,
+          execution::allocator(alloc)),
+        ASIO_MOVE_CAST(CompletionHandler)(handler));
+  }
+
+  template <typename CompletionHandler>
+  void operator()(ASIO_MOVE_ARG(CompletionHandler) handler,
+      typename enable_if<
+        execution::is_executor<
+          typename conditional<true, executor_type, CompletionHandler>::type
+        >::value
+        &&
+        detail::is_work_dispatcher_required<
+          typename decay<CompletionHandler>::type,
+          Executor
+        >::value
+      >::type* = 0) const
+  {
+    typedef typename decay<CompletionHandler>::type handler_t;
+
+    typedef typename associated_executor<
+      handler_t, Executor>::type handler_ex_t;
+    handler_ex_t handler_ex((get_associated_executor)(handler, ex_));
+
+    typename associated_allocator<handler_t>::type alloc(
+        (get_associated_allocator)(handler));
+
+    execution::execute(
+        asio::prefer(ex_,
+          execution::blocking.possibly,
+          execution::allocator(alloc)),
+        detail::work_dispatcher<handler_t, handler_ex_t>(
+          ASIO_MOVE_CAST(CompletionHandler)(handler), handler_ex));
+  }
+
+  template <typename CompletionHandler>
+  void operator()(ASIO_MOVE_ARG(CompletionHandler) handler,
+      typename enable_if<
+        !execution::is_executor<
+          typename conditional<true, executor_type, CompletionHandler>::type
+        >::value
+        &&
+        !detail::is_work_dispatcher_required<
+          typename decay<CompletionHandler>::type,
+          Executor
+        >::value
+      >::type* = 0) const
+  {
+    typedef typename decay<CompletionHandler>::type handler_t;
+
+    typename associated_allocator<handler_t>::type alloc(
+        (get_associated_allocator)(handler));
+
+    ex_.dispatch(ASIO_MOVE_CAST(CompletionHandler)(handler), alloc);
+  }
+
+  template <typename CompletionHandler>
+  void operator()(ASIO_MOVE_ARG(CompletionHandler) handler,
+      typename enable_if<
+        !execution::is_executor<
+          typename conditional<true, executor_type, CompletionHandler>::type
+        >::value
+        &&
+        detail::is_work_dispatcher_required<
+          typename decay<CompletionHandler>::type,
+          Executor
+        >::value
+      >::type* = 0) const
+  {
+    typedef typename decay<CompletionHandler>::type handler_t;
+
+    typedef typename associated_executor<
+      handler_t, Executor>::type handler_ex_t;
+    handler_ex_t handler_ex((get_associated_executor)(handler, ex_));
+
+    typename associated_allocator<handler_t>::type alloc(
+        (get_associated_allocator)(handler));
+
+    ex_.dispatch(detail::work_dispatcher<handler_t, handler_ex_t>(
+          ASIO_MOVE_CAST(CompletionHandler)(handler),
+          handler_ex), alloc);
+  }
+
+private:
+  Executor ex_;
+};
+
+} // namespace detail
+
+template <ASIO_COMPLETION_TOKEN_FOR(void()) CompletionToken>
+ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void()) dispatch(
+    ASIO_MOVE_ARG(CompletionToken) token)
+{
+  return async_initiate<CompletionToken, void()>(
+      detail::initiate_dispatch(), token);
+}
+
+template <typename Executor,
+    ASIO_COMPLETION_TOKEN_FOR(void()) CompletionToken>
+ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void()) dispatch(
+    const Executor& ex, ASIO_MOVE_ARG(CompletionToken) token,
+    typename enable_if<
+      execution::is_executor<Executor>::value || is_executor<Executor>::value
+    >::type*)
+{
+  return async_initiate<CompletionToken, void()>(
+      detail::initiate_dispatch_with_executor<Executor>(ex), token);
+}
+
+template <typename ExecutionContext,
+    ASIO_COMPLETION_TOKEN_FOR(void()) CompletionToken>
+inline ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void()) dispatch(
+    ExecutionContext& ctx, ASIO_MOVE_ARG(CompletionToken) token,
+    typename enable_if<is_convertible<
+      ExecutionContext&, execution_context&>::value>::type*)
+{
+  return async_initiate<CompletionToken, void()>(
+      detail::initiate_dispatch_with_executor<
+        typename ExecutionContext::executor_type>(
+          ctx.get_executor()), token);
+}
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IMPL_DISPATCH_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/impl/error.ipp b/link/modules/asio-standalone/asio/include/asio/impl/error.ipp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/impl/error.ipp
@@ -0,0 +1,128 @@
+//
+// impl/error.ipp
+// ~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_IMPL_ERROR_IPP
+#define ASIO_IMPL_ERROR_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <string>
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace error {
+
+#if !defined(ASIO_WINDOWS) && !defined(__CYGWIN__)
+
+namespace detail {
+
+class netdb_category : public asio::error_category
+{
+public:
+  const char* name() const ASIO_ERROR_CATEGORY_NOEXCEPT
+  {
+    return "asio.netdb";
+  }
+
+  std::string message(int value) const
+  {
+    if (value == error::host_not_found)
+      return "Host not found (authoritative)";
+    if (value == error::host_not_found_try_again)
+      return "Host not found (non-authoritative), try again later";
+    if (value == error::no_data)
+      return "The query is valid, but it does not have associated data";
+    if (value == error::no_recovery)
+      return "A non-recoverable error occurred during database lookup";
+    return "asio.netdb error";
+  }
+};
+
+} // namespace detail
+
+const asio::error_category& get_netdb_category()
+{
+  static detail::netdb_category instance;
+  return instance;
+}
+
+namespace detail {
+
+class addrinfo_category : public asio::error_category
+{
+public:
+  const char* name() const ASIO_ERROR_CATEGORY_NOEXCEPT
+  {
+    return "asio.addrinfo";
+  }
+
+  std::string message(int value) const
+  {
+    if (value == error::service_not_found)
+      return "Service not found";
+    if (value == error::socket_type_not_supported)
+      return "Socket type not supported";
+    return "asio.addrinfo error";
+  }
+};
+
+} // namespace detail
+
+const asio::error_category& get_addrinfo_category()
+{
+  static detail::addrinfo_category instance;
+  return instance;
+}
+
+#endif // !defined(ASIO_WINDOWS) && !defined(__CYGWIN__)
+
+namespace detail {
+
+class misc_category : public asio::error_category
+{
+public:
+  const char* name() const ASIO_ERROR_CATEGORY_NOEXCEPT
+  {
+    return "asio.misc";
+  }
+
+  std::string message(int value) const
+  {
+    if (value == error::already_open)
+      return "Already open";
+    if (value == error::eof)
+      return "End of file";
+    if (value == error::not_found)
+      return "Element not found";
+    if (value == error::fd_set_failure)
+      return "The descriptor does not fit into the select call's fd_set";
+    return "asio.misc error";
+  }
+};
+
+} // namespace detail
+
+const asio::error_category& get_misc_category()
+{
+  static detail::misc_category instance;
+  return instance;
+}
+
+} // namespace error
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IMPL_ERROR_IPP
diff --git a/link/modules/asio-standalone/asio/include/asio/impl/error_code.ipp b/link/modules/asio-standalone/asio/include/asio/impl/error_code.ipp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/impl/error_code.ipp
@@ -0,0 +1,206 @@
+//
+// impl/error_code.ipp
+// ~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_IMPL_ERROR_CODE_IPP
+#define ASIO_IMPL_ERROR_CODE_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+# include <winerror.h>
+#elif defined(ASIO_WINDOWS_RUNTIME)
+# include <windows.h>
+#else
+# include <cerrno>
+# include <cstring>
+# include <string>
+#endif
+#include "asio/detail/local_free_on_block_exit.hpp"
+#include "asio/detail/socket_types.hpp"
+#include "asio/error_code.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class system_category : public error_category
+{
+public:
+  const char* name() const ASIO_ERROR_CATEGORY_NOEXCEPT
+  {
+    return "asio.system";
+  }
+
+  std::string message(int value) const
+  {
+#if defined(ASIO_WINDOWS_RUNTIME) || defined(ASIO_WINDOWS_APP)
+    std::wstring wmsg(128, wchar_t());
+    for (;;)
+    {
+      DWORD wlength = ::FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM
+          | FORMAT_MESSAGE_IGNORE_INSERTS, 0, value,
+          MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+          &wmsg[0], static_cast<DWORD>(wmsg.size()), 0);
+      if (wlength == 0 && ::GetLastError() == ERROR_INSUFFICIENT_BUFFER)
+      {
+        wmsg.resize(wmsg.size() + wmsg.size() / 2);
+        continue;
+      }
+      if (wlength && wmsg[wlength - 1] == '\n')
+        --wlength;
+      if (wlength && wmsg[wlength - 1] == '\r')
+        --wlength;
+      if (wlength)
+      {
+        std::string msg(wlength * 2, char());
+        int length = ::WideCharToMultiByte(CP_ACP, 0,
+            wmsg.c_str(), static_cast<int>(wlength),
+            &msg[0], static_cast<int>(wlength * 2), 0, 0);
+        if (length <= 0)
+          return "asio.system error";
+        msg.resize(static_cast<std::size_t>(length));
+        return msg;
+      }
+      else
+        return "asio.system error";
+    }
+#elif defined(ASIO_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 "asio.system error";
+#else // defined(ASIO_WINDOWS_DESKTOP) || defined(__CYGWIN__)
+#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);
+#else
+    char buf[256] = "";
+    using namespace std;
+    return strerror_result(strerror_r(value, buf, sizeof(buf)), buf);
+#endif
+#endif // defined(ASIO_WINDOWS_DESKTOP) || defined(__CYGWIN__)
+  }
+
+#if defined(ASIO_HAS_STD_ERROR_CODE)
+  std::error_condition default_error_condition(
+      int ev) const ASIO_ERROR_CATEGORY_NOEXCEPT
+  {
+    switch (ev)
+    {
+    case access_denied:
+      return std::errc::permission_denied;
+    case address_family_not_supported:
+      return std::errc::address_family_not_supported;
+    case address_in_use:
+      return std::errc::address_in_use;
+    case already_connected:
+      return std::errc::already_connected;
+    case already_started:
+      return std::errc::connection_already_in_progress;
+    case broken_pipe:
+      return std::errc::broken_pipe;
+    case connection_aborted:
+      return std::errc::connection_aborted;
+    case connection_refused:
+      return std::errc::connection_refused;
+    case connection_reset:
+      return std::errc::connection_reset;
+    case bad_descriptor:
+      return std::errc::bad_file_descriptor;
+    case fault:
+      return std::errc::bad_address;
+    case host_unreachable:
+      return std::errc::host_unreachable;
+    case in_progress:
+      return std::errc::operation_in_progress;
+    case interrupted:
+      return std::errc::interrupted;
+    case invalid_argument:
+      return std::errc::invalid_argument;
+    case message_size:
+      return std::errc::message_size;
+    case name_too_long:
+      return std::errc::filename_too_long;
+    case network_down:
+      return std::errc::network_down;
+    case network_reset:
+      return std::errc::network_reset;
+    case network_unreachable:
+      return std::errc::network_unreachable;
+    case no_descriptors:
+      return std::errc::too_many_files_open;
+    case no_buffer_space:
+      return std::errc::no_buffer_space;
+    case no_memory:
+      return std::errc::not_enough_memory;
+    case no_permission:
+      return std::errc::operation_not_permitted;
+    case no_protocol_option:
+      return std::errc::no_protocol_option;
+    case no_such_device:
+      return std::errc::no_such_device;
+    case not_connected:
+      return std::errc::not_connected;
+    case not_socket:
+      return std::errc::not_a_socket;
+    case operation_aborted:
+      return std::errc::operation_canceled;
+    case operation_not_supported:
+      return std::errc::operation_not_supported;
+    case shut_down:
+      return std::make_error_condition(ev, *this);
+    case timed_out:
+      return std::errc::timed_out;
+    case try_again:
+      return std::errc::resource_unavailable_try_again;
+    case would_block:
+      return std::errc::operation_would_block;
+    default:
+      return std::make_error_condition(ev, *this);
+  }
+#endif // defined(ASIO_HAS_STD_ERROR_CODE)
+
+private:
+  // Helper function to adapt the result from glibc's variant of strerror_r.
+  static const char* strerror_result(int, const char* s) { return s; }
+  static const char* strerror_result(const char* s, const char*) { return s; }
+};
+
+} // namespace detail
+
+const error_category& system_category()
+{
+  static detail::system_category instance;
+  return instance;
+}
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IMPL_ERROR_CODE_IPP
diff --git a/link/modules/asio-standalone/asio/include/asio/impl/execution_context.hpp b/link/modules/asio-standalone/asio/include/asio/impl/execution_context.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/impl/execution_context.hpp
@@ -0,0 +1,109 @@
+//
+// impl/execution_context.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_IMPL_EXECUTION_CONTEXT_HPP
+#define ASIO_IMPL_EXECUTION_CONTEXT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/handler_type_requirements.hpp"
+#include "asio/detail/scoped_ptr.hpp"
+#include "asio/detail/service_registry.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+#if !defined(GENERATING_DOCUMENTATION)
+
+template <typename Service>
+inline Service& use_service(execution_context& e)
+{
+  // Check that Service meets the necessary type requirements.
+  (void)static_cast<execution_context::service*>(static_cast<Service*>(0));
+
+  return e.service_registry_->template use_service<Service>();
+}
+
+#if defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+template <typename Service, typename... Args>
+Service& make_service(execution_context& e, ASIO_MOVE_ARG(Args)... args)
+{
+  detail::scoped_ptr<Service> svc(
+      new Service(e, ASIO_MOVE_CAST(Args)(args)...));
+  e.service_registry_->template add_service<Service>(svc.get());
+  Service& result = *svc;
+  svc.release();
+  return result;
+}
+
+#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+template <typename Service>
+Service& make_service(execution_context& e)
+{
+  detail::scoped_ptr<Service> svc(new Service(e));
+  e.service_registry_->template add_service<Service>(svc.get());
+  Service& result = *svc;
+  svc.release();
+  return result;
+}
+
+#define ASIO_PRIVATE_MAKE_SERVICE_DEF(n) \
+  template <typename Service, ASIO_VARIADIC_TPARAMS(n)> \
+  Service& make_service(execution_context& e, \
+      ASIO_VARIADIC_MOVE_PARAMS(n)) \
+  { \
+    detail::scoped_ptr<Service> svc( \
+        new Service(e, ASIO_VARIADIC_MOVE_ARGS(n))); \
+    e.service_registry_->template add_service<Service>(svc.get()); \
+    Service& result = *svc; \
+    svc.release(); \
+    return result; \
+  } \
+  /**/
+  ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_MAKE_SERVICE_DEF)
+#undef ASIO_PRIVATE_MAKE_SERVICE_DEF
+
+#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+template <typename Service>
+inline void add_service(execution_context& e, Service* svc)
+{
+  // Check that Service meets the necessary type requirements.
+  (void)static_cast<execution_context::service*>(static_cast<Service*>(0));
+
+  e.service_registry_->template add_service<Service>(svc);
+}
+
+template <typename Service>
+inline bool has_service(execution_context& e)
+{
+  // Check that Service meets the necessary type requirements.
+  (void)static_cast<execution_context::service*>(static_cast<Service*>(0));
+
+  return e.service_registry_->template has_service<Service>();
+}
+
+#endif // !defined(GENERATING_DOCUMENTATION)
+
+inline execution_context& execution_context::service::context()
+{
+  return owner_;
+}
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IMPL_EXECUTION_CONTEXT_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/impl/execution_context.ipp b/link/modules/asio-standalone/asio/include/asio/impl/execution_context.ipp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/impl/execution_context.ipp
@@ -0,0 +1,82 @@
+//
+// impl/execution_context.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_IMPL_EXECUTION_CONTEXT_IPP
+#define ASIO_IMPL_EXECUTION_CONTEXT_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/execution_context.hpp"
+#include "asio/detail/service_registry.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+execution_context::execution_context()
+  : service_registry_(new asio::detail::service_registry(*this))
+{
+}
+
+execution_context::~execution_context()
+{
+  shutdown();
+  destroy();
+  delete service_registry_;
+}
+
+void execution_context::shutdown()
+{
+  service_registry_->shutdown_services();
+}
+
+void execution_context::destroy()
+{
+  service_registry_->destroy_services();
+}
+
+void execution_context::notify_fork(
+    asio::execution_context::fork_event event)
+{
+  service_registry_->notify_fork(event);
+}
+
+execution_context::service::service(execution_context& owner)
+  : owner_(owner),
+    next_(0)
+{
+}
+
+execution_context::service::~service()
+{
+}
+
+void execution_context::service::notify_fork(execution_context::fork_event)
+{
+}
+
+service_already_exists::service_already_exists()
+  : std::logic_error("Service already exists.")
+{
+}
+
+invalid_service_owner::invalid_service_owner()
+  : std::logic_error("Invalid service owner.")
+{
+}
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IMPL_EXECUTION_CONTEXT_IPP
diff --git a/link/modules/asio-standalone/asio/include/asio/impl/executor.hpp b/link/modules/asio-standalone/asio/include/asio/impl/executor.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/impl/executor.hpp
@@ -0,0 +1,301 @@
+//
+// impl/executor.hpp
+// ~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_IMPL_EXECUTOR_HPP
+#define ASIO_IMPL_EXECUTOR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if !defined(ASIO_NO_TS_EXECUTORS)
+
+#include "asio/detail/atomic_count.hpp"
+#include "asio/detail/global.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/detail/recycling_allocator.hpp"
+#include "asio/executor.hpp"
+#include "asio/system_executor.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+#if !defined(GENERATING_DOCUMENTATION)
+
+// Default polymorphic executor implementation.
+template <typename Executor, typename Allocator>
+class executor::impl
+  : public executor::impl_base
+{
+public:
+  typedef ASIO_REBIND_ALLOC(Allocator, impl) allocator_type;
+
+  static impl_base* create(const Executor& e, Allocator a = Allocator())
+  {
+    raw_mem mem(a);
+    impl* p = new (mem.ptr_) impl(e, a);
+    mem.ptr_ = 0;
+    return p;
+  }
+
+  impl(const Executor& e, const Allocator& a) ASIO_NOEXCEPT
+    : impl_base(false),
+      ref_count_(1),
+      executor_(e),
+      allocator_(a)
+  {
+  }
+
+  impl_base* clone() const ASIO_NOEXCEPT
+  {
+    detail::ref_count_up(ref_count_);
+    return const_cast<impl_base*>(static_cast<const impl_base*>(this));
+  }
+
+  void destroy() ASIO_NOEXCEPT
+  {
+    if (detail::ref_count_down(ref_count_))
+    {
+      allocator_type alloc(allocator_);
+      impl* p = this;
+      p->~impl();
+      alloc.deallocate(p, 1);
+    }
+  }
+
+  void on_work_started() ASIO_NOEXCEPT
+  {
+    executor_.on_work_started();
+  }
+
+  void on_work_finished() ASIO_NOEXCEPT
+  {
+    executor_.on_work_finished();
+  }
+
+  execution_context& context() ASIO_NOEXCEPT
+  {
+    return executor_.context();
+  }
+
+  void dispatch(ASIO_MOVE_ARG(function) f)
+  {
+    executor_.dispatch(ASIO_MOVE_CAST(function)(f), allocator_);
+  }
+
+  void post(ASIO_MOVE_ARG(function) f)
+  {
+    executor_.post(ASIO_MOVE_CAST(function)(f), allocator_);
+  }
+
+  void defer(ASIO_MOVE_ARG(function) f)
+  {
+    executor_.defer(ASIO_MOVE_CAST(function)(f), allocator_);
+  }
+
+  type_id_result_type target_type() const ASIO_NOEXCEPT
+  {
+    return type_id<Executor>();
+  }
+
+  void* target() ASIO_NOEXCEPT
+  {
+    return &executor_;
+  }
+
+  const void* target() const ASIO_NOEXCEPT
+  {
+    return &executor_;
+  }
+
+  bool equals(const impl_base* e) const ASIO_NOEXCEPT
+  {
+    if (this == e)
+      return true;
+    if (target_type() != e->target_type())
+      return false;
+    return executor_ == *static_cast<const Executor*>(e->target());
+  }
+
+private:
+  mutable detail::atomic_count ref_count_;
+  Executor executor_;
+  Allocator allocator_;
+
+  struct raw_mem
+  {
+    allocator_type allocator_;
+    impl* ptr_;
+
+    explicit raw_mem(const Allocator& a)
+      : allocator_(a),
+        ptr_(allocator_.allocate(1))
+    {
+    }
+
+    ~raw_mem()
+    {
+      if (ptr_)
+        allocator_.deallocate(ptr_, 1);
+    }
+
+  private:
+    // Disallow copying and assignment.
+    raw_mem(const raw_mem&);
+    raw_mem operator=(const raw_mem&);
+  };
+};
+
+// Polymorphic executor specialisation for system_executor.
+template <typename Allocator>
+class executor::impl<system_executor, Allocator>
+  : public executor::impl_base
+{
+public:
+  static impl_base* create(const system_executor&,
+      const Allocator& = Allocator())
+  {
+    return &detail::global<impl<system_executor, std::allocator<void> > >();
+  }
+
+  impl()
+    : impl_base(true)
+  {
+  }
+
+  impl_base* clone() const ASIO_NOEXCEPT
+  {
+    return const_cast<impl_base*>(static_cast<const impl_base*>(this));
+  }
+
+  void destroy() ASIO_NOEXCEPT
+  {
+  }
+
+  void on_work_started() ASIO_NOEXCEPT
+  {
+    executor_.on_work_started();
+  }
+
+  void on_work_finished() ASIO_NOEXCEPT
+  {
+    executor_.on_work_finished();
+  }
+
+  execution_context& context() ASIO_NOEXCEPT
+  {
+    return executor_.context();
+  }
+
+  void dispatch(ASIO_MOVE_ARG(function) f)
+  {
+    executor_.dispatch(ASIO_MOVE_CAST(function)(f),
+        std::allocator<void>());
+  }
+
+  void post(ASIO_MOVE_ARG(function) f)
+  {
+    executor_.post(ASIO_MOVE_CAST(function)(f),
+        std::allocator<void>());
+  }
+
+  void defer(ASIO_MOVE_ARG(function) f)
+  {
+    executor_.defer(ASIO_MOVE_CAST(function)(f),
+        std::allocator<void>());
+  }
+
+  type_id_result_type target_type() const ASIO_NOEXCEPT
+  {
+    return type_id<system_executor>();
+  }
+
+  void* target() ASIO_NOEXCEPT
+  {
+    return &executor_;
+  }
+
+  const void* target() const ASIO_NOEXCEPT
+  {
+    return &executor_;
+  }
+
+  bool equals(const impl_base* e) const ASIO_NOEXCEPT
+  {
+    return this == e;
+  }
+
+private:
+  system_executor executor_;
+};
+
+template <typename Executor>
+executor::executor(Executor e)
+  : impl_(impl<Executor, std::allocator<void> >::create(e))
+{
+}
+
+template <typename Executor, typename Allocator>
+executor::executor(allocator_arg_t, const Allocator& a, Executor e)
+  : impl_(impl<Executor, Allocator>::create(e, a))
+{
+}
+
+template <typename Function, typename Allocator>
+void executor::dispatch(ASIO_MOVE_ARG(Function) f,
+    const Allocator& a) const
+{
+  impl_base* i = get_impl();
+  if (i->fast_dispatch_)
+    system_executor().dispatch(ASIO_MOVE_CAST(Function)(f), a);
+  else
+    i->dispatch(function(ASIO_MOVE_CAST(Function)(f), a));
+}
+
+template <typename Function, typename Allocator>
+void executor::post(ASIO_MOVE_ARG(Function) f,
+    const Allocator& a) const
+{
+  get_impl()->post(function(ASIO_MOVE_CAST(Function)(f), a));
+}
+
+template <typename Function, typename Allocator>
+void executor::defer(ASIO_MOVE_ARG(Function) f,
+    const Allocator& a) const
+{
+  get_impl()->defer(function(ASIO_MOVE_CAST(Function)(f), a));
+}
+
+template <typename Executor>
+Executor* executor::target() ASIO_NOEXCEPT
+{
+  return impl_ && impl_->target_type() == type_id<Executor>()
+    ? static_cast<Executor*>(impl_->target()) : 0;
+}
+
+template <typename Executor>
+const Executor* executor::target() const ASIO_NOEXCEPT
+{
+  return impl_ && impl_->target_type() == type_id<Executor>()
+    ? static_cast<Executor*>(impl_->target()) : 0;
+}
+
+#endif // !defined(GENERATING_DOCUMENTATION)
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // !defined(ASIO_NO_TS_EXECUTORS)
+
+#endif // ASIO_IMPL_EXECUTOR_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/impl/executor.ipp b/link/modules/asio-standalone/asio/include/asio/impl/executor.ipp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/impl/executor.ipp
@@ -0,0 +1,43 @@
+//
+// impl/executor.ipp
+// ~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_IMPL_EXECUTOR_IPP
+#define ASIO_IMPL_EXECUTOR_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if !defined(ASIO_NO_TS_EXECUTORS)
+
+#include "asio/executor.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+bad_executor::bad_executor() ASIO_NOEXCEPT
+{
+}
+
+const char* bad_executor::what() const ASIO_NOEXCEPT_OR_NOTHROW
+{
+  return "bad executor";
+}
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // !defined(ASIO_NO_TS_EXECUTORS)
+
+#endif // ASIO_IMPL_EXECUTOR_IPP
diff --git a/link/modules/asio-standalone/asio/include/asio/impl/handler_alloc_hook.ipp b/link/modules/asio-standalone/asio/include/asio/impl/handler_alloc_hook.ipp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/impl/handler_alloc_hook.ipp
@@ -0,0 +1,61 @@
+//
+// impl/handler_alloc_hook.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_IMPL_HANDLER_ALLOC_HOOK_IPP
+#define ASIO_IMPL_HANDLER_ALLOC_HOOK_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/thread_context.hpp"
+#include "asio/detail/thread_info_base.hpp"
+#include "asio/handler_alloc_hook.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+asio_handler_allocate_is_deprecated
+asio_handler_allocate(std::size_t size, ...)
+{
+#if defined(ASIO_NO_DEPRECATED)
+  (void)size;
+  return asio_handler_allocate_is_no_longer_used();
+#elif !defined(ASIO_DISABLE_SMALL_BLOCK_RECYCLING)
+  return detail::thread_info_base::allocate(
+      detail::thread_context::thread_call_stack::top(), size);
+#else // !defined(ASIO_DISABLE_SMALL_BLOCK_RECYCLING)
+  return ::operator new(size);
+#endif // !defined(ASIO_DISABLE_SMALL_BLOCK_RECYCLING)
+}
+
+asio_handler_deallocate_is_deprecated
+asio_handler_deallocate(void* pointer, std::size_t size, ...)
+{
+#if defined(ASIO_NO_DEPRECATED)
+  (void)pointer;
+  (void)size;
+  return asio_handler_deallocate_is_no_longer_used();
+#elif !defined(ASIO_DISABLE_SMALL_BLOCK_RECYCLING)
+  detail::thread_info_base::deallocate(
+      detail::thread_context::thread_call_stack::top(), pointer, size);
+#else // !defined(ASIO_DISABLE_SMALL_BLOCK_RECYCLING)
+  (void)size;
+  ::operator delete(pointer);
+#endif // !defined(ASIO_DISABLE_SMALL_BLOCK_RECYCLING)
+}
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IMPL_HANDLER_ALLOC_HOOK_IPP
diff --git a/link/modules/asio-standalone/asio/include/asio/impl/io_context.hpp b/link/modules/asio-standalone/asio/include/asio/impl/io_context.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/impl/io_context.hpp
@@ -0,0 +1,440 @@
+//
+// impl/io_context.hpp
+// ~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_IMPL_IO_CONTEXT_HPP
+#define ASIO_IMPL_IO_CONTEXT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/completion_handler.hpp"
+#include "asio/detail/executor_op.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/handler_type_requirements.hpp"
+#include "asio/detail/non_const_lvalue.hpp"
+#include "asio/detail/recycling_allocator.hpp"
+#include "asio/detail/service_registry.hpp"
+#include "asio/detail/throw_error.hpp"
+#include "asio/detail/type_traits.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+#if !defined(GENERATING_DOCUMENTATION)
+
+template <typename Service>
+inline Service& use_service(io_context& ioc)
+{
+  // Check that Service meets the necessary type requirements.
+  (void)static_cast<execution_context::service*>(static_cast<Service*>(0));
+  (void)static_cast<const execution_context::id*>(&Service::id);
+
+  return ioc.service_registry_->template use_service<Service>(ioc);
+}
+
+template <>
+inline detail::io_context_impl& use_service<detail::io_context_impl>(
+    io_context& ioc)
+{
+  return ioc.impl_;
+}
+
+#endif // !defined(GENERATING_DOCUMENTATION)
+
+inline io_context::executor_type
+io_context::get_executor() ASIO_NOEXCEPT
+{
+  return executor_type(*this);
+}
+
+#if defined(ASIO_HAS_CHRONO)
+
+template <typename Rep, typename Period>
+std::size_t io_context::run_for(
+    const chrono::duration<Rep, Period>& rel_time)
+{
+  return this->run_until(chrono::steady_clock::now() + rel_time);
+}
+
+template <typename Clock, typename Duration>
+std::size_t io_context::run_until(
+    const chrono::time_point<Clock, Duration>& abs_time)
+{
+  std::size_t n = 0;
+  while (this->run_one_until(abs_time))
+    if (n != (std::numeric_limits<std::size_t>::max)())
+      ++n;
+  return n;
+}
+
+template <typename Rep, typename Period>
+std::size_t io_context::run_one_for(
+    const chrono::duration<Rep, Period>& rel_time)
+{
+  return this->run_one_until(chrono::steady_clock::now() + rel_time);
+}
+
+template <typename Clock, typename Duration>
+std::size_t io_context::run_one_until(
+    const chrono::time_point<Clock, Duration>& abs_time)
+{
+  typename Clock::time_point now = Clock::now();
+  while (now < abs_time)
+  {
+    typename Clock::duration rel_time = abs_time - now;
+    if (rel_time > chrono::seconds(1))
+      rel_time = chrono::seconds(1);
+
+    asio::error_code ec;
+    std::size_t s = impl_.wait_one(
+        static_cast<long>(chrono::duration_cast<
+          chrono::microseconds>(rel_time).count()), ec);
+    asio::detail::throw_error(ec);
+
+    if (s || impl_.stopped())
+      return s;
+
+    now = Clock::now();
+  }
+
+  return 0;
+}
+
+#endif // defined(ASIO_HAS_CHRONO)
+
+#if !defined(ASIO_NO_DEPRECATED)
+
+inline void io_context::reset()
+{
+  restart();
+}
+
+struct io_context::initiate_dispatch
+{
+  template <typename LegacyCompletionHandler>
+  void operator()(ASIO_MOVE_ARG(LegacyCompletionHandler) handler,
+      io_context* self) const
+  {
+    // If you get an error on the following line it means that your handler does
+    // not meet the documented type requirements for a LegacyCompletionHandler.
+    ASIO_LEGACY_COMPLETION_HANDLER_CHECK(
+        LegacyCompletionHandler, handler) type_check;
+
+    detail::non_const_lvalue<LegacyCompletionHandler> handler2(handler);
+    if (self->impl_.can_dispatch())
+    {
+      detail::fenced_block b(detail::fenced_block::full);
+      asio_handler_invoke_helpers::invoke(
+          handler2.value, handler2.value);
+    }
+    else
+    {
+      // Allocate and construct an operation to wrap the handler.
+      typedef detail::completion_handler<
+        typename decay<LegacyCompletionHandler>::type, executor_type> op;
+      typename op::ptr p = { detail::addressof(handler2.value),
+        op::ptr::allocate(handler2.value), 0 };
+      p.p = new (p.v) op(handler2.value, self->get_executor());
+
+      ASIO_HANDLER_CREATION((*self, *p.p,
+            "io_context", self, 0, "dispatch"));
+
+      self->impl_.do_dispatch(p.p);
+      p.v = p.p = 0;
+    }
+  }
+};
+
+template <typename LegacyCompletionHandler>
+ASIO_INITFN_AUTO_RESULT_TYPE(LegacyCompletionHandler, void ())
+io_context::dispatch(ASIO_MOVE_ARG(LegacyCompletionHandler) handler)
+{
+  return async_initiate<LegacyCompletionHandler, void ()>(
+      initiate_dispatch(), handler, this);
+}
+
+struct io_context::initiate_post
+{
+  template <typename LegacyCompletionHandler>
+  void operator()(ASIO_MOVE_ARG(LegacyCompletionHandler) handler,
+      io_context* self) const
+  {
+    // If you get an error on the following line it means that your handler does
+    // not meet the documented type requirements for a LegacyCompletionHandler.
+    ASIO_LEGACY_COMPLETION_HANDLER_CHECK(
+        LegacyCompletionHandler, handler) type_check;
+
+    detail::non_const_lvalue<LegacyCompletionHandler> handler2(handler);
+
+    bool is_continuation =
+      asio_handler_cont_helpers::is_continuation(handler2.value);
+
+    // Allocate and construct an operation to wrap the handler.
+    typedef detail::completion_handler<
+      typename decay<LegacyCompletionHandler>::type, executor_type> op;
+    typename op::ptr p = { detail::addressof(handler2.value),
+        op::ptr::allocate(handler2.value), 0 };
+    p.p = new (p.v) op(handler2.value, self->get_executor());
+
+    ASIO_HANDLER_CREATION((*self, *p.p,
+          "io_context", self, 0, "post"));
+
+    self->impl_.post_immediate_completion(p.p, is_continuation);
+    p.v = p.p = 0;
+  }
+};
+
+template <typename LegacyCompletionHandler>
+ASIO_INITFN_AUTO_RESULT_TYPE(LegacyCompletionHandler, void ())
+io_context::post(ASIO_MOVE_ARG(LegacyCompletionHandler) handler)
+{
+  return async_initiate<LegacyCompletionHandler, void ()>(
+      initiate_post(), handler, this);
+}
+
+template <typename Handler>
+#if defined(GENERATING_DOCUMENTATION)
+unspecified
+#else
+inline detail::wrapped_handler<io_context&, Handler>
+#endif
+io_context::wrap(Handler handler)
+{
+  return detail::wrapped_handler<io_context&, Handler>(*this, handler);
+}
+
+#endif // !defined(ASIO_NO_DEPRECATED)
+
+template <typename Allocator, unsigned int Bits>
+io_context::basic_executor_type<Allocator, Bits>&
+io_context::basic_executor_type<Allocator, Bits>::operator=(
+    const basic_executor_type& other) ASIO_NOEXCEPT
+{
+  if (this != &other)
+  {
+    io_context* old_io_context = io_context_;
+    io_context_ = other.io_context_;
+    allocator_ = other.allocator_;
+    bits_ = other.bits_;
+    if (Bits & outstanding_work_tracked)
+    {
+      if (io_context_)
+        io_context_->impl_.work_started();
+      if (old_io_context)
+        old_io_context->impl_.work_finished();
+    }
+  }
+  return *this;
+}
+
+#if defined(ASIO_HAS_MOVE)
+template <typename Allocator, unsigned int Bits>
+io_context::basic_executor_type<Allocator, Bits>&
+io_context::basic_executor_type<Allocator, Bits>::operator=(
+    basic_executor_type&& other) ASIO_NOEXCEPT
+{
+  if (this != &other)
+  {
+    io_context_ = other.io_context_;
+    allocator_ = std::move(other.allocator_);
+    bits_ = other.bits_;
+    if (Bits & outstanding_work_tracked)
+      other.io_context_ = 0;
+  }
+  return *this;
+}
+#endif // defined(ASIO_HAS_MOVE)
+
+template <typename Allocator, unsigned int Bits>
+inline bool io_context::basic_executor_type<Allocator,
+    Bits>::running_in_this_thread() const ASIO_NOEXCEPT
+{
+  return io_context_->impl_.can_dispatch();
+}
+
+template <typename Allocator, unsigned int Bits>
+template <typename Function>
+void io_context::basic_executor_type<Allocator, Bits>::execute(
+    ASIO_MOVE_ARG(Function) f) const
+{
+  typedef typename decay<Function>::type function_type;
+
+  // Invoke immediately if the blocking.possibly property is enabled and we are
+  // already inside the thread pool.
+  if ((bits_ & blocking_never) == 0 && io_context_->impl_.can_dispatch())
+  {
+    // Make a local, non-const copy of the function.
+    function_type tmp(ASIO_MOVE_CAST(Function)(f));
+
+#if defined(ASIO_HAS_STD_EXCEPTION_PTR) \
+  && !defined(ASIO_NO_EXCEPTIONS)
+    try
+    {
+#endif // defined(ASIO_HAS_STD_EXCEPTION_PTR)
+       //   && !defined(ASIO_NO_EXCEPTIONS)
+      detail::fenced_block b(detail::fenced_block::full);
+      asio_handler_invoke_helpers::invoke(tmp, tmp);
+      return;
+#if defined(ASIO_HAS_STD_EXCEPTION_PTR) \
+  && !defined(ASIO_NO_EXCEPTIONS)
+    }
+    catch (...)
+    {
+      io_context_->impl_.capture_current_exception();
+      return;
+    }
+#endif // defined(ASIO_HAS_STD_EXCEPTION_PTR)
+       //   && !defined(ASIO_NO_EXCEPTIONS)
+  }
+
+  // Allocate and construct an operation to wrap the function.
+  typedef detail::executor_op<function_type, Allocator, detail::operation> op;
+  typename op::ptr p = { detail::addressof(allocator_),
+      op::ptr::allocate(allocator_), 0 };
+  p.p = new (p.v) op(ASIO_MOVE_CAST(Function)(f), allocator_);
+
+  ASIO_HANDLER_CREATION((*io_context_, *p.p,
+        "io_context", io_context_, 0, "execute"));
+
+  io_context_->impl_.post_immediate_completion(p.p,
+      (bits_ & relationship_continuation) != 0);
+  p.v = p.p = 0;
+}
+
+#if !defined(ASIO_NO_TS_EXECUTORS)
+template <typename Allocator, unsigned int Bits>
+inline io_context& io_context::basic_executor_type<
+    Allocator, Bits>::context() const ASIO_NOEXCEPT
+{
+  return *io_context_;
+}
+
+template <typename Allocator, unsigned int Bits>
+inline void io_context::basic_executor_type<Allocator,
+    Bits>::on_work_started() const ASIO_NOEXCEPT
+{
+  io_context_->impl_.work_started();
+}
+
+template <typename Allocator, unsigned int Bits>
+inline void io_context::basic_executor_type<Allocator,
+    Bits>::on_work_finished() const ASIO_NOEXCEPT
+{
+  io_context_->impl_.work_finished();
+}
+
+template <typename Allocator, unsigned int Bits>
+template <typename Function, typename OtherAllocator>
+void io_context::basic_executor_type<Allocator, Bits>::dispatch(
+    ASIO_MOVE_ARG(Function) f, const OtherAllocator& a) const
+{
+  typedef typename decay<Function>::type function_type;
+
+  // Invoke immediately if we are already inside the thread pool.
+  if (io_context_->impl_.can_dispatch())
+  {
+    // Make a local, non-const copy of the function.
+    function_type tmp(ASIO_MOVE_CAST(Function)(f));
+
+    detail::fenced_block b(detail::fenced_block::full);
+    asio_handler_invoke_helpers::invoke(tmp, tmp);
+    return;
+  }
+
+  // Allocate and construct an operation to wrap the function.
+  typedef detail::executor_op<function_type,
+      OtherAllocator, detail::operation> op;
+  typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 };
+  p.p = new (p.v) op(ASIO_MOVE_CAST(Function)(f), a);
+
+  ASIO_HANDLER_CREATION((*io_context_, *p.p,
+        "io_context", io_context_, 0, "dispatch"));
+
+  io_context_->impl_.post_immediate_completion(p.p, false);
+  p.v = p.p = 0;
+}
+
+template <typename Allocator, unsigned int Bits>
+template <typename Function, typename OtherAllocator>
+void io_context::basic_executor_type<Allocator, Bits>::post(
+    ASIO_MOVE_ARG(Function) f, const OtherAllocator& a) const
+{
+  typedef typename decay<Function>::type function_type;
+
+  // Allocate and construct an operation to wrap the function.
+  typedef detail::executor_op<function_type,
+      OtherAllocator, detail::operation> op;
+  typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 };
+  p.p = new (p.v) op(ASIO_MOVE_CAST(Function)(f), a);
+
+  ASIO_HANDLER_CREATION((*io_context_, *p.p,
+        "io_context", io_context_, 0, "post"));
+
+  io_context_->impl_.post_immediate_completion(p.p, false);
+  p.v = p.p = 0;
+}
+
+template <typename Allocator, unsigned int Bits>
+template <typename Function, typename OtherAllocator>
+void io_context::basic_executor_type<Allocator, Bits>::defer(
+    ASIO_MOVE_ARG(Function) f, const OtherAllocator& a) const
+{
+  typedef typename decay<Function>::type function_type;
+
+  // Allocate and construct an operation to wrap the function.
+  typedef detail::executor_op<function_type,
+      OtherAllocator, detail::operation> op;
+  typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 };
+  p.p = new (p.v) op(ASIO_MOVE_CAST(Function)(f), a);
+
+  ASIO_HANDLER_CREATION((*io_context_, *p.p,
+        "io_context", io_context_, 0, "defer"));
+
+  io_context_->impl_.post_immediate_completion(p.p, true);
+  p.v = p.p = 0;
+}
+#endif // !defined(ASIO_NO_TS_EXECUTORS)
+
+#if !defined(ASIO_NO_DEPRECATED)
+inline io_context::work::work(asio::io_context& io_context)
+  : io_context_impl_(io_context.impl_)
+{
+  io_context_impl_.work_started();
+}
+
+inline io_context::work::work(const work& other)
+  : io_context_impl_(other.io_context_impl_)
+{
+  io_context_impl_.work_started();
+}
+
+inline io_context::work::~work()
+{
+  io_context_impl_.work_finished();
+}
+
+inline asio::io_context& io_context::work::get_io_context()
+{
+  return static_cast<asio::io_context&>(io_context_impl_.context());
+}
+#endif // !defined(ASIO_NO_DEPRECATED)
+
+inline asio::io_context& io_context::service::get_io_context()
+{
+  return static_cast<asio::io_context&>(context());
+}
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IMPL_IO_CONTEXT_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/impl/io_context.ipp b/link/modules/asio-standalone/asio/include/asio/impl/io_context.ipp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/impl/io_context.ipp
@@ -0,0 +1,175 @@
+//
+// impl/io_context.ipp
+// ~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_IMPL_IO_CONTEXT_IPP
+#define ASIO_IMPL_IO_CONTEXT_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/io_context.hpp"
+#include "asio/detail/concurrency_hint.hpp"
+#include "asio/detail/limits.hpp"
+#include "asio/detail/scoped_ptr.hpp"
+#include "asio/detail/service_registry.hpp"
+#include "asio/detail/throw_error.hpp"
+
+#if defined(ASIO_HAS_IOCP)
+# include "asio/detail/win_iocp_io_context.hpp"
+#else
+# include "asio/detail/scheduler.hpp"
+#endif
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+io_context::io_context()
+  : impl_(add_impl(new impl_type(*this,
+          ASIO_CONCURRENCY_HINT_DEFAULT, false)))
+{
+}
+
+io_context::io_context(int concurrency_hint)
+  : impl_(add_impl(new impl_type(*this, concurrency_hint == 1
+          ? ASIO_CONCURRENCY_HINT_1 : concurrency_hint, false)))
+{
+}
+
+io_context::impl_type& io_context::add_impl(io_context::impl_type* impl)
+{
+  asio::detail::scoped_ptr<impl_type> scoped_impl(impl);
+  asio::add_service<impl_type>(*this, scoped_impl.get());
+  return *scoped_impl.release();
+}
+
+io_context::~io_context()
+{
+}
+
+io_context::count_type io_context::run()
+{
+  asio::error_code ec;
+  count_type s = impl_.run(ec);
+  asio::detail::throw_error(ec);
+  return s;
+}
+
+#if !defined(ASIO_NO_DEPRECATED)
+io_context::count_type io_context::run(asio::error_code& ec)
+{
+  return impl_.run(ec);
+}
+#endif // !defined(ASIO_NO_DEPRECATED)
+
+io_context::count_type io_context::run_one()
+{
+  asio::error_code ec;
+  count_type s = impl_.run_one(ec);
+  asio::detail::throw_error(ec);
+  return s;
+}
+
+#if !defined(ASIO_NO_DEPRECATED)
+io_context::count_type io_context::run_one(asio::error_code& ec)
+{
+  return impl_.run_one(ec);
+}
+#endif // !defined(ASIO_NO_DEPRECATED)
+
+io_context::count_type io_context::poll()
+{
+  asio::error_code ec;
+  count_type s = impl_.poll(ec);
+  asio::detail::throw_error(ec);
+  return s;
+}
+
+#if !defined(ASIO_NO_DEPRECATED)
+io_context::count_type io_context::poll(asio::error_code& ec)
+{
+  return impl_.poll(ec);
+}
+#endif // !defined(ASIO_NO_DEPRECATED)
+
+io_context::count_type io_context::poll_one()
+{
+  asio::error_code ec;
+  count_type s = impl_.poll_one(ec);
+  asio::detail::throw_error(ec);
+  return s;
+}
+
+#if !defined(ASIO_NO_DEPRECATED)
+io_context::count_type io_context::poll_one(asio::error_code& ec)
+{
+  return impl_.poll_one(ec);
+}
+#endif // !defined(ASIO_NO_DEPRECATED)
+
+void io_context::stop()
+{
+  impl_.stop();
+}
+
+bool io_context::stopped() const
+{
+  return impl_.stopped();
+}
+
+void io_context::restart()
+{
+  impl_.restart();
+}
+
+io_context::service::service(asio::io_context& owner)
+  : execution_context::service(owner)
+{
+}
+
+io_context::service::~service()
+{
+}
+
+void io_context::service::shutdown()
+{
+#if !defined(ASIO_NO_DEPRECATED)
+  shutdown_service();
+#endif // !defined(ASIO_NO_DEPRECATED)
+}
+
+#if !defined(ASIO_NO_DEPRECATED)
+void io_context::service::shutdown_service()
+{
+}
+#endif // !defined(ASIO_NO_DEPRECATED)
+
+void io_context::service::notify_fork(io_context::fork_event ev)
+{
+#if !defined(ASIO_NO_DEPRECATED)
+  fork_service(ev);
+#else // !defined(ASIO_NO_DEPRECATED)
+  (void)ev;
+#endif // !defined(ASIO_NO_DEPRECATED)
+}
+
+#if !defined(ASIO_NO_DEPRECATED)
+void io_context::service::fork_service(io_context::fork_event)
+{
+}
+#endif // !defined(ASIO_NO_DEPRECATED)
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IMPL_IO_CONTEXT_IPP
diff --git a/link/modules/asio-standalone/asio/include/asio/impl/multiple_exceptions.ipp b/link/modules/asio-standalone/asio/include/asio/impl/multiple_exceptions.ipp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/impl/multiple_exceptions.ipp
@@ -0,0 +1,49 @@
+//
+// impl/multiple_exceptions.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_IMPL_MULTIPLE_EXCEPTIONS_IPP
+#define ASIO_IMPL_MULTIPLE_EXCEPTIONS_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/multiple_exceptions.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+#if defined(ASIO_HAS_STD_EXCEPTION_PTR)
+
+multiple_exceptions::multiple_exceptions(
+    std::exception_ptr first) ASIO_NOEXCEPT
+  : first_(ASIO_MOVE_CAST(std::exception_ptr)(first))
+{
+}
+
+const char* multiple_exceptions::what() const ASIO_NOEXCEPT_OR_NOTHROW
+{
+  return "multiple exceptions";
+}
+
+std::exception_ptr multiple_exceptions::first_exception() const
+{
+  return first_;
+}
+
+#endif // defined(ASIO_HAS_STD_EXCEPTION_PTR)
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IMPL_MULTIPLE_EXCEPTIONS_IPP
diff --git a/link/modules/asio-standalone/asio/include/asio/impl/post.hpp b/link/modules/asio-standalone/asio/include/asio/impl/post.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/impl/post.hpp
@@ -0,0 +1,248 @@
+//
+// impl/post.hpp
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_IMPL_POST_HPP
+#define ASIO_IMPL_POST_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/associated_allocator.hpp"
+#include "asio/associated_executor.hpp"
+#include "asio/detail/work_dispatcher.hpp"
+#include "asio/execution/allocator.hpp"
+#include "asio/execution/blocking.hpp"
+#include "asio/execution/relationship.hpp"
+#include "asio/prefer.hpp"
+#include "asio/require.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class initiate_post
+{
+public:
+  template <typename CompletionHandler>
+  void operator()(ASIO_MOVE_ARG(CompletionHandler) handler,
+      typename enable_if<
+        execution::is_executor<
+          typename associated_executor<
+            typename decay<CompletionHandler>::type
+          >::type
+        >::value
+      >::type* = 0) const
+  {
+    typedef typename decay<CompletionHandler>::type handler_t;
+
+    typename associated_executor<handler_t>::type ex(
+        (get_associated_executor)(handler));
+
+    typename associated_allocator<handler_t>::type alloc(
+        (get_associated_allocator)(handler));
+
+    execution::execute(
+        asio::prefer(
+          asio::require(ex, execution::blocking.never),
+          execution::relationship.fork,
+          execution::allocator(alloc)),
+        ASIO_MOVE_CAST(CompletionHandler)(handler));
+  }
+
+  template <typename CompletionHandler>
+  void operator()(ASIO_MOVE_ARG(CompletionHandler) handler,
+      typename enable_if<
+        !execution::is_executor<
+          typename associated_executor<
+            typename decay<CompletionHandler>::type
+          >::type
+        >::value
+      >::type* = 0) const
+  {
+    typedef typename decay<CompletionHandler>::type handler_t;
+
+    typename associated_executor<handler_t>::type ex(
+        (get_associated_executor)(handler));
+
+    typename associated_allocator<handler_t>::type alloc(
+        (get_associated_allocator)(handler));
+
+    ex.post(ASIO_MOVE_CAST(CompletionHandler)(handler), alloc);
+  }
+};
+
+template <typename Executor>
+class initiate_post_with_executor
+{
+public:
+  typedef Executor executor_type;
+
+  explicit initiate_post_with_executor(const Executor& ex)
+    : ex_(ex)
+  {
+  }
+
+  executor_type get_executor() const ASIO_NOEXCEPT
+  {
+    return ex_;
+  }
+
+  template <typename CompletionHandler>
+  void operator()(ASIO_MOVE_ARG(CompletionHandler) handler,
+      typename enable_if<
+        execution::is_executor<
+          typename conditional<true, executor_type, CompletionHandler>::type
+        >::value
+        &&
+        !detail::is_work_dispatcher_required<
+          typename decay<CompletionHandler>::type,
+          Executor
+        >::value
+      >::type* = 0) const
+  {
+    typedef typename decay<CompletionHandler>::type handler_t;
+
+    typename associated_allocator<handler_t>::type alloc(
+        (get_associated_allocator)(handler));
+
+    execution::execute(
+        asio::prefer(
+          asio::require(ex_, execution::blocking.never),
+          execution::relationship.fork,
+          execution::allocator(alloc)),
+        ASIO_MOVE_CAST(CompletionHandler)(handler));
+  }
+
+  template <typename CompletionHandler>
+  void operator()(ASIO_MOVE_ARG(CompletionHandler) handler,
+      typename enable_if<
+        execution::is_executor<
+          typename conditional<true, executor_type, CompletionHandler>::type
+        >::value
+        &&
+        detail::is_work_dispatcher_required<
+          typename decay<CompletionHandler>::type,
+          Executor
+        >::value
+      >::type* = 0) const
+  {
+    typedef typename decay<CompletionHandler>::type handler_t;
+
+    typedef typename associated_executor<
+      handler_t, Executor>::type handler_ex_t;
+    handler_ex_t handler_ex((get_associated_executor)(handler, ex_));
+
+    typename associated_allocator<handler_t>::type alloc(
+        (get_associated_allocator)(handler));
+
+    execution::execute(
+        asio::prefer(
+          asio::require(ex_, execution::blocking.never),
+          execution::relationship.fork,
+          execution::allocator(alloc)),
+        detail::work_dispatcher<handler_t, handler_ex_t>(
+          ASIO_MOVE_CAST(CompletionHandler)(handler), handler_ex));
+  }
+
+  template <typename CompletionHandler>
+  void operator()(ASIO_MOVE_ARG(CompletionHandler) handler,
+      typename enable_if<
+        !execution::is_executor<
+          typename conditional<true, executor_type, CompletionHandler>::type
+        >::value
+        &&
+        !detail::is_work_dispatcher_required<
+          typename decay<CompletionHandler>::type,
+          Executor
+        >::value
+      >::type* = 0) const
+  {
+    typedef typename decay<CompletionHandler>::type handler_t;
+
+    typename associated_allocator<handler_t>::type alloc(
+        (get_associated_allocator)(handler));
+
+    ex_.post(ASIO_MOVE_CAST(CompletionHandler)(handler), alloc);
+  }
+
+  template <typename CompletionHandler>
+  void operator()(ASIO_MOVE_ARG(CompletionHandler) handler,
+      typename enable_if<
+        !execution::is_executor<
+          typename conditional<true, executor_type, CompletionHandler>::type
+        >::value
+        &&
+        detail::is_work_dispatcher_required<
+          typename decay<CompletionHandler>::type,
+          Executor
+        >::value
+      >::type* = 0) const
+  {
+    typedef typename decay<CompletionHandler>::type handler_t;
+
+    typedef typename associated_executor<
+      handler_t, Executor>::type handler_ex_t;
+    handler_ex_t handler_ex((get_associated_executor)(handler, ex_));
+
+    typename associated_allocator<handler_t>::type alloc(
+        (get_associated_allocator)(handler));
+
+    ex_.post(detail::work_dispatcher<handler_t, handler_ex_t>(
+          ASIO_MOVE_CAST(CompletionHandler)(handler),
+          handler_ex), alloc);
+  }
+
+private:
+  Executor ex_;
+};
+
+} // namespace detail
+
+template <ASIO_COMPLETION_TOKEN_FOR(void()) CompletionToken>
+ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void()) post(
+    ASIO_MOVE_ARG(CompletionToken) token)
+{
+  return async_initiate<CompletionToken, void()>(
+      detail::initiate_post(), token);
+}
+
+template <typename Executor,
+    ASIO_COMPLETION_TOKEN_FOR(void()) CompletionToken>
+ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void()) post(
+    const Executor& ex, ASIO_MOVE_ARG(CompletionToken) token,
+    typename enable_if<
+      execution::is_executor<Executor>::value || is_executor<Executor>::value
+    >::type*)
+{
+  return async_initiate<CompletionToken, void()>(
+      detail::initiate_post_with_executor<Executor>(ex), token);
+}
+
+template <typename ExecutionContext,
+    ASIO_COMPLETION_TOKEN_FOR(void()) CompletionToken>
+inline ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void()) post(
+    ExecutionContext& ctx, ASIO_MOVE_ARG(CompletionToken) token,
+    typename enable_if<is_convertible<
+      ExecutionContext&, execution_context&>::value>::type*)
+{
+  return async_initiate<CompletionToken, void()>(
+      detail::initiate_post_with_executor<
+        typename ExecutionContext::executor_type>(
+          ctx.get_executor()), token);
+}
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IMPL_POST_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/impl/read.hpp b/link/modules/asio-standalone/asio/include/asio/impl/read.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/impl/read.hpp
@@ -0,0 +1,1202 @@
+//
+// impl/read.hpp
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_IMPL_READ_HPP
+#define ASIO_IMPL_READ_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <algorithm>
+#include "asio/associated_allocator.hpp"
+#include "asio/associated_executor.hpp"
+#include "asio/buffer.hpp"
+#include "asio/completion_condition.hpp"
+#include "asio/detail/array_fwd.hpp"
+#include "asio/detail/base_from_completion_cond.hpp"
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/consuming_buffers.hpp"
+#include "asio/detail/dependent_type.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_cont_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/handler_tracking.hpp"
+#include "asio/detail/handler_type_requirements.hpp"
+#include "asio/detail/non_const_lvalue.hpp"
+#include "asio/detail/throw_error.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+namespace detail
+{
+  template <typename SyncReadStream, typename MutableBufferSequence,
+      typename MutableBufferIterator, typename CompletionCondition>
+  std::size_t read_buffer_sequence(SyncReadStream& s,
+      const MutableBufferSequence& buffers, const MutableBufferIterator&,
+      CompletionCondition completion_condition, asio::error_code& ec)
+  {
+    ec = asio::error_code();
+    asio::detail::consuming_buffers<mutable_buffer,
+        MutableBufferSequence, MutableBufferIterator> tmp(buffers);
+    while (!tmp.empty())
+    {
+      if (std::size_t max_size = detail::adapt_completion_condition_result(
+            completion_condition(ec, tmp.total_consumed())))
+        tmp.consume(s.read_some(tmp.prepare(max_size), ec));
+      else
+        break;
+    }
+    return tmp.total_consumed();;
+  }
+} // namespace detail
+
+template <typename SyncReadStream, typename MutableBufferSequence,
+    typename CompletionCondition>
+std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers,
+    CompletionCondition completion_condition, asio::error_code& ec,
+    typename enable_if<
+      is_mutable_buffer_sequence<MutableBufferSequence>::value
+    >::type*)
+{
+  return detail::read_buffer_sequence(s, buffers,
+      asio::buffer_sequence_begin(buffers),
+      ASIO_MOVE_CAST(CompletionCondition)(completion_condition), ec);
+}
+
+template <typename SyncReadStream, typename MutableBufferSequence>
+inline std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers,
+    typename enable_if<
+      is_mutable_buffer_sequence<MutableBufferSequence>::value
+    >::type*)
+{
+  asio::error_code ec;
+  std::size_t bytes_transferred = read(s, buffers, transfer_all(), ec);
+  asio::detail::throw_error(ec, "read");
+  return bytes_transferred;
+}
+
+template <typename SyncReadStream, typename MutableBufferSequence>
+inline std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers,
+    asio::error_code& ec,
+    typename enable_if<
+      is_mutable_buffer_sequence<MutableBufferSequence>::value
+    >::type*)
+{
+  return read(s, buffers, transfer_all(), ec);
+}
+
+template <typename SyncReadStream, typename MutableBufferSequence,
+    typename CompletionCondition>
+inline std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers,
+    CompletionCondition completion_condition,
+    typename enable_if<
+      is_mutable_buffer_sequence<MutableBufferSequence>::value
+    >::type*)
+{
+  asio::error_code ec;
+  std::size_t bytes_transferred = read(s, buffers,
+      ASIO_MOVE_CAST(CompletionCondition)(completion_condition), ec);
+  asio::detail::throw_error(ec, "read");
+  return bytes_transferred;
+}
+
+#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1)
+
+template <typename SyncReadStream, typename DynamicBuffer_v1,
+    typename CompletionCondition>
+std::size_t read(SyncReadStream& s,
+    ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,
+    CompletionCondition completion_condition, asio::error_code& ec,
+    typename enable_if<
+      is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value
+        && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value
+    >::type*)
+{
+  typename decay<DynamicBuffer_v1>::type b(
+      ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers));
+
+  ec = asio::error_code();
+  std::size_t total_transferred = 0;
+  std::size_t max_size = detail::adapt_completion_condition_result(
+        completion_condition(ec, total_transferred));
+  std::size_t bytes_available = std::min<std::size_t>(
+        std::max<std::size_t>(512, b.capacity() - b.size()),
+        std::min<std::size_t>(max_size, b.max_size() - b.size()));
+  while (bytes_available > 0)
+  {
+    std::size_t bytes_transferred = s.read_some(b.prepare(bytes_available), ec);
+    b.commit(bytes_transferred);
+    total_transferred += bytes_transferred;
+    max_size = detail::adapt_completion_condition_result(
+          completion_condition(ec, total_transferred));
+    bytes_available = std::min<std::size_t>(
+          std::max<std::size_t>(512, b.capacity() - b.size()),
+          std::min<std::size_t>(max_size, b.max_size() - b.size()));
+  }
+  return total_transferred;
+}
+
+template <typename SyncReadStream, typename DynamicBuffer_v1>
+inline std::size_t read(SyncReadStream& s,
+    ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,
+    typename enable_if<
+      is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value
+        && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value
+    >::type*)
+{
+  asio::error_code ec;
+  std::size_t bytes_transferred = read(s,
+      ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers), transfer_all(), ec);
+  asio::detail::throw_error(ec, "read");
+  return bytes_transferred;
+}
+
+template <typename SyncReadStream, typename DynamicBuffer_v1>
+inline std::size_t read(SyncReadStream& s,
+    ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,
+    asio::error_code& ec,
+    typename enable_if<
+      is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value
+        && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value
+    >::type*)
+{
+  return read(s, ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers),
+      transfer_all(), ec);
+}
+
+template <typename SyncReadStream, typename DynamicBuffer_v1,
+    typename CompletionCondition>
+inline std::size_t read(SyncReadStream& s,
+    ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,
+    CompletionCondition completion_condition,
+    typename enable_if<
+      is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value
+        && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value
+    >::type*)
+{
+  asio::error_code ec;
+  std::size_t bytes_transferred = read(s,
+      ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers),
+      ASIO_MOVE_CAST(CompletionCondition)(completion_condition), ec);
+  asio::detail::throw_error(ec, "read");
+  return bytes_transferred;
+}
+
+#if !defined(ASIO_NO_EXTENSIONS)
+#if !defined(ASIO_NO_IOSTREAM)
+
+template <typename SyncReadStream, typename Allocator,
+    typename CompletionCondition>
+inline std::size_t read(SyncReadStream& s,
+    asio::basic_streambuf<Allocator>& b,
+    CompletionCondition completion_condition, asio::error_code& ec)
+{
+  return read(s, basic_streambuf_ref<Allocator>(b),
+      ASIO_MOVE_CAST(CompletionCondition)(completion_condition), ec);
+}
+
+template <typename SyncReadStream, typename Allocator>
+inline std::size_t read(SyncReadStream& s,
+    asio::basic_streambuf<Allocator>& b)
+{
+  return read(s, basic_streambuf_ref<Allocator>(b));
+}
+
+template <typename SyncReadStream, typename Allocator>
+inline std::size_t read(SyncReadStream& s,
+    asio::basic_streambuf<Allocator>& b,
+    asio::error_code& ec)
+{
+  return read(s, basic_streambuf_ref<Allocator>(b), ec);
+}
+
+template <typename SyncReadStream, typename Allocator,
+    typename CompletionCondition>
+inline std::size_t read(SyncReadStream& s,
+    asio::basic_streambuf<Allocator>& b,
+    CompletionCondition completion_condition)
+{
+  return read(s, basic_streambuf_ref<Allocator>(b),
+      ASIO_MOVE_CAST(CompletionCondition)(completion_condition));
+}
+
+#endif // !defined(ASIO_NO_IOSTREAM)
+#endif // !defined(ASIO_NO_EXTENSIONS)
+#endif // !defined(ASIO_NO_DYNAMIC_BUFFER_V1)
+
+template <typename SyncReadStream, typename DynamicBuffer_v2,
+    typename CompletionCondition>
+std::size_t read(SyncReadStream& s, DynamicBuffer_v2 buffers,
+    CompletionCondition completion_condition, asio::error_code& ec,
+    typename enable_if<
+      is_dynamic_buffer_v2<DynamicBuffer_v2>::value
+    >::type*)
+{
+  DynamicBuffer_v2& b = buffers;
+
+  ec = asio::error_code();
+  std::size_t total_transferred = 0;
+  std::size_t max_size = detail::adapt_completion_condition_result(
+        completion_condition(ec, total_transferred));
+  std::size_t bytes_available = std::min<std::size_t>(
+        std::max<std::size_t>(512, b.capacity() - b.size()),
+        std::min<std::size_t>(max_size, b.max_size() - b.size()));
+  while (bytes_available > 0)
+  {
+    std::size_t pos = b.size();
+    b.grow(bytes_available);
+    std::size_t bytes_transferred = s.read_some(
+        b.data(pos, bytes_available), ec);
+    b.shrink(bytes_available - bytes_transferred);
+    total_transferred += bytes_transferred;
+    max_size = detail::adapt_completion_condition_result(
+          completion_condition(ec, total_transferred));
+    bytes_available = std::min<std::size_t>(
+          std::max<std::size_t>(512, b.capacity() - b.size()),
+          std::min<std::size_t>(max_size, b.max_size() - b.size()));
+  }
+  return total_transferred;
+}
+
+template <typename SyncReadStream, typename DynamicBuffer_v2>
+inline std::size_t read(SyncReadStream& s, DynamicBuffer_v2 buffers,
+    typename enable_if<
+      is_dynamic_buffer_v2<DynamicBuffer_v2>::value
+    >::type*)
+{
+  asio::error_code ec;
+  std::size_t bytes_transferred = read(s,
+      ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers), transfer_all(), ec);
+  asio::detail::throw_error(ec, "read");
+  return bytes_transferred;
+}
+
+template <typename SyncReadStream, typename DynamicBuffer_v2>
+inline std::size_t read(SyncReadStream& s, DynamicBuffer_v2 buffers,
+    asio::error_code& ec,
+    typename enable_if<
+      is_dynamic_buffer_v2<DynamicBuffer_v2>::value
+    >::type*)
+{
+  return read(s, ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers),
+      transfer_all(), ec);
+}
+
+template <typename SyncReadStream, typename DynamicBuffer_v2,
+    typename CompletionCondition>
+inline std::size_t read(SyncReadStream& s, DynamicBuffer_v2 buffers,
+    CompletionCondition completion_condition,
+    typename enable_if<
+      is_dynamic_buffer_v2<DynamicBuffer_v2>::value
+    >::type*)
+{
+  asio::error_code ec;
+  std::size_t bytes_transferred = read(s,
+      ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers),
+      ASIO_MOVE_CAST(CompletionCondition)(completion_condition), ec);
+  asio::detail::throw_error(ec, "read");
+  return bytes_transferred;
+}
+
+namespace detail
+{
+  template <typename AsyncReadStream, typename MutableBufferSequence,
+      typename MutableBufferIterator, typename CompletionCondition,
+      typename ReadHandler>
+  class read_op
+    : detail::base_from_completion_cond<CompletionCondition>
+  {
+  public:
+    read_op(AsyncReadStream& stream, const MutableBufferSequence& buffers,
+        CompletionCondition& completion_condition, ReadHandler& handler)
+      : detail::base_from_completion_cond<
+          CompletionCondition>(completion_condition),
+        stream_(stream),
+        buffers_(buffers),
+        start_(0),
+        handler_(ASIO_MOVE_CAST(ReadHandler)(handler))
+    {
+    }
+
+#if defined(ASIO_HAS_MOVE)
+    read_op(const read_op& other)
+      : detail::base_from_completion_cond<CompletionCondition>(other),
+        stream_(other.stream_),
+        buffers_(other.buffers_),
+        start_(other.start_),
+        handler_(other.handler_)
+    {
+    }
+
+    read_op(read_op&& other)
+      : detail::base_from_completion_cond<CompletionCondition>(
+          ASIO_MOVE_CAST(detail::base_from_completion_cond<
+            CompletionCondition>)(other)),
+        stream_(other.stream_),
+        buffers_(ASIO_MOVE_CAST(buffers_type)(other.buffers_)),
+        start_(other.start_),
+        handler_(ASIO_MOVE_CAST(ReadHandler)(other.handler_))
+    {
+    }
+#endif // defined(ASIO_HAS_MOVE)
+
+    void operator()(const asio::error_code& ec,
+        std::size_t bytes_transferred, int start = 0)
+    {
+      std::size_t max_size;
+      switch (start_ = start)
+      {
+        case 1:
+        max_size = this->check_for_completion(ec, buffers_.total_consumed());
+        do
+        {
+          {
+            ASIO_HANDLER_LOCATION((__FILE__, __LINE__, "async_read"));
+            stream_.async_read_some(buffers_.prepare(max_size),
+                ASIO_MOVE_CAST(read_op)(*this));
+          }
+          return; default:
+          buffers_.consume(bytes_transferred);
+          if ((!ec && bytes_transferred == 0) || buffers_.empty())
+            break;
+          max_size = this->check_for_completion(ec, buffers_.total_consumed());
+        } while (max_size > 0);
+
+        handler_(ec, buffers_.total_consumed());
+      }
+    }
+
+  //private:
+    typedef asio::detail::consuming_buffers<mutable_buffer,
+        MutableBufferSequence, MutableBufferIterator> buffers_type;
+
+    AsyncReadStream& stream_;
+    buffers_type buffers_;
+    int start_;
+    ReadHandler handler_;
+  };
+
+  template <typename AsyncReadStream, typename MutableBufferSequence,
+      typename MutableBufferIterator, typename CompletionCondition,
+      typename ReadHandler>
+  inline asio_handler_allocate_is_deprecated
+  asio_handler_allocate(std::size_t size,
+      read_op<AsyncReadStream, MutableBufferSequence, MutableBufferIterator,
+        CompletionCondition, ReadHandler>* this_handler)
+  {
+#if defined(ASIO_NO_DEPRECATED)
+    asio_handler_alloc_helpers::allocate(size, this_handler->handler_);
+    return asio_handler_allocate_is_no_longer_used();
+#else // defined(ASIO_NO_DEPRECATED)
+    return asio_handler_alloc_helpers::allocate(
+        size, this_handler->handler_);
+#endif // defined(ASIO_NO_DEPRECATED)
+  }
+
+  template <typename AsyncReadStream, typename MutableBufferSequence,
+      typename MutableBufferIterator, typename CompletionCondition,
+      typename ReadHandler>
+  inline asio_handler_deallocate_is_deprecated
+  asio_handler_deallocate(void* pointer, std::size_t size,
+      read_op<AsyncReadStream, MutableBufferSequence, MutableBufferIterator,
+        CompletionCondition, ReadHandler>* this_handler)
+  {
+    asio_handler_alloc_helpers::deallocate(
+        pointer, size, this_handler->handler_);
+#if defined(ASIO_NO_DEPRECATED)
+    return asio_handler_deallocate_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+  }
+
+  template <typename AsyncReadStream, typename MutableBufferSequence,
+      typename MutableBufferIterator, typename CompletionCondition,
+      typename ReadHandler>
+  inline bool asio_handler_is_continuation(
+      read_op<AsyncReadStream, MutableBufferSequence, MutableBufferIterator,
+        CompletionCondition, ReadHandler>* this_handler)
+  {
+    return this_handler->start_ == 0 ? true
+      : asio_handler_cont_helpers::is_continuation(
+          this_handler->handler_);
+  }
+
+  template <typename Function, typename AsyncReadStream,
+      typename MutableBufferSequence, typename MutableBufferIterator,
+      typename CompletionCondition, typename ReadHandler>
+  inline asio_handler_invoke_is_deprecated
+  asio_handler_invoke(Function& function,
+      read_op<AsyncReadStream, MutableBufferSequence, MutableBufferIterator,
+        CompletionCondition, ReadHandler>* this_handler)
+  {
+    asio_handler_invoke_helpers::invoke(
+        function, this_handler->handler_);
+#if defined(ASIO_NO_DEPRECATED)
+    return asio_handler_invoke_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+  }
+
+  template <typename Function, typename AsyncReadStream,
+      typename MutableBufferSequence, typename MutableBufferIterator,
+      typename CompletionCondition, typename ReadHandler>
+  inline asio_handler_invoke_is_deprecated
+  asio_handler_invoke(const Function& function,
+      read_op<AsyncReadStream, MutableBufferSequence, MutableBufferIterator,
+        CompletionCondition, ReadHandler>* this_handler)
+  {
+    asio_handler_invoke_helpers::invoke(
+        function, this_handler->handler_);
+#if defined(ASIO_NO_DEPRECATED)
+    return asio_handler_invoke_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+  }
+
+  template <typename AsyncReadStream, typename MutableBufferSequence,
+      typename MutableBufferIterator, typename CompletionCondition,
+      typename ReadHandler>
+  inline void start_read_buffer_sequence_op(AsyncReadStream& stream,
+      const MutableBufferSequence& buffers, const MutableBufferIterator&,
+      CompletionCondition& completion_condition, ReadHandler& handler)
+  {
+    detail::read_op<AsyncReadStream, MutableBufferSequence,
+      MutableBufferIterator, CompletionCondition, ReadHandler>(
+        stream, buffers, completion_condition, handler)(
+          asio::error_code(), 0, 1);
+  }
+
+  template <typename AsyncReadStream>
+  class initiate_async_read_buffer_sequence
+  {
+  public:
+    typedef typename AsyncReadStream::executor_type executor_type;
+
+    explicit initiate_async_read_buffer_sequence(AsyncReadStream& stream)
+      : stream_(stream)
+    {
+    }
+
+    executor_type get_executor() const ASIO_NOEXCEPT
+    {
+      return stream_.get_executor();
+    }
+
+    template <typename ReadHandler, typename MutableBufferSequence,
+        typename CompletionCondition>
+    void operator()(ASIO_MOVE_ARG(ReadHandler) handler,
+        const MutableBufferSequence& buffers,
+        ASIO_MOVE_ARG(CompletionCondition) completion_cond) const
+    {
+      // If you get an error on the following line it means that your handler
+      // does not meet the documented type requirements for a ReadHandler.
+      ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
+
+      non_const_lvalue<ReadHandler> handler2(handler);
+      non_const_lvalue<CompletionCondition> completion_cond2(completion_cond);
+      start_read_buffer_sequence_op(stream_, buffers,
+          asio::buffer_sequence_begin(buffers),
+          completion_cond2.value, handler2.value);
+    }
+
+  private:
+    AsyncReadStream& stream_;
+  };
+} // namespace detail
+
+#if !defined(GENERATING_DOCUMENTATION)
+
+template <typename AsyncReadStream, typename MutableBufferSequence,
+    typename MutableBufferIterator, typename CompletionCondition,
+    typename ReadHandler, typename Allocator>
+struct associated_allocator<
+    detail::read_op<AsyncReadStream, MutableBufferSequence,
+      MutableBufferIterator, CompletionCondition, ReadHandler>,
+    Allocator>
+{
+  typedef typename associated_allocator<ReadHandler, Allocator>::type type;
+
+  static type get(
+      const detail::read_op<AsyncReadStream, MutableBufferSequence,
+        MutableBufferIterator, CompletionCondition, ReadHandler>& h,
+      const Allocator& a = Allocator()) ASIO_NOEXCEPT
+  {
+    return associated_allocator<ReadHandler, Allocator>::get(h.handler_, a);
+  }
+};
+
+template <typename AsyncReadStream, typename MutableBufferSequence,
+    typename MutableBufferIterator, typename CompletionCondition,
+    typename ReadHandler, typename Executor>
+struct associated_executor<
+    detail::read_op<AsyncReadStream, MutableBufferSequence,
+      MutableBufferIterator, CompletionCondition, ReadHandler>,
+    Executor>
+  : detail::associated_executor_forwarding_base<ReadHandler, Executor>
+{
+  typedef typename associated_executor<ReadHandler, Executor>::type type;
+
+  static type get(
+      const detail::read_op<AsyncReadStream, MutableBufferSequence,
+        MutableBufferIterator, CompletionCondition, ReadHandler>& h,
+      const Executor& ex = Executor()) ASIO_NOEXCEPT
+  {
+    return associated_executor<ReadHandler, Executor>::get(h.handler_, ex);
+  }
+};
+
+#endif // !defined(GENERATING_DOCUMENTATION)
+
+template <typename AsyncReadStream,
+    typename MutableBufferSequence, typename CompletionCondition,
+    ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+      std::size_t)) ReadHandler>
+inline ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,
+    void (asio::error_code, std::size_t))
+async_read(AsyncReadStream& s, const MutableBufferSequence& buffers,
+    CompletionCondition completion_condition,
+    ASIO_MOVE_ARG(ReadHandler) handler,
+    typename enable_if<
+      is_mutable_buffer_sequence<MutableBufferSequence>::value
+    >::type*)
+{
+  return async_initiate<ReadHandler,
+    void (asio::error_code, std::size_t)>(
+      detail::initiate_async_read_buffer_sequence<AsyncReadStream>(s), handler,
+      buffers, ASIO_MOVE_CAST(CompletionCondition)(completion_condition));
+}
+
+template <typename AsyncReadStream, typename MutableBufferSequence,
+    ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+      std::size_t)) ReadHandler>
+inline ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,
+    void (asio::error_code, std::size_t))
+async_read(AsyncReadStream& s, const MutableBufferSequence& buffers,
+    ASIO_MOVE_ARG(ReadHandler) handler,
+    typename enable_if<
+      is_mutable_buffer_sequence<MutableBufferSequence>::value
+    >::type*)
+{
+  return async_initiate<ReadHandler,
+    void (asio::error_code, std::size_t)>(
+      detail::initiate_async_read_buffer_sequence<AsyncReadStream>(s),
+      handler, buffers, transfer_all());
+}
+
+#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1)
+
+namespace detail
+{
+  template <typename AsyncReadStream, typename DynamicBuffer_v1,
+      typename CompletionCondition, typename ReadHandler>
+  class read_dynbuf_v1_op
+    : detail::base_from_completion_cond<CompletionCondition>
+  {
+  public:
+    template <typename BufferSequence>
+    read_dynbuf_v1_op(AsyncReadStream& stream,
+        ASIO_MOVE_ARG(BufferSequence) buffers,
+        CompletionCondition& completion_condition, ReadHandler& handler)
+      : detail::base_from_completion_cond<
+          CompletionCondition>(completion_condition),
+        stream_(stream),
+        buffers_(ASIO_MOVE_CAST(BufferSequence)(buffers)),
+        start_(0),
+        total_transferred_(0),
+        handler_(ASIO_MOVE_CAST(ReadHandler)(handler))
+    {
+    }
+
+#if defined(ASIO_HAS_MOVE)
+    read_dynbuf_v1_op(const read_dynbuf_v1_op& other)
+      : detail::base_from_completion_cond<CompletionCondition>(other),
+        stream_(other.stream_),
+        buffers_(other.buffers_),
+        start_(other.start_),
+        total_transferred_(other.total_transferred_),
+        handler_(other.handler_)
+    {
+    }
+
+    read_dynbuf_v1_op(read_dynbuf_v1_op&& other)
+      : detail::base_from_completion_cond<CompletionCondition>(
+          ASIO_MOVE_CAST(detail::base_from_completion_cond<
+            CompletionCondition>)(other)),
+        stream_(other.stream_),
+        buffers_(ASIO_MOVE_CAST(DynamicBuffer_v1)(other.buffers_)),
+        start_(other.start_),
+        total_transferred_(other.total_transferred_),
+        handler_(ASIO_MOVE_CAST(ReadHandler)(other.handler_))
+    {
+    }
+#endif // defined(ASIO_HAS_MOVE)
+
+    void operator()(const asio::error_code& ec,
+        std::size_t bytes_transferred, int start = 0)
+    {
+      std::size_t max_size, bytes_available;
+      switch (start_ = start)
+      {
+        case 1:
+        max_size = this->check_for_completion(ec, total_transferred_);
+        bytes_available = std::min<std::size_t>(
+              std::max<std::size_t>(512,
+                buffers_.capacity() - buffers_.size()),
+              std::min<std::size_t>(max_size,
+                buffers_.max_size() - buffers_.size()));
+        for (;;)
+        {
+          {
+            ASIO_HANDLER_LOCATION((__FILE__, __LINE__, "async_read"));
+            stream_.async_read_some(buffers_.prepare(bytes_available),
+                ASIO_MOVE_CAST(read_dynbuf_v1_op)(*this));
+          }
+          return; default:
+          total_transferred_ += bytes_transferred;
+          buffers_.commit(bytes_transferred);
+          max_size = this->check_for_completion(ec, total_transferred_);
+          bytes_available = std::min<std::size_t>(
+                std::max<std::size_t>(512,
+                  buffers_.capacity() - buffers_.size()),
+                std::min<std::size_t>(max_size,
+                  buffers_.max_size() - buffers_.size()));
+          if ((!ec && bytes_transferred == 0) || bytes_available == 0)
+            break;
+        }
+
+        handler_(ec, static_cast<const std::size_t&>(total_transferred_));
+      }
+    }
+
+  //private:
+    AsyncReadStream& stream_;
+    DynamicBuffer_v1 buffers_;
+    int start_;
+    std::size_t total_transferred_;
+    ReadHandler handler_;
+  };
+
+  template <typename AsyncReadStream, typename DynamicBuffer_v1,
+      typename CompletionCondition, typename ReadHandler>
+  inline asio_handler_allocate_is_deprecated
+  asio_handler_allocate(std::size_t size,
+      read_dynbuf_v1_op<AsyncReadStream, DynamicBuffer_v1,
+        CompletionCondition, ReadHandler>* this_handler)
+  {
+#if defined(ASIO_NO_DEPRECATED)
+    asio_handler_alloc_helpers::allocate(size, this_handler->handler_);
+    return asio_handler_allocate_is_no_longer_used();
+#else // defined(ASIO_NO_DEPRECATED)
+    return asio_handler_alloc_helpers::allocate(
+        size, this_handler->handler_);
+#endif // defined(ASIO_NO_DEPRECATED)
+  }
+
+  template <typename AsyncReadStream, typename DynamicBuffer_v1,
+      typename CompletionCondition, typename ReadHandler>
+  inline asio_handler_deallocate_is_deprecated
+  asio_handler_deallocate(void* pointer, std::size_t size,
+      read_dynbuf_v1_op<AsyncReadStream, DynamicBuffer_v1,
+        CompletionCondition, ReadHandler>* this_handler)
+  {
+    asio_handler_alloc_helpers::deallocate(
+        pointer, size, this_handler->handler_);
+#if defined(ASIO_NO_DEPRECATED)
+    return asio_handler_deallocate_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+  }
+
+  template <typename AsyncReadStream, typename DynamicBuffer_v1,
+      typename CompletionCondition, typename ReadHandler>
+  inline bool asio_handler_is_continuation(
+      read_dynbuf_v1_op<AsyncReadStream, DynamicBuffer_v1,
+        CompletionCondition, ReadHandler>* this_handler)
+  {
+    return this_handler->start_ == 0 ? true
+      : asio_handler_cont_helpers::is_continuation(
+          this_handler->handler_);
+  }
+
+  template <typename Function, typename AsyncReadStream,
+      typename DynamicBuffer_v1, typename CompletionCondition,
+      typename ReadHandler>
+  inline asio_handler_invoke_is_deprecated
+  asio_handler_invoke(Function& function,
+      read_dynbuf_v1_op<AsyncReadStream, DynamicBuffer_v1,
+        CompletionCondition, ReadHandler>* this_handler)
+  {
+    asio_handler_invoke_helpers::invoke(
+        function, this_handler->handler_);
+#if defined(ASIO_NO_DEPRECATED)
+    return asio_handler_invoke_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+  }
+
+  template <typename Function, typename AsyncReadStream,
+      typename DynamicBuffer_v1, typename CompletionCondition,
+      typename ReadHandler>
+  inline asio_handler_invoke_is_deprecated
+  asio_handler_invoke(const Function& function,
+      read_dynbuf_v1_op<AsyncReadStream, DynamicBuffer_v1,
+        CompletionCondition, ReadHandler>* this_handler)
+  {
+    asio_handler_invoke_helpers::invoke(
+        function, this_handler->handler_);
+#if defined(ASIO_NO_DEPRECATED)
+    return asio_handler_invoke_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+  }
+
+  template <typename AsyncReadStream>
+  class initiate_async_read_dynbuf_v1
+  {
+  public:
+    typedef typename AsyncReadStream::executor_type executor_type;
+
+    explicit initiate_async_read_dynbuf_v1(AsyncReadStream& stream)
+      : stream_(stream)
+    {
+    }
+
+    executor_type get_executor() const ASIO_NOEXCEPT
+    {
+      return stream_.get_executor();
+    }
+
+    template <typename ReadHandler, typename DynamicBuffer_v1,
+        typename CompletionCondition>
+    void operator()(ASIO_MOVE_ARG(ReadHandler) handler,
+        ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,
+        ASIO_MOVE_ARG(CompletionCondition) completion_cond) const
+    {
+      // If you get an error on the following line it means that your handler
+      // does not meet the documented type requirements for a ReadHandler.
+      ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
+
+      non_const_lvalue<ReadHandler> handler2(handler);
+      non_const_lvalue<CompletionCondition> completion_cond2(completion_cond);
+      read_dynbuf_v1_op<AsyncReadStream, typename decay<DynamicBuffer_v1>::type,
+        CompletionCondition, typename decay<ReadHandler>::type>(
+          stream_, ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers),
+            completion_cond2.value, handler2.value)(
+              asio::error_code(), 0, 1);
+    }
+
+  private:
+    AsyncReadStream& stream_;
+  };
+} // namespace detail
+
+#if !defined(GENERATING_DOCUMENTATION)
+
+template <typename AsyncReadStream, typename DynamicBuffer_v1,
+    typename CompletionCondition, typename ReadHandler, typename Allocator>
+struct associated_allocator<
+    detail::read_dynbuf_v1_op<AsyncReadStream,
+      DynamicBuffer_v1, CompletionCondition, ReadHandler>,
+    Allocator>
+{
+  typedef typename associated_allocator<ReadHandler, Allocator>::type type;
+
+  static type get(
+      const detail::read_dynbuf_v1_op<AsyncReadStream,
+        DynamicBuffer_v1, CompletionCondition, ReadHandler>& h,
+      const Allocator& a = Allocator()) ASIO_NOEXCEPT
+  {
+    return associated_allocator<ReadHandler, Allocator>::get(h.handler_, a);
+  }
+};
+
+template <typename AsyncReadStream, typename DynamicBuffer_v1,
+    typename CompletionCondition, typename ReadHandler, typename Executor>
+struct associated_executor<
+    detail::read_dynbuf_v1_op<AsyncReadStream,
+      DynamicBuffer_v1, CompletionCondition, ReadHandler>,
+    Executor>
+  : detail::associated_executor_forwarding_base<ReadHandler, Executor>
+{
+  typedef typename associated_executor<ReadHandler, Executor>::type type;
+
+  static type get(
+      const detail::read_dynbuf_v1_op<AsyncReadStream,
+        DynamicBuffer_v1, CompletionCondition, ReadHandler>& h,
+      const Executor& ex = Executor()) ASIO_NOEXCEPT
+  {
+    return associated_executor<ReadHandler, Executor>::get(h.handler_, ex);
+  }
+};
+
+#endif // !defined(GENERATING_DOCUMENTATION)
+
+template <typename AsyncReadStream, typename DynamicBuffer_v1,
+    ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+      std::size_t)) ReadHandler>
+inline ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,
+    void (asio::error_code, std::size_t))
+async_read(AsyncReadStream& s,
+    ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,
+    ASIO_MOVE_ARG(ReadHandler) handler,
+    typename enable_if<
+      is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value
+        && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value
+    >::type*)
+{
+  return async_read(s,
+      ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers),
+      transfer_all(), ASIO_MOVE_CAST(ReadHandler)(handler));
+}
+
+template <typename AsyncReadStream,
+    typename DynamicBuffer_v1, typename CompletionCondition,
+    ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+      std::size_t)) ReadHandler>
+inline ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,
+    void (asio::error_code, std::size_t))
+async_read(AsyncReadStream& s,
+    ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,
+    CompletionCondition completion_condition,
+    ASIO_MOVE_ARG(ReadHandler) handler,
+    typename enable_if<
+      is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value
+        && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value
+    >::type*)
+{
+  return async_initiate<ReadHandler,
+    void (asio::error_code, std::size_t)>(
+      detail::initiate_async_read_dynbuf_v1<AsyncReadStream>(s),
+      handler, ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers),
+      ASIO_MOVE_CAST(CompletionCondition)(completion_condition));
+}
+
+#if !defined(ASIO_NO_EXTENSIONS)
+#if !defined(ASIO_NO_IOSTREAM)
+
+template <typename AsyncReadStream, typename Allocator,
+    ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+      std::size_t)) ReadHandler>
+inline ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,
+    void (asio::error_code, std::size_t))
+async_read(AsyncReadStream& s, basic_streambuf<Allocator>& b,
+    ASIO_MOVE_ARG(ReadHandler) handler)
+{
+  return async_read(s, basic_streambuf_ref<Allocator>(b),
+      ASIO_MOVE_CAST(ReadHandler)(handler));
+}
+
+template <typename AsyncReadStream,
+    typename Allocator, typename CompletionCondition,
+    ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+      std::size_t)) ReadHandler>
+inline ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,
+    void (asio::error_code, std::size_t))
+async_read(AsyncReadStream& s, basic_streambuf<Allocator>& b,
+    CompletionCondition completion_condition,
+    ASIO_MOVE_ARG(ReadHandler) handler)
+{
+  return async_read(s, basic_streambuf_ref<Allocator>(b),
+      ASIO_MOVE_CAST(CompletionCondition)(completion_condition),
+      ASIO_MOVE_CAST(ReadHandler)(handler));
+}
+
+#endif // !defined(ASIO_NO_IOSTREAM)
+#endif // !defined(ASIO_NO_EXTENSIONS)
+#endif // !defined(ASIO_NO_DYNAMIC_BUFFER_V1)
+
+namespace detail
+{
+  template <typename AsyncReadStream, typename DynamicBuffer_v2,
+      typename CompletionCondition, typename ReadHandler>
+  class read_dynbuf_v2_op
+    : detail::base_from_completion_cond<CompletionCondition>
+  {
+  public:
+    template <typename BufferSequence>
+    read_dynbuf_v2_op(AsyncReadStream& stream,
+        ASIO_MOVE_ARG(BufferSequence) buffers,
+        CompletionCondition& completion_condition, ReadHandler& handler)
+      : detail::base_from_completion_cond<
+          CompletionCondition>(completion_condition),
+        stream_(stream),
+        buffers_(ASIO_MOVE_CAST(BufferSequence)(buffers)),
+        start_(0),
+        total_transferred_(0),
+        bytes_available_(0),
+        handler_(ASIO_MOVE_CAST(ReadHandler)(handler))
+    {
+    }
+
+#if defined(ASIO_HAS_MOVE)
+    read_dynbuf_v2_op(const read_dynbuf_v2_op& other)
+      : detail::base_from_completion_cond<CompletionCondition>(other),
+        stream_(other.stream_),
+        buffers_(other.buffers_),
+        start_(other.start_),
+        total_transferred_(other.total_transferred_),
+        bytes_available_(other.bytes_available_),
+        handler_(other.handler_)
+    {
+    }
+
+    read_dynbuf_v2_op(read_dynbuf_v2_op&& other)
+      : detail::base_from_completion_cond<CompletionCondition>(
+          ASIO_MOVE_CAST(detail::base_from_completion_cond<
+            CompletionCondition>)(other)),
+        stream_(other.stream_),
+        buffers_(ASIO_MOVE_CAST(DynamicBuffer_v2)(other.buffers_)),
+        start_(other.start_),
+        total_transferred_(other.total_transferred_),
+        bytes_available_(other.bytes_available_),
+        handler_(ASIO_MOVE_CAST(ReadHandler)(other.handler_))
+    {
+    }
+#endif // defined(ASIO_HAS_MOVE)
+
+    void operator()(const asio::error_code& ec,
+        std::size_t bytes_transferred, int start = 0)
+    {
+      std::size_t max_size, pos;
+      switch (start_ = start)
+      {
+        case 1:
+        max_size = this->check_for_completion(ec, total_transferred_);
+        bytes_available_ = std::min<std::size_t>(
+              std::max<std::size_t>(512,
+                buffers_.capacity() - buffers_.size()),
+              std::min<std::size_t>(max_size,
+                buffers_.max_size() - buffers_.size()));
+        for (;;)
+        {
+          pos = buffers_.size();
+          buffers_.grow(bytes_available_);
+          {
+            ASIO_HANDLER_LOCATION((__FILE__, __LINE__, "async_read"));
+            stream_.async_read_some(buffers_.data(pos, bytes_available_),
+                ASIO_MOVE_CAST(read_dynbuf_v2_op)(*this));
+          }
+          return; default:
+          total_transferred_ += bytes_transferred;
+          buffers_.shrink(bytes_available_ - bytes_transferred);
+          max_size = this->check_for_completion(ec, total_transferred_);
+          bytes_available_ = std::min<std::size_t>(
+                std::max<std::size_t>(512,
+                  buffers_.capacity() - buffers_.size()),
+                std::min<std::size_t>(max_size,
+                  buffers_.max_size() - buffers_.size()));
+          if ((!ec && bytes_transferred == 0) || bytes_available_ == 0)
+            break;
+        }
+
+        handler_(ec, static_cast<const std::size_t&>(total_transferred_));
+      }
+    }
+
+  //private:
+    AsyncReadStream& stream_;
+    DynamicBuffer_v2 buffers_;
+    int start_;
+    std::size_t total_transferred_;
+    std::size_t bytes_available_;
+    ReadHandler handler_;
+  };
+
+  template <typename AsyncReadStream, typename DynamicBuffer_v2,
+      typename CompletionCondition, typename ReadHandler>
+  inline asio_handler_allocate_is_deprecated
+  asio_handler_allocate(std::size_t size,
+      read_dynbuf_v2_op<AsyncReadStream, DynamicBuffer_v2,
+        CompletionCondition, ReadHandler>* this_handler)
+  {
+#if defined(ASIO_NO_DEPRECATED)
+    asio_handler_alloc_helpers::allocate(size, this_handler->handler_);
+    return asio_handler_allocate_is_no_longer_used();
+#else // defined(ASIO_NO_DEPRECATED)
+    return asio_handler_alloc_helpers::allocate(
+        size, this_handler->handler_);
+#endif // defined(ASIO_NO_DEPRECATED)
+  }
+
+  template <typename AsyncReadStream, typename DynamicBuffer_v2,
+      typename CompletionCondition, typename ReadHandler>
+  inline asio_handler_deallocate_is_deprecated
+  asio_handler_deallocate(void* pointer, std::size_t size,
+      read_dynbuf_v2_op<AsyncReadStream, DynamicBuffer_v2,
+        CompletionCondition, ReadHandler>* this_handler)
+  {
+    asio_handler_alloc_helpers::deallocate(
+        pointer, size, this_handler->handler_);
+#if defined(ASIO_NO_DEPRECATED)
+    return asio_handler_deallocate_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+  }
+
+  template <typename AsyncReadStream, typename DynamicBuffer_v2,
+      typename CompletionCondition, typename ReadHandler>
+  inline bool asio_handler_is_continuation(
+      read_dynbuf_v2_op<AsyncReadStream, DynamicBuffer_v2,
+        CompletionCondition, ReadHandler>* this_handler)
+  {
+    return this_handler->start_ == 0 ? true
+      : asio_handler_cont_helpers::is_continuation(
+          this_handler->handler_);
+  }
+
+  template <typename Function, typename AsyncReadStream,
+      typename DynamicBuffer_v2, typename CompletionCondition,
+      typename ReadHandler>
+  inline asio_handler_invoke_is_deprecated
+  asio_handler_invoke(Function& function,
+      read_dynbuf_v2_op<AsyncReadStream, DynamicBuffer_v2,
+        CompletionCondition, ReadHandler>* this_handler)
+  {
+    asio_handler_invoke_helpers::invoke(
+        function, this_handler->handler_);
+#if defined(ASIO_NO_DEPRECATED)
+    return asio_handler_invoke_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+  }
+
+  template <typename Function, typename AsyncReadStream,
+      typename DynamicBuffer_v2, typename CompletionCondition,
+      typename ReadHandler>
+  inline asio_handler_invoke_is_deprecated
+  asio_handler_invoke(const Function& function,
+      read_dynbuf_v2_op<AsyncReadStream, DynamicBuffer_v2,
+        CompletionCondition, ReadHandler>* this_handler)
+  {
+    asio_handler_invoke_helpers::invoke(
+        function, this_handler->handler_);
+#if defined(ASIO_NO_DEPRECATED)
+    return asio_handler_invoke_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+  }
+
+  template <typename AsyncReadStream>
+  class initiate_async_read_dynbuf_v2
+  {
+  public:
+    typedef typename AsyncReadStream::executor_type executor_type;
+
+    explicit initiate_async_read_dynbuf_v2(AsyncReadStream& stream)
+      : stream_(stream)
+    {
+    }
+
+    executor_type get_executor() const ASIO_NOEXCEPT
+    {
+      return stream_.get_executor();
+    }
+
+    template <typename ReadHandler, typename DynamicBuffer_v2,
+        typename CompletionCondition>
+    void operator()(ASIO_MOVE_ARG(ReadHandler) handler,
+        ASIO_MOVE_ARG(DynamicBuffer_v2) buffers,
+        ASIO_MOVE_ARG(CompletionCondition) completion_cond) const
+    {
+      // If you get an error on the following line it means that your handler
+      // does not meet the documented type requirements for a ReadHandler.
+      ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
+
+      non_const_lvalue<ReadHandler> handler2(handler);
+      non_const_lvalue<CompletionCondition> completion_cond2(completion_cond);
+      read_dynbuf_v2_op<AsyncReadStream, typename decay<DynamicBuffer_v2>::type,
+        CompletionCondition, typename decay<ReadHandler>::type>(
+          stream_, ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers),
+            completion_cond2.value, handler2.value)(
+              asio::error_code(), 0, 1);
+    }
+
+  private:
+    AsyncReadStream& stream_;
+  };
+} // namespace detail
+
+#if !defined(GENERATING_DOCUMENTATION)
+
+template <typename AsyncReadStream, typename DynamicBuffer_v2,
+    typename CompletionCondition, typename ReadHandler, typename Allocator>
+struct associated_allocator<
+    detail::read_dynbuf_v2_op<AsyncReadStream,
+      DynamicBuffer_v2, CompletionCondition, ReadHandler>,
+    Allocator>
+{
+  typedef typename associated_allocator<ReadHandler, Allocator>::type type;
+
+  static type get(
+      const detail::read_dynbuf_v2_op<AsyncReadStream,
+        DynamicBuffer_v2, CompletionCondition, ReadHandler>& h,
+      const Allocator& a = Allocator()) ASIO_NOEXCEPT
+  {
+    return associated_allocator<ReadHandler, Allocator>::get(h.handler_, a);
+  }
+};
+
+template <typename AsyncReadStream, typename DynamicBuffer_v2,
+    typename CompletionCondition, typename ReadHandler, typename Executor>
+struct associated_executor<
+    detail::read_dynbuf_v2_op<AsyncReadStream,
+      DynamicBuffer_v2, CompletionCondition, ReadHandler>,
+    Executor>
+  : detail::associated_executor_forwarding_base<ReadHandler, Executor>
+{
+  typedef typename associated_executor<ReadHandler, Executor>::type type;
+
+  static type get(
+      const detail::read_dynbuf_v2_op<AsyncReadStream,
+        DynamicBuffer_v2, CompletionCondition, ReadHandler>& h,
+      const Executor& ex = Executor()) ASIO_NOEXCEPT
+  {
+    return associated_executor<ReadHandler, Executor>::get(h.handler_, ex);
+  }
+};
+
+#endif // !defined(GENERATING_DOCUMENTATION)
+
+template <typename AsyncReadStream, typename DynamicBuffer_v2,
+    ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+      std::size_t)) ReadHandler>
+inline ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,
+    void (asio::error_code, std::size_t))
+async_read(AsyncReadStream& s, DynamicBuffer_v2 buffers,
+    ASIO_MOVE_ARG(ReadHandler) handler,
+    typename enable_if<
+      is_dynamic_buffer_v2<DynamicBuffer_v2>::value
+    >::type*)
+{
+  return async_read(s,
+      ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers),
+      transfer_all(), ASIO_MOVE_CAST(ReadHandler)(handler));
+}
+
+template <typename AsyncReadStream,
+    typename DynamicBuffer_v2, typename CompletionCondition,
+    ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+      std::size_t)) ReadHandler>
+inline ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,
+    void (asio::error_code, std::size_t))
+async_read(AsyncReadStream& s, DynamicBuffer_v2 buffers,
+    CompletionCondition completion_condition,
+    ASIO_MOVE_ARG(ReadHandler) handler,
+    typename enable_if<
+      is_dynamic_buffer_v2<DynamicBuffer_v2>::value
+    >::type*)
+{
+  return async_initiate<ReadHandler,
+    void (asio::error_code, std::size_t)>(
+      detail::initiate_async_read_dynbuf_v2<AsyncReadStream>(s),
+      handler, ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers),
+      ASIO_MOVE_CAST(CompletionCondition)(completion_condition));
+}
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IMPL_READ_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/impl/read_at.hpp b/link/modules/asio-standalone/asio/include/asio/impl/read_at.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/impl/read_at.hpp
@@ -0,0 +1,744 @@
+//
+// impl/read_at.hpp
+// ~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_IMPL_READ_AT_HPP
+#define ASIO_IMPL_READ_AT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <algorithm>
+#include "asio/associated_allocator.hpp"
+#include "asio/associated_executor.hpp"
+#include "asio/buffer.hpp"
+#include "asio/completion_condition.hpp"
+#include "asio/detail/array_fwd.hpp"
+#include "asio/detail/base_from_completion_cond.hpp"
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/consuming_buffers.hpp"
+#include "asio/detail/dependent_type.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_cont_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/handler_tracking.hpp"
+#include "asio/detail/handler_type_requirements.hpp"
+#include "asio/detail/non_const_lvalue.hpp"
+#include "asio/detail/throw_error.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+namespace detail
+{
+  template <typename SyncRandomAccessReadDevice, typename MutableBufferSequence,
+      typename MutableBufferIterator, typename CompletionCondition>
+  std::size_t read_at_buffer_sequence(SyncRandomAccessReadDevice& d,
+      uint64_t offset, const MutableBufferSequence& buffers,
+      const MutableBufferIterator&, CompletionCondition completion_condition,
+      asio::error_code& ec)
+  {
+    ec = asio::error_code();
+    asio::detail::consuming_buffers<mutable_buffer,
+        MutableBufferSequence, MutableBufferIterator> tmp(buffers);
+    while (!tmp.empty())
+    {
+      if (std::size_t max_size = detail::adapt_completion_condition_result(
+            completion_condition(ec, tmp.total_consumed())))
+      {
+        tmp.consume(d.read_some_at(offset + tmp.total_consumed(),
+              tmp.prepare(max_size), ec));
+      }
+      else
+        break;
+    }
+    return tmp.total_consumed();;
+  }
+} // namespace detail
+
+template <typename SyncRandomAccessReadDevice, typename MutableBufferSequence,
+    typename CompletionCondition>
+std::size_t read_at(SyncRandomAccessReadDevice& d,
+    uint64_t offset, const MutableBufferSequence& buffers,
+    CompletionCondition completion_condition, asio::error_code& ec)
+{
+  return detail::read_at_buffer_sequence(d, offset, buffers,
+      asio::buffer_sequence_begin(buffers),
+      ASIO_MOVE_CAST(CompletionCondition)(completion_condition), ec);
+}
+
+template <typename SyncRandomAccessReadDevice, typename MutableBufferSequence>
+inline std::size_t read_at(SyncRandomAccessReadDevice& d,
+    uint64_t offset, const MutableBufferSequence& buffers)
+{
+  asio::error_code ec;
+  std::size_t bytes_transferred = read_at(
+      d, offset, buffers, transfer_all(), ec);
+  asio::detail::throw_error(ec, "read_at");
+  return bytes_transferred;
+}
+
+template <typename SyncRandomAccessReadDevice, typename MutableBufferSequence>
+inline std::size_t read_at(SyncRandomAccessReadDevice& d,
+    uint64_t offset, const MutableBufferSequence& buffers,
+    asio::error_code& ec)
+{
+  return read_at(d, offset, buffers, transfer_all(), ec);
+}
+
+template <typename SyncRandomAccessReadDevice, typename MutableBufferSequence,
+    typename CompletionCondition>
+inline std::size_t read_at(SyncRandomAccessReadDevice& d,
+    uint64_t offset, const MutableBufferSequence& buffers,
+    CompletionCondition completion_condition)
+{
+  asio::error_code ec;
+  std::size_t bytes_transferred = read_at(d, offset, buffers,
+      ASIO_MOVE_CAST(CompletionCondition)(completion_condition), ec);
+  asio::detail::throw_error(ec, "read_at");
+  return bytes_transferred;
+}
+
+#if !defined(ASIO_NO_EXTENSIONS)
+#if !defined(ASIO_NO_IOSTREAM)
+
+template <typename SyncRandomAccessReadDevice, typename Allocator,
+    typename CompletionCondition>
+std::size_t read_at(SyncRandomAccessReadDevice& d,
+    uint64_t offset, asio::basic_streambuf<Allocator>& b,
+    CompletionCondition completion_condition, asio::error_code& ec)
+{
+  ec = asio::error_code();
+  std::size_t total_transferred = 0;
+  std::size_t max_size = detail::adapt_completion_condition_result(
+        completion_condition(ec, total_transferred));
+  std::size_t bytes_available = read_size_helper(b, max_size);
+  while (bytes_available > 0)
+  {
+    std::size_t bytes_transferred = d.read_some_at(
+        offset + total_transferred, b.prepare(bytes_available), ec);
+    b.commit(bytes_transferred);
+    total_transferred += bytes_transferred;
+    max_size = detail::adapt_completion_condition_result(
+          completion_condition(ec, total_transferred));
+    bytes_available = read_size_helper(b, max_size);
+  }
+  return total_transferred;
+}
+
+template <typename SyncRandomAccessReadDevice, typename Allocator>
+inline std::size_t read_at(SyncRandomAccessReadDevice& d,
+    uint64_t offset, asio::basic_streambuf<Allocator>& b)
+{
+  asio::error_code ec;
+  std::size_t bytes_transferred = read_at(
+      d, offset, b, transfer_all(), ec);
+  asio::detail::throw_error(ec, "read_at");
+  return bytes_transferred;
+}
+
+template <typename SyncRandomAccessReadDevice, typename Allocator>
+inline std::size_t read_at(SyncRandomAccessReadDevice& d,
+    uint64_t offset, asio::basic_streambuf<Allocator>& b,
+    asio::error_code& ec)
+{
+  return read_at(d, offset, b, transfer_all(), ec);
+}
+
+template <typename SyncRandomAccessReadDevice, typename Allocator,
+    typename CompletionCondition>
+inline std::size_t read_at(SyncRandomAccessReadDevice& d,
+    uint64_t offset, asio::basic_streambuf<Allocator>& b,
+    CompletionCondition completion_condition)
+{
+  asio::error_code ec;
+  std::size_t bytes_transferred = read_at(d, offset, b,
+      ASIO_MOVE_CAST(CompletionCondition)(completion_condition), ec);
+  asio::detail::throw_error(ec, "read_at");
+  return bytes_transferred;
+}
+
+#endif // !defined(ASIO_NO_IOSTREAM)
+#endif // !defined(ASIO_NO_EXTENSIONS)
+
+namespace detail
+{
+  template <typename AsyncRandomAccessReadDevice,
+      typename MutableBufferSequence, typename MutableBufferIterator,
+      typename CompletionCondition, typename ReadHandler>
+  class read_at_op
+    : detail::base_from_completion_cond<CompletionCondition>
+  {
+  public:
+    read_at_op(AsyncRandomAccessReadDevice& device,
+        uint64_t offset, const MutableBufferSequence& buffers,
+        CompletionCondition& completion_condition, ReadHandler& handler)
+      : detail::base_from_completion_cond<
+          CompletionCondition>(completion_condition),
+        device_(device),
+        offset_(offset),
+        buffers_(buffers),
+        start_(0),
+        handler_(ASIO_MOVE_CAST(ReadHandler)(handler))
+    {
+    }
+
+#if defined(ASIO_HAS_MOVE)
+    read_at_op(const read_at_op& other)
+      : detail::base_from_completion_cond<CompletionCondition>(other),
+        device_(other.device_),
+        offset_(other.offset_),
+        buffers_(other.buffers_),
+        start_(other.start_),
+        handler_(other.handler_)
+    {
+    }
+
+    read_at_op(read_at_op&& other)
+      : detail::base_from_completion_cond<CompletionCondition>(
+          ASIO_MOVE_CAST(detail::base_from_completion_cond<
+            CompletionCondition>)(other)),
+        device_(other.device_),
+        offset_(other.offset_),
+        buffers_(ASIO_MOVE_CAST(buffers_type)(other.buffers_)),
+        start_(other.start_),
+        handler_(ASIO_MOVE_CAST(ReadHandler)(other.handler_))
+    {
+    }
+#endif // defined(ASIO_HAS_MOVE)
+
+    void operator()(const asio::error_code& ec,
+        std::size_t bytes_transferred, int start = 0)
+    {
+      std::size_t max_size;
+      switch (start_ = start)
+      {
+        case 1:
+        max_size = this->check_for_completion(ec, buffers_.total_consumed());
+        do
+        {
+          {
+            ASIO_HANDLER_LOCATION((__FILE__, __LINE__, "async_read_at"));
+            device_.async_read_some_at(
+                offset_ + buffers_.total_consumed(), buffers_.prepare(max_size),
+                ASIO_MOVE_CAST(read_at_op)(*this));
+          }
+          return; default:
+          buffers_.consume(bytes_transferred);
+          if ((!ec && bytes_transferred == 0) || buffers_.empty())
+            break;
+          max_size = this->check_for_completion(ec, buffers_.total_consumed());
+        } while (max_size > 0);
+
+        handler_(ec, buffers_.total_consumed());
+      }
+    }
+
+  //private:
+    typedef asio::detail::consuming_buffers<mutable_buffer,
+        MutableBufferSequence, MutableBufferIterator> buffers_type;
+
+    AsyncRandomAccessReadDevice& device_;
+    uint64_t offset_;
+    buffers_type buffers_;
+    int start_;
+    ReadHandler handler_;
+  };
+
+  template <typename AsyncRandomAccessReadDevice,
+      typename MutableBufferSequence, typename MutableBufferIterator,
+      typename CompletionCondition, typename ReadHandler>
+  inline asio_handler_allocate_is_deprecated
+  asio_handler_allocate(std::size_t size,
+      read_at_op<AsyncRandomAccessReadDevice, MutableBufferSequence,
+        MutableBufferIterator, CompletionCondition, ReadHandler>* this_handler)
+  {
+#if defined(ASIO_NO_DEPRECATED)
+    asio_handler_alloc_helpers::allocate(size, this_handler->handler_);
+    return asio_handler_allocate_is_no_longer_used();
+#else // defined(ASIO_NO_DEPRECATED)
+    return asio_handler_alloc_helpers::allocate(
+        size, this_handler->handler_);
+#endif // defined(ASIO_NO_DEPRECATED)
+  }
+
+  template <typename AsyncRandomAccessReadDevice,
+      typename MutableBufferSequence, typename MutableBufferIterator,
+      typename CompletionCondition, typename ReadHandler>
+  inline asio_handler_deallocate_is_deprecated
+  asio_handler_deallocate(void* pointer, std::size_t size,
+      read_at_op<AsyncRandomAccessReadDevice, MutableBufferSequence,
+        MutableBufferIterator, CompletionCondition, ReadHandler>* this_handler)
+  {
+    asio_handler_alloc_helpers::deallocate(
+        pointer, size, this_handler->handler_);
+#if defined(ASIO_NO_DEPRECATED)
+    return asio_handler_deallocate_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+  }
+
+  template <typename AsyncRandomAccessReadDevice,
+      typename MutableBufferSequence, typename MutableBufferIterator,
+      typename CompletionCondition, typename ReadHandler>
+  inline bool asio_handler_is_continuation(
+      read_at_op<AsyncRandomAccessReadDevice, MutableBufferSequence,
+        MutableBufferIterator, CompletionCondition, ReadHandler>* this_handler)
+  {
+    return this_handler->start_ == 0 ? true
+      : asio_handler_cont_helpers::is_continuation(
+          this_handler->handler_);
+  }
+
+  template <typename Function, typename AsyncRandomAccessReadDevice,
+      typename MutableBufferSequence, typename MutableBufferIterator,
+      typename CompletionCondition, typename ReadHandler>
+  inline asio_handler_invoke_is_deprecated
+  asio_handler_invoke(Function& function,
+      read_at_op<AsyncRandomAccessReadDevice, MutableBufferSequence,
+        MutableBufferIterator, CompletionCondition, ReadHandler>* this_handler)
+  {
+    asio_handler_invoke_helpers::invoke(
+        function, this_handler->handler_);
+#if defined(ASIO_NO_DEPRECATED)
+    return asio_handler_invoke_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+  }
+
+  template <typename Function, typename AsyncRandomAccessReadDevice,
+      typename MutableBufferSequence, typename MutableBufferIterator,
+      typename CompletionCondition, typename ReadHandler>
+  inline asio_handler_invoke_is_deprecated
+  asio_handler_invoke(const Function& function,
+      read_at_op<AsyncRandomAccessReadDevice, MutableBufferSequence,
+        MutableBufferIterator, CompletionCondition, ReadHandler>* this_handler)
+  {
+    asio_handler_invoke_helpers::invoke(
+        function, this_handler->handler_);
+#if defined(ASIO_NO_DEPRECATED)
+    return asio_handler_invoke_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+  }
+
+  template <typename AsyncRandomAccessReadDevice,
+      typename MutableBufferSequence, typename MutableBufferIterator,
+      typename CompletionCondition, typename ReadHandler>
+  inline void start_read_at_buffer_sequence_op(AsyncRandomAccessReadDevice& d,
+      uint64_t offset, const MutableBufferSequence& buffers,
+      const MutableBufferIterator&, CompletionCondition& completion_condition,
+      ReadHandler& handler)
+  {
+    detail::read_at_op<AsyncRandomAccessReadDevice, MutableBufferSequence,
+      MutableBufferIterator, CompletionCondition, ReadHandler>(
+        d, offset, buffers, completion_condition, handler)(
+          asio::error_code(), 0, 1);
+  }
+
+  template <typename AsyncRandomAccessReadDevice>
+  class initiate_async_read_at_buffer_sequence
+  {
+  public:
+    typedef typename AsyncRandomAccessReadDevice::executor_type executor_type;
+
+    explicit initiate_async_read_at_buffer_sequence(
+        AsyncRandomAccessReadDevice& device)
+      : device_(device)
+    {
+    }
+
+    executor_type get_executor() const ASIO_NOEXCEPT
+    {
+      return device_.get_executor();
+    }
+
+    template <typename ReadHandler, typename MutableBufferSequence,
+        typename CompletionCondition>
+    void operator()(ASIO_MOVE_ARG(ReadHandler) handler,
+        uint64_t offset, const MutableBufferSequence& buffers,
+        ASIO_MOVE_ARG(CompletionCondition) completion_cond) const
+    {
+      // If you get an error on the following line it means that your handler
+      // does not meet the documented type requirements for a ReadHandler.
+      ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
+
+      non_const_lvalue<ReadHandler> handler2(handler);
+      non_const_lvalue<CompletionCondition> completion_cond2(completion_cond);
+      start_read_at_buffer_sequence_op(device_, offset, buffers,
+          asio::buffer_sequence_begin(buffers),
+          completion_cond2.value, handler2.value);
+    }
+
+  private:
+    AsyncRandomAccessReadDevice& device_;
+  };
+} // namespace detail
+
+#if !defined(GENERATING_DOCUMENTATION)
+
+template <typename AsyncRandomAccessReadDevice,
+    typename MutableBufferSequence, typename MutableBufferIterator,
+    typename CompletionCondition, typename ReadHandler, typename Allocator>
+struct associated_allocator<
+    detail::read_at_op<AsyncRandomAccessReadDevice, MutableBufferSequence,
+    MutableBufferIterator, CompletionCondition, ReadHandler>,
+    Allocator>
+{
+  typedef typename associated_allocator<ReadHandler, Allocator>::type type;
+
+  static type get(
+      const detail::read_at_op<AsyncRandomAccessReadDevice,
+      MutableBufferSequence, MutableBufferIterator,
+      CompletionCondition, ReadHandler>& h,
+      const Allocator& a = Allocator()) ASIO_NOEXCEPT
+  {
+    return associated_allocator<ReadHandler, Allocator>::get(h.handler_, a);
+  }
+};
+
+template <typename AsyncRandomAccessReadDevice,
+    typename MutableBufferSequence, typename MutableBufferIterator,
+    typename CompletionCondition, typename ReadHandler, typename Executor>
+struct associated_executor<
+    detail::read_at_op<AsyncRandomAccessReadDevice, MutableBufferSequence,
+    MutableBufferIterator, CompletionCondition, ReadHandler>,
+    Executor>
+  : detail::associated_executor_forwarding_base<ReadHandler, Executor>
+{
+  typedef typename associated_executor<ReadHandler, Executor>::type type;
+
+  static type get(
+      const detail::read_at_op<AsyncRandomAccessReadDevice,
+      MutableBufferSequence, MutableBufferIterator,
+      CompletionCondition, ReadHandler>& h,
+      const Executor& ex = Executor()) ASIO_NOEXCEPT
+  {
+    return associated_executor<ReadHandler, Executor>::get(h.handler_, ex);
+  }
+};
+
+#endif // !defined(GENERATING_DOCUMENTATION)
+
+template <typename AsyncRandomAccessReadDevice,
+    typename MutableBufferSequence, typename CompletionCondition,
+    ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+      std::size_t)) ReadHandler>
+inline ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,
+    void (asio::error_code, std::size_t))
+async_read_at(AsyncRandomAccessReadDevice& d,
+    uint64_t offset, const MutableBufferSequence& buffers,
+    CompletionCondition completion_condition,
+    ASIO_MOVE_ARG(ReadHandler) handler)
+{
+  return async_initiate<ReadHandler,
+    void (asio::error_code, std::size_t)>(
+      detail::initiate_async_read_at_buffer_sequence<
+        AsyncRandomAccessReadDevice>(d),
+      handler, offset, buffers,
+      ASIO_MOVE_CAST(CompletionCondition)(completion_condition));
+}
+
+template <typename AsyncRandomAccessReadDevice, typename MutableBufferSequence,
+    ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+      std::size_t)) ReadHandler>
+inline ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,
+    void (asio::error_code, std::size_t))
+async_read_at(AsyncRandomAccessReadDevice& d,
+    uint64_t offset, const MutableBufferSequence& buffers,
+    ASIO_MOVE_ARG(ReadHandler) handler)
+{
+  return async_initiate<ReadHandler,
+    void (asio::error_code, std::size_t)>(
+      detail::initiate_async_read_at_buffer_sequence<
+        AsyncRandomAccessReadDevice>(d),
+      handler, offset, buffers, transfer_all());
+}
+
+#if !defined(ASIO_NO_EXTENSIONS)
+#if !defined(ASIO_NO_IOSTREAM)
+
+namespace detail
+{
+  template <typename AsyncRandomAccessReadDevice, typename Allocator,
+      typename CompletionCondition, typename ReadHandler>
+  class read_at_streambuf_op
+    : detail::base_from_completion_cond<CompletionCondition>
+  {
+  public:
+    read_at_streambuf_op(AsyncRandomAccessReadDevice& device,
+        uint64_t offset, basic_streambuf<Allocator>& streambuf,
+        CompletionCondition& completion_condition, ReadHandler& handler)
+      : detail::base_from_completion_cond<
+          CompletionCondition>(completion_condition),
+        device_(device),
+        offset_(offset),
+        streambuf_(streambuf),
+        start_(0),
+        total_transferred_(0),
+        handler_(ASIO_MOVE_CAST(ReadHandler)(handler))
+    {
+    }
+
+#if defined(ASIO_HAS_MOVE)
+    read_at_streambuf_op(const read_at_streambuf_op& other)
+      : detail::base_from_completion_cond<CompletionCondition>(other),
+        device_(other.device_),
+        offset_(other.offset_),
+        streambuf_(other.streambuf_),
+        start_(other.start_),
+        total_transferred_(other.total_transferred_),
+        handler_(other.handler_)
+    {
+    }
+
+    read_at_streambuf_op(read_at_streambuf_op&& other)
+      : detail::base_from_completion_cond<CompletionCondition>(
+          ASIO_MOVE_CAST(detail::base_from_completion_cond<
+            CompletionCondition>)(other)),
+        device_(other.device_),
+        offset_(other.offset_),
+        streambuf_(other.streambuf_),
+        start_(other.start_),
+        total_transferred_(other.total_transferred_),
+        handler_(ASIO_MOVE_CAST(ReadHandler)(other.handler_))
+    {
+    }
+#endif // defined(ASIO_HAS_MOVE)
+
+    void operator()(const asio::error_code& ec,
+        std::size_t bytes_transferred, int start = 0)
+    {
+      std::size_t max_size, bytes_available;
+      switch (start_ = start)
+      {
+        case 1:
+        max_size = this->check_for_completion(ec, total_transferred_);
+        bytes_available = read_size_helper(streambuf_, max_size);
+        for (;;)
+        {
+          {
+            ASIO_HANDLER_LOCATION((__FILE__, __LINE__, "async_read_at"));
+            device_.async_read_some_at(offset_ + total_transferred_,
+                streambuf_.prepare(bytes_available),
+                ASIO_MOVE_CAST(read_at_streambuf_op)(*this));
+          }
+          return; default:
+          total_transferred_ += bytes_transferred;
+          streambuf_.commit(bytes_transferred);
+          max_size = this->check_for_completion(ec, total_transferred_);
+          bytes_available = read_size_helper(streambuf_, max_size);
+          if ((!ec && bytes_transferred == 0) || bytes_available == 0)
+            break;
+        }
+
+        handler_(ec, static_cast<const std::size_t&>(total_transferred_));
+      }
+    }
+
+  //private:
+    AsyncRandomAccessReadDevice& device_;
+    uint64_t offset_;
+    asio::basic_streambuf<Allocator>& streambuf_;
+    int start_;
+    std::size_t total_transferred_;
+    ReadHandler handler_;
+  };
+
+  template <typename AsyncRandomAccessReadDevice, typename Allocator,
+      typename CompletionCondition, typename ReadHandler>
+  inline asio_handler_allocate_is_deprecated
+  asio_handler_allocate(std::size_t size,
+      read_at_streambuf_op<AsyncRandomAccessReadDevice, Allocator,
+        CompletionCondition, ReadHandler>* this_handler)
+  {
+#if defined(ASIO_NO_DEPRECATED)
+    asio_handler_alloc_helpers::allocate(size, this_handler->handler_);
+    return asio_handler_allocate_is_no_longer_used();
+#else // defined(ASIO_NO_DEPRECATED)
+    return asio_handler_alloc_helpers::allocate(
+        size, this_handler->handler_);
+#endif // defined(ASIO_NO_DEPRECATED)
+  }
+
+  template <typename AsyncRandomAccessReadDevice, typename Allocator,
+      typename CompletionCondition, typename ReadHandler>
+  inline asio_handler_deallocate_is_deprecated
+  asio_handler_deallocate(void* pointer, std::size_t size,
+      read_at_streambuf_op<AsyncRandomAccessReadDevice, Allocator,
+        CompletionCondition, ReadHandler>* this_handler)
+  {
+    asio_handler_alloc_helpers::deallocate(
+        pointer, size, this_handler->handler_);
+#if defined(ASIO_NO_DEPRECATED)
+    return asio_handler_deallocate_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+  }
+
+  template <typename AsyncRandomAccessReadDevice, typename Allocator,
+      typename CompletionCondition, typename ReadHandler>
+  inline bool asio_handler_is_continuation(
+      read_at_streambuf_op<AsyncRandomAccessReadDevice, Allocator,
+        CompletionCondition, ReadHandler>* this_handler)
+  {
+    return this_handler->start_ == 0 ? true
+      : asio_handler_cont_helpers::is_continuation(
+          this_handler->handler_);
+  }
+
+  template <typename Function, typename AsyncRandomAccessReadDevice,
+      typename Allocator, typename CompletionCondition, typename ReadHandler>
+  inline asio_handler_invoke_is_deprecated
+  asio_handler_invoke(Function& function,
+      read_at_streambuf_op<AsyncRandomAccessReadDevice, Allocator,
+        CompletionCondition, ReadHandler>* this_handler)
+  {
+    asio_handler_invoke_helpers::invoke(
+        function, this_handler->handler_);
+#if defined(ASIO_NO_DEPRECATED)
+    return asio_handler_invoke_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+  }
+
+  template <typename Function, typename AsyncRandomAccessReadDevice,
+      typename Allocator, typename CompletionCondition, typename ReadHandler>
+  inline asio_handler_invoke_is_deprecated
+  asio_handler_invoke(const Function& function,
+      read_at_streambuf_op<AsyncRandomAccessReadDevice, Allocator,
+        CompletionCondition, ReadHandler>* this_handler)
+  {
+    asio_handler_invoke_helpers::invoke(
+        function, this_handler->handler_);
+#if defined(ASIO_NO_DEPRECATED)
+    return asio_handler_invoke_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+  }
+
+  template <typename AsyncRandomAccessReadDevice>
+  class initiate_async_read_at_streambuf
+  {
+  public:
+    typedef typename AsyncRandomAccessReadDevice::executor_type executor_type;
+
+    explicit initiate_async_read_at_streambuf(
+        AsyncRandomAccessReadDevice& device)
+      : device_(device)
+    {
+    }
+
+    executor_type get_executor() const ASIO_NOEXCEPT
+    {
+      return device_.get_executor();
+    }
+
+    template <typename ReadHandler,
+        typename Allocator, typename CompletionCondition>
+    void operator()(ASIO_MOVE_ARG(ReadHandler) handler,
+        uint64_t offset, basic_streambuf<Allocator>* b,
+        ASIO_MOVE_ARG(CompletionCondition) completion_cond) const
+    {
+      // If you get an error on the following line it means that your handler
+      // does not meet the documented type requirements for a ReadHandler.
+      ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
+
+      non_const_lvalue<ReadHandler> handler2(handler);
+      non_const_lvalue<CompletionCondition> completion_cond2(completion_cond);
+      read_at_streambuf_op<AsyncRandomAccessReadDevice, Allocator,
+        CompletionCondition, typename decay<ReadHandler>::type>(
+          device_, offset, *b, completion_cond2.value, handler2.value)(
+            asio::error_code(), 0, 1);
+    }
+
+  private:
+    AsyncRandomAccessReadDevice& device_;
+  };
+} // namespace detail
+
+#if !defined(GENERATING_DOCUMENTATION)
+
+template <typename AsyncRandomAccessReadDevice, typename Allocator,
+    typename CompletionCondition, typename ReadHandler, typename Allocator1>
+struct associated_allocator<
+    detail::read_at_streambuf_op<AsyncRandomAccessReadDevice,
+      Allocator, CompletionCondition, ReadHandler>,
+    Allocator1>
+{
+  typedef typename associated_allocator<ReadHandler, Allocator1>::type type;
+
+  static type get(
+      const detail::read_at_streambuf_op<AsyncRandomAccessReadDevice,
+        Allocator, CompletionCondition, ReadHandler>& h,
+      const Allocator1& a = Allocator1()) ASIO_NOEXCEPT
+  {
+    return associated_allocator<ReadHandler, Allocator1>::get(h.handler_, a);
+  }
+};
+
+template <typename AsyncRandomAccessReadDevice, typename Executor,
+    typename CompletionCondition, typename ReadHandler, typename Executor1>
+struct associated_executor<
+    detail::read_at_streambuf_op<AsyncRandomAccessReadDevice,
+      Executor, CompletionCondition, ReadHandler>,
+    Executor1>
+  : detail::associated_executor_forwarding_base<ReadHandler, Executor>
+{
+  typedef typename associated_executor<ReadHandler, Executor1>::type type;
+
+  static type get(
+      const detail::read_at_streambuf_op<AsyncRandomAccessReadDevice,
+        Executor, CompletionCondition, ReadHandler>& h,
+      const Executor1& ex = Executor1()) ASIO_NOEXCEPT
+  {
+    return associated_executor<ReadHandler, Executor1>::get(h.handler_, ex);
+  }
+};
+
+#endif // !defined(GENERATING_DOCUMENTATION)
+
+template <typename AsyncRandomAccessReadDevice,
+    typename Allocator, typename CompletionCondition,
+    ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+      std::size_t)) ReadHandler>
+inline ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,
+    void (asio::error_code, std::size_t))
+async_read_at(AsyncRandomAccessReadDevice& d,
+    uint64_t offset, asio::basic_streambuf<Allocator>& b,
+    CompletionCondition completion_condition,
+    ASIO_MOVE_ARG(ReadHandler) handler)
+{
+  return async_initiate<ReadHandler,
+    void (asio::error_code, std::size_t)>(
+      detail::initiate_async_read_at_streambuf<AsyncRandomAccessReadDevice>(d),
+      handler, offset, &b,
+      ASIO_MOVE_CAST(CompletionCondition)(completion_condition));
+}
+
+template <typename AsyncRandomAccessReadDevice, typename Allocator,
+    ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+      std::size_t)) ReadHandler>
+inline ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,
+    void (asio::error_code, std::size_t))
+async_read_at(AsyncRandomAccessReadDevice& d,
+    uint64_t offset, asio::basic_streambuf<Allocator>& b,
+    ASIO_MOVE_ARG(ReadHandler) handler)
+{
+  return async_initiate<ReadHandler,
+    void (asio::error_code, std::size_t)>(
+      detail::initiate_async_read_at_streambuf<AsyncRandomAccessReadDevice>(d),
+      handler, offset, &b, transfer_all());
+}
+
+#endif // !defined(ASIO_NO_IOSTREAM)
+#endif // !defined(ASIO_NO_EXTENSIONS)
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IMPL_READ_AT_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/impl/read_until.hpp b/link/modules/asio-standalone/asio/include/asio/impl/read_until.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/impl/read_until.hpp
@@ -0,0 +1,3335 @@
+//
+// impl/read_until.hpp
+// ~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_IMPL_READ_UNTIL_HPP
+#define ASIO_IMPL_READ_UNTIL_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <algorithm>
+#include <string>
+#include <vector>
+#include <utility>
+#include "asio/associated_allocator.hpp"
+#include "asio/associated_executor.hpp"
+#include "asio/buffer.hpp"
+#include "asio/buffers_iterator.hpp"
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_cont_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/handler_tracking.hpp"
+#include "asio/detail/handler_type_requirements.hpp"
+#include "asio/detail/limits.hpp"
+#include "asio/detail/non_const_lvalue.hpp"
+#include "asio/detail/throw_error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+namespace detail
+{
+  // Algorithm that finds a subsequence of equal values in a sequence. Returns
+  // (iterator,true) if a full match was found, in which case the iterator
+  // points to the beginning of the match. Returns (iterator,false) if a
+  // partial match was found at the end of the first sequence, in which case
+  // the iterator points to the beginning of the partial match. Returns
+  // (last1,false) if no full or partial match was found.
+  template <typename Iterator1, typename Iterator2>
+  std::pair<Iterator1, bool> partial_search(
+      Iterator1 first1, Iterator1 last1, Iterator2 first2, Iterator2 last2)
+  {
+    for (Iterator1 iter1 = first1; iter1 != last1; ++iter1)
+    {
+      Iterator1 test_iter1 = iter1;
+      Iterator2 test_iter2 = first2;
+      for (;; ++test_iter1, ++test_iter2)
+      {
+        if (test_iter2 == last2)
+          return std::make_pair(iter1, true);
+        if (test_iter1 == last1)
+        {
+          if (test_iter2 != first2)
+            return std::make_pair(iter1, false);
+          else
+            break;
+        }
+        if (*test_iter1 != *test_iter2)
+          break;
+      }
+    }
+    return std::make_pair(last1, false);
+  }
+} // namespace detail
+
+#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1)
+
+template <typename SyncReadStream, typename DynamicBuffer_v1>
+inline std::size_t read_until(SyncReadStream& s,
+    ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, char delim,
+    typename enable_if<
+      is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value
+        && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value
+    >::type*)
+{
+  asio::error_code ec;
+  std::size_t bytes_transferred = read_until(s,
+      ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers), delim, ec);
+  asio::detail::throw_error(ec, "read_until");
+  return bytes_transferred;
+}
+
+template <typename SyncReadStream, typename DynamicBuffer_v1>
+std::size_t read_until(SyncReadStream& s,
+    ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,
+    char delim, asio::error_code& ec,
+    typename enable_if<
+      is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value
+        && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value
+    >::type*)
+{
+  typename decay<DynamicBuffer_v1>::type b(
+      ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers));
+
+  std::size_t search_position = 0;
+  for (;;)
+  {
+    // Determine the range of the data to be searched.
+    typedef typename DynamicBuffer_v1::const_buffers_type buffers_type;
+    typedef buffers_iterator<buffers_type> iterator;
+    buffers_type data_buffers = b.data();
+    iterator begin = iterator::begin(data_buffers);
+    iterator start_pos = begin + search_position;
+    iterator end = iterator::end(data_buffers);
+
+    // Look for a match.
+    iterator iter = std::find(start_pos, end, delim);
+    if (iter != end)
+    {
+      // Found a match. We're done.
+      ec = asio::error_code();
+      return iter - begin + 1;
+    }
+    else
+    {
+      // No match. Next search can start with the new data.
+      search_position = end - begin;
+    }
+
+    // Check if buffer is full.
+    if (b.size() == b.max_size())
+    {
+      ec = error::not_found;
+      return 0;
+    }
+
+    // Need more data.
+    std::size_t bytes_to_read = std::min<std::size_t>(
+          std::max<std::size_t>(512, b.capacity() - b.size()),
+          std::min<std::size_t>(65536, b.max_size() - b.size()));
+    b.commit(s.read_some(b.prepare(bytes_to_read), ec));
+    if (ec)
+      return 0;
+  }
+}
+
+template <typename SyncReadStream, typename DynamicBuffer_v1>
+inline std::size_t read_until(SyncReadStream& s,
+    ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,
+    ASIO_STRING_VIEW_PARAM delim,
+    typename enable_if<
+      is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value
+        && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value
+    >::type*)
+{
+  asio::error_code ec;
+  std::size_t bytes_transferred = read_until(s,
+      ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers), delim, ec);
+  asio::detail::throw_error(ec, "read_until");
+  return bytes_transferred;
+}
+
+template <typename SyncReadStream, typename DynamicBuffer_v1>
+std::size_t read_until(SyncReadStream& s,
+    ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,
+    ASIO_STRING_VIEW_PARAM delim, asio::error_code& ec,
+    typename enable_if<
+      is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value
+        && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value
+    >::type*)
+{
+  typename decay<DynamicBuffer_v1>::type b(
+      ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers));
+
+  std::size_t search_position = 0;
+  for (;;)
+  {
+    // Determine the range of the data to be searched.
+    typedef typename DynamicBuffer_v1::const_buffers_type buffers_type;
+    typedef buffers_iterator<buffers_type> iterator;
+    buffers_type data_buffers = b.data();
+    iterator begin = iterator::begin(data_buffers);
+    iterator start_pos = begin + search_position;
+    iterator end = iterator::end(data_buffers);
+
+    // Look for a match.
+    std::pair<iterator, bool> result = detail::partial_search(
+        start_pos, end, delim.begin(), delim.end());
+    if (result.first != end)
+    {
+      if (result.second)
+      {
+        // Full match. We're done.
+        ec = asio::error_code();
+        return result.first - begin + delim.length();
+      }
+      else
+      {
+        // Partial match. Next search needs to start from beginning of match.
+        search_position = result.first - begin;
+      }
+    }
+    else
+    {
+      // No match. Next search can start with the new data.
+      search_position = end - begin;
+    }
+
+    // Check if buffer is full.
+    if (b.size() == b.max_size())
+    {
+      ec = error::not_found;
+      return 0;
+    }
+
+    // Need more data.
+    std::size_t bytes_to_read = std::min<std::size_t>(
+          std::max<std::size_t>(512, b.capacity() - b.size()),
+          std::min<std::size_t>(65536, b.max_size() - b.size()));
+    b.commit(s.read_some(b.prepare(bytes_to_read), ec));
+    if (ec)
+      return 0;
+  }
+}
+
+#if !defined(ASIO_NO_EXTENSIONS)
+#if defined(ASIO_HAS_BOOST_REGEX)
+
+template <typename SyncReadStream, typename DynamicBuffer_v1>
+inline std::size_t read_until(SyncReadStream& s,
+    ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,
+    const boost::regex& expr,
+    typename enable_if<
+      is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value
+        && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value
+    >::type*)
+{
+  asio::error_code ec;
+  std::size_t bytes_transferred = read_until(s,
+      ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers), expr, ec);
+  asio::detail::throw_error(ec, "read_until");
+  return bytes_transferred;
+}
+
+template <typename SyncReadStream, typename DynamicBuffer_v1>
+std::size_t read_until(SyncReadStream& s,
+    ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,
+    const boost::regex& expr, asio::error_code& ec,
+    typename enable_if<
+      is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value
+        && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value
+    >::type*)
+{
+  typename decay<DynamicBuffer_v1>::type b(
+      ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers));
+
+  std::size_t search_position = 0;
+  for (;;)
+  {
+    // Determine the range of the data to be searched.
+    typedef typename DynamicBuffer_v1::const_buffers_type buffers_type;
+    typedef buffers_iterator<buffers_type> iterator;
+    buffers_type data_buffers = b.data();
+    iterator begin = iterator::begin(data_buffers);
+    iterator start_pos = begin + search_position;
+    iterator end = iterator::end(data_buffers);
+
+    // Look for a match.
+    boost::match_results<iterator,
+      typename std::vector<boost::sub_match<iterator> >::allocator_type>
+        match_results;
+    if (regex_search(start_pos, end, match_results, expr,
+          boost::match_default | boost::match_partial))
+    {
+      if (match_results[0].matched)
+      {
+        // Full match. We're done.
+        ec = asio::error_code();
+        return match_results[0].second - begin;
+      }
+      else
+      {
+        // Partial match. Next search needs to start from beginning of match.
+        search_position = match_results[0].first - begin;
+      }
+    }
+    else
+    {
+      // No match. Next search can start with the new data.
+      search_position = end - begin;
+    }
+
+    // Check if buffer is full.
+    if (b.size() == b.max_size())
+    {
+      ec = error::not_found;
+      return 0;
+    }
+
+    // Need more data.
+    std::size_t bytes_to_read = std::min<std::size_t>(
+          std::max<std::size_t>(512, b.capacity() - b.size()),
+          std::min<std::size_t>(65536, b.max_size() - b.size()));
+    b.commit(s.read_some(b.prepare(bytes_to_read), ec));
+    if (ec)
+      return 0;
+  }
+}
+
+#endif // defined(ASIO_HAS_BOOST_REGEX)
+
+template <typename SyncReadStream,
+    typename DynamicBuffer_v1, typename MatchCondition>
+inline std::size_t read_until(SyncReadStream& s,
+    ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,
+    MatchCondition match_condition,
+    typename enable_if<
+      is_match_condition<MatchCondition>::value
+        && is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value
+        && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value
+    >::type*)
+{
+  asio::error_code ec;
+  std::size_t bytes_transferred = read_until(s,
+      ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers),
+      match_condition, ec);
+  asio::detail::throw_error(ec, "read_until");
+  return bytes_transferred;
+}
+
+template <typename SyncReadStream,
+    typename DynamicBuffer_v1, typename MatchCondition>
+std::size_t read_until(SyncReadStream& s,
+    ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,
+    MatchCondition match_condition, asio::error_code& ec,
+    typename enable_if<
+      is_match_condition<MatchCondition>::value
+        && is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value
+        && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value
+    >::type*)
+{
+  typename decay<DynamicBuffer_v1>::type b(
+      ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers));
+
+  std::size_t search_position = 0;
+  for (;;)
+  {
+    // Determine the range of the data to be searched.
+    typedef typename DynamicBuffer_v1::const_buffers_type buffers_type;
+    typedef buffers_iterator<buffers_type> iterator;
+    buffers_type data_buffers = b.data();
+    iterator begin = iterator::begin(data_buffers);
+    iterator start_pos = begin + search_position;
+    iterator end = iterator::end(data_buffers);
+
+    // Look for a match.
+    std::pair<iterator, bool> result = match_condition(start_pos, end);
+    if (result.second)
+    {
+      // Full match. We're done.
+      ec = asio::error_code();
+      return result.first - begin;
+    }
+    else if (result.first != end)
+    {
+      // Partial match. Next search needs to start from beginning of match.
+      search_position = result.first - begin;
+    }
+    else
+    {
+      // No match. Next search can start with the new data.
+      search_position = end - begin;
+    }
+
+    // Check if buffer is full.
+    if (b.size() == b.max_size())
+    {
+      ec = error::not_found;
+      return 0;
+    }
+
+    // Need more data.
+    std::size_t bytes_to_read = std::min<std::size_t>(
+          std::max<std::size_t>(512, b.capacity() - b.size()),
+          std::min<std::size_t>(65536, b.max_size() - b.size()));
+    b.commit(s.read_some(b.prepare(bytes_to_read), ec));
+    if (ec)
+      return 0;
+  }
+}
+
+#if !defined(ASIO_NO_IOSTREAM)
+
+template <typename SyncReadStream, typename Allocator>
+inline std::size_t read_until(SyncReadStream& s,
+    asio::basic_streambuf<Allocator>& b, char delim)
+{
+  return read_until(s, basic_streambuf_ref<Allocator>(b), delim);
+}
+
+template <typename SyncReadStream, typename Allocator>
+inline std::size_t read_until(SyncReadStream& s,
+    asio::basic_streambuf<Allocator>& b, char delim,
+    asio::error_code& ec)
+{
+  return read_until(s, basic_streambuf_ref<Allocator>(b), delim, ec);
+}
+
+template <typename SyncReadStream, typename Allocator>
+inline std::size_t read_until(SyncReadStream& s,
+    asio::basic_streambuf<Allocator>& b,
+    ASIO_STRING_VIEW_PARAM delim)
+{
+  return read_until(s, basic_streambuf_ref<Allocator>(b), delim);
+}
+
+template <typename SyncReadStream, typename Allocator>
+inline std::size_t read_until(SyncReadStream& s,
+    asio::basic_streambuf<Allocator>& b,
+    ASIO_STRING_VIEW_PARAM delim, asio::error_code& ec)
+{
+  return read_until(s, basic_streambuf_ref<Allocator>(b), delim, ec);
+}
+
+#if defined(ASIO_HAS_BOOST_REGEX)
+
+template <typename SyncReadStream, typename Allocator>
+inline std::size_t read_until(SyncReadStream& s,
+    asio::basic_streambuf<Allocator>& b, const boost::regex& expr)
+{
+  return read_until(s, basic_streambuf_ref<Allocator>(b), expr);
+}
+
+template <typename SyncReadStream, typename Allocator>
+inline std::size_t read_until(SyncReadStream& s,
+    asio::basic_streambuf<Allocator>& b, const boost::regex& expr,
+    asio::error_code& ec)
+{
+  return read_until(s, basic_streambuf_ref<Allocator>(b), expr, ec);
+}
+
+#endif // defined(ASIO_HAS_BOOST_REGEX)
+
+template <typename SyncReadStream, typename Allocator, typename MatchCondition>
+inline std::size_t read_until(SyncReadStream& s,
+    asio::basic_streambuf<Allocator>& b, MatchCondition match_condition,
+    typename enable_if<is_match_condition<MatchCondition>::value>::type*)
+{
+  return read_until(s, basic_streambuf_ref<Allocator>(b), match_condition);
+}
+
+template <typename SyncReadStream, typename Allocator, typename MatchCondition>
+inline std::size_t read_until(SyncReadStream& s,
+    asio::basic_streambuf<Allocator>& b,
+    MatchCondition match_condition, asio::error_code& ec,
+    typename enable_if<is_match_condition<MatchCondition>::value>::type*)
+{
+  return read_until(s, basic_streambuf_ref<Allocator>(b), match_condition, ec);
+}
+
+#endif // !defined(ASIO_NO_IOSTREAM)
+#endif // !defined(ASIO_NO_EXTENSIONS)
+#endif // !defined(ASIO_NO_DYNAMIC_BUFFER_V1)
+
+template <typename SyncReadStream, typename DynamicBuffer_v2>
+inline std::size_t read_until(SyncReadStream& s,
+    DynamicBuffer_v2 buffers, char delim,
+    typename enable_if<
+      is_dynamic_buffer_v2<DynamicBuffer_v2>::value
+    >::type*)
+{
+  asio::error_code ec;
+  std::size_t bytes_transferred = read_until(s,
+      ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers), delim, ec);
+  asio::detail::throw_error(ec, "read_until");
+  return bytes_transferred;
+}
+
+template <typename SyncReadStream, typename DynamicBuffer_v2>
+std::size_t read_until(SyncReadStream& s, DynamicBuffer_v2 buffers,
+    char delim, asio::error_code& ec,
+    typename enable_if<
+      is_dynamic_buffer_v2<DynamicBuffer_v2>::value
+    >::type*)
+{
+  DynamicBuffer_v2& b = buffers;
+
+  std::size_t search_position = 0;
+  for (;;)
+  {
+    // Determine the range of the data to be searched.
+    typedef typename DynamicBuffer_v2::const_buffers_type buffers_type;
+    typedef buffers_iterator<buffers_type> iterator;
+    buffers_type data_buffers =
+      const_cast<const DynamicBuffer_v2&>(b).data(0, b.size());
+    iterator begin = iterator::begin(data_buffers);
+    iterator start_pos = begin + search_position;
+    iterator end = iterator::end(data_buffers);
+
+    // Look for a match.
+    iterator iter = std::find(start_pos, end, delim);
+    if (iter != end)
+    {
+      // Found a match. We're done.
+      ec = asio::error_code();
+      return iter - begin + 1;
+    }
+    else
+    {
+      // No match. Next search can start with the new data.
+      search_position = end - begin;
+    }
+
+    // Check if buffer is full.
+    if (b.size() == b.max_size())
+    {
+      ec = error::not_found;
+      return 0;
+    }
+
+    // Need more data.
+    std::size_t bytes_to_read = std::min<std::size_t>(
+          std::max<std::size_t>(512, b.capacity() - b.size()),
+          std::min<std::size_t>(65536, b.max_size() - b.size()));
+    std::size_t pos = b.size();
+    b.grow(bytes_to_read);
+    std::size_t bytes_transferred = s.read_some(b.data(pos, bytes_to_read), ec);
+    b.shrink(bytes_to_read - bytes_transferred);
+    if (ec)
+      return 0;
+  }
+}
+
+template <typename SyncReadStream, typename DynamicBuffer_v2>
+inline std::size_t read_until(SyncReadStream& s,
+    DynamicBuffer_v2 buffers, ASIO_STRING_VIEW_PARAM delim,
+    typename enable_if<
+      is_dynamic_buffer_v2<DynamicBuffer_v2>::value
+    >::type*)
+{
+  asio::error_code ec;
+  std::size_t bytes_transferred = read_until(s,
+      ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers), delim, ec);
+  asio::detail::throw_error(ec, "read_until");
+  return bytes_transferred;
+}
+
+template <typename SyncReadStream, typename DynamicBuffer_v2>
+std::size_t read_until(SyncReadStream& s, DynamicBuffer_v2 buffers,
+    ASIO_STRING_VIEW_PARAM delim, asio::error_code& ec,
+    typename enable_if<
+      is_dynamic_buffer_v2<DynamicBuffer_v2>::value
+    >::type*)
+{
+  DynamicBuffer_v2& b = buffers;
+
+  std::size_t search_position = 0;
+  for (;;)
+  {
+    // Determine the range of the data to be searched.
+    typedef typename DynamicBuffer_v2::const_buffers_type buffers_type;
+    typedef buffers_iterator<buffers_type> iterator;
+    buffers_type data_buffers =
+      const_cast<const DynamicBuffer_v2&>(b).data(0, b.size());
+    iterator begin = iterator::begin(data_buffers);
+    iterator start_pos = begin + search_position;
+    iterator end = iterator::end(data_buffers);
+
+    // Look for a match.
+    std::pair<iterator, bool> result = detail::partial_search(
+        start_pos, end, delim.begin(), delim.end());
+    if (result.first != end)
+    {
+      if (result.second)
+      {
+        // Full match. We're done.
+        ec = asio::error_code();
+        return result.first - begin + delim.length();
+      }
+      else
+      {
+        // Partial match. Next search needs to start from beginning of match.
+        search_position = result.first - begin;
+      }
+    }
+    else
+    {
+      // No match. Next search can start with the new data.
+      search_position = end - begin;
+    }
+
+    // Check if buffer is full.
+    if (b.size() == b.max_size())
+    {
+      ec = error::not_found;
+      return 0;
+    }
+
+    // Need more data.
+    std::size_t bytes_to_read = std::min<std::size_t>(
+          std::max<std::size_t>(512, b.capacity() - b.size()),
+          std::min<std::size_t>(65536, b.max_size() - b.size()));
+    std::size_t pos = b.size();
+    b.grow(bytes_to_read);
+    std::size_t bytes_transferred = s.read_some(b.data(pos, bytes_to_read), ec);
+    b.shrink(bytes_to_read - bytes_transferred);
+    if (ec)
+      return 0;
+  }
+}
+
+#if !defined(ASIO_NO_EXTENSIONS)
+#if defined(ASIO_HAS_BOOST_REGEX)
+
+template <typename SyncReadStream, typename DynamicBuffer_v2>
+inline std::size_t read_until(SyncReadStream& s,
+    DynamicBuffer_v2 buffers, const boost::regex& expr,
+    typename enable_if<
+      is_dynamic_buffer_v2<DynamicBuffer_v2>::value
+    >::type*)
+{
+  asio::error_code ec;
+  std::size_t bytes_transferred = read_until(s,
+      ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers), expr, ec);
+  asio::detail::throw_error(ec, "read_until");
+  return bytes_transferred;
+}
+
+template <typename SyncReadStream, typename DynamicBuffer_v2>
+std::size_t read_until(SyncReadStream& s, DynamicBuffer_v2 buffers,
+    const boost::regex& expr, asio::error_code& ec,
+    typename enable_if<
+      is_dynamic_buffer_v2<DynamicBuffer_v2>::value
+    >::type*)
+{
+  DynamicBuffer_v2& b = buffers;
+
+  std::size_t search_position = 0;
+  for (;;)
+  {
+    // Determine the range of the data to be searched.
+    typedef typename DynamicBuffer_v2::const_buffers_type buffers_type;
+    typedef buffers_iterator<buffers_type> iterator;
+    buffers_type data_buffers =
+      const_cast<const DynamicBuffer_v2&>(b).data(0, b.size());
+    iterator begin = iterator::begin(data_buffers);
+    iterator start_pos = begin + search_position;
+    iterator end = iterator::end(data_buffers);
+
+    // Look for a match.
+    boost::match_results<iterator,
+      typename std::vector<boost::sub_match<iterator> >::allocator_type>
+        match_results;
+    if (regex_search(start_pos, end, match_results, expr,
+          boost::match_default | boost::match_partial))
+    {
+      if (match_results[0].matched)
+      {
+        // Full match. We're done.
+        ec = asio::error_code();
+        return match_results[0].second - begin;
+      }
+      else
+      {
+        // Partial match. Next search needs to start from beginning of match.
+        search_position = match_results[0].first - begin;
+      }
+    }
+    else
+    {
+      // No match. Next search can start with the new data.
+      search_position = end - begin;
+    }
+
+    // Check if buffer is full.
+    if (b.size() == b.max_size())
+    {
+      ec = error::not_found;
+      return 0;
+    }
+
+    // Need more data.
+    std::size_t bytes_to_read = std::min<std::size_t>(
+          std::max<std::size_t>(512, b.capacity() - b.size()),
+          std::min<std::size_t>(65536, b.max_size() - b.size()));
+    std::size_t pos = b.size();
+    b.grow(bytes_to_read);
+    std::size_t bytes_transferred = s.read_some(b.data(pos, bytes_to_read), ec);
+    b.shrink(bytes_to_read - bytes_transferred);
+    if (ec)
+      return 0;
+  }
+}
+
+#endif // defined(ASIO_HAS_BOOST_REGEX)
+
+template <typename SyncReadStream,
+    typename DynamicBuffer_v2, typename MatchCondition>
+inline std::size_t read_until(SyncReadStream& s,
+    DynamicBuffer_v2 buffers, MatchCondition match_condition,
+    typename enable_if<
+      is_match_condition<MatchCondition>::value
+        && is_dynamic_buffer_v2<DynamicBuffer_v2>::value
+    >::type*)
+{
+  asio::error_code ec;
+  std::size_t bytes_transferred = read_until(s,
+      ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers),
+      match_condition, ec);
+  asio::detail::throw_error(ec, "read_until");
+  return bytes_transferred;
+}
+
+template <typename SyncReadStream,
+    typename DynamicBuffer_v2, typename MatchCondition>
+std::size_t read_until(SyncReadStream& s, DynamicBuffer_v2 buffers,
+    MatchCondition match_condition, asio::error_code& ec,
+    typename enable_if<
+      is_match_condition<MatchCondition>::value
+        && is_dynamic_buffer_v2<DynamicBuffer_v2>::value
+    >::type*)
+{
+  DynamicBuffer_v2& b = buffers;
+
+  std::size_t search_position = 0;
+  for (;;)
+  {
+    // Determine the range of the data to be searched.
+    typedef typename DynamicBuffer_v2::const_buffers_type buffers_type;
+    typedef buffers_iterator<buffers_type> iterator;
+    buffers_type data_buffers =
+      const_cast<const DynamicBuffer_v2&>(b).data(0, b.size());
+    iterator begin = iterator::begin(data_buffers);
+    iterator start_pos = begin + search_position;
+    iterator end = iterator::end(data_buffers);
+
+    // Look for a match.
+    std::pair<iterator, bool> result = match_condition(start_pos, end);
+    if (result.second)
+    {
+      // Full match. We're done.
+      ec = asio::error_code();
+      return result.first - begin;
+    }
+    else if (result.first != end)
+    {
+      // Partial match. Next search needs to start from beginning of match.
+      search_position = result.first - begin;
+    }
+    else
+    {
+      // No match. Next search can start with the new data.
+      search_position = end - begin;
+    }
+
+    // Check if buffer is full.
+    if (b.size() == b.max_size())
+    {
+      ec = error::not_found;
+      return 0;
+    }
+
+    // Need more data.
+    std::size_t bytes_to_read = std::min<std::size_t>(
+          std::max<std::size_t>(512, b.capacity() - b.size()),
+          std::min<std::size_t>(65536, b.max_size() - b.size()));
+    std::size_t pos = b.size();
+    b.grow(bytes_to_read);
+    std::size_t bytes_transferred = s.read_some(b.data(pos, bytes_to_read), ec);
+    b.shrink(bytes_to_read - bytes_transferred);
+    if (ec)
+      return 0;
+  }
+}
+
+#endif // !defined(ASIO_NO_EXTENSIONS)
+
+#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1)
+
+namespace detail
+{
+  template <typename AsyncReadStream,
+      typename DynamicBuffer_v1, typename ReadHandler>
+  class read_until_delim_op_v1
+  {
+  public:
+    template <typename BufferSequence>
+    read_until_delim_op_v1(AsyncReadStream& stream,
+        ASIO_MOVE_ARG(BufferSequence) buffers,
+        char delim, ReadHandler& handler)
+      : stream_(stream),
+        buffers_(ASIO_MOVE_CAST(BufferSequence)(buffers)),
+        delim_(delim),
+        start_(0),
+        search_position_(0),
+        handler_(ASIO_MOVE_CAST(ReadHandler)(handler))
+    {
+    }
+
+#if defined(ASIO_HAS_MOVE)
+    read_until_delim_op_v1(const read_until_delim_op_v1& other)
+      : stream_(other.stream_),
+        buffers_(other.buffers_),
+        delim_(other.delim_),
+        start_(other.start_),
+        search_position_(other.search_position_),
+        handler_(other.handler_)
+    {
+    }
+
+    read_until_delim_op_v1(read_until_delim_op_v1&& other)
+      : stream_(other.stream_),
+        buffers_(ASIO_MOVE_CAST(DynamicBuffer_v1)(other.buffers_)),
+        delim_(other.delim_),
+        start_(other.start_),
+        search_position_(other.search_position_),
+        handler_(ASIO_MOVE_CAST(ReadHandler)(other.handler_))
+    {
+    }
+#endif // defined(ASIO_HAS_MOVE)
+
+    void operator()(const asio::error_code& ec,
+        std::size_t bytes_transferred, int start = 0)
+    {
+      const std::size_t not_found = (std::numeric_limits<std::size_t>::max)();
+      std::size_t bytes_to_read;
+      switch (start_ = start)
+      {
+      case 1:
+        for (;;)
+        {
+          {
+            // Determine the range of the data to be searched.
+            typedef typename DynamicBuffer_v1::const_buffers_type
+              buffers_type;
+            typedef buffers_iterator<buffers_type> iterator;
+            buffers_type data_buffers = buffers_.data();
+            iterator begin = iterator::begin(data_buffers);
+            iterator start_pos = begin + search_position_;
+            iterator end = iterator::end(data_buffers);
+
+            // Look for a match.
+            iterator iter = std::find(start_pos, end, delim_);
+            if (iter != end)
+            {
+              // Found a match. We're done.
+              search_position_ = iter - begin + 1;
+              bytes_to_read = 0;
+            }
+
+            // No match yet. Check if buffer is full.
+            else if (buffers_.size() == buffers_.max_size())
+            {
+              search_position_ = not_found;
+              bytes_to_read = 0;
+            }
+
+            // Need to read some more data.
+            else
+            {
+              // Next search can start with the new data.
+              search_position_ = end - begin;
+              bytes_to_read = std::min<std::size_t>(
+                    std::max<std::size_t>(512,
+                      buffers_.capacity() - buffers_.size()),
+                    std::min<std::size_t>(65536,
+                      buffers_.max_size() - buffers_.size()));
+            }
+          }
+
+          // Check if we're done.
+          if (!start && bytes_to_read == 0)
+            break;
+
+          // Start a new asynchronous read operation to obtain more data.
+          {
+            ASIO_HANDLER_LOCATION((
+                  __FILE__, __LINE__, "async_read_until"));
+            stream_.async_read_some(buffers_.prepare(bytes_to_read),
+                ASIO_MOVE_CAST(read_until_delim_op_v1)(*this));
+          }
+          return; default:
+          buffers_.commit(bytes_transferred);
+          if (ec || bytes_transferred == 0)
+            break;
+        }
+
+        const asio::error_code result_ec =
+          (search_position_ == not_found)
+          ? error::not_found : ec;
+
+        const std::size_t result_n =
+          (ec || search_position_ == not_found)
+          ? 0 : search_position_;
+
+        handler_(result_ec, result_n);
+      }
+    }
+
+  //private:
+    AsyncReadStream& stream_;
+    DynamicBuffer_v1 buffers_;
+    char delim_;
+    int start_;
+    std::size_t search_position_;
+    ReadHandler handler_;
+  };
+
+  template <typename AsyncReadStream,
+      typename DynamicBuffer_v1, typename ReadHandler>
+  inline asio_handler_allocate_is_deprecated
+  asio_handler_allocate(std::size_t size,
+      read_until_delim_op_v1<AsyncReadStream,
+        DynamicBuffer_v1, ReadHandler>* this_handler)
+  {
+#if defined(ASIO_NO_DEPRECATED)
+    asio_handler_alloc_helpers::allocate(size, this_handler->handler_);
+    return asio_handler_allocate_is_no_longer_used();
+#else // defined(ASIO_NO_DEPRECATED)
+    return asio_handler_alloc_helpers::allocate(
+        size, this_handler->handler_);
+#endif // defined(ASIO_NO_DEPRECATED)
+  }
+
+  template <typename AsyncReadStream,
+      typename DynamicBuffer_v1, typename ReadHandler>
+  inline asio_handler_deallocate_is_deprecated
+  asio_handler_deallocate(void* pointer, std::size_t size,
+      read_until_delim_op_v1<AsyncReadStream,
+        DynamicBuffer_v1, ReadHandler>* this_handler)
+  {
+    asio_handler_alloc_helpers::deallocate(
+        pointer, size, this_handler->handler_);
+#if defined(ASIO_NO_DEPRECATED)
+    return asio_handler_deallocate_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+  }
+
+  template <typename AsyncReadStream,
+      typename DynamicBuffer_v1, typename ReadHandler>
+  inline bool asio_handler_is_continuation(
+      read_until_delim_op_v1<AsyncReadStream,
+        DynamicBuffer_v1, ReadHandler>* this_handler)
+  {
+    return this_handler->start_ == 0 ? true
+      : asio_handler_cont_helpers::is_continuation(
+          this_handler->handler_);
+  }
+
+  template <typename Function, typename AsyncReadStream,
+      typename DynamicBuffer_v1, typename ReadHandler>
+  inline asio_handler_invoke_is_deprecated
+  asio_handler_invoke(Function& function,
+      read_until_delim_op_v1<AsyncReadStream,
+        DynamicBuffer_v1, ReadHandler>* this_handler)
+  {
+    asio_handler_invoke_helpers::invoke(
+        function, this_handler->handler_);
+#if defined(ASIO_NO_DEPRECATED)
+    return asio_handler_invoke_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+  }
+
+  template <typename Function, typename AsyncReadStream,
+      typename DynamicBuffer_v1, typename ReadHandler>
+  inline asio_handler_invoke_is_deprecated
+  asio_handler_invoke(const Function& function,
+      read_until_delim_op_v1<AsyncReadStream,
+        DynamicBuffer_v1, ReadHandler>* this_handler)
+  {
+    asio_handler_invoke_helpers::invoke(
+        function, this_handler->handler_);
+#if defined(ASIO_NO_DEPRECATED)
+    return asio_handler_invoke_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+  }
+
+  template <typename AsyncReadStream>
+  class initiate_async_read_until_delim_v1
+  {
+  public:
+    typedef typename AsyncReadStream::executor_type executor_type;
+
+    explicit initiate_async_read_until_delim_v1(AsyncReadStream& stream)
+      : stream_(stream)
+    {
+    }
+
+    executor_type get_executor() const ASIO_NOEXCEPT
+    {
+      return stream_.get_executor();
+    }
+
+    template <typename ReadHandler, typename DynamicBuffer_v1>
+    void operator()(ASIO_MOVE_ARG(ReadHandler) handler,
+        ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,
+        char delim) const
+    {
+      // If you get an error on the following line it means that your handler
+      // does not meet the documented type requirements for a ReadHandler.
+      ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
+
+      non_const_lvalue<ReadHandler> handler2(handler);
+      read_until_delim_op_v1<AsyncReadStream,
+        typename decay<DynamicBuffer_v1>::type,
+          typename decay<ReadHandler>::type>(
+            stream_, ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers),
+            delim, handler2.value)(asio::error_code(), 0, 1);
+    }
+
+  private:
+    AsyncReadStream& stream_;
+  };
+} // namespace detail
+
+#if !defined(GENERATING_DOCUMENTATION)
+
+template <typename AsyncReadStream, typename DynamicBuffer_v1,
+    typename ReadHandler, typename Allocator>
+struct associated_allocator<
+    detail::read_until_delim_op_v1<AsyncReadStream,
+      DynamicBuffer_v1, ReadHandler>,
+    Allocator>
+{
+  typedef typename associated_allocator<ReadHandler, Allocator>::type type;
+
+  static type get(
+      const detail::read_until_delim_op_v1<AsyncReadStream,
+        DynamicBuffer_v1, ReadHandler>& h,
+      const Allocator& a = Allocator()) ASIO_NOEXCEPT
+  {
+    return associated_allocator<ReadHandler, Allocator>::get(h.handler_, a);
+  }
+};
+
+template <typename AsyncReadStream, typename DynamicBuffer_v1,
+    typename ReadHandler, typename Executor>
+struct associated_executor<
+    detail::read_until_delim_op_v1<AsyncReadStream,
+      DynamicBuffer_v1, ReadHandler>,
+    Executor>
+  : detail::associated_executor_forwarding_base<ReadHandler, Executor>
+{
+  typedef typename associated_executor<ReadHandler, Executor>::type type;
+
+  static type get(
+      const detail::read_until_delim_op_v1<AsyncReadStream,
+        DynamicBuffer_v1, ReadHandler>& h,
+      const Executor& ex = Executor()) ASIO_NOEXCEPT
+  {
+    return associated_executor<ReadHandler, Executor>::get(h.handler_, ex);
+  }
+};
+
+#endif // !defined(GENERATING_DOCUMENTATION)
+
+template <typename AsyncReadStream, typename DynamicBuffer_v1,
+    ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+      std::size_t)) ReadHandler>
+ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,
+    void (asio::error_code, std::size_t))
+async_read_until(AsyncReadStream& s,
+    ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,
+    char delim, ASIO_MOVE_ARG(ReadHandler) handler,
+    typename enable_if<
+      is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value
+        && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value
+    >::type*)
+{
+  return async_initiate<ReadHandler,
+    void (asio::error_code, std::size_t)>(
+      detail::initiate_async_read_until_delim_v1<AsyncReadStream>(s),
+      handler, ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers), delim);
+}
+
+namespace detail
+{
+  template <typename AsyncReadStream,
+      typename DynamicBuffer_v1, typename ReadHandler>
+  class read_until_delim_string_op_v1
+  {
+  public:
+    template <typename BufferSequence>
+    read_until_delim_string_op_v1(AsyncReadStream& stream,
+        ASIO_MOVE_ARG(BufferSequence) buffers,
+        const std::string& delim, ReadHandler& handler)
+      : stream_(stream),
+        buffers_(ASIO_MOVE_CAST(BufferSequence)(buffers)),
+        delim_(delim),
+        start_(0),
+        search_position_(0),
+        handler_(ASIO_MOVE_CAST(ReadHandler)(handler))
+    {
+    }
+
+#if defined(ASIO_HAS_MOVE)
+    read_until_delim_string_op_v1(const read_until_delim_string_op_v1& other)
+      : stream_(other.stream_),
+        buffers_(other.buffers_),
+        delim_(other.delim_),
+        start_(other.start_),
+        search_position_(other.search_position_),
+        handler_(other.handler_)
+    {
+    }
+
+    read_until_delim_string_op_v1(read_until_delim_string_op_v1&& other)
+      : stream_(other.stream_),
+        buffers_(ASIO_MOVE_CAST(DynamicBuffer_v1)(other.buffers_)),
+        delim_(ASIO_MOVE_CAST(std::string)(other.delim_)),
+        start_(other.start_),
+        search_position_(other.search_position_),
+        handler_(ASIO_MOVE_CAST(ReadHandler)(other.handler_))
+    {
+    }
+#endif // defined(ASIO_HAS_MOVE)
+
+    void operator()(const asio::error_code& ec,
+        std::size_t bytes_transferred, int start = 0)
+    {
+      const std::size_t not_found = (std::numeric_limits<std::size_t>::max)();
+      std::size_t bytes_to_read;
+      switch (start_ = start)
+      {
+      case 1:
+        for (;;)
+        {
+          {
+            // Determine the range of the data to be searched.
+            typedef typename DynamicBuffer_v1::const_buffers_type
+              buffers_type;
+            typedef buffers_iterator<buffers_type> iterator;
+            buffers_type data_buffers = buffers_.data();
+            iterator begin = iterator::begin(data_buffers);
+            iterator start_pos = begin + search_position_;
+            iterator end = iterator::end(data_buffers);
+
+            // Look for a match.
+            std::pair<iterator, bool> result = detail::partial_search(
+                start_pos, end, delim_.begin(), delim_.end());
+            if (result.first != end && result.second)
+            {
+              // Full match. We're done.
+              search_position_ = result.first - begin + delim_.length();
+              bytes_to_read = 0;
+            }
+
+            // No match yet. Check if buffer is full.
+            else if (buffers_.size() == buffers_.max_size())
+            {
+              search_position_ = not_found;
+              bytes_to_read = 0;
+            }
+
+            // Need to read some more data.
+            else
+            {
+              if (result.first != end)
+              {
+                // Partial match. Next search needs to start from beginning of
+                // match.
+                search_position_ = result.first - begin;
+              }
+              else
+              {
+                // Next search can start with the new data.
+                search_position_ = end - begin;
+              }
+
+              bytes_to_read = std::min<std::size_t>(
+                    std::max<std::size_t>(512,
+                      buffers_.capacity() - buffers_.size()),
+                    std::min<std::size_t>(65536,
+                      buffers_.max_size() - buffers_.size()));
+            }
+          }
+
+          // Check if we're done.
+          if (!start && bytes_to_read == 0)
+            break;
+
+          // Start a new asynchronous read operation to obtain more data.
+          {
+            ASIO_HANDLER_LOCATION((
+                  __FILE__, __LINE__, "async_read_until"));
+            stream_.async_read_some(buffers_.prepare(bytes_to_read),
+                ASIO_MOVE_CAST(read_until_delim_string_op_v1)(*this));
+          }
+          return; default:
+          buffers_.commit(bytes_transferred);
+          if (ec || bytes_transferred == 0)
+            break;
+        }
+
+        const asio::error_code result_ec =
+          (search_position_ == not_found)
+          ? error::not_found : ec;
+
+        const std::size_t result_n =
+          (ec || search_position_ == not_found)
+          ? 0 : search_position_;
+
+        handler_(result_ec, result_n);
+      }
+    }
+
+  //private:
+    AsyncReadStream& stream_;
+    DynamicBuffer_v1 buffers_;
+    std::string delim_;
+    int start_;
+    std::size_t search_position_;
+    ReadHandler handler_;
+  };
+
+  template <typename AsyncReadStream,
+      typename DynamicBuffer_v1, typename ReadHandler>
+  inline asio_handler_allocate_is_deprecated
+  asio_handler_allocate(std::size_t size,
+      read_until_delim_string_op_v1<AsyncReadStream,
+        DynamicBuffer_v1, ReadHandler>* this_handler)
+  {
+#if defined(ASIO_NO_DEPRECATED)
+    asio_handler_alloc_helpers::allocate(size, this_handler->handler_);
+    return asio_handler_allocate_is_no_longer_used();
+#else // defined(ASIO_NO_DEPRECATED)
+    return asio_handler_alloc_helpers::allocate(
+        size, this_handler->handler_);
+#endif // defined(ASIO_NO_DEPRECATED)
+  }
+
+  template <typename AsyncReadStream,
+      typename DynamicBuffer_v1, typename ReadHandler>
+  inline asio_handler_deallocate_is_deprecated
+  asio_handler_deallocate(void* pointer, std::size_t size,
+      read_until_delim_string_op_v1<AsyncReadStream,
+        DynamicBuffer_v1, ReadHandler>* this_handler)
+  {
+    asio_handler_alloc_helpers::deallocate(
+        pointer, size, this_handler->handler_);
+#if defined(ASIO_NO_DEPRECATED)
+    return asio_handler_deallocate_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+  }
+
+  template <typename AsyncReadStream,
+      typename DynamicBuffer_v1, typename ReadHandler>
+  inline bool asio_handler_is_continuation(
+      read_until_delim_string_op_v1<AsyncReadStream,
+        DynamicBuffer_v1, ReadHandler>* this_handler)
+  {
+    return this_handler->start_ == 0 ? true
+      : asio_handler_cont_helpers::is_continuation(
+          this_handler->handler_);
+  }
+
+  template <typename Function, typename AsyncReadStream,
+      typename DynamicBuffer_v1, typename ReadHandler>
+  inline asio_handler_invoke_is_deprecated
+  asio_handler_invoke(Function& function,
+      read_until_delim_string_op_v1<AsyncReadStream,
+        DynamicBuffer_v1, ReadHandler>* this_handler)
+  {
+    asio_handler_invoke_helpers::invoke(
+        function, this_handler->handler_);
+#if defined(ASIO_NO_DEPRECATED)
+    return asio_handler_invoke_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+  }
+
+  template <typename Function, typename AsyncReadStream,
+      typename DynamicBuffer_v1, typename ReadHandler>
+  inline asio_handler_invoke_is_deprecated
+  asio_handler_invoke(const Function& function,
+      read_until_delim_string_op_v1<AsyncReadStream,
+        DynamicBuffer_v1, ReadHandler>* this_handler)
+  {
+    asio_handler_invoke_helpers::invoke(
+        function, this_handler->handler_);
+#if defined(ASIO_NO_DEPRECATED)
+    return asio_handler_invoke_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+  }
+
+  template <typename AsyncReadStream>
+  class initiate_async_read_until_delim_string_v1
+  {
+  public:
+    typedef typename AsyncReadStream::executor_type executor_type;
+
+    explicit initiate_async_read_until_delim_string_v1(AsyncReadStream& stream)
+      : stream_(stream)
+    {
+    }
+
+    executor_type get_executor() const ASIO_NOEXCEPT
+    {
+      return stream_.get_executor();
+    }
+
+    template <typename ReadHandler, typename DynamicBuffer_v1>
+    void operator()(ASIO_MOVE_ARG(ReadHandler) handler,
+        ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,
+        const std::string& delim) const
+    {
+      // If you get an error on the following line it means that your handler
+      // does not meet the documented type requirements for a ReadHandler.
+      ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
+
+      non_const_lvalue<ReadHandler> handler2(handler);
+      read_until_delim_string_op_v1<AsyncReadStream,
+        typename decay<DynamicBuffer_v1>::type,
+          typename decay<ReadHandler>::type>(
+            stream_, ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers),
+            delim, handler2.value)(asio::error_code(), 0, 1);
+    }
+
+  private:
+    AsyncReadStream& stream_;
+  };
+} // namespace detail
+
+#if !defined(GENERATING_DOCUMENTATION)
+
+template <typename AsyncReadStream, typename DynamicBuffer_v1,
+    typename ReadHandler, typename Allocator>
+struct associated_allocator<
+    detail::read_until_delim_string_op_v1<AsyncReadStream,
+      DynamicBuffer_v1, ReadHandler>,
+    Allocator>
+{
+  typedef typename associated_allocator<ReadHandler, Allocator>::type type;
+
+  static type get(
+      const detail::read_until_delim_string_op_v1<AsyncReadStream,
+        DynamicBuffer_v1, ReadHandler>& h,
+      const Allocator& a = Allocator()) ASIO_NOEXCEPT
+  {
+    return associated_allocator<ReadHandler, Allocator>::get(h.handler_, a);
+  }
+};
+
+template <typename AsyncReadStream, typename DynamicBuffer_v1,
+    typename ReadHandler, typename Executor>
+struct associated_executor<
+    detail::read_until_delim_string_op_v1<AsyncReadStream,
+      DynamicBuffer_v1, ReadHandler>,
+    Executor>
+  : detail::associated_executor_forwarding_base<ReadHandler, Executor>
+{
+  typedef typename associated_executor<ReadHandler, Executor>::type type;
+
+  static type get(
+      const detail::read_until_delim_string_op_v1<AsyncReadStream,
+        DynamicBuffer_v1, ReadHandler>& h,
+      const Executor& ex = Executor()) ASIO_NOEXCEPT
+  {
+    return associated_executor<ReadHandler, Executor>::get(h.handler_, ex);
+  }
+};
+
+#endif // !defined(GENERATING_DOCUMENTATION)
+
+template <typename AsyncReadStream, typename DynamicBuffer_v1,
+    ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+      std::size_t)) ReadHandler>
+ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,
+    void (asio::error_code, std::size_t))
+async_read_until(AsyncReadStream& s,
+    ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,
+    ASIO_STRING_VIEW_PARAM delim,
+    ASIO_MOVE_ARG(ReadHandler) handler,
+    typename enable_if<
+      is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value
+        && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value
+    >::type*)
+{
+  return async_initiate<ReadHandler,
+    void (asio::error_code, std::size_t)>(
+      detail::initiate_async_read_until_delim_string_v1<AsyncReadStream>(s),
+      handler, ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers),
+      static_cast<std::string>(delim));
+}
+
+#if !defined(ASIO_NO_EXTENSIONS)
+#if defined(ASIO_HAS_BOOST_REGEX)
+
+namespace detail
+{
+  template <typename AsyncReadStream, typename DynamicBuffer_v1,
+      typename RegEx, typename ReadHandler>
+  class read_until_expr_op_v1
+  {
+  public:
+    template <typename BufferSequence>
+    read_until_expr_op_v1(AsyncReadStream& stream,
+        ASIO_MOVE_ARG(BufferSequence) buffers,
+        const boost::regex& expr, ReadHandler& handler)
+      : stream_(stream),
+        buffers_(ASIO_MOVE_CAST(BufferSequence)(buffers)),
+        expr_(expr),
+        start_(0),
+        search_position_(0),
+        handler_(ASIO_MOVE_CAST(ReadHandler)(handler))
+    {
+    }
+
+#if defined(ASIO_HAS_MOVE)
+    read_until_expr_op_v1(const read_until_expr_op_v1& other)
+      : stream_(other.stream_),
+        buffers_(other.buffers_),
+        expr_(other.expr_),
+        start_(other.start_),
+        search_position_(other.search_position_),
+        handler_(other.handler_)
+    {
+    }
+
+    read_until_expr_op_v1(read_until_expr_op_v1&& other)
+      : stream_(other.stream_),
+        buffers_(ASIO_MOVE_CAST(DynamicBuffer_v1)(other.buffers_)),
+        expr_(other.expr_),
+        start_(other.start_),
+        search_position_(other.search_position_),
+        handler_(ASIO_MOVE_CAST(ReadHandler)(other.handler_))
+    {
+    }
+#endif // defined(ASIO_HAS_MOVE)
+
+    void operator()(const asio::error_code& ec,
+        std::size_t bytes_transferred, int start = 0)
+    {
+      const std::size_t not_found = (std::numeric_limits<std::size_t>::max)();
+      std::size_t bytes_to_read;
+      switch (start_ = start)
+      {
+      case 1:
+        for (;;)
+        {
+          {
+            // Determine the range of the data to be searched.
+            typedef typename DynamicBuffer_v1::const_buffers_type
+              buffers_type;
+            typedef buffers_iterator<buffers_type> iterator;
+            buffers_type data_buffers = buffers_.data();
+            iterator begin = iterator::begin(data_buffers);
+            iterator start_pos = begin + search_position_;
+            iterator end = iterator::end(data_buffers);
+
+            // Look for a match.
+            boost::match_results<iterator,
+              typename std::vector<boost::sub_match<iterator> >::allocator_type>
+                match_results;
+            bool match = regex_search(start_pos, end, match_results, expr_,
+                boost::match_default | boost::match_partial);
+            if (match && match_results[0].matched)
+            {
+              // Full match. We're done.
+              search_position_ = match_results[0].second - begin;
+              bytes_to_read = 0;
+            }
+
+            // No match yet. Check if buffer is full.
+            else if (buffers_.size() == buffers_.max_size())
+            {
+              search_position_ = not_found;
+              bytes_to_read = 0;
+            }
+
+            // Need to read some more data.
+            else
+            {
+              if (match)
+              {
+                // Partial match. Next search needs to start from beginning of
+                // match.
+                search_position_ = match_results[0].first - begin;
+              }
+              else
+              {
+                // Next search can start with the new data.
+                search_position_ = end - begin;
+              }
+
+              bytes_to_read = std::min<std::size_t>(
+                    std::max<std::size_t>(512,
+                      buffers_.capacity() - buffers_.size()),
+                    std::min<std::size_t>(65536,
+                      buffers_.max_size() - buffers_.size()));
+            }
+          }
+
+          // Check if we're done.
+          if (!start && bytes_to_read == 0)
+            break;
+
+          // Start a new asynchronous read operation to obtain more data.
+          {
+            ASIO_HANDLER_LOCATION((
+                  __FILE__, __LINE__, "async_read_until"));
+            stream_.async_read_some(buffers_.prepare(bytes_to_read),
+                ASIO_MOVE_CAST(read_until_expr_op_v1)(*this));
+          }
+          return; default:
+          buffers_.commit(bytes_transferred);
+          if (ec || bytes_transferred == 0)
+            break;
+        }
+
+        const asio::error_code result_ec =
+          (search_position_ == not_found)
+          ? error::not_found : ec;
+
+        const std::size_t result_n =
+          (ec || search_position_ == not_found)
+          ? 0 : search_position_;
+
+        handler_(result_ec, result_n);
+      }
+    }
+
+  //private:
+    AsyncReadStream& stream_;
+    DynamicBuffer_v1 buffers_;
+    RegEx expr_;
+    int start_;
+    std::size_t search_position_;
+    ReadHandler handler_;
+  };
+
+  template <typename AsyncReadStream, typename DynamicBuffer_v1,
+      typename RegEx, typename ReadHandler>
+  inline asio_handler_allocate_is_deprecated
+  asio_handler_allocate(std::size_t size,
+      read_until_expr_op_v1<AsyncReadStream,
+        DynamicBuffer_v1, RegEx, ReadHandler>* this_handler)
+  {
+#if defined(ASIO_NO_DEPRECATED)
+    asio_handler_alloc_helpers::allocate(size, this_handler->handler_);
+    return asio_handler_allocate_is_no_longer_used();
+#else // defined(ASIO_NO_DEPRECATED)
+    return asio_handler_alloc_helpers::allocate(
+        size, this_handler->handler_);
+#endif // defined(ASIO_NO_DEPRECATED)
+  }
+
+  template <typename AsyncReadStream, typename DynamicBuffer_v1,
+      typename RegEx, typename ReadHandler>
+  inline asio_handler_deallocate_is_deprecated
+  asio_handler_deallocate(void* pointer, std::size_t size,
+      read_until_expr_op_v1<AsyncReadStream,
+        DynamicBuffer_v1, RegEx, ReadHandler>* this_handler)
+  {
+    asio_handler_alloc_helpers::deallocate(
+        pointer, size, this_handler->handler_);
+#if defined(ASIO_NO_DEPRECATED)
+    return asio_handler_deallocate_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+  }
+
+  template <typename AsyncReadStream, typename DynamicBuffer_v1,
+      typename RegEx, typename ReadHandler>
+  inline bool asio_handler_is_continuation(
+      read_until_expr_op_v1<AsyncReadStream,
+        DynamicBuffer_v1, RegEx, ReadHandler>* this_handler)
+  {
+    return this_handler->start_ == 0 ? true
+      : asio_handler_cont_helpers::is_continuation(
+          this_handler->handler_);
+  }
+
+  template <typename Function, typename AsyncReadStream,
+      typename DynamicBuffer_v1, typename RegEx, typename ReadHandler>
+  inline asio_handler_invoke_is_deprecated
+  asio_handler_invoke(Function& function,
+      read_until_expr_op_v1<AsyncReadStream,
+        DynamicBuffer_v1, RegEx, ReadHandler>* this_handler)
+  {
+    asio_handler_invoke_helpers::invoke(
+        function, this_handler->handler_);
+#if defined(ASIO_NO_DEPRECATED)
+    return asio_handler_invoke_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+  }
+
+  template <typename Function, typename AsyncReadStream,
+      typename DynamicBuffer_v1, typename RegEx, typename ReadHandler>
+  inline asio_handler_invoke_is_deprecated
+  asio_handler_invoke(const Function& function,
+      read_until_expr_op_v1<AsyncReadStream,
+        DynamicBuffer_v1, RegEx, ReadHandler>* this_handler)
+  {
+    asio_handler_invoke_helpers::invoke(
+        function, this_handler->handler_);
+#if defined(ASIO_NO_DEPRECATED)
+    return asio_handler_invoke_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+  }
+
+  template <typename AsyncReadStream>
+  class initiate_async_read_until_expr_v1
+  {
+  public:
+    typedef typename AsyncReadStream::executor_type executor_type;
+
+    explicit initiate_async_read_until_expr_v1(AsyncReadStream& stream)
+      : stream_(stream)
+    {
+    }
+
+    executor_type get_executor() const ASIO_NOEXCEPT
+    {
+      return stream_.get_executor();
+    }
+
+    template <typename ReadHandler, typename DynamicBuffer_v1, typename RegEx>
+    void operator()(ASIO_MOVE_ARG(ReadHandler) handler,
+        ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, const RegEx& expr) const
+    {
+      // If you get an error on the following line it means that your handler
+      // does not meet the documented type requirements for a ReadHandler.
+      ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
+
+      non_const_lvalue<ReadHandler> handler2(handler);
+      read_until_expr_op_v1<AsyncReadStream,
+        typename decay<DynamicBuffer_v1>::type,
+          RegEx, typename decay<ReadHandler>::type>(
+            stream_, ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers),
+            expr, handler2.value)(asio::error_code(), 0, 1);
+    }
+
+  private:
+    AsyncReadStream& stream_;
+  };
+} // namespace detail
+
+#if !defined(GENERATING_DOCUMENTATION)
+
+template <typename AsyncReadStream, typename DynamicBuffer_v1,
+    typename RegEx, typename ReadHandler, typename Allocator>
+struct associated_allocator<
+    detail::read_until_expr_op_v1<AsyncReadStream,
+      DynamicBuffer_v1, RegEx, ReadHandler>,
+    Allocator>
+{
+  typedef typename associated_allocator<ReadHandler, Allocator>::type type;
+
+  static type get(
+      const detail::read_until_expr_op_v1<AsyncReadStream,
+        DynamicBuffer_v1, RegEx, ReadHandler>& h,
+      const Allocator& a = Allocator()) ASIO_NOEXCEPT
+  {
+    return associated_allocator<ReadHandler, Allocator>::get(h.handler_, a);
+  }
+};
+
+template <typename AsyncReadStream, typename DynamicBuffer_v1,
+    typename RegEx, typename ReadHandler, typename Executor>
+struct associated_executor<
+    detail::read_until_expr_op_v1<AsyncReadStream,
+      DynamicBuffer_v1, RegEx, ReadHandler>,
+    Executor>
+  : detail::associated_executor_forwarding_base<ReadHandler, Executor>
+{
+  typedef typename associated_executor<ReadHandler, Executor>::type type;
+
+  static type get(
+      const detail::read_until_expr_op_v1<AsyncReadStream,
+        DynamicBuffer_v1, RegEx, ReadHandler>& h,
+      const Executor& ex = Executor()) ASIO_NOEXCEPT
+  {
+    return associated_executor<ReadHandler, Executor>::get(h.handler_, ex);
+  }
+};
+
+#endif // !defined(GENERATING_DOCUMENTATION)
+
+template <typename AsyncReadStream, typename DynamicBuffer_v1,
+    ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+      std::size_t)) ReadHandler>
+ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,
+    void (asio::error_code, std::size_t))
+async_read_until(AsyncReadStream& s,
+    ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,
+    const boost::regex& expr,
+    ASIO_MOVE_ARG(ReadHandler) handler,
+    typename enable_if<
+      is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value
+        && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value
+    >::type*)
+{
+  return async_initiate<ReadHandler,
+    void (asio::error_code, std::size_t)>(
+      detail::initiate_async_read_until_expr_v1<AsyncReadStream>(s),
+      handler, ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers), expr);
+}
+
+#endif // defined(ASIO_HAS_BOOST_REGEX)
+
+namespace detail
+{
+  template <typename AsyncReadStream, typename DynamicBuffer_v1,
+      typename MatchCondition, typename ReadHandler>
+  class read_until_match_op_v1
+  {
+  public:
+    template <typename BufferSequence>
+    read_until_match_op_v1(AsyncReadStream& stream,
+        ASIO_MOVE_ARG(BufferSequence) buffers,
+        MatchCondition match_condition, ReadHandler& handler)
+      : stream_(stream),
+        buffers_(ASIO_MOVE_CAST(BufferSequence)(buffers)),
+        match_condition_(match_condition),
+        start_(0),
+        search_position_(0),
+        handler_(ASIO_MOVE_CAST(ReadHandler)(handler))
+    {
+    }
+
+#if defined(ASIO_HAS_MOVE)
+    read_until_match_op_v1(const read_until_match_op_v1& other)
+      : stream_(other.stream_),
+        buffers_(other.buffers_),
+        match_condition_(other.match_condition_),
+        start_(other.start_),
+        search_position_(other.search_position_),
+        handler_(other.handler_)
+    {
+    }
+
+    read_until_match_op_v1(read_until_match_op_v1&& other)
+      : stream_(other.stream_),
+        buffers_(ASIO_MOVE_CAST(DynamicBuffer_v1)(other.buffers_)),
+        match_condition_(other.match_condition_),
+        start_(other.start_),
+        search_position_(other.search_position_),
+        handler_(ASIO_MOVE_CAST(ReadHandler)(other.handler_))
+    {
+    }
+#endif // defined(ASIO_HAS_MOVE)
+
+    void operator()(const asio::error_code& ec,
+        std::size_t bytes_transferred, int start = 0)
+    {
+      const std::size_t not_found = (std::numeric_limits<std::size_t>::max)();
+      std::size_t bytes_to_read;
+      switch (start_ = start)
+      {
+      case 1:
+        for (;;)
+        {
+          {
+            // Determine the range of the data to be searched.
+            typedef typename DynamicBuffer_v1::const_buffers_type
+              buffers_type;
+            typedef buffers_iterator<buffers_type> iterator;
+            buffers_type data_buffers = buffers_.data();
+            iterator begin = iterator::begin(data_buffers);
+            iterator start_pos = begin + search_position_;
+            iterator end = iterator::end(data_buffers);
+
+            // Look for a match.
+            std::pair<iterator, bool> result = match_condition_(start_pos, end);
+            if (result.second)
+            {
+              // Full match. We're done.
+              search_position_ = result.first - begin;
+              bytes_to_read = 0;
+            }
+
+            // No match yet. Check if buffer is full.
+            else if (buffers_.size() == buffers_.max_size())
+            {
+              search_position_ = not_found;
+              bytes_to_read = 0;
+            }
+
+            // Need to read some more data.
+            else
+            {
+              if (result.first != end)
+              {
+                // Partial match. Next search needs to start from beginning of
+                // match.
+                search_position_ = result.first - begin;
+              }
+              else
+              {
+                // Next search can start with the new data.
+                search_position_ = end - begin;
+              }
+
+              bytes_to_read = std::min<std::size_t>(
+                    std::max<std::size_t>(512,
+                      buffers_.capacity() - buffers_.size()),
+                    std::min<std::size_t>(65536,
+                      buffers_.max_size() - buffers_.size()));
+            }
+          }
+
+          // Check if we're done.
+          if (!start && bytes_to_read == 0)
+            break;
+
+          // Start a new asynchronous read operation to obtain more data.
+          {
+            ASIO_HANDLER_LOCATION((
+                  __FILE__, __LINE__, "async_read_until"));
+            stream_.async_read_some(buffers_.prepare(bytes_to_read),
+                ASIO_MOVE_CAST(read_until_match_op_v1)(*this));
+          }
+          return; default:
+          buffers_.commit(bytes_transferred);
+          if (ec || bytes_transferred == 0)
+            break;
+        }
+
+        const asio::error_code result_ec =
+          (search_position_ == not_found)
+          ? error::not_found : ec;
+
+        const std::size_t result_n =
+          (ec || search_position_ == not_found)
+          ? 0 : search_position_;
+
+        handler_(result_ec, result_n);
+      }
+    }
+
+  //private:
+    AsyncReadStream& stream_;
+    DynamicBuffer_v1 buffers_;
+    MatchCondition match_condition_;
+    int start_;
+    std::size_t search_position_;
+    ReadHandler handler_;
+  };
+
+  template <typename AsyncReadStream, typename DynamicBuffer_v1,
+      typename MatchCondition, typename ReadHandler>
+  inline asio_handler_allocate_is_deprecated
+  asio_handler_allocate(std::size_t size,
+      read_until_match_op_v1<AsyncReadStream, DynamicBuffer_v1,
+        MatchCondition, ReadHandler>* this_handler)
+  {
+#if defined(ASIO_NO_DEPRECATED)
+    asio_handler_alloc_helpers::allocate(size, this_handler->handler_);
+    return asio_handler_allocate_is_no_longer_used();
+#else // defined(ASIO_NO_DEPRECATED)
+    return asio_handler_alloc_helpers::allocate(
+        size, this_handler->handler_);
+#endif // defined(ASIO_NO_DEPRECATED)
+  }
+
+  template <typename AsyncReadStream, typename DynamicBuffer_v1,
+      typename MatchCondition, typename ReadHandler>
+  inline asio_handler_deallocate_is_deprecated
+  asio_handler_deallocate(void* pointer, std::size_t size,
+      read_until_match_op_v1<AsyncReadStream, DynamicBuffer_v1,
+        MatchCondition, ReadHandler>* this_handler)
+  {
+    asio_handler_alloc_helpers::deallocate(
+        pointer, size, this_handler->handler_);
+#if defined(ASIO_NO_DEPRECATED)
+    return asio_handler_deallocate_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+  }
+
+  template <typename AsyncReadStream, typename DynamicBuffer_v1,
+      typename MatchCondition, typename ReadHandler>
+  inline bool asio_handler_is_continuation(
+      read_until_match_op_v1<AsyncReadStream, DynamicBuffer_v1,
+        MatchCondition, ReadHandler>* this_handler)
+  {
+    return this_handler->start_ == 0 ? true
+      : asio_handler_cont_helpers::is_continuation(
+          this_handler->handler_);
+  }
+
+  template <typename Function, typename AsyncReadStream,
+      typename DynamicBuffer_v1, typename MatchCondition,
+      typename ReadHandler>
+  inline asio_handler_invoke_is_deprecated
+  asio_handler_invoke(Function& function,
+      read_until_match_op_v1<AsyncReadStream, DynamicBuffer_v1,
+        MatchCondition, ReadHandler>* this_handler)
+  {
+    asio_handler_invoke_helpers::invoke(
+        function, this_handler->handler_);
+#if defined(ASIO_NO_DEPRECATED)
+    return asio_handler_invoke_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+  }
+
+  template <typename Function, typename AsyncReadStream,
+      typename DynamicBuffer_v1, typename MatchCondition,
+      typename ReadHandler>
+  inline asio_handler_invoke_is_deprecated
+  asio_handler_invoke(const Function& function,
+      read_until_match_op_v1<AsyncReadStream, DynamicBuffer_v1,
+      MatchCondition, ReadHandler>* this_handler)
+  {
+    asio_handler_invoke_helpers::invoke(
+        function, this_handler->handler_);
+#if defined(ASIO_NO_DEPRECATED)
+    return asio_handler_invoke_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+  }
+
+  template <typename AsyncReadStream>
+  class initiate_async_read_until_match_v1
+  {
+  public:
+    typedef typename AsyncReadStream::executor_type executor_type;
+
+    explicit initiate_async_read_until_match_v1(AsyncReadStream& stream)
+      : stream_(stream)
+    {
+    }
+
+    executor_type get_executor() const ASIO_NOEXCEPT
+    {
+      return stream_.get_executor();
+    }
+
+    template <typename ReadHandler,
+        typename DynamicBuffer_v1, typename MatchCondition>
+    void operator()(ASIO_MOVE_ARG(ReadHandler) handler,
+        ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,
+        MatchCondition match_condition) const
+    {
+      // If you get an error on the following line it means that your handler
+      // does not meet the documented type requirements for a ReadHandler.
+      ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
+
+      non_const_lvalue<ReadHandler> handler2(handler);
+      read_until_match_op_v1<AsyncReadStream,
+        typename decay<DynamicBuffer_v1>::type,
+          MatchCondition, typename decay<ReadHandler>::type>(
+            stream_, ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers),
+            match_condition, handler2.value)(asio::error_code(), 0, 1);
+    }
+
+  private:
+    AsyncReadStream& stream_;
+  };
+} // namespace detail
+
+#if !defined(GENERATING_DOCUMENTATION)
+
+template <typename AsyncReadStream, typename DynamicBuffer_v1,
+    typename MatchCondition, typename ReadHandler, typename Allocator>
+struct associated_allocator<
+    detail::read_until_match_op_v1<AsyncReadStream,
+      DynamicBuffer_v1, MatchCondition, ReadHandler>,
+    Allocator>
+{
+  typedef typename associated_allocator<ReadHandler, Allocator>::type type;
+
+  static type get(
+      const detail::read_until_match_op_v1<AsyncReadStream,
+        DynamicBuffer_v1, MatchCondition, ReadHandler>& h,
+      const Allocator& a = Allocator()) ASIO_NOEXCEPT
+  {
+    return associated_allocator<ReadHandler, Allocator>::get(h.handler_, a);
+  }
+};
+
+template <typename AsyncReadStream, typename DynamicBuffer_v1,
+    typename MatchCondition, typename ReadHandler, typename Executor>
+struct associated_executor<
+    detail::read_until_match_op_v1<AsyncReadStream,
+      DynamicBuffer_v1, MatchCondition, ReadHandler>,
+    Executor>
+  : detail::associated_executor_forwarding_base<ReadHandler, Executor>
+{
+  typedef typename associated_executor<ReadHandler, Executor>::type type;
+
+  static type get(
+      const detail::read_until_match_op_v1<AsyncReadStream,
+        DynamicBuffer_v1, MatchCondition, ReadHandler>& h,
+      const Executor& ex = Executor()) ASIO_NOEXCEPT
+  {
+    return associated_executor<ReadHandler, Executor>::get(h.handler_, ex);
+  }
+};
+
+#endif // !defined(GENERATING_DOCUMENTATION)
+
+template <typename AsyncReadStream,
+    typename DynamicBuffer_v1, typename MatchCondition,
+    ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+      std::size_t)) ReadHandler>
+ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,
+    void (asio::error_code, std::size_t))
+async_read_until(AsyncReadStream& s,
+    ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,
+    MatchCondition match_condition, ASIO_MOVE_ARG(ReadHandler) handler,
+    typename enable_if<
+      is_match_condition<MatchCondition>::value
+        && is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value
+        && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value
+    >::type*)
+{
+  return async_initiate<ReadHandler,
+    void (asio::error_code, std::size_t)>(
+      detail::initiate_async_read_until_match_v1<AsyncReadStream>(s), handler,
+      ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers), match_condition);
+}
+
+#if !defined(ASIO_NO_IOSTREAM)
+
+template <typename AsyncReadStream, typename Allocator,
+    ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+      std::size_t)) ReadHandler>
+inline ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,
+    void (asio::error_code, std::size_t))
+async_read_until(AsyncReadStream& s,
+    asio::basic_streambuf<Allocator>& b,
+    char delim, ASIO_MOVE_ARG(ReadHandler) handler)
+{
+  return async_read_until(s, basic_streambuf_ref<Allocator>(b),
+      delim, ASIO_MOVE_CAST(ReadHandler)(handler));
+}
+
+template <typename AsyncReadStream, typename Allocator,
+    ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+      std::size_t)) ReadHandler>
+inline ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,
+    void (asio::error_code, std::size_t))
+async_read_until(AsyncReadStream& s,
+    asio::basic_streambuf<Allocator>& b,
+    ASIO_STRING_VIEW_PARAM delim,
+    ASIO_MOVE_ARG(ReadHandler) handler)
+{
+  return async_read_until(s, basic_streambuf_ref<Allocator>(b),
+      delim, ASIO_MOVE_CAST(ReadHandler)(handler));
+}
+
+#if defined(ASIO_HAS_BOOST_REGEX)
+
+template <typename AsyncReadStream, typename Allocator,
+    ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+      std::size_t)) ReadHandler>
+inline ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,
+    void (asio::error_code, std::size_t))
+async_read_until(AsyncReadStream& s,
+    asio::basic_streambuf<Allocator>& b, const boost::regex& expr,
+    ASIO_MOVE_ARG(ReadHandler) handler)
+{
+  return async_read_until(s, basic_streambuf_ref<Allocator>(b),
+      expr, ASIO_MOVE_CAST(ReadHandler)(handler));
+}
+
+#endif // defined(ASIO_HAS_BOOST_REGEX)
+
+template <typename AsyncReadStream, typename Allocator, typename MatchCondition,
+    ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+      std::size_t)) ReadHandler>
+inline ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,
+    void (asio::error_code, std::size_t))
+async_read_until(AsyncReadStream& s,
+    asio::basic_streambuf<Allocator>& b,
+    MatchCondition match_condition, ASIO_MOVE_ARG(ReadHandler) handler,
+    typename enable_if<is_match_condition<MatchCondition>::value>::type*)
+{
+  return async_read_until(s, basic_streambuf_ref<Allocator>(b),
+      match_condition, ASIO_MOVE_CAST(ReadHandler)(handler));
+}
+
+#endif // !defined(ASIO_NO_IOSTREAM)
+#endif // !defined(ASIO_NO_EXTENSIONS)
+#endif // !defined(ASIO_NO_DYNAMIC_BUFFER_V1)
+
+namespace detail
+{
+  template <typename AsyncReadStream,
+      typename DynamicBuffer_v2, typename ReadHandler>
+  class read_until_delim_op_v2
+  {
+  public:
+    template <typename BufferSequence>
+    read_until_delim_op_v2(AsyncReadStream& stream,
+        ASIO_MOVE_ARG(BufferSequence) buffers,
+        char delim, ReadHandler& handler)
+      : stream_(stream),
+        buffers_(ASIO_MOVE_CAST(BufferSequence)(buffers)),
+        delim_(delim),
+        start_(0),
+        search_position_(0),
+        bytes_to_read_(0),
+        handler_(ASIO_MOVE_CAST(ReadHandler)(handler))
+    {
+    }
+
+#if defined(ASIO_HAS_MOVE)
+    read_until_delim_op_v2(const read_until_delim_op_v2& other)
+      : stream_(other.stream_),
+        buffers_(other.buffers_),
+        delim_(other.delim_),
+        start_(other.start_),
+        search_position_(other.search_position_),
+        bytes_to_read_(other.bytes_to_read_),
+        handler_(other.handler_)
+    {
+    }
+
+    read_until_delim_op_v2(read_until_delim_op_v2&& other)
+      : stream_(other.stream_),
+        buffers_(ASIO_MOVE_CAST(DynamicBuffer_v2)(other.buffers_)),
+        delim_(other.delim_),
+        start_(other.start_),
+        search_position_(other.search_position_),
+        bytes_to_read_(other.bytes_to_read_),
+        handler_(ASIO_MOVE_CAST(ReadHandler)(other.handler_))
+    {
+    }
+#endif // defined(ASIO_HAS_MOVE)
+
+    void operator()(const asio::error_code& ec,
+        std::size_t bytes_transferred, int start = 0)
+    {
+      const std::size_t not_found = (std::numeric_limits<std::size_t>::max)();
+      std::size_t pos;
+      switch (start_ = start)
+      {
+      case 1:
+        for (;;)
+        {
+          {
+            // Determine the range of the data to be searched.
+            typedef typename DynamicBuffer_v2::const_buffers_type
+              buffers_type;
+            typedef buffers_iterator<buffers_type> iterator;
+            buffers_type data_buffers =
+              const_cast<const DynamicBuffer_v2&>(buffers_).data(
+                  0, buffers_.size());
+            iterator begin = iterator::begin(data_buffers);
+            iterator start_pos = begin + search_position_;
+            iterator end = iterator::end(data_buffers);
+
+            // Look for a match.
+            iterator iter = std::find(start_pos, end, delim_);
+            if (iter != end)
+            {
+              // Found a match. We're done.
+              search_position_ = iter - begin + 1;
+              bytes_to_read_ = 0;
+            }
+
+            // No match yet. Check if buffer is full.
+            else if (buffers_.size() == buffers_.max_size())
+            {
+              search_position_ = not_found;
+              bytes_to_read_ = 0;
+            }
+
+            // Need to read some more data.
+            else
+            {
+              // Next search can start with the new data.
+              search_position_ = end - begin;
+              bytes_to_read_ = std::min<std::size_t>(
+                    std::max<std::size_t>(512,
+                      buffers_.capacity() - buffers_.size()),
+                    std::min<std::size_t>(65536,
+                      buffers_.max_size() - buffers_.size()));
+            }
+          }
+
+          // Check if we're done.
+          if (!start && bytes_to_read_ == 0)
+            break;
+
+          // Start a new asynchronous read operation to obtain more data.
+          pos = buffers_.size();
+          buffers_.grow(bytes_to_read_);
+          {
+            ASIO_HANDLER_LOCATION((
+                  __FILE__, __LINE__, "async_read_until"));
+            stream_.async_read_some(buffers_.data(pos, bytes_to_read_),
+                ASIO_MOVE_CAST(read_until_delim_op_v2)(*this));
+          }
+          return; default:
+          buffers_.shrink(bytes_to_read_ - bytes_transferred);
+          if (ec || bytes_transferred == 0)
+            break;
+        }
+
+        const asio::error_code result_ec =
+          (search_position_ == not_found)
+          ? error::not_found : ec;
+
+        const std::size_t result_n =
+          (ec || search_position_ == not_found)
+          ? 0 : search_position_;
+
+        handler_(result_ec, result_n);
+      }
+    }
+
+  //private:
+    AsyncReadStream& stream_;
+    DynamicBuffer_v2 buffers_;
+    char delim_;
+    int start_;
+    std::size_t search_position_;
+    std::size_t bytes_to_read_;
+    ReadHandler handler_;
+  };
+
+  template <typename AsyncReadStream,
+      typename DynamicBuffer_v2, typename ReadHandler>
+  inline asio_handler_allocate_is_deprecated
+  asio_handler_allocate(std::size_t size,
+      read_until_delim_op_v2<AsyncReadStream,
+        DynamicBuffer_v2, ReadHandler>* this_handler)
+  {
+#if defined(ASIO_NO_DEPRECATED)
+    asio_handler_alloc_helpers::allocate(size, this_handler->handler_);
+    return asio_handler_allocate_is_no_longer_used();
+#else // defined(ASIO_NO_DEPRECATED)
+    return asio_handler_alloc_helpers::allocate(
+        size, this_handler->handler_);
+#endif // defined(ASIO_NO_DEPRECATED)
+  }
+
+  template <typename AsyncReadStream,
+      typename DynamicBuffer_v2, typename ReadHandler>
+  inline asio_handler_deallocate_is_deprecated
+  asio_handler_deallocate(void* pointer, std::size_t size,
+      read_until_delim_op_v2<AsyncReadStream,
+        DynamicBuffer_v2, ReadHandler>* this_handler)
+  {
+    asio_handler_alloc_helpers::deallocate(
+        pointer, size, this_handler->handler_);
+#if defined(ASIO_NO_DEPRECATED)
+    return asio_handler_deallocate_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+  }
+
+  template <typename AsyncReadStream,
+      typename DynamicBuffer_v2, typename ReadHandler>
+  inline bool asio_handler_is_continuation(
+      read_until_delim_op_v2<AsyncReadStream,
+        DynamicBuffer_v2, ReadHandler>* this_handler)
+  {
+    return this_handler->start_ == 0 ? true
+      : asio_handler_cont_helpers::is_continuation(
+          this_handler->handler_);
+  }
+
+  template <typename Function, typename AsyncReadStream,
+      typename DynamicBuffer_v2, typename ReadHandler>
+  inline asio_handler_invoke_is_deprecated
+  asio_handler_invoke(Function& function,
+      read_until_delim_op_v2<AsyncReadStream,
+        DynamicBuffer_v2, ReadHandler>* this_handler)
+  {
+    asio_handler_invoke_helpers::invoke(
+        function, this_handler->handler_);
+#if defined(ASIO_NO_DEPRECATED)
+    return asio_handler_invoke_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+  }
+
+  template <typename Function, typename AsyncReadStream,
+      typename DynamicBuffer_v2, typename ReadHandler>
+  inline asio_handler_invoke_is_deprecated
+  asio_handler_invoke(const Function& function,
+      read_until_delim_op_v2<AsyncReadStream,
+        DynamicBuffer_v2, ReadHandler>* this_handler)
+  {
+    asio_handler_invoke_helpers::invoke(
+        function, this_handler->handler_);
+#if defined(ASIO_NO_DEPRECATED)
+    return asio_handler_invoke_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+  }
+
+  template <typename AsyncReadStream>
+  class initiate_async_read_until_delim_v2
+  {
+  public:
+    typedef typename AsyncReadStream::executor_type executor_type;
+
+    explicit initiate_async_read_until_delim_v2(AsyncReadStream& stream)
+      : stream_(stream)
+    {
+    }
+
+    executor_type get_executor() const ASIO_NOEXCEPT
+    {
+      return stream_.get_executor();
+    }
+
+    template <typename ReadHandler, typename DynamicBuffer_v2>
+    void operator()(ASIO_MOVE_ARG(ReadHandler) handler,
+        ASIO_MOVE_ARG(DynamicBuffer_v2) buffers, char delim) const
+    {
+      // If you get an error on the following line it means that your handler
+      // does not meet the documented type requirements for a ReadHandler.
+      ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
+
+      non_const_lvalue<ReadHandler> handler2(handler);
+      read_until_delim_op_v2<AsyncReadStream,
+        typename decay<DynamicBuffer_v2>::type,
+          typename decay<ReadHandler>::type>(
+            stream_, ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers),
+            delim, handler2.value)(asio::error_code(), 0, 1);
+    }
+
+  private:
+    AsyncReadStream& stream_;
+  };
+} // namespace detail
+
+#if !defined(GENERATING_DOCUMENTATION)
+
+template <typename AsyncReadStream, typename DynamicBuffer_v2,
+    typename ReadHandler, typename Allocator>
+struct associated_allocator<
+    detail::read_until_delim_op_v2<AsyncReadStream,
+      DynamicBuffer_v2, ReadHandler>,
+    Allocator>
+{
+  typedef typename associated_allocator<ReadHandler, Allocator>::type type;
+
+  static type get(
+      const detail::read_until_delim_op_v2<AsyncReadStream,
+        DynamicBuffer_v2, ReadHandler>& h,
+      const Allocator& a = Allocator()) ASIO_NOEXCEPT
+  {
+    return associated_allocator<ReadHandler, Allocator>::get(h.handler_, a);
+  }
+};
+
+template <typename AsyncReadStream, typename DynamicBuffer_v2,
+    typename ReadHandler, typename Executor>
+struct associated_executor<
+    detail::read_until_delim_op_v2<AsyncReadStream,
+      DynamicBuffer_v2, ReadHandler>,
+    Executor>
+  : detail::associated_executor_forwarding_base<ReadHandler, Executor>
+{
+  typedef typename associated_executor<ReadHandler, Executor>::type type;
+
+  static type get(
+      const detail::read_until_delim_op_v2<AsyncReadStream,
+        DynamicBuffer_v2, ReadHandler>& h,
+      const Executor& ex = Executor()) ASIO_NOEXCEPT
+  {
+    return associated_executor<ReadHandler, Executor>::get(h.handler_, ex);
+  }
+};
+
+#endif // !defined(GENERATING_DOCUMENTATION)
+
+template <typename AsyncReadStream, typename DynamicBuffer_v2,
+    ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+      std::size_t)) ReadHandler>
+ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,
+    void (asio::error_code, std::size_t))
+async_read_until(AsyncReadStream& s, DynamicBuffer_v2 buffers,
+    char delim, ASIO_MOVE_ARG(ReadHandler) handler,
+    typename enable_if<
+      is_dynamic_buffer_v2<DynamicBuffer_v2>::value
+    >::type*)
+{
+  return async_initiate<ReadHandler,
+    void (asio::error_code, std::size_t)>(
+      detail::initiate_async_read_until_delim_v2<AsyncReadStream>(s),
+      handler, ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers), delim);
+}
+
+namespace detail
+{
+  template <typename AsyncReadStream,
+      typename DynamicBuffer_v2, typename ReadHandler>
+  class read_until_delim_string_op_v2
+  {
+  public:
+    template <typename BufferSequence>
+    read_until_delim_string_op_v2(AsyncReadStream& stream,
+        ASIO_MOVE_ARG(BufferSequence) buffers,
+        const std::string& delim, ReadHandler& handler)
+      : stream_(stream),
+        buffers_(ASIO_MOVE_CAST(BufferSequence)(buffers)),
+        delim_(delim),
+        start_(0),
+        search_position_(0),
+        bytes_to_read_(0),
+        handler_(ASIO_MOVE_CAST(ReadHandler)(handler))
+    {
+    }
+
+#if defined(ASIO_HAS_MOVE)
+    read_until_delim_string_op_v2(const read_until_delim_string_op_v2& other)
+      : stream_(other.stream_),
+        buffers_(other.buffers_),
+        delim_(other.delim_),
+        start_(other.start_),
+        search_position_(other.search_position_),
+        bytes_to_read_(other.bytes_to_read_),
+        handler_(other.handler_)
+    {
+    }
+
+    read_until_delim_string_op_v2(read_until_delim_string_op_v2&& other)
+      : stream_(other.stream_),
+        buffers_(ASIO_MOVE_CAST(DynamicBuffer_v2)(other.buffers_)),
+        delim_(ASIO_MOVE_CAST(std::string)(other.delim_)),
+        start_(other.start_),
+        search_position_(other.search_position_),
+        bytes_to_read_(other.bytes_to_read_),
+        handler_(ASIO_MOVE_CAST(ReadHandler)(other.handler_))
+    {
+    }
+#endif // defined(ASIO_HAS_MOVE)
+
+    void operator()(const asio::error_code& ec,
+        std::size_t bytes_transferred, int start = 0)
+    {
+      const std::size_t not_found = (std::numeric_limits<std::size_t>::max)();
+      std::size_t pos;
+      switch (start_ = start)
+      {
+      case 1:
+        for (;;)
+        {
+          {
+            // Determine the range of the data to be searched.
+            typedef typename DynamicBuffer_v2::const_buffers_type
+              buffers_type;
+            typedef buffers_iterator<buffers_type> iterator;
+            buffers_type data_buffers =
+              const_cast<const DynamicBuffer_v2&>(buffers_).data(
+                  0, buffers_.size());
+            iterator begin = iterator::begin(data_buffers);
+            iterator start_pos = begin + search_position_;
+            iterator end = iterator::end(data_buffers);
+
+            // Look for a match.
+            std::pair<iterator, bool> result = detail::partial_search(
+                start_pos, end, delim_.begin(), delim_.end());
+            if (result.first != end && result.second)
+            {
+              // Full match. We're done.
+              search_position_ = result.first - begin + delim_.length();
+              bytes_to_read_ = 0;
+            }
+
+            // No match yet. Check if buffer is full.
+            else if (buffers_.size() == buffers_.max_size())
+            {
+              search_position_ = not_found;
+              bytes_to_read_ = 0;
+            }
+
+            // Need to read some more data.
+            else
+            {
+              if (result.first != end)
+              {
+                // Partial match. Next search needs to start from beginning of
+                // match.
+                search_position_ = result.first - begin;
+              }
+              else
+              {
+                // Next search can start with the new data.
+                search_position_ = end - begin;
+              }
+
+              bytes_to_read_ = std::min<std::size_t>(
+                    std::max<std::size_t>(512,
+                      buffers_.capacity() - buffers_.size()),
+                    std::min<std::size_t>(65536,
+                      buffers_.max_size() - buffers_.size()));
+            }
+          }
+
+          // Check if we're done.
+          if (!start && bytes_to_read_ == 0)
+            break;
+
+          // Start a new asynchronous read operation to obtain more data.
+          pos = buffers_.size();
+          buffers_.grow(bytes_to_read_);
+          {
+            ASIO_HANDLER_LOCATION((
+                  __FILE__, __LINE__, "async_read_until"));
+            stream_.async_read_some(buffers_.data(pos, bytes_to_read_),
+                ASIO_MOVE_CAST(read_until_delim_string_op_v2)(*this));
+          }
+          return; default:
+          buffers_.shrink(bytes_to_read_ - bytes_transferred);
+          if (ec || bytes_transferred == 0)
+            break;
+        }
+
+        const asio::error_code result_ec =
+          (search_position_ == not_found)
+          ? error::not_found : ec;
+
+        const std::size_t result_n =
+          (ec || search_position_ == not_found)
+          ? 0 : search_position_;
+
+        handler_(result_ec, result_n);
+      }
+    }
+
+  //private:
+    AsyncReadStream& stream_;
+    DynamicBuffer_v2 buffers_;
+    std::string delim_;
+    int start_;
+    std::size_t search_position_;
+    std::size_t bytes_to_read_;
+    ReadHandler handler_;
+  };
+
+  template <typename AsyncReadStream,
+      typename DynamicBuffer_v2, typename ReadHandler>
+  inline asio_handler_allocate_is_deprecated
+  asio_handler_allocate(std::size_t size,
+      read_until_delim_string_op_v2<AsyncReadStream,
+        DynamicBuffer_v2, ReadHandler>* this_handler)
+  {
+#if defined(ASIO_NO_DEPRECATED)
+    asio_handler_alloc_helpers::allocate(size, this_handler->handler_);
+    return asio_handler_allocate_is_no_longer_used();
+#else // defined(ASIO_NO_DEPRECATED)
+    return asio_handler_alloc_helpers::allocate(
+        size, this_handler->handler_);
+#endif // defined(ASIO_NO_DEPRECATED)
+  }
+
+  template <typename AsyncReadStream,
+      typename DynamicBuffer_v2, typename ReadHandler>
+  inline asio_handler_deallocate_is_deprecated
+  asio_handler_deallocate(void* pointer, std::size_t size,
+      read_until_delim_string_op_v2<AsyncReadStream,
+        DynamicBuffer_v2, ReadHandler>* this_handler)
+  {
+    asio_handler_alloc_helpers::deallocate(
+        pointer, size, this_handler->handler_);
+#if defined(ASIO_NO_DEPRECATED)
+    return asio_handler_deallocate_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+  }
+
+  template <typename AsyncReadStream,
+      typename DynamicBuffer_v2, typename ReadHandler>
+  inline bool asio_handler_is_continuation(
+      read_until_delim_string_op_v2<AsyncReadStream,
+        DynamicBuffer_v2, ReadHandler>* this_handler)
+  {
+    return this_handler->start_ == 0 ? true
+      : asio_handler_cont_helpers::is_continuation(
+          this_handler->handler_);
+  }
+
+  template <typename Function, typename AsyncReadStream,
+      typename DynamicBuffer_v2, typename ReadHandler>
+  inline asio_handler_invoke_is_deprecated
+  asio_handler_invoke(Function& function,
+      read_until_delim_string_op_v2<AsyncReadStream,
+        DynamicBuffer_v2, ReadHandler>* this_handler)
+  {
+    asio_handler_invoke_helpers::invoke(
+        function, this_handler->handler_);
+#if defined(ASIO_NO_DEPRECATED)
+    return asio_handler_invoke_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+  }
+
+  template <typename Function, typename AsyncReadStream,
+      typename DynamicBuffer_v2, typename ReadHandler>
+  inline asio_handler_invoke_is_deprecated
+  asio_handler_invoke(const Function& function,
+      read_until_delim_string_op_v2<AsyncReadStream,
+        DynamicBuffer_v2, ReadHandler>* this_handler)
+  {
+    asio_handler_invoke_helpers::invoke(
+        function, this_handler->handler_);
+#if defined(ASIO_NO_DEPRECATED)
+    return asio_handler_invoke_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+  }
+
+  template <typename AsyncReadStream>
+  class initiate_async_read_until_delim_string_v2
+  {
+  public:
+    typedef typename AsyncReadStream::executor_type executor_type;
+
+    explicit initiate_async_read_until_delim_string_v2(AsyncReadStream& stream)
+      : stream_(stream)
+    {
+    }
+
+    executor_type get_executor() const ASIO_NOEXCEPT
+    {
+      return stream_.get_executor();
+    }
+
+    template <typename ReadHandler, typename DynamicBuffer_v2>
+    void operator()(ASIO_MOVE_ARG(ReadHandler) handler,
+        ASIO_MOVE_ARG(DynamicBuffer_v2) buffers,
+        const std::string& delim) const
+    {
+      // If you get an error on the following line it means that your handler
+      // does not meet the documented type requirements for a ReadHandler.
+      ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
+
+      non_const_lvalue<ReadHandler> handler2(handler);
+      read_until_delim_string_op_v2<AsyncReadStream,
+        typename decay<DynamicBuffer_v2>::type,
+          typename decay<ReadHandler>::type>(
+            stream_, ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers),
+            delim, handler2.value)(asio::error_code(), 0, 1);
+    }
+
+  private:
+    AsyncReadStream& stream_;
+  };
+} // namespace detail
+
+#if !defined(GENERATING_DOCUMENTATION)
+
+template <typename AsyncReadStream, typename DynamicBuffer_v2,
+    typename ReadHandler, typename Allocator>
+struct associated_allocator<
+    detail::read_until_delim_string_op_v2<AsyncReadStream,
+      DynamicBuffer_v2, ReadHandler>,
+    Allocator>
+{
+  typedef typename associated_allocator<ReadHandler, Allocator>::type type;
+
+  static type get(
+      const detail::read_until_delim_string_op_v2<AsyncReadStream,
+        DynamicBuffer_v2, ReadHandler>& h,
+      const Allocator& a = Allocator()) ASIO_NOEXCEPT
+  {
+    return associated_allocator<ReadHandler, Allocator>::get(h.handler_, a);
+  }
+};
+
+template <typename AsyncReadStream, typename DynamicBuffer_v2,
+    typename ReadHandler, typename Executor>
+struct associated_executor<
+    detail::read_until_delim_string_op_v2<AsyncReadStream,
+      DynamicBuffer_v2, ReadHandler>,
+    Executor>
+  : detail::associated_executor_forwarding_base<ReadHandler, Executor>
+{
+  typedef typename associated_executor<ReadHandler, Executor>::type type;
+
+  static type get(
+      const detail::read_until_delim_string_op_v2<AsyncReadStream,
+        DynamicBuffer_v2, ReadHandler>& h,
+      const Executor& ex = Executor()) ASIO_NOEXCEPT
+  {
+    return associated_executor<ReadHandler, Executor>::get(h.handler_, ex);
+  }
+};
+
+#endif // !defined(GENERATING_DOCUMENTATION)
+
+template <typename AsyncReadStream,
+    typename DynamicBuffer_v2,
+    ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+      std::size_t)) ReadHandler>
+ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,
+    void (asio::error_code, std::size_t))
+async_read_until(AsyncReadStream& s,
+    DynamicBuffer_v2 buffers, ASIO_STRING_VIEW_PARAM delim,
+    ASIO_MOVE_ARG(ReadHandler) handler,
+    typename enable_if<
+      is_dynamic_buffer_v2<DynamicBuffer_v2>::value
+    >::type*)
+{
+  return async_initiate<ReadHandler,
+    void (asio::error_code, std::size_t)>(
+      detail::initiate_async_read_until_delim_string_v2<AsyncReadStream>(s),
+      handler, ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers),
+      static_cast<std::string>(delim));
+}
+
+#if !defined(ASIO_NO_EXTENSIONS)
+#if defined(ASIO_HAS_BOOST_REGEX)
+
+namespace detail
+{
+  template <typename AsyncReadStream, typename DynamicBuffer_v2,
+      typename RegEx, typename ReadHandler>
+  class read_until_expr_op_v2
+  {
+  public:
+    template <typename BufferSequence>
+    read_until_expr_op_v2(AsyncReadStream& stream,
+        ASIO_MOVE_ARG(BufferSequence) buffers,
+        const boost::regex& expr, ReadHandler& handler)
+      : stream_(stream),
+        buffers_(ASIO_MOVE_CAST(BufferSequence)(buffers)),
+        expr_(expr),
+        start_(0),
+        search_position_(0),
+        bytes_to_read_(0),
+        handler_(ASIO_MOVE_CAST(ReadHandler)(handler))
+    {
+    }
+
+#if defined(ASIO_HAS_MOVE)
+    read_until_expr_op_v2(const read_until_expr_op_v2& other)
+      : stream_(other.stream_),
+        buffers_(other.buffers_),
+        expr_(other.expr_),
+        start_(other.start_),
+        search_position_(other.search_position_),
+        bytes_to_read_(other.bytes_to_read_),
+        handler_(other.handler_)
+    {
+    }
+
+    read_until_expr_op_v2(read_until_expr_op_v2&& other)
+      : stream_(other.stream_),
+        buffers_(ASIO_MOVE_CAST(DynamicBuffer_v2)(other.buffers_)),
+        expr_(other.expr_),
+        start_(other.start_),
+        search_position_(other.search_position_),
+        bytes_to_read_(other.bytes_to_read_),
+        handler_(ASIO_MOVE_CAST(ReadHandler)(other.handler_))
+    {
+    }
+#endif // defined(ASIO_HAS_MOVE)
+
+    void operator()(const asio::error_code& ec,
+        std::size_t bytes_transferred, int start = 0)
+    {
+      const std::size_t not_found = (std::numeric_limits<std::size_t>::max)();
+      std::size_t pos;
+      switch (start_ = start)
+      {
+      case 1:
+        for (;;)
+        {
+          {
+            // Determine the range of the data to be searched.
+            typedef typename DynamicBuffer_v2::const_buffers_type
+              buffers_type;
+            typedef buffers_iterator<buffers_type> iterator;
+            buffers_type data_buffers =
+              const_cast<const DynamicBuffer_v2&>(buffers_).data(
+                  0, buffers_.size());
+            iterator begin = iterator::begin(data_buffers);
+            iterator start_pos = begin + search_position_;
+            iterator end = iterator::end(data_buffers);
+
+            // Look for a match.
+            boost::match_results<iterator,
+              typename std::vector<boost::sub_match<iterator> >::allocator_type>
+                match_results;
+            bool match = regex_search(start_pos, end, match_results, expr_,
+                boost::match_default | boost::match_partial);
+            if (match && match_results[0].matched)
+            {
+              // Full match. We're done.
+              search_position_ = match_results[0].second - begin;
+              bytes_to_read_ = 0;
+            }
+
+            // No match yet. Check if buffer is full.
+            else if (buffers_.size() == buffers_.max_size())
+            {
+              search_position_ = not_found;
+              bytes_to_read_ = 0;
+            }
+
+            // Need to read some more data.
+            else
+            {
+              if (match)
+              {
+                // Partial match. Next search needs to start from beginning of
+                // match.
+                search_position_ = match_results[0].first - begin;
+              }
+              else
+              {
+                // Next search can start with the new data.
+                search_position_ = end - begin;
+              }
+
+              bytes_to_read_ = std::min<std::size_t>(
+                    std::max<std::size_t>(512,
+                      buffers_.capacity() - buffers_.size()),
+                    std::min<std::size_t>(65536,
+                      buffers_.max_size() - buffers_.size()));
+            }
+          }
+
+          // Check if we're done.
+          if (!start && bytes_to_read_ == 0)
+            break;
+
+          // Start a new asynchronous read operation to obtain more data.
+          pos = buffers_.size();
+          buffers_.grow(bytes_to_read_);
+          {
+            ASIO_HANDLER_LOCATION((
+                  __FILE__, __LINE__, "async_read_until"));
+            stream_.async_read_some(buffers_.data(pos, bytes_to_read_),
+                ASIO_MOVE_CAST(read_until_expr_op_v2)(*this));
+          }
+          return; default:
+          buffers_.shrink(bytes_to_read_ - bytes_transferred);
+          if (ec || bytes_transferred == 0)
+            break;
+        }
+
+        const asio::error_code result_ec =
+          (search_position_ == not_found)
+          ? error::not_found : ec;
+
+        const std::size_t result_n =
+          (ec || search_position_ == not_found)
+          ? 0 : search_position_;
+
+        handler_(result_ec, result_n);
+      }
+    }
+
+  //private:
+    AsyncReadStream& stream_;
+    DynamicBuffer_v2 buffers_;
+    RegEx expr_;
+    int start_;
+    std::size_t search_position_;
+    std::size_t bytes_to_read_;
+    ReadHandler handler_;
+  };
+
+  template <typename AsyncReadStream, typename DynamicBuffer_v2,
+      typename RegEx, typename ReadHandler>
+  inline asio_handler_allocate_is_deprecated
+  asio_handler_allocate(std::size_t size,
+      read_until_expr_op_v2<AsyncReadStream,
+        DynamicBuffer_v2, RegEx, ReadHandler>* this_handler)
+  {
+#if defined(ASIO_NO_DEPRECATED)
+    asio_handler_alloc_helpers::allocate(size, this_handler->handler_);
+    return asio_handler_allocate_is_no_longer_used();
+#else // defined(ASIO_NO_DEPRECATED)
+    return asio_handler_alloc_helpers::allocate(
+        size, this_handler->handler_);
+#endif // defined(ASIO_NO_DEPRECATED)
+  }
+
+  template <typename AsyncReadStream, typename DynamicBuffer_v2,
+      typename RegEx, typename ReadHandler>
+  inline asio_handler_deallocate_is_deprecated
+  asio_handler_deallocate(void* pointer, std::size_t size,
+      read_until_expr_op_v2<AsyncReadStream,
+        DynamicBuffer_v2, RegEx, ReadHandler>* this_handler)
+  {
+    asio_handler_alloc_helpers::deallocate(
+        pointer, size, this_handler->handler_);
+#if defined(ASIO_NO_DEPRECATED)
+    return asio_handler_deallocate_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+  }
+
+  template <typename AsyncReadStream, typename DynamicBuffer_v2,
+      typename RegEx, typename ReadHandler>
+  inline bool asio_handler_is_continuation(
+      read_until_expr_op_v2<AsyncReadStream,
+        DynamicBuffer_v2, RegEx, ReadHandler>* this_handler)
+  {
+    return this_handler->start_ == 0 ? true
+      : asio_handler_cont_helpers::is_continuation(
+          this_handler->handler_);
+  }
+
+  template <typename Function, typename AsyncReadStream,
+      typename DynamicBuffer_v2, typename RegEx, typename ReadHandler>
+  inline asio_handler_invoke_is_deprecated
+  asio_handler_invoke(Function& function,
+      read_until_expr_op_v2<AsyncReadStream,
+        DynamicBuffer_v2, RegEx, ReadHandler>* this_handler)
+  {
+    asio_handler_invoke_helpers::invoke(
+        function, this_handler->handler_);
+#if defined(ASIO_NO_DEPRECATED)
+    return asio_handler_invoke_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+  }
+
+  template <typename Function, typename AsyncReadStream,
+      typename DynamicBuffer_v2, typename RegEx, typename ReadHandler>
+  inline asio_handler_invoke_is_deprecated
+  asio_handler_invoke(const Function& function,
+      read_until_expr_op_v2<AsyncReadStream,
+        DynamicBuffer_v2, RegEx, ReadHandler>* this_handler)
+  {
+    asio_handler_invoke_helpers::invoke(
+        function, this_handler->handler_);
+#if defined(ASIO_NO_DEPRECATED)
+    return asio_handler_invoke_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+  }
+
+  template <typename AsyncReadStream>
+  class initiate_async_read_until_expr_v2
+  {
+  public:
+    typedef typename AsyncReadStream::executor_type executor_type;
+
+    explicit initiate_async_read_until_expr_v2(AsyncReadStream& stream)
+      : stream_(stream)
+    {
+    }
+
+    executor_type get_executor() const ASIO_NOEXCEPT
+    {
+      return stream_.get_executor();
+    }
+
+    template <typename ReadHandler, typename DynamicBuffer_v2, typename RegEx>
+    void operator()(ASIO_MOVE_ARG(ReadHandler) handler,
+        ASIO_MOVE_ARG(DynamicBuffer_v2) buffers,
+        const RegEx& expr) const
+    {
+      // If you get an error on the following line it means that your handler
+      // does not meet the documented type requirements for a ReadHandler.
+      ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
+
+      non_const_lvalue<ReadHandler> handler2(handler);
+      read_until_expr_op_v2<AsyncReadStream,
+        typename decay<DynamicBuffer_v2>::type,
+          RegEx, typename decay<ReadHandler>::type>(
+            stream_, ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers),
+            expr, handler2.value)(asio::error_code(), 0, 1);
+    }
+
+  private:
+    AsyncReadStream& stream_;
+  };
+} // namespace detail
+
+#if !defined(GENERATING_DOCUMENTATION)
+
+template <typename AsyncReadStream, typename DynamicBuffer_v2,
+    typename RegEx, typename ReadHandler, typename Allocator>
+struct associated_allocator<
+    detail::read_until_expr_op_v2<AsyncReadStream,
+      DynamicBuffer_v2, RegEx, ReadHandler>,
+    Allocator>
+{
+  typedef typename associated_allocator<ReadHandler, Allocator>::type type;
+
+  static type get(
+      const detail::read_until_expr_op_v2<AsyncReadStream,
+        DynamicBuffer_v2, RegEx, ReadHandler>& h,
+      const Allocator& a = Allocator()) ASIO_NOEXCEPT
+  {
+    return associated_allocator<ReadHandler, Allocator>::get(h.handler_, a);
+  }
+};
+
+template <typename AsyncReadStream, typename DynamicBuffer_v2,
+    typename RegEx, typename ReadHandler, typename Executor>
+struct associated_executor<
+    detail::read_until_expr_op_v2<AsyncReadStream,
+      DynamicBuffer_v2, RegEx, ReadHandler>,
+    Executor>
+  : detail::associated_executor_forwarding_base<ReadHandler, Executor>
+{
+  typedef typename associated_executor<ReadHandler, Executor>::type type;
+
+  static type get(
+      const detail::read_until_expr_op_v2<AsyncReadStream,
+        DynamicBuffer_v2, RegEx, ReadHandler>& h,
+      const Executor& ex = Executor()) ASIO_NOEXCEPT
+  {
+    return associated_executor<ReadHandler, Executor>::get(h.handler_, ex);
+  }
+};
+
+#endif // !defined(GENERATING_DOCUMENTATION)
+
+template <typename AsyncReadStream, typename DynamicBuffer_v2,
+    ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+      std::size_t)) ReadHandler>
+ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,
+    void (asio::error_code, std::size_t))
+async_read_until(AsyncReadStream& s, DynamicBuffer_v2 buffers,
+    const boost::regex& expr, ASIO_MOVE_ARG(ReadHandler) handler,
+    typename enable_if<
+      is_dynamic_buffer_v2<DynamicBuffer_v2>::value
+    >::type*)
+{
+  return async_initiate<ReadHandler,
+    void (asio::error_code, std::size_t)>(
+      detail::initiate_async_read_until_expr_v2<AsyncReadStream>(s),
+      handler, ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers), expr);
+}
+
+#endif // defined(ASIO_HAS_BOOST_REGEX)
+
+namespace detail
+{
+  template <typename AsyncReadStream, typename DynamicBuffer_v2,
+      typename MatchCondition, typename ReadHandler>
+  class read_until_match_op_v2
+  {
+  public:
+    template <typename BufferSequence>
+    read_until_match_op_v2(AsyncReadStream& stream,
+        ASIO_MOVE_ARG(BufferSequence) buffers,
+        MatchCondition match_condition, ReadHandler& handler)
+      : stream_(stream),
+        buffers_(ASIO_MOVE_CAST(BufferSequence)(buffers)),
+        match_condition_(match_condition),
+        start_(0),
+        search_position_(0),
+        bytes_to_read_(0),
+        handler_(ASIO_MOVE_CAST(ReadHandler)(handler))
+    {
+    }
+
+#if defined(ASIO_HAS_MOVE)
+    read_until_match_op_v2(const read_until_match_op_v2& other)
+      : stream_(other.stream_),
+        buffers_(other.buffers_),
+        match_condition_(other.match_condition_),
+        start_(other.start_),
+        search_position_(other.search_position_),
+        bytes_to_read_(other.bytes_to_read_),
+        handler_(other.handler_)
+    {
+    }
+
+    read_until_match_op_v2(read_until_match_op_v2&& other)
+      : stream_(other.stream_),
+        buffers_(ASIO_MOVE_CAST(DynamicBuffer_v2)(other.buffers_)),
+        match_condition_(other.match_condition_),
+        start_(other.start_),
+        search_position_(other.search_position_),
+        bytes_to_read_(other.bytes_to_read_),
+        handler_(ASIO_MOVE_CAST(ReadHandler)(other.handler_))
+    {
+    }
+#endif // defined(ASIO_HAS_MOVE)
+
+    void operator()(const asio::error_code& ec,
+        std::size_t bytes_transferred, int start = 0)
+    {
+      const std::size_t not_found = (std::numeric_limits<std::size_t>::max)();
+      std::size_t pos;
+      switch (start_ = start)
+      {
+      case 1:
+        for (;;)
+        {
+          {
+            // Determine the range of the data to be searched.
+            typedef typename DynamicBuffer_v2::const_buffers_type
+              buffers_type;
+            typedef buffers_iterator<buffers_type> iterator;
+            buffers_type data_buffers =
+              const_cast<const DynamicBuffer_v2&>(buffers_).data(
+                  0, buffers_.size());
+            iterator begin = iterator::begin(data_buffers);
+            iterator start_pos = begin + search_position_;
+            iterator end = iterator::end(data_buffers);
+
+            // Look for a match.
+            std::pair<iterator, bool> result = match_condition_(start_pos, end);
+            if (result.second)
+            {
+              // Full match. We're done.
+              search_position_ = result.first - begin;
+              bytes_to_read_ = 0;
+            }
+
+            // No match yet. Check if buffer is full.
+            else if (buffers_.size() == buffers_.max_size())
+            {
+              search_position_ = not_found;
+              bytes_to_read_ = 0;
+            }
+
+            // Need to read some more data.
+            else
+            {
+              if (result.first != end)
+              {
+                // Partial match. Next search needs to start from beginning of
+                // match.
+                search_position_ = result.first - begin;
+              }
+              else
+              {
+                // Next search can start with the new data.
+                search_position_ = end - begin;
+              }
+
+              bytes_to_read_ = std::min<std::size_t>(
+                    std::max<std::size_t>(512,
+                      buffers_.capacity() - buffers_.size()),
+                    std::min<std::size_t>(65536,
+                      buffers_.max_size() - buffers_.size()));
+            }
+          }
+
+          // Check if we're done.
+          if (!start && bytes_to_read_ == 0)
+            break;
+
+          // Start a new asynchronous read operation to obtain more data.
+          pos = buffers_.size();
+          buffers_.grow(bytes_to_read_);
+          {
+            ASIO_HANDLER_LOCATION((
+                  __FILE__, __LINE__, "async_read_until"));
+            stream_.async_read_some(buffers_.data(pos, bytes_to_read_),
+                ASIO_MOVE_CAST(read_until_match_op_v2)(*this));
+          }
+          return; default:
+          buffers_.shrink(bytes_to_read_ - bytes_transferred);
+          if (ec || bytes_transferred == 0)
+            break;
+        }
+
+        const asio::error_code result_ec =
+          (search_position_ == not_found)
+          ? error::not_found : ec;
+
+        const std::size_t result_n =
+          (ec || search_position_ == not_found)
+          ? 0 : search_position_;
+
+        handler_(result_ec, result_n);
+      }
+    }
+
+  //private:
+    AsyncReadStream& stream_;
+    DynamicBuffer_v2 buffers_;
+    MatchCondition match_condition_;
+    int start_;
+    std::size_t search_position_;
+    std::size_t bytes_to_read_;
+    ReadHandler handler_;
+  };
+
+  template <typename AsyncReadStream, typename DynamicBuffer_v2,
+      typename MatchCondition, typename ReadHandler>
+  inline asio_handler_allocate_is_deprecated
+  asio_handler_allocate(std::size_t size,
+      read_until_match_op_v2<AsyncReadStream, DynamicBuffer_v2,
+        MatchCondition, ReadHandler>* this_handler)
+  {
+#if defined(ASIO_NO_DEPRECATED)
+    asio_handler_alloc_helpers::allocate(size, this_handler->handler_);
+    return asio_handler_allocate_is_no_longer_used();
+#else // defined(ASIO_NO_DEPRECATED)
+    return asio_handler_alloc_helpers::allocate(
+        size, this_handler->handler_);
+#endif // defined(ASIO_NO_DEPRECATED)
+  }
+
+  template <typename AsyncReadStream, typename DynamicBuffer_v2,
+      typename MatchCondition, typename ReadHandler>
+  inline asio_handler_deallocate_is_deprecated
+  asio_handler_deallocate(void* pointer, std::size_t size,
+      read_until_match_op_v2<AsyncReadStream, DynamicBuffer_v2,
+        MatchCondition, ReadHandler>* this_handler)
+  {
+    asio_handler_alloc_helpers::deallocate(
+        pointer, size, this_handler->handler_);
+#if defined(ASIO_NO_DEPRECATED)
+    return asio_handler_deallocate_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+  }
+
+  template <typename AsyncReadStream, typename DynamicBuffer_v2,
+      typename MatchCondition, typename ReadHandler>
+  inline bool asio_handler_is_continuation(
+      read_until_match_op_v2<AsyncReadStream, DynamicBuffer_v2,
+        MatchCondition, ReadHandler>* this_handler)
+  {
+    return this_handler->start_ == 0 ? true
+      : asio_handler_cont_helpers::is_continuation(
+          this_handler->handler_);
+  }
+
+  template <typename Function, typename AsyncReadStream,
+      typename DynamicBuffer_v2, typename MatchCondition,
+      typename ReadHandler>
+  inline asio_handler_invoke_is_deprecated
+  asio_handler_invoke(Function& function,
+      read_until_match_op_v2<AsyncReadStream, DynamicBuffer_v2,
+        MatchCondition, ReadHandler>* this_handler)
+  {
+    asio_handler_invoke_helpers::invoke(
+        function, this_handler->handler_);
+#if defined(ASIO_NO_DEPRECATED)
+    return asio_handler_invoke_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+  }
+
+  template <typename Function, typename AsyncReadStream,
+      typename DynamicBuffer_v2, typename MatchCondition,
+      typename ReadHandler>
+  inline asio_handler_invoke_is_deprecated
+  asio_handler_invoke(const Function& function,
+      read_until_match_op_v2<AsyncReadStream, DynamicBuffer_v2,
+      MatchCondition, ReadHandler>* this_handler)
+  {
+    asio_handler_invoke_helpers::invoke(
+        function, this_handler->handler_);
+#if defined(ASIO_NO_DEPRECATED)
+    return asio_handler_invoke_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+  }
+
+  template <typename AsyncReadStream>
+  class initiate_async_read_until_match_v2
+  {
+  public:
+    typedef typename AsyncReadStream::executor_type executor_type;
+
+    explicit initiate_async_read_until_match_v2(AsyncReadStream& stream)
+      : stream_(stream)
+    {
+    }
+
+    executor_type get_executor() const ASIO_NOEXCEPT
+    {
+      return stream_.get_executor();
+    }
+
+    template <typename ReadHandler,
+        typename DynamicBuffer_v2, typename MatchCondition>
+    void operator()(ASIO_MOVE_ARG(ReadHandler) handler,
+        ASIO_MOVE_ARG(DynamicBuffer_v2) buffers,
+        MatchCondition match_condition) const
+    {
+      // If you get an error on the following line it means that your handler
+      // does not meet the documented type requirements for a ReadHandler.
+      ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
+
+      non_const_lvalue<ReadHandler> handler2(handler);
+      read_until_match_op_v2<AsyncReadStream,
+        typename decay<DynamicBuffer_v2>::type,
+          MatchCondition, typename decay<ReadHandler>::type>(
+            stream_, ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers),
+            match_condition, handler2.value)(asio::error_code(), 0, 1);
+    }
+
+  private:
+    AsyncReadStream& stream_;
+  };
+} // namespace detail
+
+#if !defined(GENERATING_DOCUMENTATION)
+
+template <typename AsyncReadStream, typename DynamicBuffer_v2,
+    typename MatchCondition, typename ReadHandler, typename Allocator>
+struct associated_allocator<
+    detail::read_until_match_op_v2<AsyncReadStream,
+      DynamicBuffer_v2, MatchCondition, ReadHandler>,
+    Allocator>
+{
+  typedef typename associated_allocator<ReadHandler, Allocator>::type type;
+
+  static type get(
+      const detail::read_until_match_op_v2<AsyncReadStream,
+        DynamicBuffer_v2, MatchCondition, ReadHandler>& h,
+      const Allocator& a = Allocator()) ASIO_NOEXCEPT
+  {
+    return associated_allocator<ReadHandler, Allocator>::get(h.handler_, a);
+  }
+};
+
+template <typename AsyncReadStream, typename DynamicBuffer_v2,
+    typename MatchCondition, typename ReadHandler, typename Executor>
+struct associated_executor<
+    detail::read_until_match_op_v2<AsyncReadStream,
+      DynamicBuffer_v2, MatchCondition, ReadHandler>,
+    Executor>
+  : detail::associated_executor_forwarding_base<ReadHandler, Executor>
+{
+  typedef typename associated_executor<ReadHandler, Executor>::type type;
+
+  static type get(
+      const detail::read_until_match_op_v2<AsyncReadStream,
+        DynamicBuffer_v2, MatchCondition, ReadHandler>& h,
+      const Executor& ex = Executor()) ASIO_NOEXCEPT
+  {
+    return associated_executor<ReadHandler, Executor>::get(h.handler_, ex);
+  }
+};
+
+#endif // !defined(GENERATING_DOCUMENTATION)
+
+template <typename AsyncReadStream,
+    typename DynamicBuffer_v2, typename MatchCondition,
+    ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+      std::size_t)) ReadHandler>
+ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,
+    void (asio::error_code, std::size_t))
+async_read_until(AsyncReadStream& s, DynamicBuffer_v2 buffers,
+    MatchCondition match_condition, ASIO_MOVE_ARG(ReadHandler) handler,
+    typename enable_if<
+      is_match_condition<MatchCondition>::value
+        && is_dynamic_buffer_v2<DynamicBuffer_v2>::value
+    >::type*)
+{
+  return async_initiate<ReadHandler,
+    void (asio::error_code, std::size_t)>(
+      detail::initiate_async_read_until_match_v2<AsyncReadStream>(s), handler,
+      ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers), match_condition);
+}
+
+#endif // !defined(ASIO_NO_EXTENSIONS)
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IMPL_READ_UNTIL_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/impl/redirect_error.hpp b/link/modules/asio-standalone/asio/include/asio/impl/redirect_error.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/impl/redirect_error.hpp
@@ -0,0 +1,390 @@
+
+// impl/redirect_error.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_IMPL_REDIRECT_ERROR_HPP
+#define ASIO_IMPL_REDIRECT_ERROR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/associated_executor.hpp"
+#include "asio/associated_allocator.hpp"
+#include "asio/async_result.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_cont_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/type_traits.hpp"
+#include "asio/detail/variadic_templates.hpp"
+#include "asio/system_error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+// Class to adapt a redirect_error_t as a completion handler.
+template <typename Handler>
+class redirect_error_handler
+{
+public:
+  typedef void result_type;
+
+  template <typename CompletionToken>
+  redirect_error_handler(redirect_error_t<CompletionToken> e)
+    : ec_(e.ec_),
+      handler_(ASIO_MOVE_CAST(CompletionToken)(e.token_))
+  {
+  }
+
+  template <typename RedirectedHandler>
+  redirect_error_handler(asio::error_code& ec,
+      ASIO_MOVE_ARG(RedirectedHandler) h)
+    : ec_(ec),
+      handler_(ASIO_MOVE_CAST(RedirectedHandler)(h))
+  {
+  }
+
+  void operator()()
+  {
+    handler_();
+  }
+
+#if defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+  template <typename Arg, typename... Args>
+  typename enable_if<
+    !is_same<typename decay<Arg>::type, asio::error_code>::value
+  >::type
+  operator()(ASIO_MOVE_ARG(Arg) arg, ASIO_MOVE_ARG(Args)... args)
+  {
+    handler_(ASIO_MOVE_CAST(Arg)(arg),
+        ASIO_MOVE_CAST(Args)(args)...);
+  }
+
+  template <typename... Args>
+  void operator()(const asio::error_code& ec,
+      ASIO_MOVE_ARG(Args)... args)
+  {
+    ec_ = ec;
+    handler_(ASIO_MOVE_CAST(Args)(args)...);
+  }
+
+#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+  template <typename Arg>
+  typename enable_if<
+    !is_same<typename decay<Arg>::type, asio::error_code>::value
+  >::type
+  operator()(ASIO_MOVE_ARG(Arg) arg)
+  {
+    handler_(ASIO_MOVE_CAST(Arg)(arg));
+  }
+
+  void operator()(const asio::error_code& ec)
+  {
+    ec_ = ec;
+    handler_();
+  }
+
+#define ASIO_PRIVATE_REDIRECT_ERROR_DEF(n) \
+  template <typename Arg, ASIO_VARIADIC_TPARAMS(n)> \
+  typename enable_if< \
+    !is_same<typename decay<Arg>::type, asio::error_code>::value \
+  >::type \
+  operator()(ASIO_MOVE_ARG(Arg) arg, ASIO_VARIADIC_MOVE_PARAMS(n)) \
+  { \
+    handler_(ASIO_MOVE_CAST(Arg)(arg), \
+        ASIO_VARIADIC_MOVE_ARGS(n)); \
+  } \
+  \
+  template <ASIO_VARIADIC_TPARAMS(n)> \
+  void operator()(const asio::error_code& ec, \
+      ASIO_VARIADIC_MOVE_PARAMS(n)) \
+  { \
+    ec_ = ec; \
+    handler_(ASIO_VARIADIC_MOVE_ARGS(n)); \
+  } \
+  /**/
+  ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_REDIRECT_ERROR_DEF)
+#undef ASIO_PRIVATE_REDIRECT_ERROR_DEF
+
+#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+//private:
+  asio::error_code& ec_;
+  Handler handler_;
+};
+
+template <typename Handler>
+inline asio_handler_allocate_is_deprecated
+asio_handler_allocate(std::size_t size,
+    redirect_error_handler<Handler>* this_handler)
+{
+#if defined(ASIO_NO_DEPRECATED)
+  asio_handler_alloc_helpers::allocate(size, this_handler->handler_);
+  return asio_handler_allocate_is_no_longer_used();
+#else // defined(ASIO_NO_DEPRECATED)
+  return asio_handler_alloc_helpers::allocate(
+      size, this_handler->handler_);
+#endif // defined(ASIO_NO_DEPRECATED)
+}
+
+template <typename Handler>
+inline asio_handler_deallocate_is_deprecated
+asio_handler_deallocate(void* pointer, std::size_t size,
+    redirect_error_handler<Handler>* this_handler)
+{
+  asio_handler_alloc_helpers::deallocate(
+      pointer, size, this_handler->handler_);
+#if defined(ASIO_NO_DEPRECATED)
+  return asio_handler_deallocate_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+}
+
+template <typename Handler>
+inline bool asio_handler_is_continuation(
+    redirect_error_handler<Handler>* this_handler)
+{
+  return asio_handler_cont_helpers::is_continuation(
+        this_handler->handler_);
+}
+
+template <typename Function, typename Handler>
+inline asio_handler_invoke_is_deprecated
+asio_handler_invoke(Function& function,
+    redirect_error_handler<Handler>* this_handler)
+{
+  asio_handler_invoke_helpers::invoke(
+      function, this_handler->handler_);
+#if defined(ASIO_NO_DEPRECATED)
+  return asio_handler_invoke_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+}
+
+template <typename Function, typename Handler>
+inline asio_handler_invoke_is_deprecated
+asio_handler_invoke(const Function& function,
+    redirect_error_handler<Handler>* this_handler)
+{
+  asio_handler_invoke_helpers::invoke(
+      function, this_handler->handler_);
+#if defined(ASIO_NO_DEPRECATED)
+  return asio_handler_invoke_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+}
+
+template <typename Signature>
+struct redirect_error_signature
+{
+  typedef Signature type;
+};
+
+#if defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+template <typename R, typename... Args>
+struct redirect_error_signature<R(asio::error_code, Args...)>
+{
+  typedef R type(Args...);
+};
+
+template <typename R, typename... Args>
+struct redirect_error_signature<R(const asio::error_code&, Args...)>
+{
+  typedef R type(Args...);
+};
+
+#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+template <typename R>
+struct redirect_error_signature<R(asio::error_code)>
+{
+  typedef R type();
+};
+
+template <typename R>
+struct redirect_error_signature<R(const asio::error_code&)>
+{
+  typedef R type();
+};
+
+#define ASIO_PRIVATE_REDIRECT_ERROR_DEF(n) \
+  template <typename R, ASIO_VARIADIC_TPARAMS(n)> \
+  struct redirect_error_signature< \
+      R(asio::error_code, ASIO_VARIADIC_TARGS(n))> \
+  { \
+    typedef R type(ASIO_VARIADIC_TARGS(n)); \
+  }; \
+  \
+  template <typename R, ASIO_VARIADIC_TPARAMS(n)> \
+  struct redirect_error_signature< \
+      R(const asio::error_code&, ASIO_VARIADIC_TARGS(n))> \
+  { \
+    typedef R type(ASIO_VARIADIC_TARGS(n)); \
+  }; \
+  /**/
+  ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_REDIRECT_ERROR_DEF)
+#undef ASIO_PRIVATE_REDIRECT_ERROR_DEF
+
+#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+} // namespace detail
+
+#if !defined(GENERATING_DOCUMENTATION)
+
+template <typename CompletionToken, typename Signature>
+struct async_result<redirect_error_t<CompletionToken>, Signature>
+{
+  typedef typename async_result<CompletionToken,
+    typename detail::redirect_error_signature<Signature>::type>
+      ::return_type return_type;
+
+  template <typename Initiation>
+  struct init_wrapper
+  {
+    template <typename Init>
+    init_wrapper(asio::error_code& ec, ASIO_MOVE_ARG(Init) init)
+      : ec_(ec),
+        initiation_(ASIO_MOVE_CAST(Init)(init))
+    {
+    }
+
+#if defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+    template <typename Handler, typename... Args>
+    void operator()(
+        ASIO_MOVE_ARG(Handler) handler,
+        ASIO_MOVE_ARG(Args)... args)
+    {
+      ASIO_MOVE_CAST(Initiation)(initiation_)(
+          detail::redirect_error_handler<
+            typename decay<Handler>::type>(
+              ec_, ASIO_MOVE_CAST(Handler)(handler)),
+          ASIO_MOVE_CAST(Args)(args)...);
+    }
+
+#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+    template <typename Handler>
+    void operator()(
+        ASIO_MOVE_ARG(Handler) handler)
+    {
+      ASIO_MOVE_CAST(Initiation)(initiation_)(
+          detail::redirect_error_handler<
+            typename decay<Handler>::type>(
+              ec_, ASIO_MOVE_CAST(Handler)(handler)));
+    }
+
+#define ASIO_PRIVATE_INIT_WRAPPER_DEF(n) \
+    template <typename Handler, ASIO_VARIADIC_TPARAMS(n)> \
+    void operator()( \
+        ASIO_MOVE_ARG(Handler) handler, \
+        ASIO_VARIADIC_MOVE_PARAMS(n)) \
+    { \
+      ASIO_MOVE_CAST(Initiation)(initiation_)( \
+          detail::redirect_error_handler< \
+            typename decay<Handler>::type>( \
+              ec_, ASIO_MOVE_CAST(Handler)(handler)), \
+          ASIO_VARIADIC_MOVE_ARGS(n)); \
+    } \
+    /**/
+    ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_INIT_WRAPPER_DEF)
+#undef ASIO_PRIVATE_INIT_WRAPPER_DEF
+
+#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+    asio::error_code& ec_;
+    Initiation initiation_;
+  };
+
+#if defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+  template <typename Initiation, typename RawCompletionToken, typename... Args>
+  static return_type initiate(
+      ASIO_MOVE_ARG(Initiation) initiation,
+      ASIO_MOVE_ARG(RawCompletionToken) token,
+      ASIO_MOVE_ARG(Args)... args)
+  {
+    return async_initiate<CompletionToken,
+      typename detail::redirect_error_signature<Signature>::type>(
+        init_wrapper<typename decay<Initiation>::type>(
+          token.ec_, ASIO_MOVE_CAST(Initiation)(initiation)),
+        token.token_, ASIO_MOVE_CAST(Args)(args)...);
+  }
+
+#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+  template <typename Initiation, typename RawCompletionToken>
+  static return_type initiate(
+      ASIO_MOVE_ARG(Initiation) initiation,
+      ASIO_MOVE_ARG(RawCompletionToken) token)
+  {
+    return async_initiate<CompletionToken,
+      typename detail::redirect_error_signature<Signature>::type>(
+        init_wrapper<typename decay<Initiation>::type>(
+          token.ec_, ASIO_MOVE_CAST(Initiation)(initiation)),
+        token.token_);
+  }
+
+#define ASIO_PRIVATE_INITIATE_DEF(n) \
+  template <typename Initiation, typename RawCompletionToken, \
+      ASIO_VARIADIC_TPARAMS(n)> \
+  static return_type initiate( \
+      ASIO_MOVE_ARG(Initiation) initiation, \
+      ASIO_MOVE_ARG(RawCompletionToken) token, \
+      ASIO_VARIADIC_MOVE_PARAMS(n)) \
+  { \
+    return async_initiate<CompletionToken, \
+      typename detail::redirect_error_signature<Signature>::type>( \
+        init_wrapper<typename decay<Initiation>::type>( \
+          token.ec_, ASIO_MOVE_CAST(Initiation)(initiation)), \
+        token.token_, ASIO_VARIADIC_MOVE_ARGS(n)); \
+  } \
+  /**/
+  ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_INITIATE_DEF)
+#undef ASIO_PRIVATE_INITIATE_DEF
+
+#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+};
+
+template <typename Handler, typename Executor>
+struct associated_executor<detail::redirect_error_handler<Handler>, Executor>
+{
+  typedef typename associated_executor<Handler, Executor>::type type;
+
+  static type get(
+      const detail::redirect_error_handler<Handler>& h,
+      const Executor& ex = Executor()) ASIO_NOEXCEPT
+  {
+    return associated_executor<Handler, Executor>::get(h.handler_, ex);
+  }
+};
+
+template <typename Handler, typename Allocator>
+struct associated_allocator<detail::redirect_error_handler<Handler>, Allocator>
+{
+  typedef typename associated_allocator<Handler, Allocator>::type type;
+
+  static type get(
+      const detail::redirect_error_handler<Handler>& h,
+      const Allocator& a = Allocator()) ASIO_NOEXCEPT
+  {
+    return associated_allocator<Handler, Allocator>::get(h.handler_, a);
+  }
+};
+
+#endif // !defined(GENERATING_DOCUMENTATION)
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IMPL_REDIRECT_ERROR_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/impl/serial_port_base.hpp b/link/modules/asio-standalone/asio/include/asio/impl/serial_port_base.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/impl/serial_port_base.hpp
@@ -0,0 +1,59 @@
+//
+// impl/serial_port_base.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.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 ASIO_IMPL_SERIAL_PORT_BASE_HPP
+#define ASIO_IMPL_SERIAL_PORT_BASE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+inline serial_port_base::baud_rate::baud_rate(unsigned int rate)
+  : value_(rate)
+{
+}
+
+inline unsigned int serial_port_base::baud_rate::value() const
+{
+  return value_;
+}
+
+inline serial_port_base::flow_control::type
+serial_port_base::flow_control::value() const
+{
+  return value_;
+}
+
+inline serial_port_base::parity::type serial_port_base::parity::value() const
+{
+  return value_;
+}
+
+inline serial_port_base::stop_bits::type
+serial_port_base::stop_bits::value() const
+{
+  return value_;
+}
+
+inline unsigned int serial_port_base::character_size::value() const
+{
+  return value_;
+}
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IMPL_SERIAL_PORT_BASE_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/impl/serial_port_base.ipp b/link/modules/asio-standalone/asio/include/asio/impl/serial_port_base.ipp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/impl/serial_port_base.ipp
@@ -0,0 +1,554 @@
+//
+// impl/serial_port_base.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.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 ASIO_IMPL_SERIAL_PORT_BASE_IPP
+#define ASIO_IMPL_SERIAL_PORT_BASE_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_SERIAL_PORT)
+
+#include <stdexcept>
+#include "asio/error.hpp"
+#include "asio/serial_port_base.hpp"
+#include "asio/detail/throw_exception.hpp"
+
+#if defined(GENERATING_DOCUMENTATION)
+# define ASIO_OPTION_STORAGE implementation_defined
+#elif defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+# define ASIO_OPTION_STORAGE DCB
+#else
+# define ASIO_OPTION_STORAGE termios
+#endif
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+ASIO_SYNC_OP_VOID serial_port_base::baud_rate::store(
+    ASIO_OPTION_STORAGE& storage, asio::error_code& ec) const
+{
+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+  storage.BaudRate = value_;
+#else
+  speed_t baud;
+  switch (value_)
+  {
+  // Do POSIX-specified rates first.
+  case 0: baud = B0; break;
+  case 50: baud = B50; break;
+  case 75: baud = B75; break;
+  case 110: baud = B110; break;
+  case 134: baud = B134; break;
+  case 150: baud = B150; break;
+  case 200: baud = B200; break;
+  case 300: baud = B300; break;
+  case 600: baud = B600; break;
+  case 1200: baud = B1200; break;
+  case 1800: baud = B1800; break;
+  case 2400: baud = B2400; break;
+  case 4800: baud = B4800; break;
+  case 9600: baud = B9600; break;
+  case 19200: baud = B19200; break;
+  case 38400: baud = B38400; break;
+  // And now the extended ones conditionally.
+# ifdef B7200
+  case 7200: baud = B7200; break;
+# endif
+# ifdef B14400
+  case 14400: baud = B14400; break;
+# endif
+# ifdef B57600
+  case 57600: baud = B57600; break;
+# endif
+# ifdef B115200
+  case 115200: baud = B115200; break;
+# endif
+# ifdef B230400
+  case 230400: baud = B230400; break;
+# endif
+# ifdef B460800
+  case 460800: baud = B460800; break;
+# endif
+# ifdef B500000
+  case 500000: baud = B500000; break;
+# endif
+# ifdef B576000
+  case 576000: baud = B576000; break;
+# endif
+# ifdef B921600
+  case 921600: baud = B921600; break;
+# endif
+# ifdef B1000000
+  case 1000000: baud = B1000000; break;
+# endif
+# ifdef B1152000
+  case 1152000: baud = B1152000; break;
+# endif
+# ifdef B2000000
+  case 2000000: baud = B2000000; break;
+# endif
+# ifdef B3000000
+  case 3000000: baud = B3000000; break;
+# endif
+# ifdef B3500000
+  case 3500000: baud = B3500000; break;
+# endif
+# ifdef B4000000
+  case 4000000: baud = B4000000; break;
+# endif
+  default:
+    ec = asio::error::invalid_argument;
+    ASIO_SYNC_OP_VOID_RETURN(ec);
+  }
+# if defined(_BSD_SOURCE) || defined(_DEFAULT_SOURCE)
+  ::cfsetspeed(&storage, baud);
+# else
+  ::cfsetispeed(&storage, baud);
+  ::cfsetospeed(&storage, baud);
+# endif
+#endif
+  ec = asio::error_code();
+  ASIO_SYNC_OP_VOID_RETURN(ec);
+}
+
+ASIO_SYNC_OP_VOID serial_port_base::baud_rate::load(
+    const ASIO_OPTION_STORAGE& storage, asio::error_code& ec)
+{
+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+  value_ = storage.BaudRate;
+#else
+  speed_t baud = ::cfgetospeed(&storage);
+  switch (baud)
+  {
+  // First do those specified by POSIX.
+  case B0: value_ = 0; break;
+  case B50: value_ = 50; break;
+  case B75: value_ = 75; break;
+  case B110: value_ = 110; break;
+  case B134: value_ = 134; break;
+  case B150: value_ = 150; break;
+  case B200: value_ = 200; break;
+  case B300: value_ = 300; break;
+  case B600: value_ = 600; break;
+  case B1200: value_ = 1200; break;
+  case B1800: value_ = 1800; break;
+  case B2400: value_ = 2400; break;
+  case B4800: value_ = 4800; break;
+  case B9600: value_ = 9600; break;
+  case B19200: value_ = 19200; break;
+  case B38400: value_ = 38400; break;
+  // Now conditionally handle a bunch of extended rates.
+# ifdef B7200
+  case B7200: value_ = 7200; break;
+# endif
+# ifdef B14400
+  case B14400: value_ = 14400; break;
+# endif
+# ifdef B57600
+  case B57600: value_ = 57600; break;
+# endif
+# ifdef B115200
+  case B115200: value_ = 115200; break;
+# endif
+# ifdef B230400
+  case B230400: value_ = 230400; break;
+# endif
+# ifdef B460800
+  case B460800: value_ = 460800; break;
+# endif
+# ifdef B500000
+  case B500000: value_ = 500000; break;
+# endif
+# ifdef B576000
+  case B576000: value_ = 576000; break;
+# endif
+# ifdef B921600
+  case B921600: value_ = 921600; break;
+# endif
+# ifdef B1000000
+  case B1000000: value_ = 1000000; break;
+# endif
+# ifdef B1152000
+  case B1152000: value_ = 1152000; break;
+# endif
+# ifdef B2000000
+  case B2000000: value_ = 2000000; break;
+# endif
+# ifdef B3000000
+  case B3000000: value_ = 3000000; break;
+# endif
+# ifdef B3500000
+  case B3500000: value_ = 3500000; break;
+# endif
+# ifdef B4000000
+  case B4000000: value_ = 4000000; break;
+# endif
+  default:
+    value_ = 0;
+    ec = asio::error::invalid_argument;
+    ASIO_SYNC_OP_VOID_RETURN(ec);
+  }
+#endif
+  ec = asio::error_code();
+  ASIO_SYNC_OP_VOID_RETURN(ec);
+}
+
+serial_port_base::flow_control::flow_control(
+    serial_port_base::flow_control::type t)
+  : value_(t)
+{
+  if (t != none && t != software && t != hardware)
+  {
+    std::out_of_range ex("invalid flow_control value");
+    asio::detail::throw_exception(ex);
+  }
+}
+
+ASIO_SYNC_OP_VOID serial_port_base::flow_control::store(
+    ASIO_OPTION_STORAGE& storage, asio::error_code& ec) const
+{
+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+  storage.fOutxCtsFlow = FALSE;
+  storage.fOutxDsrFlow = FALSE;
+  storage.fTXContinueOnXoff = TRUE;
+  storage.fDtrControl = DTR_CONTROL_ENABLE;
+  storage.fDsrSensitivity = FALSE;
+  storage.fOutX = FALSE;
+  storage.fInX = FALSE;
+  storage.fRtsControl = RTS_CONTROL_ENABLE;
+  switch (value_)
+  {
+  case none:
+    break;
+  case software:
+    storage.fOutX = TRUE;
+    storage.fInX = TRUE;
+    break;
+  case hardware:
+    storage.fOutxCtsFlow = TRUE;
+    storage.fRtsControl = RTS_CONTROL_HANDSHAKE;
+    break;
+  default:
+    break;
+  }
+#else
+  switch (value_)
+  {
+  case none:
+    storage.c_iflag &= ~(IXOFF | IXON);
+# if defined(_BSD_SOURCE) || defined(_DEFAULT_SOURCE)
+    storage.c_cflag &= ~CRTSCTS;
+# elif defined(__QNXNTO__)
+    storage.c_cflag &= ~(IHFLOW | OHFLOW);
+# endif
+    break;
+  case software:
+    storage.c_iflag |= IXOFF | IXON;
+# if defined(_BSD_SOURCE) || defined(_DEFAULT_SOURCE)
+    storage.c_cflag &= ~CRTSCTS;
+# elif defined(__QNXNTO__)
+    storage.c_cflag &= ~(IHFLOW | OHFLOW);
+# endif
+    break;
+  case hardware:
+# if defined(_BSD_SOURCE) || defined(_DEFAULT_SOURCE)
+    storage.c_iflag &= ~(IXOFF | IXON);
+    storage.c_cflag |= CRTSCTS;
+    break;
+# elif defined(__QNXNTO__)
+    storage.c_iflag &= ~(IXOFF | IXON);
+    storage.c_cflag |= (IHFLOW | OHFLOW);
+    break;
+# else
+    ec = asio::error::operation_not_supported;
+    ASIO_SYNC_OP_VOID_RETURN(ec);
+# endif
+  default:
+    break;
+  }
+#endif
+  ec = asio::error_code();
+  ASIO_SYNC_OP_VOID_RETURN(ec);
+}
+
+ASIO_SYNC_OP_VOID serial_port_base::flow_control::load(
+    const ASIO_OPTION_STORAGE& storage, asio::error_code& ec)
+{
+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+  if (storage.fOutX && storage.fInX)
+  {
+    value_ = software;
+  }
+  else if (storage.fOutxCtsFlow && storage.fRtsControl == RTS_CONTROL_HANDSHAKE)
+  {
+    value_ = hardware;
+  }
+  else
+  {
+    value_ = none;
+  }
+#else
+  if (storage.c_iflag & (IXOFF | IXON))
+  {
+    value_ = software;
+  }
+# if defined(_BSD_SOURCE) || defined(_DEFAULT_SOURCE)
+  else if (storage.c_cflag & CRTSCTS)
+  {
+    value_ = hardware;
+  }
+# elif defined(__QNXNTO__)
+  else if (storage.c_cflag & IHFLOW && storage.c_cflag & OHFLOW)
+  {
+    value_ = hardware;
+  }
+# endif
+  else
+  {
+    value_ = none;
+  }
+#endif
+  ec = asio::error_code();
+  ASIO_SYNC_OP_VOID_RETURN(ec);
+}
+
+serial_port_base::parity::parity(serial_port_base::parity::type t)
+  : value_(t)
+{
+  if (t != none && t != odd && t != even)
+  {
+    std::out_of_range ex("invalid parity value");
+    asio::detail::throw_exception(ex);
+  }
+}
+
+ASIO_SYNC_OP_VOID serial_port_base::parity::store(
+    ASIO_OPTION_STORAGE& storage, asio::error_code& ec) const
+{
+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+  switch (value_)
+  {
+  case none:
+    storage.fParity = FALSE;
+    storage.Parity = NOPARITY;
+    break;
+  case odd:
+    storage.fParity = TRUE;
+    storage.Parity = ODDPARITY;
+    break;
+  case even:
+    storage.fParity = TRUE;
+    storage.Parity = EVENPARITY;
+    break;
+  default:
+    break;
+  }
+#else
+  switch (value_)
+  {
+  case none:
+    storage.c_iflag |= IGNPAR;
+    storage.c_cflag &= ~(PARENB | PARODD);
+    break;
+  case even:
+    storage.c_iflag &= ~(IGNPAR | PARMRK);
+    storage.c_iflag |= INPCK;
+    storage.c_cflag |= PARENB;
+    storage.c_cflag &= ~PARODD;
+    break;
+  case odd:
+    storage.c_iflag &= ~(IGNPAR | PARMRK);
+    storage.c_iflag |= INPCK;
+    storage.c_cflag |= (PARENB | PARODD);
+    break;
+  default:
+    break;
+  }
+#endif
+  ec = asio::error_code();
+  ASIO_SYNC_OP_VOID_RETURN(ec);
+}
+
+ASIO_SYNC_OP_VOID serial_port_base::parity::load(
+    const ASIO_OPTION_STORAGE& storage, asio::error_code& ec)
+{
+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+  if (storage.Parity == EVENPARITY)
+  {
+    value_ = even;
+  }
+  else if (storage.Parity == ODDPARITY)
+  {
+    value_ = odd;
+  }
+  else
+  {
+    value_ = none;
+  }
+#else
+  if (storage.c_cflag & PARENB)
+  {
+    if (storage.c_cflag & PARODD)
+    {
+      value_ = odd;
+    }
+    else
+    {
+      value_ = even;
+    }
+  }
+  else
+  {
+    value_ = none;
+  }
+#endif
+  ec = asio::error_code();
+  ASIO_SYNC_OP_VOID_RETURN(ec);
+}
+
+serial_port_base::stop_bits::stop_bits(
+    serial_port_base::stop_bits::type t)
+  : value_(t)
+{
+  if (t != one && t != onepointfive && t != two)
+  {
+    std::out_of_range ex("invalid stop_bits value");
+    asio::detail::throw_exception(ex);
+  }
+}
+
+ASIO_SYNC_OP_VOID serial_port_base::stop_bits::store(
+    ASIO_OPTION_STORAGE& storage, asio::error_code& ec) const
+{
+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+  switch (value_)
+  {
+  case one:
+    storage.StopBits = ONESTOPBIT;
+    break;
+  case onepointfive:
+    storage.StopBits = ONE5STOPBITS;
+    break;
+  case two:
+    storage.StopBits = TWOSTOPBITS;
+    break;
+  default:
+    break;
+  }
+#else
+  switch (value_)
+  {
+  case one:
+    storage.c_cflag &= ~CSTOPB;
+    break;
+  case two:
+    storage.c_cflag |= CSTOPB;
+    break;
+  default:
+    ec = asio::error::operation_not_supported;
+    ASIO_SYNC_OP_VOID_RETURN(ec);
+  }
+#endif
+  ec = asio::error_code();
+  ASIO_SYNC_OP_VOID_RETURN(ec);
+}
+
+ASIO_SYNC_OP_VOID serial_port_base::stop_bits::load(
+    const ASIO_OPTION_STORAGE& storage, asio::error_code& ec)
+{
+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+  if (storage.StopBits == ONESTOPBIT)
+  {
+    value_ = one;
+  }
+  else if (storage.StopBits == ONE5STOPBITS)
+  {
+    value_ = onepointfive;
+  }
+  else if (storage.StopBits == TWOSTOPBITS)
+  {
+    value_ = two;
+  }
+  else
+  {
+    value_ = one;
+  }
+#else
+  value_ = (storage.c_cflag & CSTOPB) ? two : one;
+#endif
+  ec = asio::error_code();
+  ASIO_SYNC_OP_VOID_RETURN(ec);
+}
+
+serial_port_base::character_size::character_size(unsigned int t)
+  : value_(t)
+{
+  if (t < 5 || t > 8)
+  {
+    std::out_of_range ex("invalid character_size value");
+    asio::detail::throw_exception(ex);
+  }
+}
+
+ASIO_SYNC_OP_VOID serial_port_base::character_size::store(
+    ASIO_OPTION_STORAGE& storage, asio::error_code& ec) const
+{
+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+  storage.ByteSize = value_;
+#else
+  storage.c_cflag &= ~CSIZE;
+  switch (value_)
+  {
+  case 5: storage.c_cflag |= CS5; break;
+  case 6: storage.c_cflag |= CS6; break;
+  case 7: storage.c_cflag |= CS7; break;
+  case 8: storage.c_cflag |= CS8; break;
+  default: break;
+  }
+#endif
+  ec = asio::error_code();
+  ASIO_SYNC_OP_VOID_RETURN(ec);
+}
+
+ASIO_SYNC_OP_VOID serial_port_base::character_size::load(
+    const ASIO_OPTION_STORAGE& storage, asio::error_code& ec)
+{
+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+  value_ = storage.ByteSize;
+#else
+  if ((storage.c_cflag & CSIZE) == CS5) { value_ = 5; }
+  else if ((storage.c_cflag & CSIZE) == CS6) { value_ = 6; }
+  else if ((storage.c_cflag & CSIZE) == CS7) { value_ = 7; }
+  else if ((storage.c_cflag & CSIZE) == CS8) { value_ = 8; }
+  else
+  {
+    // Hmmm, use 8 for now.
+    value_ = 8;
+  }
+#endif
+  ec = asio::error_code();
+  ASIO_SYNC_OP_VOID_RETURN(ec);
+}
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#undef ASIO_OPTION_STORAGE
+
+#endif // defined(ASIO_HAS_SERIAL_PORT)
+
+#endif // ASIO_IMPL_SERIAL_PORT_BASE_IPP
diff --git a/link/modules/asio-standalone/asio/include/asio/impl/spawn.hpp b/link/modules/asio-standalone/asio/include/asio/impl/spawn.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/impl/spawn.hpp
@@ -0,0 +1,526 @@
+//
+// impl/spawn.hpp
+// ~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_IMPL_SPAWN_HPP
+#define ASIO_IMPL_SPAWN_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/associated_allocator.hpp"
+#include "asio/associated_executor.hpp"
+#include "asio/async_result.hpp"
+#include "asio/bind_executor.hpp"
+#include "asio/detail/atomic_count.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_cont_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/detail/noncopyable.hpp"
+#include "asio/detail/type_traits.hpp"
+#include "asio/system_error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+  template <typename Handler, typename T>
+  class coro_handler
+  {
+  public:
+    coro_handler(basic_yield_context<Handler> ctx)
+      : coro_(ctx.coro_.lock()),
+        ca_(ctx.ca_),
+        handler_(ctx.handler_),
+        ready_(0),
+        ec_(ctx.ec_),
+        value_(0)
+    {
+    }
+
+    void operator()(T value)
+    {
+      *ec_ = asio::error_code();
+      *value_ = ASIO_MOVE_CAST(T)(value);
+      if (--*ready_ == 0)
+        (*coro_)();
+    }
+
+    void operator()(asio::error_code ec, T value)
+    {
+      *ec_ = ec;
+      *value_ = ASIO_MOVE_CAST(T)(value);
+      if (--*ready_ == 0)
+        (*coro_)();
+    }
+
+  //private:
+    shared_ptr<typename basic_yield_context<Handler>::callee_type> coro_;
+    typename basic_yield_context<Handler>::caller_type& ca_;
+    Handler handler_;
+    atomic_count* ready_;
+    asio::error_code* ec_;
+    T* value_;
+  };
+
+  template <typename Handler>
+  class coro_handler<Handler, void>
+  {
+  public:
+    coro_handler(basic_yield_context<Handler> ctx)
+      : coro_(ctx.coro_.lock()),
+        ca_(ctx.ca_),
+        handler_(ctx.handler_),
+        ready_(0),
+        ec_(ctx.ec_)
+    {
+    }
+
+    void operator()()
+    {
+      *ec_ = asio::error_code();
+      if (--*ready_ == 0)
+        (*coro_)();
+    }
+
+    void operator()(asio::error_code ec)
+    {
+      *ec_ = ec;
+      if (--*ready_ == 0)
+        (*coro_)();
+    }
+
+  //private:
+    shared_ptr<typename basic_yield_context<Handler>::callee_type> coro_;
+    typename basic_yield_context<Handler>::caller_type& ca_;
+    Handler handler_;
+    atomic_count* ready_;
+    asio::error_code* ec_;
+  };
+
+  template <typename Handler, typename T>
+  inline asio_handler_allocate_is_deprecated
+  asio_handler_allocate(std::size_t size,
+      coro_handler<Handler, T>* this_handler)
+  {
+#if defined(ASIO_NO_DEPRECATED)
+    asio_handler_alloc_helpers::allocate(size, this_handler->handler_);
+    return asio_handler_allocate_is_no_longer_used();
+#else // defined(ASIO_NO_DEPRECATED)
+    return asio_handler_alloc_helpers::allocate(
+        size, this_handler->handler_);
+#endif // defined(ASIO_NO_DEPRECATED)
+  }
+
+  template <typename Handler, typename T>
+  inline asio_handler_deallocate_is_deprecated
+  asio_handler_deallocate(void* pointer, std::size_t size,
+      coro_handler<Handler, T>* this_handler)
+  {
+    asio_handler_alloc_helpers::deallocate(
+        pointer, size, this_handler->handler_);
+#if defined(ASIO_NO_DEPRECATED)
+    return asio_handler_deallocate_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+  }
+
+  template <typename Handler, typename T>
+  inline bool asio_handler_is_continuation(coro_handler<Handler, T>*)
+  {
+    return true;
+  }
+
+  template <typename Function, typename Handler, typename T>
+  inline asio_handler_invoke_is_deprecated
+  asio_handler_invoke(Function& function,
+      coro_handler<Handler, T>* this_handler)
+  {
+    asio_handler_invoke_helpers::invoke(
+        function, this_handler->handler_);
+#if defined(ASIO_NO_DEPRECATED)
+    return asio_handler_invoke_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+  }
+
+  template <typename Function, typename Handler, typename T>
+  inline asio_handler_invoke_is_deprecated
+  asio_handler_invoke(const Function& function,
+      coro_handler<Handler, T>* this_handler)
+  {
+    asio_handler_invoke_helpers::invoke(
+        function, this_handler->handler_);
+#if defined(ASIO_NO_DEPRECATED)
+    return asio_handler_invoke_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+  }
+
+  template <typename Handler, typename T>
+  class coro_async_result
+  {
+  public:
+    typedef coro_handler<Handler, T> completion_handler_type;
+    typedef T return_type;
+
+    explicit coro_async_result(completion_handler_type& h)
+      : handler_(h),
+        ca_(h.ca_),
+        ready_(2)
+    {
+      h.ready_ = &ready_;
+      out_ec_ = h.ec_;
+      if (!out_ec_) h.ec_ = &ec_;
+      h.value_ = &value_;
+    }
+
+    return_type get()
+    {
+      // Must not hold shared_ptr to coro while suspended.
+      handler_.coro_.reset();
+
+      if (--ready_ != 0)
+        ca_();
+      if (!out_ec_ && ec_) throw asio::system_error(ec_);
+      return ASIO_MOVE_CAST(return_type)(value_);
+    }
+
+  private:
+    completion_handler_type& handler_;
+    typename basic_yield_context<Handler>::caller_type& ca_;
+    atomic_count ready_;
+    asio::error_code* out_ec_;
+    asio::error_code ec_;
+    return_type value_;
+  };
+
+  template <typename Handler>
+  class coro_async_result<Handler, void>
+  {
+  public:
+    typedef coro_handler<Handler, void> completion_handler_type;
+    typedef void return_type;
+
+    explicit coro_async_result(completion_handler_type& h)
+      : handler_(h),
+        ca_(h.ca_),
+        ready_(2)
+    {
+      h.ready_ = &ready_;
+      out_ec_ = h.ec_;
+      if (!out_ec_) h.ec_ = &ec_;
+    }
+
+    void get()
+    {
+      // Must not hold shared_ptr to coro while suspended.
+      handler_.coro_.reset();
+
+      if (--ready_ != 0)
+        ca_();
+      if (!out_ec_ && ec_) throw asio::system_error(ec_);
+    }
+
+  private:
+    completion_handler_type& handler_;
+    typename basic_yield_context<Handler>::caller_type& ca_;
+    atomic_count ready_;
+    asio::error_code* out_ec_;
+    asio::error_code ec_;
+  };
+
+} // namespace detail
+
+#if !defined(GENERATING_DOCUMENTATION)
+
+template <typename Handler, typename ReturnType>
+class async_result<basic_yield_context<Handler>, ReturnType()>
+  : public detail::coro_async_result<Handler, void>
+{
+public:
+  explicit async_result(
+    typename detail::coro_async_result<Handler,
+      void>::completion_handler_type& h)
+    : detail::coro_async_result<Handler, void>(h)
+  {
+  }
+};
+
+template <typename Handler, typename ReturnType, typename Arg1>
+class async_result<basic_yield_context<Handler>, ReturnType(Arg1)>
+  : public detail::coro_async_result<Handler, typename decay<Arg1>::type>
+{
+public:
+  explicit async_result(
+    typename detail::coro_async_result<Handler,
+      typename decay<Arg1>::type>::completion_handler_type& h)
+    : detail::coro_async_result<Handler, typename decay<Arg1>::type>(h)
+  {
+  }
+};
+
+template <typename Handler, typename ReturnType>
+class async_result<basic_yield_context<Handler>,
+    ReturnType(asio::error_code)>
+  : public detail::coro_async_result<Handler, void>
+{
+public:
+  explicit async_result(
+    typename detail::coro_async_result<Handler,
+      void>::completion_handler_type& h)
+    : detail::coro_async_result<Handler, void>(h)
+  {
+  }
+};
+
+template <typename Handler, typename ReturnType, typename Arg2>
+class async_result<basic_yield_context<Handler>,
+    ReturnType(asio::error_code, Arg2)>
+  : public detail::coro_async_result<Handler, typename decay<Arg2>::type>
+{
+public:
+  explicit async_result(
+    typename detail::coro_async_result<Handler,
+      typename decay<Arg2>::type>::completion_handler_type& h)
+    : detail::coro_async_result<Handler, typename decay<Arg2>::type>(h)
+  {
+  }
+};
+
+template <typename Handler, typename T, typename Allocator>
+struct associated_allocator<detail::coro_handler<Handler, T>, Allocator>
+{
+  typedef typename associated_allocator<Handler, Allocator>::type type;
+
+  static type get(const detail::coro_handler<Handler, T>& h,
+      const Allocator& a = Allocator()) ASIO_NOEXCEPT
+  {
+    return associated_allocator<Handler, Allocator>::get(h.handler_, a);
+  }
+};
+
+template <typename Handler, typename T, typename Executor>
+struct associated_executor<detail::coro_handler<Handler, T>, Executor>
+{
+  typedef typename associated_executor<Handler, Executor>::type type;
+
+  static type get(const detail::coro_handler<Handler, T>& h,
+      const Executor& ex = Executor()) ASIO_NOEXCEPT
+  {
+    return associated_executor<Handler, Executor>::get(h.handler_, ex);
+  }
+};
+
+namespace detail {
+
+  template <typename Handler, typename Function>
+  struct spawn_data : private noncopyable
+  {
+    template <typename Hand, typename Func>
+    spawn_data(ASIO_MOVE_ARG(Hand) handler,
+        bool call_handler, ASIO_MOVE_ARG(Func) function)
+      : handler_(ASIO_MOVE_CAST(Hand)(handler)),
+        call_handler_(call_handler),
+        function_(ASIO_MOVE_CAST(Func)(function))
+    {
+    }
+
+    weak_ptr<typename basic_yield_context<Handler>::callee_type> coro_;
+    Handler handler_;
+    bool call_handler_;
+    Function function_;
+  };
+
+  template <typename Handler, typename Function>
+  struct coro_entry_point
+  {
+    void operator()(typename basic_yield_context<Handler>::caller_type& ca)
+    {
+      shared_ptr<spawn_data<Handler, Function> > data(data_);
+#if !defined(BOOST_COROUTINES_UNIDIRECT) && !defined(BOOST_COROUTINES_V2)
+      ca(); // Yield until coroutine pointer has been initialised.
+#endif // !defined(BOOST_COROUTINES_UNIDIRECT) && !defined(BOOST_COROUTINES_V2)
+      const basic_yield_context<Handler> yield(
+          data->coro_, ca, data->handler_);
+
+      (data->function_)(yield);
+      if (data->call_handler_)
+        (data->handler_)();
+    }
+
+    shared_ptr<spawn_data<Handler, Function> > data_;
+  };
+
+  template <typename Handler, typename Function>
+  struct spawn_helper
+  {
+    typedef typename associated_allocator<Handler>::type allocator_type;
+
+    allocator_type get_allocator() const ASIO_NOEXCEPT
+    {
+      return (get_associated_allocator)(data_->handler_);
+    }
+
+    typedef typename associated_executor<Handler>::type executor_type;
+
+    executor_type get_executor() const ASIO_NOEXCEPT
+    {
+      return (get_associated_executor)(data_->handler_);
+    }
+
+    void operator()()
+    {
+      typedef typename basic_yield_context<Handler>::callee_type callee_type;
+      coro_entry_point<Handler, Function> entry_point = { data_ };
+      shared_ptr<callee_type> coro(new callee_type(entry_point, attributes_));
+      data_->coro_ = coro;
+      (*coro)();
+    }
+
+    shared_ptr<spawn_data<Handler, Function> > data_;
+    boost::coroutines::attributes attributes_;
+  };
+
+  template <typename Function, typename Handler, typename Function1>
+  inline asio_handler_invoke_is_deprecated
+  asio_handler_invoke(Function& function,
+      spawn_helper<Handler, Function1>* this_handler)
+  {
+    asio_handler_invoke_helpers::invoke(
+        function, this_handler->data_->handler_);
+#if defined(ASIO_NO_DEPRECATED)
+    return asio_handler_invoke_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+  }
+
+  template <typename Function, typename Handler, typename Function1>
+  inline asio_handler_invoke_is_deprecated
+  asio_handler_invoke(const Function& function,
+      spawn_helper<Handler, Function1>* this_handler)
+  {
+    asio_handler_invoke_helpers::invoke(
+        function, this_handler->data_->handler_);
+#if defined(ASIO_NO_DEPRECATED)
+    return asio_handler_invoke_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+  }
+
+  inline void default_spawn_handler() {}
+
+} // namespace detail
+
+template <typename Function>
+inline void spawn(ASIO_MOVE_ARG(Function) function,
+    const boost::coroutines::attributes& attributes)
+{
+  typedef typename decay<Function>::type function_type;
+
+  typename associated_executor<function_type>::type ex(
+      (get_associated_executor)(function));
+
+  asio::spawn(ex, ASIO_MOVE_CAST(Function)(function), attributes);
+}
+
+template <typename Handler, typename Function>
+void spawn(ASIO_MOVE_ARG(Handler) handler,
+    ASIO_MOVE_ARG(Function) function,
+    const boost::coroutines::attributes& attributes,
+    typename enable_if<
+      !is_executor<typename decay<Handler>::type>::value &&
+      !execution::is_executor<typename decay<Handler>::type>::value &&
+      !is_convertible<Handler&, execution_context&>::value>::type*)
+{
+  typedef typename decay<Handler>::type handler_type;
+  typedef typename decay<Function>::type function_type;
+
+  detail::spawn_helper<handler_type, function_type> helper;
+  helper.data_.reset(
+      new detail::spawn_data<handler_type, function_type>(
+        ASIO_MOVE_CAST(Handler)(handler), true,
+        ASIO_MOVE_CAST(Function)(function)));
+  helper.attributes_ = attributes;
+
+  asio::dispatch(helper);
+}
+
+template <typename Handler, typename Function>
+void spawn(basic_yield_context<Handler> ctx,
+    ASIO_MOVE_ARG(Function) function,
+    const boost::coroutines::attributes& attributes)
+{
+  typedef typename decay<Function>::type function_type;
+
+  Handler handler(ctx.handler_); // Explicit copy that might be moved from.
+
+  detail::spawn_helper<Handler, function_type> helper;
+  helper.data_.reset(
+      new detail::spawn_data<Handler, function_type>(
+        ASIO_MOVE_CAST(Handler)(handler), false,
+        ASIO_MOVE_CAST(Function)(function)));
+  helper.attributes_ = attributes;
+
+  asio::dispatch(helper);
+}
+
+template <typename Function, typename Executor>
+inline void spawn(const Executor& ex,
+    ASIO_MOVE_ARG(Function) function,
+    const boost::coroutines::attributes& attributes,
+    typename enable_if<
+      is_executor<Executor>::value || execution::is_executor<Executor>::value
+    >::type*)
+{
+  asio::spawn(asio::strand<Executor>(ex),
+      ASIO_MOVE_CAST(Function)(function), attributes);
+}
+
+template <typename Function, typename Executor>
+inline void spawn(const strand<Executor>& ex,
+    ASIO_MOVE_ARG(Function) function,
+    const boost::coroutines::attributes& attributes)
+{
+  asio::spawn(asio::bind_executor(
+        ex, &detail::default_spawn_handler),
+      ASIO_MOVE_CAST(Function)(function), attributes);
+}
+
+#if !defined(ASIO_NO_TS_EXECUTORS)
+
+template <typename Function>
+inline void spawn(const asio::io_context::strand& s,
+    ASIO_MOVE_ARG(Function) function,
+    const boost::coroutines::attributes& attributes)
+{
+  asio::spawn(asio::bind_executor(
+        s, &detail::default_spawn_handler),
+      ASIO_MOVE_CAST(Function)(function), attributes);
+}
+
+#endif // !defined(ASIO_NO_TS_EXECUTORS)
+
+template <typename Function, typename ExecutionContext>
+inline void spawn(ExecutionContext& ctx,
+    ASIO_MOVE_ARG(Function) function,
+    const boost::coroutines::attributes& attributes,
+    typename enable_if<is_convertible<
+      ExecutionContext&, execution_context&>::value>::type*)
+{
+  asio::spawn(ctx.get_executor(),
+      ASIO_MOVE_CAST(Function)(function), attributes);
+}
+
+#endif // !defined(GENERATING_DOCUMENTATION)
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IMPL_SPAWN_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/impl/src.hpp b/link/modules/asio-standalone/asio/include/asio/impl/src.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/impl/src.hpp
@@ -0,0 +1,85 @@
+//
+// impl/src.hpp
+// ~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_IMPL_SRC_HPP
+#define ASIO_IMPL_SRC_HPP
+
+#define ASIO_SOURCE
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HEADER_ONLY)
+# error Do not compile Asio library source with ASIO_HEADER_ONLY defined
+#endif
+
+#include "asio/impl/error.ipp"
+#include "asio/impl/error_code.ipp"
+#include "asio/impl/execution_context.ipp"
+#include "asio/impl/executor.ipp"
+#include "asio/impl/handler_alloc_hook.ipp"
+#include "asio/impl/io_context.ipp"
+#include "asio/impl/multiple_exceptions.ipp"
+#include "asio/impl/serial_port_base.ipp"
+#include "asio/impl/system_context.ipp"
+#include "asio/impl/thread_pool.ipp"
+#include "asio/detail/impl/buffer_sequence_adapter.ipp"
+#include "asio/detail/impl/descriptor_ops.ipp"
+#include "asio/detail/impl/dev_poll_reactor.ipp"
+#include "asio/detail/impl/epoll_reactor.ipp"
+#include "asio/detail/impl/eventfd_select_interrupter.ipp"
+#include "asio/detail/impl/handler_tracking.ipp"
+#include "asio/detail/impl/kqueue_reactor.ipp"
+#include "asio/detail/impl/null_event.ipp"
+#include "asio/detail/impl/pipe_select_interrupter.ipp"
+#include "asio/detail/impl/posix_event.ipp"
+#include "asio/detail/impl/posix_mutex.ipp"
+#include "asio/detail/impl/posix_thread.ipp"
+#include "asio/detail/impl/posix_tss_ptr.ipp"
+#include "asio/detail/impl/reactive_descriptor_service.ipp"
+#include "asio/detail/impl/reactive_serial_port_service.ipp"
+#include "asio/detail/impl/reactive_socket_service_base.ipp"
+#include "asio/detail/impl/resolver_service_base.ipp"
+#include "asio/detail/impl/scheduler.ipp"
+#include "asio/detail/impl/select_reactor.ipp"
+#include "asio/detail/impl/service_registry.ipp"
+#include "asio/detail/impl/signal_set_service.ipp"
+#include "asio/detail/impl/socket_ops.ipp"
+#include "asio/detail/impl/socket_select_interrupter.ipp"
+#include "asio/detail/impl/strand_executor_service.ipp"
+#include "asio/detail/impl/strand_service.ipp"
+#include "asio/detail/impl/throw_error.ipp"
+#include "asio/detail/impl/timer_queue_ptime.ipp"
+#include "asio/detail/impl/timer_queue_set.ipp"
+#include "asio/detail/impl/win_iocp_handle_service.ipp"
+#include "asio/detail/impl/win_iocp_io_context.ipp"
+#include "asio/detail/impl/win_iocp_serial_port_service.ipp"
+#include "asio/detail/impl/win_iocp_socket_service_base.ipp"
+#include "asio/detail/impl/win_event.ipp"
+#include "asio/detail/impl/win_mutex.ipp"
+#include "asio/detail/impl/win_object_handle_service.ipp"
+#include "asio/detail/impl/win_static_mutex.ipp"
+#include "asio/detail/impl/win_thread.ipp"
+#include "asio/detail/impl/win_tss_ptr.ipp"
+#include "asio/detail/impl/winrt_ssocket_service_base.ipp"
+#include "asio/detail/impl/winrt_timer_scheduler.ipp"
+#include "asio/detail/impl/winsock_init.ipp"
+#include "asio/execution/impl/bad_executor.ipp"
+#include "asio/execution/impl/receiver_invocation_error.ipp"
+#include "asio/generic/detail/impl/endpoint.ipp"
+#include "asio/ip/impl/address.ipp"
+#include "asio/ip/impl/address_v4.ipp"
+#include "asio/ip/impl/address_v6.ipp"
+#include "asio/ip/impl/host_name.ipp"
+#include "asio/ip/impl/network_v4.ipp"
+#include "asio/ip/impl/network_v6.ipp"
+#include "asio/ip/detail/impl/endpoint.ipp"
+#include "asio/local/detail/impl/endpoint.ipp"
+
+#endif // ASIO_IMPL_SRC_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/impl/system_context.hpp b/link/modules/asio-standalone/asio/include/asio/impl/system_context.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/impl/system_context.hpp
@@ -0,0 +1,34 @@
+//
+// impl/system_context.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_IMPL_SYSTEM_CONTEXT_HPP
+#define ASIO_IMPL_SYSTEM_CONTEXT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/system_executor.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+inline system_context::executor_type
+system_context::get_executor() ASIO_NOEXCEPT
+{
+  return system_executor();
+}
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IMPL_SYSTEM_CONTEXT_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/impl/system_context.ipp b/link/modules/asio-standalone/asio/include/asio/impl/system_context.ipp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/impl/system_context.ipp
@@ -0,0 +1,92 @@
+//
+// impl/system_context.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_IMPL_SYSTEM_CONTEXT_IPP
+#define ASIO_IMPL_SYSTEM_CONTEXT_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/system_context.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+struct system_context::thread_function
+{
+  detail::scheduler* scheduler_;
+
+  void operator()()
+  {
+#if !defined(ASIO_NO_EXCEPTIONS)
+    try
+    {
+#endif// !defined(ASIO_NO_EXCEPTIONS)
+      asio::error_code ec;
+      scheduler_->run(ec);
+#if !defined(ASIO_NO_EXCEPTIONS)
+    }
+    catch (...)
+    {
+      std::terminate();
+    }
+#endif// !defined(ASIO_NO_EXCEPTIONS)
+  }
+};
+
+system_context::system_context()
+  : scheduler_(add_scheduler(new detail::scheduler(*this, 0, false)))
+{
+  scheduler_.work_started();
+
+  thread_function f = { &scheduler_ };
+  num_threads_ = detail::thread::hardware_concurrency() * 2;
+  num_threads_ = num_threads_ ? num_threads_ : 2;
+  threads_.create_threads(f, num_threads_);
+}
+
+system_context::~system_context()
+{
+  scheduler_.work_finished();
+  scheduler_.stop();
+  threads_.join();
+}
+
+void system_context::stop()
+{
+  scheduler_.stop();
+}
+
+bool system_context::stopped() const ASIO_NOEXCEPT
+{
+  return scheduler_.stopped();
+}
+
+void system_context::join()
+{
+  scheduler_.work_finished();
+  threads_.join();
+}
+
+detail::scheduler& system_context::add_scheduler(detail::scheduler* s)
+{
+  detail::scoped_ptr<detail::scheduler> scoped_impl(s);
+  asio::add_service<detail::scheduler>(*this, scoped_impl.get());
+  return *scoped_impl.release();
+}
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IMPL_SYSTEM_CONTEXT_IPP
diff --git a/link/modules/asio-standalone/asio/include/asio/impl/system_executor.hpp b/link/modules/asio-standalone/asio/include/asio/impl/system_executor.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/impl/system_executor.hpp
@@ -0,0 +1,186 @@
+//
+// impl/system_executor.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_IMPL_SYSTEM_EXECUTOR_HPP
+#define ASIO_IMPL_SYSTEM_EXECUTOR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/executor_op.hpp"
+#include "asio/detail/global.hpp"
+#include "asio/detail/recycling_allocator.hpp"
+#include "asio/detail/type_traits.hpp"
+#include "asio/system_context.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+template <typename Blocking, typename Relationship, typename Allocator>
+inline system_context&
+basic_system_executor<Blocking, Relationship, Allocator>::query(
+    execution::context_t) ASIO_NOEXCEPT
+{
+  return detail::global<system_context>();
+}
+
+template <typename Blocking, typename Relationship, typename Allocator>
+inline std::size_t
+basic_system_executor<Blocking, Relationship, Allocator>::query(
+    execution::occupancy_t) const ASIO_NOEXCEPT
+{
+  return detail::global<system_context>().num_threads_;
+}
+
+template <typename Blocking, typename Relationship, typename Allocator>
+template <typename Function>
+inline void
+basic_system_executor<Blocking, Relationship, Allocator>::do_execute(
+    ASIO_MOVE_ARG(Function) f, execution::blocking_t::possibly_t) const
+{
+  // Obtain a non-const instance of the function.
+  detail::non_const_lvalue<Function> f2(f);
+
+#if !defined(ASIO_NO_EXCEPTIONS)
+  try
+  {
+#endif// !defined(ASIO_NO_EXCEPTIONS)
+    detail::fenced_block b(detail::fenced_block::full);
+    asio_handler_invoke_helpers::invoke(f2.value, f2.value);
+#if !defined(ASIO_NO_EXCEPTIONS)
+  }
+  catch (...)
+  {
+    std::terminate();
+  }
+#endif// !defined(ASIO_NO_EXCEPTIONS)
+}
+
+template <typename Blocking, typename Relationship, typename Allocator>
+template <typename Function>
+inline void
+basic_system_executor<Blocking, Relationship, Allocator>::do_execute(
+    ASIO_MOVE_ARG(Function) f, execution::blocking_t::always_t) const
+{
+  // Obtain a non-const instance of the function.
+  detail::non_const_lvalue<Function> f2(f);
+
+#if !defined(ASIO_NO_EXCEPTIONS)
+  try
+  {
+#endif// !defined(ASIO_NO_EXCEPTIONS)
+    detail::fenced_block b(detail::fenced_block::full);
+    asio_handler_invoke_helpers::invoke(f2.value, f2.value);
+#if !defined(ASIO_NO_EXCEPTIONS)
+  }
+  catch (...)
+  {
+    std::terminate();
+  }
+#endif// !defined(ASIO_NO_EXCEPTIONS)
+}
+
+template <typename Blocking, typename Relationship, typename Allocator>
+template <typename Function>
+void basic_system_executor<Blocking, Relationship, Allocator>::do_execute(
+    ASIO_MOVE_ARG(Function) f, execution::blocking_t::never_t) const
+{
+  system_context& ctx = detail::global<system_context>();
+
+  // Allocate and construct an operation to wrap the function.
+  typedef typename decay<Function>::type function_type;
+  typedef detail::executor_op<function_type, Allocator> op;
+  typename op::ptr p = { detail::addressof(allocator_),
+      op::ptr::allocate(allocator_), 0 };
+  p.p = new (p.v) op(ASIO_MOVE_CAST(Function)(f), allocator_);
+
+  if (is_same<Relationship, execution::relationship_t::continuation_t>::value)
+  {
+    ASIO_HANDLER_CREATION((ctx, *p.p,
+          "system_executor", &ctx, 0, "execute(blk=never,rel=cont)"));
+  }
+  else
+  {
+    ASIO_HANDLER_CREATION((ctx, *p.p,
+          "system_executor", &ctx, 0, "execute(blk=never,rel=fork)"));
+  }
+
+  ctx.scheduler_.post_immediate_completion(p.p,
+      is_same<Relationship, execution::relationship_t::continuation_t>::value);
+  p.v = p.p = 0;
+}
+
+#if !defined(ASIO_NO_TS_EXECUTORS)
+template <typename Blocking, typename Relationship, typename Allocator>
+inline system_context& basic_system_executor<
+    Blocking, Relationship, Allocator>::context() const ASIO_NOEXCEPT
+{
+  return detail::global<system_context>();
+}
+
+template <typename Blocking, typename Relationship, typename Allocator>
+template <typename Function, typename OtherAllocator>
+void basic_system_executor<Blocking, Relationship, Allocator>::dispatch(
+    ASIO_MOVE_ARG(Function) f, const OtherAllocator&) const
+{
+  typename decay<Function>::type tmp(ASIO_MOVE_CAST(Function)(f));
+  asio_handler_invoke_helpers::invoke(tmp, tmp);
+}
+
+template <typename Blocking, typename Relationship, typename Allocator>
+template <typename Function, typename OtherAllocator>
+void basic_system_executor<Blocking, Relationship, Allocator>::post(
+    ASIO_MOVE_ARG(Function) f, const OtherAllocator& a) const
+{
+  typedef typename decay<Function>::type function_type;
+
+  system_context& ctx = detail::global<system_context>();
+
+  // Allocate and construct an operation to wrap the function.
+  typedef detail::executor_op<function_type, OtherAllocator> op;
+  typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 };
+  p.p = new (p.v) op(ASIO_MOVE_CAST(Function)(f), a);
+
+  ASIO_HANDLER_CREATION((ctx, *p.p,
+        "system_executor", &this->context(), 0, "post"));
+
+  ctx.scheduler_.post_immediate_completion(p.p, false);
+  p.v = p.p = 0;
+}
+
+template <typename Blocking, typename Relationship, typename Allocator>
+template <typename Function, typename OtherAllocator>
+void basic_system_executor<Blocking, Relationship, Allocator>::defer(
+    ASIO_MOVE_ARG(Function) f, const OtherAllocator& a) const
+{
+  typedef typename decay<Function>::type function_type;
+
+  system_context& ctx = detail::global<system_context>();
+
+  // Allocate and construct an operation to wrap the function.
+  typedef detail::executor_op<function_type, OtherAllocator> op;
+  typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 };
+  p.p = new (p.v) op(ASIO_MOVE_CAST(Function)(f), a);
+
+  ASIO_HANDLER_CREATION((ctx, *p.p,
+        "system_executor", &this->context(), 0, "defer"));
+
+  ctx.scheduler_.post_immediate_completion(p.p, true);
+  p.v = p.p = 0;
+}
+#endif // !defined(ASIO_NO_TS_EXECUTORS)
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IMPL_SYSTEM_EXECUTOR_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/impl/thread_pool.hpp b/link/modules/asio-standalone/asio/include/asio/impl/thread_pool.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/impl/thread_pool.hpp
@@ -0,0 +1,350 @@
+//
+// impl/thread_pool.hpp
+// ~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_IMPL_THREAD_POOL_HPP
+#define ASIO_IMPL_THREAD_POOL_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/blocking_executor_op.hpp"
+#include "asio/detail/bulk_executor_op.hpp"
+#include "asio/detail/executor_op.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/non_const_lvalue.hpp"
+#include "asio/detail/recycling_allocator.hpp"
+#include "asio/detail/type_traits.hpp"
+#include "asio/execution_context.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+inline thread_pool::executor_type
+thread_pool::get_executor() ASIO_NOEXCEPT
+{
+  return executor_type(*this);
+}
+
+inline thread_pool::executor_type
+thread_pool::executor() ASIO_NOEXCEPT
+{
+  return executor_type(*this);
+}
+
+inline thread_pool::scheduler_type
+thread_pool::scheduler() ASIO_NOEXCEPT
+{
+  return scheduler_type(*this);
+}
+
+template <typename Allocator, unsigned int Bits>
+thread_pool::basic_executor_type<Allocator, Bits>&
+thread_pool::basic_executor_type<Allocator, Bits>::operator=(
+    const basic_executor_type& other) ASIO_NOEXCEPT
+{
+  if (this != &other)
+  {
+    thread_pool* old_thread_pool = pool_;
+    pool_ = other.pool_;
+    allocator_ = other.allocator_;
+    bits_ = other.bits_;
+    if (Bits & outstanding_work_tracked)
+    {
+      if (pool_)
+        pool_->scheduler_.work_started();
+      if (old_thread_pool)
+        old_thread_pool->scheduler_.work_finished();
+    }
+  }
+  return *this;
+}
+
+#if defined(ASIO_HAS_MOVE)
+template <typename Allocator, unsigned int Bits>
+thread_pool::basic_executor_type<Allocator, Bits>&
+thread_pool::basic_executor_type<Allocator, Bits>::operator=(
+    basic_executor_type&& other) ASIO_NOEXCEPT
+{
+  if (this != &other)
+  {
+    pool_ = other.pool_;
+    allocator_ = std::move(other.allocator_);
+    bits_ = other.bits_;
+    if (Bits & outstanding_work_tracked)
+      other.pool_ = 0;
+  }
+  return *this;
+}
+#endif // defined(ASIO_HAS_MOVE)
+
+template <typename Allocator, unsigned int Bits>
+inline bool thread_pool::basic_executor_type<Allocator,
+    Bits>::running_in_this_thread() const ASIO_NOEXCEPT
+{
+  return pool_->scheduler_.can_dispatch();
+}
+
+template <typename Allocator, unsigned int Bits>
+template <typename Function>
+void thread_pool::basic_executor_type<Allocator,
+    Bits>::do_execute(ASIO_MOVE_ARG(Function) f, false_type) const
+{
+  typedef typename decay<Function>::type function_type;
+
+  // Invoke immediately if the blocking.possibly property is enabled and we are
+  // already inside the thread pool.
+  if ((bits_ & blocking_never) == 0 && pool_->scheduler_.can_dispatch())
+  {
+    // Make a local, non-const copy of the function.
+    function_type tmp(ASIO_MOVE_CAST(Function)(f));
+
+#if defined(ASIO_HAS_STD_EXCEPTION_PTR) \
+  && !defined(ASIO_NO_EXCEPTIONS)
+    try
+    {
+#endif // defined(ASIO_HAS_STD_EXCEPTION_PTR)
+       //   && !defined(ASIO_NO_EXCEPTIONS)
+      detail::fenced_block b(detail::fenced_block::full);
+      asio_handler_invoke_helpers::invoke(tmp, tmp);
+      return;
+#if defined(ASIO_HAS_STD_EXCEPTION_PTR) \
+  && !defined(ASIO_NO_EXCEPTIONS)
+    }
+    catch (...)
+    {
+      pool_->scheduler_.capture_current_exception();
+      return;
+    }
+#endif // defined(ASIO_HAS_STD_EXCEPTION_PTR)
+       //   && !defined(ASIO_NO_EXCEPTIONS)
+  }
+
+  // Allocate and construct an operation to wrap the function.
+  typedef detail::executor_op<function_type, Allocator> op;
+  typename op::ptr p = { detail::addressof(allocator_),
+      op::ptr::allocate(allocator_), 0 };
+  p.p = new (p.v) op(ASIO_MOVE_CAST(Function)(f), allocator_);
+
+  if ((bits_ & relationship_continuation) != 0)
+  {
+    ASIO_HANDLER_CREATION((*pool_, *p.p,
+          "thread_pool", pool_, 0, "execute(blk=never,rel=cont)"));
+  }
+  else
+  {
+    ASIO_HANDLER_CREATION((*pool_, *p.p,
+          "thread_pool", pool_, 0, "execute(blk=never,rel=fork)"));
+  }
+
+  pool_->scheduler_.post_immediate_completion(p.p,
+      (bits_ & relationship_continuation) != 0);
+  p.v = p.p = 0;
+}
+
+template <typename Allocator, unsigned int Bits>
+template <typename Function>
+void thread_pool::basic_executor_type<Allocator,
+    Bits>::do_execute(ASIO_MOVE_ARG(Function) f, true_type) const
+{
+  // Obtain a non-const instance of the function.
+  detail::non_const_lvalue<Function> f2(f);
+
+  // Invoke immediately if we are already inside the thread pool.
+  if (pool_->scheduler_.can_dispatch())
+  {
+#if !defined(ASIO_NO_EXCEPTIONS)
+    try
+    {
+#endif // !defined(ASIO_NO_EXCEPTIONS)
+      detail::fenced_block b(detail::fenced_block::full);
+      asio_handler_invoke_helpers::invoke(f2.value, f2.value);
+      return;
+#if !defined(ASIO_NO_EXCEPTIONS)
+    }
+    catch (...)
+    {
+      std::terminate();
+    }
+#endif // !defined(ASIO_NO_EXCEPTIONS)
+  }
+
+  // Construct an operation to wrap the function.
+  typedef typename decay<Function>::type function_type;
+  detail::blocking_executor_op<function_type> op(f2.value);
+
+  ASIO_HANDLER_CREATION((*pool_, op,
+        "thread_pool", pool_, 0, "execute(blk=always)"));
+
+  pool_->scheduler_.post_immediate_completion(&op, false);
+  op.wait();
+}
+
+template <typename Allocator, unsigned int Bits>
+template <typename Function>
+void thread_pool::basic_executor_type<Allocator, Bits>::do_bulk_execute(
+    ASIO_MOVE_ARG(Function) f, std::size_t n, false_type) const
+{
+  typedef typename decay<Function>::type function_type;
+  typedef detail::bulk_executor_op<function_type, Allocator> op;
+
+  // Allocate and construct operations to wrap the function.
+  detail::op_queue<detail::scheduler_operation> ops;
+  for (std::size_t i = 0; i < n; ++i)
+  {
+    typename op::ptr p = { detail::addressof(allocator_),
+        op::ptr::allocate(allocator_), 0 };
+    p.p = new (p.v) op(ASIO_MOVE_CAST(Function)(f), allocator_, i);
+    ops.push(p.p);
+
+    if ((bits_ & relationship_continuation) != 0)
+    {
+      ASIO_HANDLER_CREATION((*pool_, *p.p,
+            "thread_pool", pool_, 0, "bulk_execute(blk=never,rel=cont)"));
+    }
+    else
+    {
+      ASIO_HANDLER_CREATION((*pool_, *p.p,
+            "thread_pool", pool_, 0, "bulk)execute(blk=never,rel=fork)"));
+    }
+
+    p.v = p.p = 0;
+  }
+
+  pool_->scheduler_.post_immediate_completions(n,
+      ops, (bits_ & relationship_continuation) != 0);
+}
+
+template <typename Function>
+struct thread_pool_always_blocking_function_adapter
+{
+  typename decay<Function>::type* f;
+  std::size_t n;
+
+  void operator()()
+  {
+    for (std::size_t i = 0; i < n; ++i)
+    {
+      (*f)(i);
+    }
+  }
+};
+
+template <typename Allocator, unsigned int Bits>
+template <typename Function>
+void thread_pool::basic_executor_type<Allocator, Bits>::do_bulk_execute(
+    ASIO_MOVE_ARG(Function) f, std::size_t n, true_type) const
+{
+  // Obtain a non-const instance of the function.
+  detail::non_const_lvalue<Function> f2(f);
+
+  thread_pool_always_blocking_function_adapter<Function>
+    adapter = { detail::addressof(f2.value), n };
+
+  this->do_execute(adapter, true_type());
+}
+
+#if !defined(ASIO_NO_TS_EXECUTORS)
+template <typename Allocator, unsigned int Bits>
+inline thread_pool& thread_pool::basic_executor_type<
+    Allocator, Bits>::context() const ASIO_NOEXCEPT
+{
+  return *pool_;
+}
+
+template <typename Allocator, unsigned int Bits>
+inline void thread_pool::basic_executor_type<Allocator,
+    Bits>::on_work_started() const ASIO_NOEXCEPT
+{
+  pool_->scheduler_.work_started();
+}
+
+template <typename Allocator, unsigned int Bits>
+inline void thread_pool::basic_executor_type<Allocator,
+    Bits>::on_work_finished() const ASIO_NOEXCEPT
+{
+  pool_->scheduler_.work_finished();
+}
+
+template <typename Allocator, unsigned int Bits>
+template <typename Function, typename OtherAllocator>
+void thread_pool::basic_executor_type<Allocator, Bits>::dispatch(
+    ASIO_MOVE_ARG(Function) f, const OtherAllocator& a) const
+{
+  typedef typename decay<Function>::type function_type;
+
+  // Invoke immediately if we are already inside the thread pool.
+  if (pool_->scheduler_.can_dispatch())
+  {
+    // Make a local, non-const copy of the function.
+    function_type tmp(ASIO_MOVE_CAST(Function)(f));
+
+    detail::fenced_block b(detail::fenced_block::full);
+    asio_handler_invoke_helpers::invoke(tmp, tmp);
+    return;
+  }
+
+  // Allocate and construct an operation to wrap the function.
+  typedef detail::executor_op<function_type, OtherAllocator> op;
+  typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 };
+  p.p = new (p.v) op(ASIO_MOVE_CAST(Function)(f), a);
+
+  ASIO_HANDLER_CREATION((*pool_, *p.p,
+        "thread_pool", pool_, 0, "dispatch"));
+
+  pool_->scheduler_.post_immediate_completion(p.p, false);
+  p.v = p.p = 0;
+}
+
+template <typename Allocator, unsigned int Bits>
+template <typename Function, typename OtherAllocator>
+void thread_pool::basic_executor_type<Allocator, Bits>::post(
+    ASIO_MOVE_ARG(Function) f, const OtherAllocator& a) const
+{
+  typedef typename decay<Function>::type function_type;
+
+  // Allocate and construct an operation to wrap the function.
+  typedef detail::executor_op<function_type, OtherAllocator> op;
+  typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 };
+  p.p = new (p.v) op(ASIO_MOVE_CAST(Function)(f), a);
+
+  ASIO_HANDLER_CREATION((*pool_, *p.p,
+        "thread_pool", pool_, 0, "post"));
+
+  pool_->scheduler_.post_immediate_completion(p.p, false);
+  p.v = p.p = 0;
+}
+
+template <typename Allocator, unsigned int Bits>
+template <typename Function, typename OtherAllocator>
+void thread_pool::basic_executor_type<Allocator, Bits>::defer(
+    ASIO_MOVE_ARG(Function) f, const OtherAllocator& a) const
+{
+  typedef typename decay<Function>::type function_type;
+
+  // Allocate and construct an operation to wrap the function.
+  typedef detail::executor_op<function_type, OtherAllocator> op;
+  typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 };
+  p.p = new (p.v) op(ASIO_MOVE_CAST(Function)(f), a);
+
+  ASIO_HANDLER_CREATION((*pool_, *p.p,
+        "thread_pool", pool_, 0, "defer"));
+
+  pool_->scheduler_.post_immediate_completion(p.p, true);
+  p.v = p.p = 0;
+}
+#endif // !defined(ASIO_NO_TS_EXECUTORS)
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IMPL_THREAD_POOL_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/impl/thread_pool.ipp b/link/modules/asio-standalone/asio/include/asio/impl/thread_pool.ipp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/impl/thread_pool.ipp
@@ -0,0 +1,141 @@
+//
+// impl/thread_pool.ipp
+// ~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_IMPL_THREAD_POOL_IPP
+#define ASIO_IMPL_THREAD_POOL_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <stdexcept>
+#include "asio/thread_pool.hpp"
+#include "asio/detail/throw_exception.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+struct thread_pool::thread_function
+{
+  detail::scheduler* scheduler_;
+
+  void operator()()
+  {
+#if !defined(ASIO_NO_EXCEPTIONS)
+    try
+    {
+#endif// !defined(ASIO_NO_EXCEPTIONS)
+      asio::error_code ec;
+      scheduler_->run(ec);
+#if !defined(ASIO_NO_EXCEPTIONS)
+    }
+    catch (...)
+    {
+      std::terminate();
+    }
+#endif// !defined(ASIO_NO_EXCEPTIONS)
+  }
+};
+
+#if !defined(ASIO_NO_TS_EXECUTORS)
+namespace detail {
+
+inline long default_thread_pool_size()
+{
+  std::size_t num_threads = thread::hardware_concurrency() * 2;
+  num_threads = num_threads == 0 ? 2 : num_threads;
+  return static_cast<long>(num_threads);
+}
+
+} // namespace detail
+
+thread_pool::thread_pool()
+  : scheduler_(add_scheduler(new detail::scheduler(*this, 0, false))),
+    num_threads_(detail::default_thread_pool_size())
+{
+  scheduler_.work_started();
+
+  thread_function f = { &scheduler_ };
+  threads_.create_threads(f, static_cast<std::size_t>(num_threads_));
+}
+#endif // !defined(ASIO_NO_TS_EXECUTORS)
+
+namespace detail {
+
+inline long clamp_thread_pool_size(std::size_t n)
+{
+  if (n > 0x7FFFFFFF)
+  {
+    std::out_of_range ex("thread pool size");
+    asio::detail::throw_exception(ex);
+  }
+  return static_cast<long>(n & 0x7FFFFFFF);
+}
+
+} // namespace detail
+
+thread_pool::thread_pool(std::size_t num_threads)
+  : scheduler_(add_scheduler(new detail::scheduler(
+          *this, num_threads == 1 ? 1 : 0, false))),
+    num_threads_(detail::clamp_thread_pool_size(num_threads))
+{
+  scheduler_.work_started();
+
+  thread_function f = { &scheduler_ };
+  threads_.create_threads(f, static_cast<std::size_t>(num_threads_));
+}
+
+thread_pool::~thread_pool()
+{
+  stop();
+  join();
+}
+
+void thread_pool::stop()
+{
+  scheduler_.stop();
+}
+
+void thread_pool::attach()
+{
+  ++num_threads_;
+  thread_function f = { &scheduler_ };
+  f();
+}
+
+void thread_pool::join()
+{
+  if (!threads_.empty())
+  {
+    scheduler_.work_finished();
+    threads_.join();
+  }
+}
+
+detail::scheduler& thread_pool::add_scheduler(detail::scheduler* s)
+{
+  detail::scoped_ptr<detail::scheduler> scoped_impl(s);
+  asio::add_service<detail::scheduler>(*this, scoped_impl.get());
+  return *scoped_impl.release();
+}
+
+void thread_pool::wait()
+{
+  scheduler_.work_finished();
+  threads_.join();
+}
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IMPL_THREAD_POOL_IPP
diff --git a/link/modules/asio-standalone/asio/include/asio/impl/use_awaitable.hpp b/link/modules/asio-standalone/asio/include/asio/impl/use_awaitable.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/impl/use_awaitable.hpp
@@ -0,0 +1,279 @@
+//
+// impl/use_awaitable.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_IMPL_USE_AWAITABLE_HPP
+#define ASIO_IMPL_USE_AWAITABLE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/async_result.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Executor, typename T>
+class awaitable_handler_base
+  : public awaitable_thread<Executor>
+{
+public:
+  typedef void result_type;
+  typedef awaitable<T, Executor> awaitable_type;
+
+  // Construct from the entry point of a new thread of execution.
+  awaitable_handler_base(awaitable<void, Executor> a, const Executor& ex)
+    : awaitable_thread<Executor>(std::move(a), ex)
+  {
+  }
+
+  // Transfer ownership from another awaitable_thread.
+  explicit awaitable_handler_base(awaitable_thread<Executor>* h)
+    : awaitable_thread<Executor>(std::move(*h))
+  {
+  }
+
+protected:
+  awaitable_frame<T, Executor>* frame() noexcept
+  {
+    return static_cast<awaitable_frame<T, Executor>*>(this->top_of_stack_);
+  }
+};
+
+template <typename, typename...>
+class awaitable_handler;
+
+template <typename Executor>
+class awaitable_handler<Executor>
+  : public awaitable_handler_base<Executor, void>
+{
+public:
+  using awaitable_handler_base<Executor, void>::awaitable_handler_base;
+
+  void operator()()
+  {
+    this->frame()->attach_thread(this);
+    this->frame()->return_void();
+    this->frame()->pop_frame();
+    this->pump();
+  }
+};
+
+template <typename Executor>
+class awaitable_handler<Executor, asio::error_code>
+  : public awaitable_handler_base<Executor, void>
+{
+public:
+  using awaitable_handler_base<Executor, void>::awaitable_handler_base;
+
+  void operator()(const asio::error_code& ec)
+  {
+    this->frame()->attach_thread(this);
+    if (ec)
+      this->frame()->set_error(ec);
+    else
+      this->frame()->return_void();
+    this->frame()->pop_frame();
+    this->pump();
+  }
+};
+
+template <typename Executor>
+class awaitable_handler<Executor, std::exception_ptr>
+  : public awaitable_handler_base<Executor, void>
+{
+public:
+  using awaitable_handler_base<Executor, void>::awaitable_handler_base;
+
+  void operator()(std::exception_ptr ex)
+  {
+    this->frame()->attach_thread(this);
+    if (ex)
+      this->frame()->set_except(ex);
+    else
+      this->frame()->return_void();
+    this->frame()->pop_frame();
+    this->pump();
+  }
+};
+
+template <typename Executor, typename T>
+class awaitable_handler<Executor, T>
+  : public awaitable_handler_base<Executor, T>
+{
+public:
+  using awaitable_handler_base<Executor, T>::awaitable_handler_base;
+
+  template <typename Arg>
+  void operator()(Arg&& arg)
+  {
+    this->frame()->attach_thread(this);
+    this->frame()->return_value(std::forward<Arg>(arg));
+    this->frame()->pop_frame();
+    this->pump();
+  }
+};
+
+template <typename Executor, typename T>
+class awaitable_handler<Executor, asio::error_code, T>
+  : public awaitable_handler_base<Executor, T>
+{
+public:
+  using awaitable_handler_base<Executor, T>::awaitable_handler_base;
+
+  template <typename Arg>
+  void operator()(const asio::error_code& ec, Arg&& arg)
+  {
+    this->frame()->attach_thread(this);
+    if (ec)
+      this->frame()->set_error(ec);
+    else
+      this->frame()->return_value(std::forward<Arg>(arg));
+    this->frame()->pop_frame();
+    this->pump();
+  }
+};
+
+template <typename Executor, typename T>
+class awaitable_handler<Executor, std::exception_ptr, T>
+  : public awaitable_handler_base<Executor, T>
+{
+public:
+  using awaitable_handler_base<Executor, T>::awaitable_handler_base;
+
+  template <typename Arg>
+  void operator()(std::exception_ptr ex, Arg&& arg)
+  {
+    this->frame()->attach_thread(this);
+    if (ex)
+      this->frame()->set_except(ex);
+    else
+      this->frame()->return_value(std::forward<Arg>(arg));
+    this->frame()->pop_frame();
+    this->pump();
+  }
+};
+
+template <typename Executor, typename... Ts>
+class awaitable_handler
+  : public awaitable_handler_base<Executor, std::tuple<Ts...>>
+{
+public:
+  using awaitable_handler_base<Executor,
+    std::tuple<Ts...>>::awaitable_handler_base;
+
+  template <typename... Args>
+  void operator()(Args&&... args)
+  {
+    this->frame()->attach_thread(this);
+    this->frame()->return_values(std::forward<Args>(args)...);
+    this->frame()->pop_frame();
+    this->pump();
+  }
+};
+
+template <typename Executor, typename... Ts>
+class awaitable_handler<Executor, asio::error_code, Ts...>
+  : public awaitable_handler_base<Executor, std::tuple<Ts...>>
+{
+public:
+  using awaitable_handler_base<Executor,
+    std::tuple<Ts...>>::awaitable_handler_base;
+
+  template <typename... Args>
+  void operator()(const asio::error_code& ec, Args&&... args)
+  {
+    this->frame()->attach_thread(this);
+    if (ec)
+      this->frame()->set_error(ec);
+    else
+      this->frame()->return_values(std::forward<Args>(args)...);
+    this->frame()->pop_frame();
+    this->pump();
+  }
+};
+
+template <typename Executor, typename... Ts>
+class awaitable_handler<Executor, std::exception_ptr, Ts...>
+  : public awaitable_handler_base<Executor, std::tuple<Ts...>>
+{
+public:
+  using awaitable_handler_base<Executor,
+    std::tuple<Ts...>>::awaitable_handler_base;
+
+  template <typename... Args>
+  void operator()(std::exception_ptr ex, Args&&... args)
+  {
+    this->frame()->attach_thread(this);
+    if (ex)
+      this->frame()->set_except(ex);
+    else
+      this->frame()->return_values(std::forward<Args>(args)...);
+    this->frame()->pop_frame();
+    this->pump();
+  }
+};
+
+} // namespace detail
+
+#if !defined(GENERATING_DOCUMENTATION)
+
+template <typename Executor, typename R, typename... Args>
+class async_result<use_awaitable_t<Executor>, R(Args...)>
+{
+public:
+  typedef typename detail::awaitable_handler<
+      Executor, typename decay<Args>::type...> handler_type;
+  typedef typename handler_type::awaitable_type return_type;
+
+#if defined(_MSC_VER)
+  template <typename T>
+  static T dummy_return()
+  {
+    return std::move(*static_cast<T*>(nullptr));
+  }
+
+  template <>
+  static void dummy_return()
+  {
+  }
+#endif // defined(_MSC_VER)
+
+  template <typename Initiation, typename... InitArgs>
+  static return_type initiate(Initiation initiation,
+      use_awaitable_t<Executor> u, InitArgs... args)
+  {
+    (void)u;
+
+    co_await [&](auto* frame)
+      {
+        ASIO_HANDLER_LOCATION((u.file_name_, u.line_, u.function_name_));
+        handler_type handler(frame->detach_thread());
+        std::move(initiation)(std::move(handler), std::move(args)...);
+        return static_cast<handler_type*>(nullptr);
+      };
+
+    for (;;) {} // Never reached.
+#if defined(_MSC_VER)
+    co_return dummy_return<typename return_type::value_type>();
+#endif // defined(_MSC_VER)
+  }
+};
+
+#endif // !defined(GENERATING_DOCUMENTATION)
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IMPL_USE_AWAITABLE_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/impl/use_future.hpp b/link/modules/asio-standalone/asio/include/asio/impl/use_future.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/impl/use_future.hpp
@@ -0,0 +1,1028 @@
+//
+// impl/use_future.hpp
+// ~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_IMPL_USE_FUTURE_HPP
+#define ASIO_IMPL_USE_FUTURE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <tuple>
+#include "asio/async_result.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/dispatch.hpp"
+#include "asio/error_code.hpp"
+#include "asio/execution.hpp"
+#include "asio/packaged_task.hpp"
+#include "asio/system_error.hpp"
+#include "asio/system_executor.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+#if defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+template <typename T, typename F, typename... Args>
+inline void promise_invoke_and_set(std::promise<T>& p,
+    F& f, ASIO_MOVE_ARG(Args)... args)
+{
+#if !defined(ASIO_NO_EXCEPTIONS)
+  try
+#endif // !defined(ASIO_NO_EXCEPTIONS)
+  {
+    p.set_value(f(ASIO_MOVE_CAST(Args)(args)...));
+  }
+#if !defined(ASIO_NO_EXCEPTIONS)
+  catch (...)
+  {
+    p.set_exception(std::current_exception());
+  }
+#endif // !defined(ASIO_NO_EXCEPTIONS)
+}
+
+template <typename F, typename... Args>
+inline void promise_invoke_and_set(std::promise<void>& p,
+    F& f, ASIO_MOVE_ARG(Args)... args)
+{
+#if !defined(ASIO_NO_EXCEPTIONS)
+  try
+#endif // !defined(ASIO_NO_EXCEPTIONS)
+  {
+    f(ASIO_MOVE_CAST(Args)(args)...);
+    p.set_value();
+  }
+#if !defined(ASIO_NO_EXCEPTIONS)
+  catch (...)
+  {
+    p.set_exception(std::current_exception());
+  }
+#endif // !defined(ASIO_NO_EXCEPTIONS)
+}
+
+#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+template <typename T, typename F>
+inline void promise_invoke_and_set(std::promise<T>& p, F& f)
+{
+#if !defined(ASIO_NO_EXCEPTIONS)
+  try
+#endif // !defined(ASIO_NO_EXCEPTIONS)
+  {
+    p.set_value(f());
+  }
+#if !defined(ASIO_NO_EXCEPTIONS)
+  catch (...)
+  {
+    p.set_exception(std::current_exception());
+  }
+#endif // !defined(ASIO_NO_EXCEPTIONS)
+}
+
+template <typename F, typename Args>
+inline void promise_invoke_and_set(std::promise<void>& p, F& f)
+{
+#if !defined(ASIO_NO_EXCEPTIONS)
+  try
+#endif // !defined(ASIO_NO_EXCEPTIONS)
+  {
+    f();
+    p.set_value();
+#if !defined(ASIO_NO_EXCEPTIONS)
+  }
+  catch (...)
+  {
+    p.set_exception(std::current_exception());
+  }
+#endif // !defined(ASIO_NO_EXCEPTIONS)
+}
+
+#if defined(ASIO_NO_EXCEPTIONS)
+
+#define ASIO_PRIVATE_PROMISE_INVOKE_DEF(n) \
+  template <typename T, typename F, ASIO_VARIADIC_TPARAMS(n)> \
+  inline void promise_invoke_and_set(std::promise<T>& p, \
+      F& f, ASIO_VARIADIC_MOVE_PARAMS(n)) \
+  { \
+    p.set_value(f(ASIO_VARIADIC_MOVE_ARGS(n))); \
+  } \
+  \
+  template <typename F, ASIO_VARIADIC_TPARAMS(n)> \
+  inline void promise_invoke_and_set(std::promise<void>& p, \
+      F& f, ASIO_VARIADIC_MOVE_PARAMS(n)) \
+  { \
+    f(ASIO_VARIADIC_MOVE_ARGS(n)); \
+    p.set_value(); \
+  } \
+  /**/
+  ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_PROMISE_INVOKE_DEF)
+#undef ASIO_PRIVATE_PROMISE_INVOKE_DEF
+
+#else // defined(ASIO_NO_EXCEPTIONS)
+
+#define ASIO_PRIVATE_PROMISE_INVOKE_DEF(n) \
+  template <typename T, typename F, ASIO_VARIADIC_TPARAMS(n)> \
+  inline void promise_invoke_and_set(std::promise<T>& p, \
+      F& f, ASIO_VARIADIC_MOVE_PARAMS(n)) \
+  { \
+    try \
+    { \
+      p.set_value(f(ASIO_VARIADIC_MOVE_ARGS(n))); \
+    } \
+    catch (...) \
+    { \
+      p.set_exception(std::current_exception()); \
+    } \
+  } \
+  \
+  template <typename F, ASIO_VARIADIC_TPARAMS(n)> \
+  inline void promise_invoke_and_set(std::promise<void>& p, \
+      F& f, ASIO_VARIADIC_MOVE_PARAMS(n)) \
+  { \
+    try \
+    { \
+      f(ASIO_VARIADIC_MOVE_ARGS(n)); \
+      p.set_value(); \
+    } \
+    catch (...) \
+    { \
+      p.set_exception(std::current_exception()); \
+    } \
+  } \
+  /**/
+  ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_PROMISE_INVOKE_DEF)
+#undef ASIO_PRIVATE_PROMISE_INVOKE_DEF
+
+#endif // defined(ASIO_NO_EXCEPTIONS)
+
+#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+// A function object adapter to invoke a nullary function object and capture
+// any exception thrown into a promise.
+template <typename T, typename F>
+class promise_invoker
+{
+public:
+  promise_invoker(const shared_ptr<std::promise<T> >& p,
+      ASIO_MOVE_ARG(F) f)
+    : p_(p), f_(ASIO_MOVE_CAST(F)(f))
+  {
+  }
+
+  void operator()()
+  {
+#if !defined(ASIO_NO_EXCEPTIONS)
+    try
+#endif // !defined(ASIO_NO_EXCEPTIONS)
+    {
+      f_();
+    }
+#if !defined(ASIO_NO_EXCEPTIONS)
+    catch (...)
+    {
+      p_->set_exception(std::current_exception());
+    }
+#endif // !defined(ASIO_NO_EXCEPTIONS)
+  }
+
+private:
+  shared_ptr<std::promise<T> > p_;
+  typename decay<F>::type f_;
+};
+
+// An executor that adapts the system_executor to capture any exeption thrown
+// by a submitted function object and save it into a promise.
+template <typename T, typename Blocking = execution::blocking_t::possibly_t>
+class promise_executor
+{
+public:
+  explicit promise_executor(const shared_ptr<std::promise<T> >& p)
+    : p_(p)
+  {
+  }
+
+  static ASIO_CONSTEXPR Blocking query(execution::blocking_t)
+  {
+    return Blocking();
+  }
+
+  promise_executor<T, execution::blocking_t::possibly_t>
+  require(execution::blocking_t::possibly_t) const
+  {
+    return promise_executor<T, execution::blocking_t::possibly_t>(p_);
+  }
+
+  promise_executor<T, execution::blocking_t::never_t>
+  require(execution::blocking_t::never_t) const
+  {
+    return promise_executor<T, execution::blocking_t::never_t>(p_);
+  }
+
+  template <typename F>
+  void execute(ASIO_MOVE_ARG(F) f) const
+  {
+    execution::execute(
+        asio::require(system_executor(), Blocking()),
+        promise_invoker<T, F>(p_, ASIO_MOVE_CAST(F)(f)));
+  }
+
+#if !defined(ASIO_NO_TS_EXECUTORS)
+  execution_context& context() const ASIO_NOEXCEPT
+  {
+    return system_executor().context();
+  }
+
+  void on_work_started() const ASIO_NOEXCEPT {}
+  void on_work_finished() const ASIO_NOEXCEPT {}
+
+  template <typename F, typename A>
+  void dispatch(ASIO_MOVE_ARG(F) f, const A&) const
+  {
+    promise_invoker<T, F>(p_, ASIO_MOVE_CAST(F)(f))();
+  }
+
+  template <typename F, typename A>
+  void post(ASIO_MOVE_ARG(F) f, const A& a) const
+  {
+    system_executor().post(
+        promise_invoker<T, F>(p_, ASIO_MOVE_CAST(F)(f)), a);
+  }
+
+  template <typename F, typename A>
+  void defer(ASIO_MOVE_ARG(F) f, const A& a) const
+  {
+    system_executor().defer(
+        promise_invoker<T, F>(p_, ASIO_MOVE_CAST(F)(f)), a);
+  }
+#endif // !defined(ASIO_NO_TS_EXECUTORS)
+
+  friend bool operator==(const promise_executor& a,
+      const promise_executor& b) ASIO_NOEXCEPT
+  {
+    return a.p_ == b.p_;
+  }
+
+  friend bool operator!=(const promise_executor& a,
+      const promise_executor& b) ASIO_NOEXCEPT
+  {
+    return a.p_ != b.p_;
+  }
+
+private:
+  shared_ptr<std::promise<T> > p_;
+};
+
+// The base class for all completion handlers that create promises.
+template <typename T>
+class promise_creator
+{
+public:
+  typedef promise_executor<T> executor_type;
+
+  executor_type get_executor() const ASIO_NOEXCEPT
+  {
+    return executor_type(p_);
+  }
+
+  typedef std::future<T> future_type;
+
+  future_type get_future()
+  {
+    return p_->get_future();
+  }
+
+protected:
+  template <typename Allocator>
+  void create_promise(const Allocator& a)
+  {
+    ASIO_REBIND_ALLOC(Allocator, char) b(a);
+    p_ = std::allocate_shared<std::promise<T>>(b, std::allocator_arg, b);
+  }
+
+  shared_ptr<std::promise<T> > p_;
+};
+
+// For completion signature void().
+class promise_handler_0
+  : public promise_creator<void>
+{
+public:
+  void operator()()
+  {
+    this->p_->set_value();
+  }
+};
+
+// For completion signature void(error_code).
+class promise_handler_ec_0
+  : public promise_creator<void>
+{
+public:
+  void operator()(const asio::error_code& ec)
+  {
+    if (ec)
+    {
+      this->p_->set_exception(
+          std::make_exception_ptr(
+            asio::system_error(ec)));
+    }
+    else
+    {
+      this->p_->set_value();
+    }
+  }
+};
+
+// For completion signature void(exception_ptr).
+class promise_handler_ex_0
+  : public promise_creator<void>
+{
+public:
+  void operator()(const std::exception_ptr& ex)
+  {
+    if (ex)
+    {
+      this->p_->set_exception(ex);
+    }
+    else
+    {
+      this->p_->set_value();
+    }
+  }
+};
+
+// For completion signature void(T).
+template <typename T>
+class promise_handler_1
+  : public promise_creator<T>
+{
+public:
+  template <typename Arg>
+  void operator()(ASIO_MOVE_ARG(Arg) arg)
+  {
+    this->p_->set_value(ASIO_MOVE_CAST(Arg)(arg));
+  }
+};
+
+// For completion signature void(error_code, T).
+template <typename T>
+class promise_handler_ec_1
+  : public promise_creator<T>
+{
+public:
+  template <typename Arg>
+  void operator()(const asio::error_code& ec,
+      ASIO_MOVE_ARG(Arg) arg)
+  {
+    if (ec)
+    {
+      this->p_->set_exception(
+          std::make_exception_ptr(
+            asio::system_error(ec)));
+    }
+    else
+      this->p_->set_value(ASIO_MOVE_CAST(Arg)(arg));
+  }
+};
+
+// For completion signature void(exception_ptr, T).
+template <typename T>
+class promise_handler_ex_1
+  : public promise_creator<T>
+{
+public:
+  template <typename Arg>
+  void operator()(const std::exception_ptr& ex,
+      ASIO_MOVE_ARG(Arg) arg)
+  {
+    if (ex)
+      this->p_->set_exception(ex);
+    else
+      this->p_->set_value(ASIO_MOVE_CAST(Arg)(arg));
+  }
+};
+
+// For completion signature void(T1, ..., Tn);
+template <typename T>
+class promise_handler_n
+  : public promise_creator<T>
+{
+public:
+#if defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+  template <typename... Args>
+  void operator()(ASIO_MOVE_ARG(Args)... args)
+  {
+    this->p_->set_value(
+        std::forward_as_tuple(
+          ASIO_MOVE_CAST(Args)(args)...));
+  }
+
+#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+#define ASIO_PRIVATE_CALL_OP_DEF(n) \
+  template <ASIO_VARIADIC_TPARAMS(n)> \
+  void operator()(ASIO_VARIADIC_MOVE_PARAMS(n)) \
+  {\
+    this->p_->set_value( \
+        std::forward_as_tuple( \
+          ASIO_VARIADIC_MOVE_ARGS(n))); \
+  } \
+  /**/
+  ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_CALL_OP_DEF)
+#undef ASIO_PRIVATE_CALL_OP_DEF
+
+#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+};
+
+// For completion signature void(error_code, T1, ..., Tn);
+template <typename T>
+class promise_handler_ec_n
+  : public promise_creator<T>
+{
+public:
+#if defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+  template <typename... Args>
+  void operator()(const asio::error_code& ec,
+      ASIO_MOVE_ARG(Args)... args)
+  {
+    if (ec)
+    {
+      this->p_->set_exception(
+          std::make_exception_ptr(
+            asio::system_error(ec)));
+    }
+    else
+    {
+      this->p_->set_value(
+          std::forward_as_tuple(
+            ASIO_MOVE_CAST(Args)(args)...));
+    }
+  }
+
+#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+#define ASIO_PRIVATE_CALL_OP_DEF(n) \
+  template <ASIO_VARIADIC_TPARAMS(n)> \
+  void operator()(const asio::error_code& ec, \
+      ASIO_VARIADIC_MOVE_PARAMS(n)) \
+  {\
+    if (ec) \
+    { \
+      this->p_->set_exception( \
+          std::make_exception_ptr( \
+            asio::system_error(ec))); \
+    } \
+    else \
+    { \
+      this->p_->set_value( \
+          std::forward_as_tuple( \
+            ASIO_VARIADIC_MOVE_ARGS(n))); \
+    } \
+  } \
+  /**/
+  ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_CALL_OP_DEF)
+#undef ASIO_PRIVATE_CALL_OP_DEF
+
+#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+};
+
+// For completion signature void(exception_ptr, T1, ..., Tn);
+template <typename T>
+class promise_handler_ex_n
+  : public promise_creator<T>
+{
+public:
+#if defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+  template <typename... Args>
+  void operator()(const std::exception_ptr& ex,
+      ASIO_MOVE_ARG(Args)... args)
+  {
+    if (ex)
+      this->p_->set_exception(ex);
+    else
+    {
+      this->p_->set_value(
+          std::forward_as_tuple(
+            ASIO_MOVE_CAST(Args)(args)...));
+    }
+  }
+
+#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+#define ASIO_PRIVATE_CALL_OP_DEF(n) \
+  template <ASIO_VARIADIC_TPARAMS(n)> \
+  void operator()(const std::exception_ptr& ex, \
+      ASIO_VARIADIC_MOVE_PARAMS(n)) \
+  {\
+    if (ex) \
+      this->p_->set_exception(ex); \
+    else \
+    { \
+      this->p_->set_value( \
+          std::forward_as_tuple( \
+            ASIO_VARIADIC_MOVE_ARGS(n))); \
+    } \
+  } \
+  /**/
+  ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_CALL_OP_DEF)
+#undef ASIO_PRIVATE_CALL_OP_DEF
+
+#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+};
+
+// Helper template to choose the appropriate concrete promise handler
+// implementation based on the supplied completion signature.
+template <typename> class promise_handler_selector;
+
+template <>
+class promise_handler_selector<void()>
+  : public promise_handler_0 {};
+
+template <>
+class promise_handler_selector<void(asio::error_code)>
+  : public promise_handler_ec_0 {};
+
+template <>
+class promise_handler_selector<void(std::exception_ptr)>
+  : public promise_handler_ex_0 {};
+
+template <typename Arg>
+class promise_handler_selector<void(Arg)>
+  : public promise_handler_1<Arg> {};
+
+template <typename Arg>
+class promise_handler_selector<void(asio::error_code, Arg)>
+  : public promise_handler_ec_1<Arg> {};
+
+template <typename Arg>
+class promise_handler_selector<void(std::exception_ptr, Arg)>
+  : public promise_handler_ex_1<Arg> {};
+
+#if defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+template <typename... Arg>
+class promise_handler_selector<void(Arg...)>
+  : public promise_handler_n<std::tuple<Arg...> > {};
+
+template <typename... Arg>
+class promise_handler_selector<void(asio::error_code, Arg...)>
+  : public promise_handler_ec_n<std::tuple<Arg...> > {};
+
+template <typename... Arg>
+class promise_handler_selector<void(std::exception_ptr, Arg...)>
+  : public promise_handler_ex_n<std::tuple<Arg...> > {};
+
+#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+#define ASIO_PRIVATE_PROMISE_SELECTOR_DEF(n) \
+  template <typename Arg, ASIO_VARIADIC_TPARAMS(n)> \
+  class promise_handler_selector< \
+    void(Arg, ASIO_VARIADIC_TARGS(n))> \
+      : public promise_handler_n< \
+        std::tuple<Arg, ASIO_VARIADIC_TARGS(n)> > {}; \
+  \
+  template <typename Arg, ASIO_VARIADIC_TPARAMS(n)> \
+  class promise_handler_selector< \
+    void(asio::error_code, Arg, ASIO_VARIADIC_TARGS(n))> \
+      : public promise_handler_ec_n< \
+        std::tuple<Arg, ASIO_VARIADIC_TARGS(n)> > {}; \
+  \
+  template <typename Arg, ASIO_VARIADIC_TPARAMS(n)> \
+  class promise_handler_selector< \
+    void(std::exception_ptr, Arg, ASIO_VARIADIC_TARGS(n))> \
+      : public promise_handler_ex_n< \
+        std::tuple<Arg, ASIO_VARIADIC_TARGS(n)> > {}; \
+  /**/
+  ASIO_VARIADIC_GENERATE_5(ASIO_PRIVATE_PROMISE_SELECTOR_DEF)
+#undef ASIO_PRIVATE_PROMISE_SELECTOR_DEF
+
+#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+// Completion handlers produced from the use_future completion token, when not
+// using use_future::operator().
+template <typename Signature, typename Allocator>
+class promise_handler
+  : public promise_handler_selector<Signature>
+{
+public:
+  typedef Allocator allocator_type;
+  typedef void result_type;
+
+  promise_handler(use_future_t<Allocator> u)
+    : allocator_(u.get_allocator())
+  {
+    this->create_promise(allocator_);
+  }
+
+  allocator_type get_allocator() const ASIO_NOEXCEPT
+  {
+    return allocator_;
+  }
+
+private:
+  Allocator allocator_;
+};
+
+template <typename Function>
+struct promise_function_wrapper
+{
+  explicit promise_function_wrapper(Function& f)
+    : function_(ASIO_MOVE_CAST(Function)(f))
+  {
+  }
+
+  explicit promise_function_wrapper(const Function& f)
+    : function_(f)
+  {
+  }
+
+  void operator()()
+  {
+    function_();
+  }
+
+  Function function_;
+};
+
+#if !defined(ASIO_NO_DEPRECATED)
+
+template <typename Function, typename Signature, typename Allocator>
+inline void asio_handler_invoke(Function& f,
+    promise_handler<Signature, Allocator>* h)
+{
+  typename promise_handler<Signature, Allocator>::executor_type
+    ex(h->get_executor());
+  asio::dispatch(ex, promise_function_wrapper<Function>(f));
+}
+
+template <typename Function, typename Signature, typename Allocator>
+inline void asio_handler_invoke(const Function& f,
+    promise_handler<Signature, Allocator>* h)
+{
+  typename promise_handler<Signature, Allocator>::executor_type
+    ex(h->get_executor());
+  asio::dispatch(ex, promise_function_wrapper<Function>(f));
+}
+
+#endif // !defined(ASIO_NO_DEPRECATED)
+
+// Helper base class for async_result specialisation.
+template <typename Signature, typename Allocator>
+class promise_async_result
+{
+public:
+  typedef promise_handler<Signature, Allocator> completion_handler_type;
+  typedef typename completion_handler_type::future_type return_type;
+
+  explicit promise_async_result(completion_handler_type& h)
+    : future_(h.get_future())
+  {
+  }
+
+  return_type get()
+  {
+    return ASIO_MOVE_CAST(return_type)(future_);
+  }
+
+private:
+  return_type future_;
+};
+
+// Return value from use_future::operator().
+template <typename Function, typename Allocator>
+class packaged_token
+{
+public:
+  packaged_token(Function f, const Allocator& a)
+    : function_(ASIO_MOVE_CAST(Function)(f)),
+      allocator_(a)
+  {
+  }
+
+//private:
+  Function function_;
+  Allocator allocator_;
+};
+
+// Completion handlers produced from the use_future completion token, when
+// using use_future::operator().
+template <typename Function, typename Allocator, typename Result>
+class packaged_handler
+  : public promise_creator<Result>
+{
+public:
+  typedef Allocator allocator_type;
+  typedef void result_type;
+
+  packaged_handler(packaged_token<Function, Allocator> t)
+    : function_(ASIO_MOVE_CAST(Function)(t.function_)),
+      allocator_(t.allocator_)
+  {
+    this->create_promise(allocator_);
+  }
+
+  allocator_type get_allocator() const ASIO_NOEXCEPT
+  {
+    return allocator_;
+  }
+
+#if defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+  template <typename... Args>
+  void operator()(ASIO_MOVE_ARG(Args)... args)
+  {
+    (promise_invoke_and_set)(*this->p_,
+        function_, ASIO_MOVE_CAST(Args)(args)...);
+  }
+
+#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+  void operator()()
+  {
+    (promise_invoke_and_set)(*this->p_, function_);
+  }
+
+#define ASIO_PRIVATE_CALL_OP_DEF(n) \
+  template <ASIO_VARIADIC_TPARAMS(n)> \
+  void operator()(ASIO_VARIADIC_MOVE_PARAMS(n)) \
+  {\
+    (promise_invoke_and_set)(*this->p_, \
+        function_, ASIO_VARIADIC_MOVE_ARGS(n)); \
+  } \
+  /**/
+  ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_CALL_OP_DEF)
+#undef ASIO_PRIVATE_CALL_OP_DEF
+
+#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+private:
+  Function function_;
+  Allocator allocator_;
+};
+
+#if !defined(ASIO_NO_DEPRECATED)
+
+template <typename Function,
+    typename Function1, typename Allocator, typename Result>
+inline void asio_handler_invoke(Function& f,
+    packaged_handler<Function1, Allocator, Result>* h)
+{
+  typename packaged_handler<Function1, Allocator, Result>::executor_type
+    ex(h->get_executor());
+  asio::dispatch(ex, promise_function_wrapper<Function>(f));
+}
+
+template <typename Function,
+    typename Function1, typename Allocator, typename Result>
+inline void asio_handler_invoke(const Function& f,
+    packaged_handler<Function1, Allocator, Result>* h)
+{
+  typename packaged_handler<Function1, Allocator, Result>::executor_type
+    ex(h->get_executor());
+  asio::dispatch(ex, promise_function_wrapper<Function>(f));
+}
+
+#endif // !defined(ASIO_NO_DEPRECATED)
+
+// Helper base class for async_result specialisation.
+template <typename Function, typename Allocator, typename Result>
+class packaged_async_result
+{
+public:
+  typedef packaged_handler<Function, Allocator, Result> completion_handler_type;
+  typedef typename completion_handler_type::future_type return_type;
+
+  explicit packaged_async_result(completion_handler_type& h)
+    : future_(h.get_future())
+  {
+  }
+
+  return_type get()
+  {
+    return ASIO_MOVE_CAST(return_type)(future_);
+  }
+
+private:
+  return_type future_;
+};
+
+} // namespace detail
+
+template <typename Allocator> template <typename Function>
+inline detail::packaged_token<typename decay<Function>::type, Allocator>
+use_future_t<Allocator>::operator()(ASIO_MOVE_ARG(Function) f) const
+{
+  return detail::packaged_token<typename decay<Function>::type, Allocator>(
+      ASIO_MOVE_CAST(Function)(f), allocator_);
+}
+
+#if !defined(GENERATING_DOCUMENTATION)
+
+#if defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+template <typename Allocator, typename Result, typename... Args>
+class async_result<use_future_t<Allocator>, Result(Args...)>
+  : public detail::promise_async_result<
+      void(typename decay<Args>::type...), Allocator>
+{
+public:
+  explicit async_result(
+    typename detail::promise_async_result<void(typename decay<Args>::type...),
+      Allocator>::completion_handler_type& h)
+    : detail::promise_async_result<
+        void(typename decay<Args>::type...), Allocator>(h)
+  {
+  }
+};
+
+template <typename Function, typename Allocator,
+    typename Result, typename... Args>
+class async_result<detail::packaged_token<Function, Allocator>, Result(Args...)>
+  : public detail::packaged_async_result<Function, Allocator,
+      typename result_of<Function(Args...)>::type>
+{
+public:
+  explicit async_result(
+    typename detail::packaged_async_result<Function, Allocator,
+      typename result_of<Function(Args...)>::type>::completion_handler_type& h)
+    : detail::packaged_async_result<Function, Allocator,
+        typename result_of<Function(Args...)>::type>(h)
+  {
+  }
+};
+
+#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+template <typename Allocator, typename Result>
+class async_result<use_future_t<Allocator>, Result()>
+  : public detail::promise_async_result<void(), Allocator>
+{
+public:
+  explicit async_result(
+    typename detail::promise_async_result<
+      void(), Allocator>::completion_handler_type& h)
+    : detail::promise_async_result<void(), Allocator>(h)
+  {
+  }
+};
+
+template <typename Function, typename Allocator, typename Result>
+class async_result<detail::packaged_token<Function, Allocator>, Result()>
+  : public detail::packaged_async_result<Function, Allocator,
+      typename result_of<Function()>::type>
+{
+public:
+  explicit async_result(
+    typename detail::packaged_async_result<Function, Allocator,
+      typename result_of<Function()>::type>::completion_handler_type& h)
+    : detail::packaged_async_result<Function, Allocator,
+        typename result_of<Function()>::type>(h)
+  {
+  }
+};
+
+#define ASIO_PRIVATE_ASYNC_RESULT_DEF(n) \
+  template <typename Allocator, \
+      typename Result, ASIO_VARIADIC_TPARAMS(n)> \
+  class async_result<use_future_t<Allocator>, \
+      Result(ASIO_VARIADIC_TARGS(n))> \
+    : public detail::promise_async_result< \
+        void(ASIO_VARIADIC_DECAY(n)), Allocator> \
+  { \
+  public: \
+    explicit async_result( \
+      typename detail::promise_async_result< \
+        void(ASIO_VARIADIC_DECAY(n)), \
+        Allocator>::completion_handler_type& h) \
+      : detail::promise_async_result< \
+          void(ASIO_VARIADIC_DECAY(n)), Allocator>(h) \
+    { \
+    } \
+  }; \
+  \
+  template <typename Function, typename Allocator, \
+      typename Result, ASIO_VARIADIC_TPARAMS(n)> \
+  class async_result<detail::packaged_token<Function, Allocator>, \
+      Result(ASIO_VARIADIC_TARGS(n))> \
+    : public detail::packaged_async_result<Function, Allocator, \
+        typename result_of<Function(ASIO_VARIADIC_TARGS(n))>::type> \
+  { \
+  public: \
+    explicit async_result( \
+      typename detail::packaged_async_result<Function, Allocator, \
+        typename result_of<Function(ASIO_VARIADIC_TARGS(n))>::type \
+        >::completion_handler_type& h) \
+      : detail::packaged_async_result<Function, Allocator, \
+          typename result_of<Function(ASIO_VARIADIC_TARGS(n))>::type>(h) \
+    { \
+    } \
+  }; \
+  /**/
+  ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_ASYNC_RESULT_DEF)
+#undef ASIO_PRIVATE_ASYNC_RESULT_DEF
+
+#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+namespace traits {
+
+#if !defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)
+
+template <typename T, typename Blocking>
+struct equality_comparable<
+    asio::detail::promise_executor<T, Blocking> >
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
+};
+
+#endif // !defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)
+
+#if !defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)
+
+template <typename T, typename Blocking, typename Function>
+struct execute_member<
+    asio::detail::promise_executor<T, Blocking>, Function>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
+  typedef void result_type;
+};
+
+#endif // !defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)
+
+#if !defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_TRAIT)
+
+template <typename T, typename Blocking, typename Property>
+struct query_static_constexpr_member<
+    asio::detail::promise_executor<T, Blocking>,
+    Property,
+    typename asio::enable_if<
+      asio::is_convertible<
+        Property,
+        asio::execution::blocking_t
+      >::value
+    >::type
+  >
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
+  typedef Blocking result_type;
+
+  static ASIO_CONSTEXPR result_type value() ASIO_NOEXCEPT
+  {
+    return Blocking();
+  }
+};
+
+#endif // !defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_TRAIT)
+
+#if !defined(ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT)
+
+template <typename T, typename Blocking>
+struct require_member<
+    asio::detail::promise_executor<T, Blocking>,
+    execution::blocking_t::possibly_t
+  >
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
+  typedef asio::detail::promise_executor<T,
+      execution::blocking_t::possibly_t> result_type;
+};
+
+template <typename T, typename Blocking>
+struct require_member<
+    asio::detail::promise_executor<T, Blocking>,
+    execution::blocking_t::never_t
+  >
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
+  typedef asio::detail::promise_executor<T,
+      execution::blocking_t::never_t> result_type;
+};
+
+#endif // !defined(ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT)
+
+} // namespace traits
+
+#endif // !defined(GENERATING_DOCUMENTATION)
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IMPL_USE_FUTURE_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/impl/write.hpp b/link/modules/asio-standalone/asio/include/asio/impl/write.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/impl/write.hpp
@@ -0,0 +1,1104 @@
+//
+// impl/write.hpp
+// ~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_IMPL_WRITE_HPP
+#define ASIO_IMPL_WRITE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/associated_allocator.hpp"
+#include "asio/associated_executor.hpp"
+#include "asio/buffer.hpp"
+#include "asio/completion_condition.hpp"
+#include "asio/detail/array_fwd.hpp"
+#include "asio/detail/base_from_completion_cond.hpp"
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/consuming_buffers.hpp"
+#include "asio/detail/dependent_type.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_cont_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/handler_tracking.hpp"
+#include "asio/detail/handler_type_requirements.hpp"
+#include "asio/detail/non_const_lvalue.hpp"
+#include "asio/detail/throw_error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+namespace detail
+{
+  template <typename SyncWriteStream, typename ConstBufferSequence,
+      typename ConstBufferIterator, typename CompletionCondition>
+  std::size_t write_buffer_sequence(SyncWriteStream& s,
+      const ConstBufferSequence& buffers, const ConstBufferIterator&,
+      CompletionCondition completion_condition, asio::error_code& ec)
+  {
+    ec = asio::error_code();
+    asio::detail::consuming_buffers<const_buffer,
+        ConstBufferSequence, ConstBufferIterator> tmp(buffers);
+    while (!tmp.empty())
+    {
+      if (std::size_t max_size = detail::adapt_completion_condition_result(
+            completion_condition(ec, tmp.total_consumed())))
+        tmp.consume(s.write_some(tmp.prepare(max_size), ec));
+      else
+        break;
+    }
+    return tmp.total_consumed();;
+  }
+} // namespace detail
+
+template <typename SyncWriteStream, typename ConstBufferSequence,
+    typename CompletionCondition>
+inline std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers,
+    CompletionCondition completion_condition, asio::error_code& ec,
+    typename enable_if<
+      is_const_buffer_sequence<ConstBufferSequence>::value
+    >::type*)
+{
+  return detail::write_buffer_sequence(s, buffers,
+      asio::buffer_sequence_begin(buffers),
+      ASIO_MOVE_CAST(CompletionCondition)(completion_condition), ec);
+}
+
+template <typename SyncWriteStream, typename ConstBufferSequence>
+inline std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers,
+    typename enable_if<
+      is_const_buffer_sequence<ConstBufferSequence>::value
+    >::type*)
+{
+  asio::error_code ec;
+  std::size_t bytes_transferred = write(s, buffers, transfer_all(), ec);
+  asio::detail::throw_error(ec, "write");
+  return bytes_transferred;
+}
+
+template <typename SyncWriteStream, typename ConstBufferSequence>
+inline std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers,
+    asio::error_code& ec,
+    typename enable_if<
+      is_const_buffer_sequence<ConstBufferSequence>::value
+    >::type*)
+{
+  return write(s, buffers, transfer_all(), ec);
+}
+
+template <typename SyncWriteStream, typename ConstBufferSequence,
+    typename CompletionCondition>
+inline std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers,
+    CompletionCondition completion_condition,
+    typename enable_if<
+      is_const_buffer_sequence<ConstBufferSequence>::value
+    >::type*)
+{
+  asio::error_code ec;
+  std::size_t bytes_transferred = write(s, buffers,
+      ASIO_MOVE_CAST(CompletionCondition)(completion_condition), ec);
+  asio::detail::throw_error(ec, "write");
+  return bytes_transferred;
+}
+
+#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1)
+
+template <typename SyncWriteStream, typename DynamicBuffer_v1,
+    typename CompletionCondition>
+std::size_t write(SyncWriteStream& s,
+    ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,
+    CompletionCondition completion_condition, asio::error_code& ec,
+    typename enable_if<
+      is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value
+        && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value
+    >::type*)
+{
+  typename decay<DynamicBuffer_v1>::type b(
+      ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers));
+
+  std::size_t bytes_transferred = write(s, b.data(),
+      ASIO_MOVE_CAST(CompletionCondition)(completion_condition), ec);
+  b.consume(bytes_transferred);
+  return bytes_transferred;
+}
+
+template <typename SyncWriteStream, typename DynamicBuffer_v1>
+inline std::size_t write(SyncWriteStream& s,
+    ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,
+    typename enable_if<
+      is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value
+        && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value
+    >::type*)
+{
+  asio::error_code ec;
+  std::size_t bytes_transferred = write(s,
+      ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers),
+      transfer_all(), ec);
+  asio::detail::throw_error(ec, "write");
+  return bytes_transferred;
+}
+
+template <typename SyncWriteStream, typename DynamicBuffer_v1>
+inline std::size_t write(SyncWriteStream& s,
+    ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,
+    asio::error_code& ec,
+    typename enable_if<
+      is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value
+        && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value
+    >::type*)
+{
+  return write(s, ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers),
+      transfer_all(), ec);
+}
+
+template <typename SyncWriteStream, typename DynamicBuffer_v1,
+    typename CompletionCondition>
+inline std::size_t write(SyncWriteStream& s,
+    ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,
+    CompletionCondition completion_condition,
+    typename enable_if<
+      is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value
+        && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value
+    >::type*)
+{
+  asio::error_code ec;
+  std::size_t bytes_transferred = write(s,
+      ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers),
+      ASIO_MOVE_CAST(CompletionCondition)(completion_condition), ec);
+  asio::detail::throw_error(ec, "write");
+  return bytes_transferred;
+}
+
+#if !defined(ASIO_NO_EXTENSIONS)
+#if !defined(ASIO_NO_IOSTREAM)
+
+template <typename SyncWriteStream, typename Allocator,
+    typename CompletionCondition>
+inline std::size_t write(SyncWriteStream& s,
+    asio::basic_streambuf<Allocator>& b,
+    CompletionCondition completion_condition, asio::error_code& ec)
+{
+  return write(s, basic_streambuf_ref<Allocator>(b),
+      ASIO_MOVE_CAST(CompletionCondition)(completion_condition), ec);
+}
+
+template <typename SyncWriteStream, typename Allocator>
+inline std::size_t write(SyncWriteStream& s,
+    asio::basic_streambuf<Allocator>& b)
+{
+  return write(s, basic_streambuf_ref<Allocator>(b));
+}
+
+template <typename SyncWriteStream, typename Allocator>
+inline std::size_t write(SyncWriteStream& s,
+    asio::basic_streambuf<Allocator>& b,
+    asio::error_code& ec)
+{
+  return write(s, basic_streambuf_ref<Allocator>(b), ec);
+}
+
+template <typename SyncWriteStream, typename Allocator,
+    typename CompletionCondition>
+inline std::size_t write(SyncWriteStream& s,
+    asio::basic_streambuf<Allocator>& b,
+    CompletionCondition completion_condition)
+{
+  return write(s, basic_streambuf_ref<Allocator>(b),
+      ASIO_MOVE_CAST(CompletionCondition)(completion_condition));
+}
+
+#endif // !defined(ASIO_NO_IOSTREAM)
+#endif // !defined(ASIO_NO_EXTENSIONS)
+#endif // !defined(ASIO_NO_DYNAMIC_BUFFER_V1)
+
+template <typename SyncWriteStream, typename DynamicBuffer_v2,
+    typename CompletionCondition>
+std::size_t write(SyncWriteStream& s, DynamicBuffer_v2 buffers,
+    CompletionCondition completion_condition, asio::error_code& ec,
+    typename enable_if<
+      is_dynamic_buffer_v2<DynamicBuffer_v2>::value
+    >::type*)
+{
+  std::size_t bytes_transferred = write(s, buffers.data(0, buffers.size()),
+      ASIO_MOVE_CAST(CompletionCondition)(completion_condition), ec);
+  buffers.consume(bytes_transferred);
+  return bytes_transferred;
+}
+
+template <typename SyncWriteStream, typename DynamicBuffer_v2>
+inline std::size_t write(SyncWriteStream& s, DynamicBuffer_v2 buffers,
+    typename enable_if<
+      is_dynamic_buffer_v2<DynamicBuffer_v2>::value
+    >::type*)
+{
+  asio::error_code ec;
+  std::size_t bytes_transferred = write(s,
+      ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers),
+      transfer_all(), ec);
+  asio::detail::throw_error(ec, "write");
+  return bytes_transferred;
+}
+
+template <typename SyncWriteStream, typename DynamicBuffer_v2>
+inline std::size_t write(SyncWriteStream& s, DynamicBuffer_v2 buffers,
+    asio::error_code& ec,
+    typename enable_if<
+      is_dynamic_buffer_v2<DynamicBuffer_v2>::value
+    >::type*)
+{
+  return write(s, ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers),
+      transfer_all(), ec);
+}
+
+template <typename SyncWriteStream, typename DynamicBuffer_v2,
+    typename CompletionCondition>
+inline std::size_t write(SyncWriteStream& s, DynamicBuffer_v2 buffers,
+    CompletionCondition completion_condition,
+    typename enable_if<
+      is_dynamic_buffer_v2<DynamicBuffer_v2>::value
+    >::type*)
+{
+  asio::error_code ec;
+  std::size_t bytes_transferred = write(s,
+      ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers),
+      ASIO_MOVE_CAST(CompletionCondition)(completion_condition), ec);
+  asio::detail::throw_error(ec, "write");
+  return bytes_transferred;
+}
+
+namespace detail
+{
+  template <typename AsyncWriteStream, typename ConstBufferSequence,
+      typename ConstBufferIterator, typename CompletionCondition,
+      typename WriteHandler>
+  class write_op
+    : detail::base_from_completion_cond<CompletionCondition>
+  {
+  public:
+    write_op(AsyncWriteStream& stream, const ConstBufferSequence& buffers,
+        CompletionCondition& completion_condition, WriteHandler& handler)
+      : detail::base_from_completion_cond<
+          CompletionCondition>(completion_condition),
+        stream_(stream),
+        buffers_(buffers),
+        start_(0),
+        handler_(ASIO_MOVE_CAST(WriteHandler)(handler))
+    {
+    }
+
+#if defined(ASIO_HAS_MOVE)
+    write_op(const write_op& other)
+      : detail::base_from_completion_cond<CompletionCondition>(other),
+        stream_(other.stream_),
+        buffers_(other.buffers_),
+        start_(other.start_),
+        handler_(other.handler_)
+    {
+    }
+
+    write_op(write_op&& other)
+      : detail::base_from_completion_cond<CompletionCondition>(
+          ASIO_MOVE_CAST(detail::base_from_completion_cond<
+            CompletionCondition>)(other)),
+        stream_(other.stream_),
+        buffers_(ASIO_MOVE_CAST(buffers_type)(other.buffers_)),
+        start_(other.start_),
+        handler_(ASIO_MOVE_CAST(WriteHandler)(other.handler_))
+    {
+    }
+#endif // defined(ASIO_HAS_MOVE)
+
+    void operator()(const asio::error_code& ec,
+        std::size_t bytes_transferred, int start = 0)
+    {
+      std::size_t max_size;
+      switch (start_ = start)
+      {
+        case 1:
+        max_size = this->check_for_completion(ec, buffers_.total_consumed());
+        do
+        {
+          {
+            ASIO_HANDLER_LOCATION((__FILE__, __LINE__, "async_write"));
+            stream_.async_write_some(buffers_.prepare(max_size),
+                ASIO_MOVE_CAST(write_op)(*this));
+          }
+          return; default:
+          buffers_.consume(bytes_transferred);
+          if ((!ec && bytes_transferred == 0) || buffers_.empty())
+            break;
+          max_size = this->check_for_completion(ec, buffers_.total_consumed());
+        } while (max_size > 0);
+
+        handler_(ec, buffers_.total_consumed());
+      }
+    }
+
+  //private:
+    typedef asio::detail::consuming_buffers<const_buffer,
+        ConstBufferSequence, ConstBufferIterator> buffers_type;
+
+    AsyncWriteStream& stream_;
+    buffers_type buffers_;
+    int start_;
+    WriteHandler handler_;
+  };
+
+  template <typename AsyncWriteStream, typename ConstBufferSequence,
+      typename ConstBufferIterator, typename CompletionCondition,
+      typename WriteHandler>
+  inline asio_handler_allocate_is_deprecated
+  asio_handler_allocate(std::size_t size,
+      write_op<AsyncWriteStream, ConstBufferSequence, ConstBufferIterator,
+        CompletionCondition, WriteHandler>* this_handler)
+  {
+#if defined(ASIO_NO_DEPRECATED)
+    asio_handler_alloc_helpers::allocate(size, this_handler->handler_);
+    return asio_handler_allocate_is_no_longer_used();
+#else // defined(ASIO_NO_DEPRECATED)
+    return asio_handler_alloc_helpers::allocate(
+        size, this_handler->handler_);
+#endif // defined(ASIO_NO_DEPRECATED)
+  }
+
+  template <typename AsyncWriteStream, typename ConstBufferSequence,
+      typename ConstBufferIterator, typename CompletionCondition,
+      typename WriteHandler>
+  inline asio_handler_deallocate_is_deprecated
+  asio_handler_deallocate(void* pointer, std::size_t size,
+      write_op<AsyncWriteStream, ConstBufferSequence, ConstBufferIterator,
+        CompletionCondition, WriteHandler>* this_handler)
+  {
+    asio_handler_alloc_helpers::deallocate(
+        pointer, size, this_handler->handler_);
+#if defined(ASIO_NO_DEPRECATED)
+    return asio_handler_deallocate_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+  }
+
+  template <typename AsyncWriteStream, typename ConstBufferSequence,
+      typename ConstBufferIterator, typename CompletionCondition,
+      typename WriteHandler>
+  inline bool asio_handler_is_continuation(
+      write_op<AsyncWriteStream, ConstBufferSequence, ConstBufferIterator,
+        CompletionCondition, WriteHandler>* this_handler)
+  {
+    return this_handler->start_ == 0 ? true
+      : asio_handler_cont_helpers::is_continuation(
+          this_handler->handler_);
+  }
+
+  template <typename Function, typename AsyncWriteStream,
+      typename ConstBufferSequence, typename ConstBufferIterator,
+      typename CompletionCondition, typename WriteHandler>
+  inline asio_handler_invoke_is_deprecated
+  asio_handler_invoke(Function& function,
+      write_op<AsyncWriteStream, ConstBufferSequence, ConstBufferIterator,
+        CompletionCondition, WriteHandler>* this_handler)
+  {
+    asio_handler_invoke_helpers::invoke(
+        function, this_handler->handler_);
+#if defined(ASIO_NO_DEPRECATED)
+    return asio_handler_invoke_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+  }
+
+  template <typename Function, typename AsyncWriteStream,
+      typename ConstBufferSequence, typename ConstBufferIterator,
+      typename CompletionCondition, typename WriteHandler>
+  inline asio_handler_invoke_is_deprecated
+  asio_handler_invoke(const Function& function,
+      write_op<AsyncWriteStream, ConstBufferSequence, ConstBufferIterator,
+        CompletionCondition, WriteHandler>* this_handler)
+  {
+    asio_handler_invoke_helpers::invoke(
+        function, this_handler->handler_);
+#if defined(ASIO_NO_DEPRECATED)
+    return asio_handler_invoke_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+  }
+
+  template <typename AsyncWriteStream, typename ConstBufferSequence,
+      typename ConstBufferIterator, typename CompletionCondition,
+      typename WriteHandler>
+  inline void start_write_buffer_sequence_op(AsyncWriteStream& stream,
+      const ConstBufferSequence& buffers, const ConstBufferIterator&,
+      CompletionCondition& completion_condition, WriteHandler& handler)
+  {
+    detail::write_op<AsyncWriteStream, ConstBufferSequence,
+      ConstBufferIterator, CompletionCondition, WriteHandler>(
+        stream, buffers, completion_condition, handler)(
+          asio::error_code(), 0, 1);
+  }
+
+  template <typename AsyncWriteStream>
+  class initiate_async_write_buffer_sequence
+  {
+  public:
+    typedef typename AsyncWriteStream::executor_type executor_type;
+
+    explicit initiate_async_write_buffer_sequence(AsyncWriteStream& stream)
+      : stream_(stream)
+    {
+    }
+
+    executor_type get_executor() const ASIO_NOEXCEPT
+    {
+      return stream_.get_executor();
+    }
+
+    template <typename WriteHandler, typename ConstBufferSequence,
+        typename CompletionCondition>
+    void operator()(ASIO_MOVE_ARG(WriteHandler) handler,
+        const ConstBufferSequence& buffers,
+        ASIO_MOVE_ARG(CompletionCondition) completion_cond) const
+    {
+      // If you get an error on the following line it means that your handler
+      // does not meet the documented type requirements for a WriteHandler.
+      ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check;
+
+      non_const_lvalue<WriteHandler> handler2(handler);
+      non_const_lvalue<CompletionCondition> completion_cond2(completion_cond);
+      start_write_buffer_sequence_op(stream_, buffers,
+          asio::buffer_sequence_begin(buffers),
+          completion_cond2.value, handler2.value);
+    }
+
+  private:
+    AsyncWriteStream& stream_;
+  };
+} // namespace detail
+
+#if !defined(GENERATING_DOCUMENTATION)
+
+template <typename AsyncWriteStream, typename ConstBufferSequence,
+    typename ConstBufferIterator, typename CompletionCondition,
+    typename WriteHandler, typename Allocator>
+struct associated_allocator<
+    detail::write_op<AsyncWriteStream, ConstBufferSequence,
+      ConstBufferIterator, CompletionCondition, WriteHandler>,
+    Allocator>
+{
+  typedef typename associated_allocator<WriteHandler, Allocator>::type type;
+
+  static type get(
+      const detail::write_op<AsyncWriteStream, ConstBufferSequence,
+        ConstBufferIterator, CompletionCondition, WriteHandler>& h,
+      const Allocator& a = Allocator()) ASIO_NOEXCEPT
+  {
+    return associated_allocator<WriteHandler, Allocator>::get(h.handler_, a);
+  }
+};
+
+template <typename AsyncWriteStream, typename ConstBufferSequence,
+    typename ConstBufferIterator, typename CompletionCondition,
+    typename WriteHandler, typename Executor>
+struct associated_executor<
+    detail::write_op<AsyncWriteStream, ConstBufferSequence,
+      ConstBufferIterator, CompletionCondition, WriteHandler>,
+    Executor>
+  : detail::associated_executor_forwarding_base<WriteHandler, Executor>
+{
+  typedef typename associated_executor<WriteHandler, Executor>::type type;
+
+  static type get(
+      const detail::write_op<AsyncWriteStream, ConstBufferSequence,
+        ConstBufferIterator, CompletionCondition, WriteHandler>& h,
+      const Executor& ex = Executor()) ASIO_NOEXCEPT
+  {
+    return associated_executor<WriteHandler, Executor>::get(h.handler_, ex);
+  }
+};
+
+#endif // !defined(GENERATING_DOCUMENTATION)
+
+template <typename AsyncWriteStream,
+    typename ConstBufferSequence, typename CompletionCondition,
+    ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+      std::size_t)) WriteHandler>
+inline ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,
+    void (asio::error_code, std::size_t))
+async_write(AsyncWriteStream& s, const ConstBufferSequence& buffers,
+    CompletionCondition completion_condition,
+    ASIO_MOVE_ARG(WriteHandler) handler,
+    typename enable_if<
+      is_const_buffer_sequence<ConstBufferSequence>::value
+    >::type*)
+{
+  return async_initiate<WriteHandler,
+    void (asio::error_code, std::size_t)>(
+      detail::initiate_async_write_buffer_sequence<AsyncWriteStream>(s),
+      handler, buffers,
+      ASIO_MOVE_CAST(CompletionCondition)(completion_condition));
+}
+
+template <typename AsyncWriteStream, typename ConstBufferSequence,
+    ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+      std::size_t)) WriteHandler>
+inline ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,
+    void (asio::error_code, std::size_t))
+async_write(AsyncWriteStream& s, const ConstBufferSequence& buffers,
+    ASIO_MOVE_ARG(WriteHandler) handler,
+    typename enable_if<
+      is_const_buffer_sequence<ConstBufferSequence>::value
+    >::type*)
+{
+  return async_initiate<WriteHandler,
+    void (asio::error_code, std::size_t)>(
+      detail::initiate_async_write_buffer_sequence<AsyncWriteStream>(s),
+      handler, buffers, transfer_all());
+}
+
+#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1)
+
+namespace detail
+{
+  template <typename AsyncWriteStream, typename DynamicBuffer_v1,
+      typename CompletionCondition, typename WriteHandler>
+  class write_dynbuf_v1_op
+  {
+  public:
+    template <typename BufferSequence>
+    write_dynbuf_v1_op(AsyncWriteStream& stream,
+        ASIO_MOVE_ARG(BufferSequence) buffers,
+        CompletionCondition& completion_condition, WriteHandler& handler)
+      : stream_(stream),
+        buffers_(ASIO_MOVE_CAST(BufferSequence)(buffers)),
+        completion_condition_(
+          ASIO_MOVE_CAST(CompletionCondition)(completion_condition)),
+        handler_(ASIO_MOVE_CAST(WriteHandler)(handler))
+    {
+    }
+
+#if defined(ASIO_HAS_MOVE)
+    write_dynbuf_v1_op(const write_dynbuf_v1_op& other)
+      : stream_(other.stream_),
+        buffers_(other.buffers_),
+        completion_condition_(other.completion_condition_),
+        handler_(other.handler_)
+    {
+    }
+
+    write_dynbuf_v1_op(write_dynbuf_v1_op&& other)
+      : stream_(other.stream_),
+        buffers_(ASIO_MOVE_CAST(DynamicBuffer_v1)(other.buffers_)),
+        completion_condition_(
+          ASIO_MOVE_CAST(CompletionCondition)(
+            other.completion_condition_)),
+        handler_(ASIO_MOVE_CAST(WriteHandler)(other.handler_))
+    {
+    }
+#endif // defined(ASIO_HAS_MOVE)
+
+    void operator()(const asio::error_code& ec,
+        std::size_t bytes_transferred, int start = 0)
+    {
+      switch (start)
+      {
+        case 1:
+        async_write(stream_, buffers_.data(),
+            ASIO_MOVE_CAST(CompletionCondition)(completion_condition_),
+            ASIO_MOVE_CAST(write_dynbuf_v1_op)(*this));
+        return; default:
+        buffers_.consume(bytes_transferred);
+        handler_(ec, static_cast<const std::size_t&>(bytes_transferred));
+      }
+    }
+
+  //private:
+    AsyncWriteStream& stream_;
+    DynamicBuffer_v1 buffers_;
+    CompletionCondition completion_condition_;
+    WriteHandler handler_;
+  };
+
+  template <typename AsyncWriteStream, typename DynamicBuffer_v1,
+      typename CompletionCondition, typename WriteHandler>
+  inline asio_handler_allocate_is_deprecated
+  asio_handler_allocate(std::size_t size,
+      write_dynbuf_v1_op<AsyncWriteStream, DynamicBuffer_v1,
+        CompletionCondition, WriteHandler>* this_handler)
+  {
+#if defined(ASIO_NO_DEPRECATED)
+    asio_handler_alloc_helpers::allocate(size, this_handler->handler_);
+    return asio_handler_allocate_is_no_longer_used();
+#else // defined(ASIO_NO_DEPRECATED)
+    return asio_handler_alloc_helpers::allocate(
+        size, this_handler->handler_);
+#endif // defined(ASIO_NO_DEPRECATED)
+  }
+
+  template <typename AsyncWriteStream, typename DynamicBuffer_v1,
+      typename CompletionCondition, typename WriteHandler>
+  inline asio_handler_deallocate_is_deprecated
+  asio_handler_deallocate(void* pointer, std::size_t size,
+      write_dynbuf_v1_op<AsyncWriteStream, DynamicBuffer_v1,
+        CompletionCondition, WriteHandler>* this_handler)
+  {
+    asio_handler_alloc_helpers::deallocate(
+        pointer, size, this_handler->handler_);
+#if defined(ASIO_NO_DEPRECATED)
+    return asio_handler_deallocate_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+  }
+
+  template <typename AsyncWriteStream, typename DynamicBuffer_v1,
+      typename CompletionCondition, typename WriteHandler>
+  inline bool asio_handler_is_continuation(
+      write_dynbuf_v1_op<AsyncWriteStream, DynamicBuffer_v1,
+        CompletionCondition, WriteHandler>* this_handler)
+  {
+    return asio_handler_cont_helpers::is_continuation(
+        this_handler->handler_);
+  }
+
+  template <typename Function, typename AsyncWriteStream,
+      typename DynamicBuffer_v1, typename CompletionCondition,
+      typename WriteHandler>
+  inline asio_handler_invoke_is_deprecated
+  asio_handler_invoke(Function& function,
+      write_dynbuf_v1_op<AsyncWriteStream, DynamicBuffer_v1,
+        CompletionCondition, WriteHandler>* this_handler)
+  {
+    asio_handler_invoke_helpers::invoke(
+        function, this_handler->handler_);
+#if defined(ASIO_NO_DEPRECATED)
+    return asio_handler_invoke_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+  }
+
+  template <typename Function, typename AsyncWriteStream,
+      typename DynamicBuffer_v1, typename CompletionCondition,
+      typename WriteHandler>
+  inline asio_handler_invoke_is_deprecated
+  asio_handler_invoke(const Function& function,
+      write_dynbuf_v1_op<AsyncWriteStream, DynamicBuffer_v1,
+        CompletionCondition, WriteHandler>* this_handler)
+  {
+    asio_handler_invoke_helpers::invoke(
+        function, this_handler->handler_);
+#if defined(ASIO_NO_DEPRECATED)
+    return asio_handler_invoke_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+  }
+
+  template <typename AsyncWriteStream>
+  class initiate_async_write_dynbuf_v1
+  {
+  public:
+    typedef typename AsyncWriteStream::executor_type executor_type;
+
+    explicit initiate_async_write_dynbuf_v1(AsyncWriteStream& stream)
+      : stream_(stream)
+    {
+    }
+
+    executor_type get_executor() const ASIO_NOEXCEPT
+    {
+      return stream_.get_executor();
+    }
+
+    template <typename WriteHandler, typename DynamicBuffer_v1,
+        typename CompletionCondition>
+    void operator()(ASIO_MOVE_ARG(WriteHandler) handler,
+        ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,
+        ASIO_MOVE_ARG(CompletionCondition) completion_cond) const
+    {
+      // If you get an error on the following line it means that your handler
+      // does not meet the documented type requirements for a WriteHandler.
+      ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check;
+
+      non_const_lvalue<WriteHandler> handler2(handler);
+      non_const_lvalue<CompletionCondition> completion_cond2(completion_cond);
+      write_dynbuf_v1_op<AsyncWriteStream,
+        typename decay<DynamicBuffer_v1>::type,
+          CompletionCondition, typename decay<WriteHandler>::type>(
+            stream_, ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers),
+              completion_cond2.value, handler2.value)(
+                asio::error_code(), 0, 1);
+    }
+
+  private:
+    AsyncWriteStream& stream_;
+  };
+} // namespace detail
+
+#if !defined(GENERATING_DOCUMENTATION)
+
+template <typename AsyncWriteStream, typename DynamicBuffer_v1,
+    typename CompletionCondition, typename WriteHandler, typename Allocator>
+struct associated_allocator<
+    detail::write_dynbuf_v1_op<AsyncWriteStream,
+      DynamicBuffer_v1, CompletionCondition, WriteHandler>,
+    Allocator>
+{
+  typedef typename associated_allocator<WriteHandler, Allocator>::type type;
+
+  static type get(
+      const detail::write_dynbuf_v1_op<AsyncWriteStream,
+        DynamicBuffer_v1, CompletionCondition, WriteHandler>& h,
+      const Allocator& a = Allocator()) ASIO_NOEXCEPT
+  {
+    return associated_allocator<WriteHandler, Allocator>::get(h.handler_, a);
+  }
+};
+
+template <typename AsyncWriteStream, typename DynamicBuffer_v1,
+    typename CompletionCondition, typename WriteHandler, typename Executor>
+struct associated_executor<
+    detail::write_dynbuf_v1_op<AsyncWriteStream,
+      DynamicBuffer_v1, CompletionCondition, WriteHandler>,
+    Executor>
+  : detail::associated_executor_forwarding_base<WriteHandler, Executor>
+{
+  typedef typename associated_executor<WriteHandler, Executor>::type type;
+
+  static type get(
+      const detail::write_dynbuf_v1_op<AsyncWriteStream,
+        DynamicBuffer_v1, CompletionCondition, WriteHandler>& h,
+      const Executor& ex = Executor()) ASIO_NOEXCEPT
+  {
+    return associated_executor<WriteHandler, Executor>::get(h.handler_, ex);
+  }
+};
+
+#endif // !defined(GENERATING_DOCUMENTATION)
+
+template <typename AsyncWriteStream, typename DynamicBuffer_v1,
+    ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+      std::size_t)) WriteHandler>
+inline ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,
+    void (asio::error_code, std::size_t))
+async_write(AsyncWriteStream& s,
+    ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,
+    ASIO_MOVE_ARG(WriteHandler) handler,
+    typename enable_if<
+      is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value
+        && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value
+    >::type*)
+{
+  return async_write(s,
+      ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers),
+      transfer_all(), ASIO_MOVE_CAST(WriteHandler)(handler));
+}
+
+template <typename AsyncWriteStream,
+    typename DynamicBuffer_v1, typename CompletionCondition,
+    ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+      std::size_t)) WriteHandler>
+inline ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,
+    void (asio::error_code, std::size_t))
+async_write(AsyncWriteStream& s,
+    ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,
+    CompletionCondition completion_condition,
+    ASIO_MOVE_ARG(WriteHandler) handler,
+    typename enable_if<
+      is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value
+        && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value
+    >::type*)
+{
+  return async_initiate<WriteHandler,
+    void (asio::error_code, std::size_t)>(
+      detail::initiate_async_write_dynbuf_v1<AsyncWriteStream>(s),
+      handler, ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers),
+      ASIO_MOVE_CAST(CompletionCondition)(completion_condition));
+}
+
+#if !defined(ASIO_NO_EXTENSIONS)
+#if !defined(ASIO_NO_IOSTREAM)
+
+template <typename AsyncWriteStream, typename Allocator,
+    ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+      std::size_t)) WriteHandler>
+inline ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,
+    void (asio::error_code, std::size_t))
+async_write(AsyncWriteStream& s,
+    asio::basic_streambuf<Allocator>& b,
+    ASIO_MOVE_ARG(WriteHandler) handler)
+{
+  return async_write(s, basic_streambuf_ref<Allocator>(b),
+      ASIO_MOVE_CAST(WriteHandler)(handler));
+}
+
+template <typename AsyncWriteStream,
+    typename Allocator, typename CompletionCondition,
+    ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+      std::size_t)) WriteHandler>
+inline ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,
+    void (asio::error_code, std::size_t))
+async_write(AsyncWriteStream& s,
+    asio::basic_streambuf<Allocator>& b,
+    CompletionCondition completion_condition,
+    ASIO_MOVE_ARG(WriteHandler) handler)
+{
+  return async_write(s, basic_streambuf_ref<Allocator>(b),
+      ASIO_MOVE_CAST(CompletionCondition)(completion_condition),
+      ASIO_MOVE_CAST(WriteHandler)(handler));
+}
+
+#endif // !defined(ASIO_NO_IOSTREAM)
+#endif // !defined(ASIO_NO_EXTENSIONS)
+#endif // !defined(ASIO_NO_DYNAMIC_BUFFER_V1)
+
+namespace detail
+{
+  template <typename AsyncWriteStream, typename DynamicBuffer_v2,
+      typename CompletionCondition, typename WriteHandler>
+  class write_dynbuf_v2_op
+  {
+  public:
+    template <typename BufferSequence>
+    write_dynbuf_v2_op(AsyncWriteStream& stream,
+        ASIO_MOVE_ARG(BufferSequence) buffers,
+        CompletionCondition& completion_condition, WriteHandler& handler)
+      : stream_(stream),
+        buffers_(ASIO_MOVE_CAST(BufferSequence)(buffers)),
+        completion_condition_(
+          ASIO_MOVE_CAST(CompletionCondition)(completion_condition)),
+        handler_(ASIO_MOVE_CAST(WriteHandler)(handler))
+    {
+    }
+
+#if defined(ASIO_HAS_MOVE)
+    write_dynbuf_v2_op(const write_dynbuf_v2_op& other)
+      : stream_(other.stream_),
+        buffers_(other.buffers_),
+        completion_condition_(other.completion_condition_),
+        handler_(other.handler_)
+    {
+    }
+
+    write_dynbuf_v2_op(write_dynbuf_v2_op&& other)
+      : stream_(other.stream_),
+        buffers_(ASIO_MOVE_CAST(DynamicBuffer_v2)(other.buffers_)),
+        completion_condition_(
+          ASIO_MOVE_CAST(CompletionCondition)(
+            other.completion_condition_)),
+        handler_(ASIO_MOVE_CAST(WriteHandler)(other.handler_))
+    {
+    }
+#endif // defined(ASIO_HAS_MOVE)
+
+    void operator()(const asio::error_code& ec,
+        std::size_t bytes_transferred, int start = 0)
+    {
+      switch (start)
+      {
+        case 1:
+        async_write(stream_, buffers_.data(0, buffers_.size()),
+            ASIO_MOVE_CAST(CompletionCondition)(completion_condition_),
+            ASIO_MOVE_CAST(write_dynbuf_v2_op)(*this));
+        return; default:
+        buffers_.consume(bytes_transferred);
+        handler_(ec, static_cast<const std::size_t&>(bytes_transferred));
+      }
+    }
+
+  //private:
+    AsyncWriteStream& stream_;
+    DynamicBuffer_v2 buffers_;
+    CompletionCondition completion_condition_;
+    WriteHandler handler_;
+  };
+
+  template <typename AsyncWriteStream, typename DynamicBuffer_v2,
+      typename CompletionCondition, typename WriteHandler>
+  inline asio_handler_allocate_is_deprecated
+  asio_handler_allocate(std::size_t size,
+      write_dynbuf_v2_op<AsyncWriteStream, DynamicBuffer_v2,
+        CompletionCondition, WriteHandler>* this_handler)
+  {
+#if defined(ASIO_NO_DEPRECATED)
+    asio_handler_alloc_helpers::allocate(size, this_handler->handler_);
+    return asio_handler_allocate_is_no_longer_used();
+#else // defined(ASIO_NO_DEPRECATED)
+    return asio_handler_alloc_helpers::allocate(
+        size, this_handler->handler_);
+#endif // defined(ASIO_NO_DEPRECATED)
+  }
+
+  template <typename AsyncWriteStream, typename DynamicBuffer_v2,
+      typename CompletionCondition, typename WriteHandler>
+  inline asio_handler_deallocate_is_deprecated
+  asio_handler_deallocate(void* pointer, std::size_t size,
+      write_dynbuf_v2_op<AsyncWriteStream, DynamicBuffer_v2,
+        CompletionCondition, WriteHandler>* this_handler)
+  {
+    asio_handler_alloc_helpers::deallocate(
+        pointer, size, this_handler->handler_);
+#if defined(ASIO_NO_DEPRECATED)
+    return asio_handler_deallocate_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+  }
+
+  template <typename AsyncWriteStream, typename DynamicBuffer_v2,
+      typename CompletionCondition, typename WriteHandler>
+  inline bool asio_handler_is_continuation(
+      write_dynbuf_v2_op<AsyncWriteStream, DynamicBuffer_v2,
+        CompletionCondition, WriteHandler>* this_handler)
+  {
+    return asio_handler_cont_helpers::is_continuation(
+        this_handler->handler_);
+  }
+
+  template <typename Function, typename AsyncWriteStream,
+      typename DynamicBuffer_v2, typename CompletionCondition,
+      typename WriteHandler>
+  inline asio_handler_invoke_is_deprecated
+  asio_handler_invoke(Function& function,
+      write_dynbuf_v2_op<AsyncWriteStream, DynamicBuffer_v2,
+        CompletionCondition, WriteHandler>* this_handler)
+  {
+    asio_handler_invoke_helpers::invoke(
+        function, this_handler->handler_);
+#if defined(ASIO_NO_DEPRECATED)
+    return asio_handler_invoke_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+  }
+
+  template <typename Function, typename AsyncWriteStream,
+      typename DynamicBuffer_v2, typename CompletionCondition,
+      typename WriteHandler>
+  inline asio_handler_invoke_is_deprecated
+  asio_handler_invoke(const Function& function,
+      write_dynbuf_v2_op<AsyncWriteStream, DynamicBuffer_v2,
+        CompletionCondition, WriteHandler>* this_handler)
+  {
+    asio_handler_invoke_helpers::invoke(
+        function, this_handler->handler_);
+#if defined(ASIO_NO_DEPRECATED)
+    return asio_handler_invoke_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+  }
+
+  template <typename AsyncWriteStream>
+  class initiate_async_write_dynbuf_v2
+  {
+  public:
+    typedef typename AsyncWriteStream::executor_type executor_type;
+
+    explicit initiate_async_write_dynbuf_v2(AsyncWriteStream& stream)
+      : stream_(stream)
+    {
+    }
+
+    executor_type get_executor() const ASIO_NOEXCEPT
+    {
+      return stream_.get_executor();
+    }
+
+    template <typename WriteHandler, typename DynamicBuffer_v2,
+        typename CompletionCondition>
+    void operator()(ASIO_MOVE_ARG(WriteHandler) handler,
+        ASIO_MOVE_ARG(DynamicBuffer_v2) buffers,
+        ASIO_MOVE_ARG(CompletionCondition) completion_cond) const
+    {
+      // If you get an error on the following line it means that your handler
+      // does not meet the documented type requirements for a WriteHandler.
+      ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check;
+
+      non_const_lvalue<WriteHandler> handler2(handler);
+      non_const_lvalue<CompletionCondition> completion_cond2(completion_cond);
+      write_dynbuf_v2_op<AsyncWriteStream,
+        typename decay<DynamicBuffer_v2>::type,
+          CompletionCondition, typename decay<WriteHandler>::type>(
+            stream_, ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers),
+              completion_cond2.value, handler2.value)(
+                asio::error_code(), 0, 1);
+    }
+
+  private:
+    AsyncWriteStream& stream_;
+  };
+} // namespace detail
+
+#if !defined(GENERATING_DOCUMENTATION)
+
+template <typename AsyncWriteStream, typename DynamicBuffer_v2,
+    typename CompletionCondition, typename WriteHandler, typename Allocator>
+struct associated_allocator<
+    detail::write_dynbuf_v2_op<AsyncWriteStream,
+      DynamicBuffer_v2, CompletionCondition, WriteHandler>,
+    Allocator>
+{
+  typedef typename associated_allocator<WriteHandler, Allocator>::type type;
+
+  static type get(
+      const detail::write_dynbuf_v2_op<AsyncWriteStream,
+        DynamicBuffer_v2, CompletionCondition, WriteHandler>& h,
+      const Allocator& a = Allocator()) ASIO_NOEXCEPT
+  {
+    return associated_allocator<WriteHandler, Allocator>::get(h.handler_, a);
+  }
+};
+
+template <typename AsyncWriteStream, typename DynamicBuffer_v2,
+    typename CompletionCondition, typename WriteHandler, typename Executor>
+struct associated_executor<
+    detail::write_dynbuf_v2_op<AsyncWriteStream,
+      DynamicBuffer_v2, CompletionCondition, WriteHandler>,
+    Executor>
+  : detail::associated_executor_forwarding_base<WriteHandler, Executor>
+{
+  typedef typename associated_executor<WriteHandler, Executor>::type type;
+
+  static type get(
+      const detail::write_dynbuf_v2_op<AsyncWriteStream,
+        DynamicBuffer_v2, CompletionCondition, WriteHandler>& h,
+      const Executor& ex = Executor()) ASIO_NOEXCEPT
+  {
+    return associated_executor<WriteHandler, Executor>::get(h.handler_, ex);
+  }
+};
+
+#endif // !defined(GENERATING_DOCUMENTATION)
+
+template <typename AsyncWriteStream, typename DynamicBuffer_v2,
+    ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+      std::size_t)) WriteHandler>
+inline ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,
+    void (asio::error_code, std::size_t))
+async_write(AsyncWriteStream& s, DynamicBuffer_v2 buffers,
+    ASIO_MOVE_ARG(WriteHandler) handler,
+    typename enable_if<
+      is_dynamic_buffer_v2<DynamicBuffer_v2>::value
+    >::type*)
+{
+  return async_write(s,
+      ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers),
+      transfer_all(), ASIO_MOVE_CAST(WriteHandler)(handler));
+}
+
+template <typename AsyncWriteStream,
+    typename DynamicBuffer_v2, typename CompletionCondition,
+    ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+      std::size_t)) WriteHandler>
+inline ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,
+    void (asio::error_code, std::size_t))
+async_write(AsyncWriteStream& s, DynamicBuffer_v2 buffers,
+    CompletionCondition completion_condition,
+    ASIO_MOVE_ARG(WriteHandler) handler,
+    typename enable_if<
+      is_dynamic_buffer_v2<DynamicBuffer_v2>::value
+    >::type*)
+{
+  return async_initiate<WriteHandler,
+    void (asio::error_code, std::size_t)>(
+      detail::initiate_async_write_dynbuf_v2<AsyncWriteStream>(s),
+      handler, ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers),
+      ASIO_MOVE_CAST(CompletionCondition)(completion_condition));
+}
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IMPL_WRITE_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/impl/write_at.hpp b/link/modules/asio-standalone/asio/include/asio/impl/write_at.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/impl/write_at.hpp
@@ -0,0 +1,666 @@
+//
+// impl/write_at.hpp
+// ~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_IMPL_WRITE_AT_HPP
+#define ASIO_IMPL_WRITE_AT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/associated_allocator.hpp"
+#include "asio/associated_executor.hpp"
+#include "asio/buffer.hpp"
+#include "asio/completion_condition.hpp"
+#include "asio/detail/array_fwd.hpp"
+#include "asio/detail/base_from_completion_cond.hpp"
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/consuming_buffers.hpp"
+#include "asio/detail/dependent_type.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_cont_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/handler_tracking.hpp"
+#include "asio/detail/handler_type_requirements.hpp"
+#include "asio/detail/non_const_lvalue.hpp"
+#include "asio/detail/throw_error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+namespace detail
+{
+  template <typename SyncRandomAccessWriteDevice, typename ConstBufferSequence,
+      typename ConstBufferIterator, typename CompletionCondition>
+  std::size_t write_at_buffer_sequence(SyncRandomAccessWriteDevice& d,
+      uint64_t offset, const ConstBufferSequence& buffers,
+      const ConstBufferIterator&, CompletionCondition completion_condition,
+      asio::error_code& ec)
+  {
+    ec = asio::error_code();
+    asio::detail::consuming_buffers<const_buffer,
+        ConstBufferSequence, ConstBufferIterator> tmp(buffers);
+    while (!tmp.empty())
+    {
+      if (std::size_t max_size = detail::adapt_completion_condition_result(
+            completion_condition(ec, tmp.total_consumed())))
+      {
+        tmp.consume(d.write_some_at(offset + tmp.total_consumed(),
+              tmp.prepare(max_size), ec));
+      }
+      else
+        break;
+    }
+    return tmp.total_consumed();;
+  }
+} // namespace detail
+
+template <typename SyncRandomAccessWriteDevice, typename ConstBufferSequence,
+    typename CompletionCondition>
+std::size_t write_at(SyncRandomAccessWriteDevice& d,
+    uint64_t offset, const ConstBufferSequence& buffers,
+    CompletionCondition completion_condition, asio::error_code& ec)
+{
+  return detail::write_at_buffer_sequence(d, offset, buffers,
+      asio::buffer_sequence_begin(buffers),
+      ASIO_MOVE_CAST(CompletionCondition)(completion_condition), ec);
+}
+
+template <typename SyncRandomAccessWriteDevice, typename ConstBufferSequence>
+inline std::size_t write_at(SyncRandomAccessWriteDevice& d,
+    uint64_t offset, const ConstBufferSequence& buffers)
+{
+  asio::error_code ec;
+  std::size_t bytes_transferred = write_at(
+      d, offset, buffers, transfer_all(), ec);
+  asio::detail::throw_error(ec, "write_at");
+  return bytes_transferred;
+}
+
+template <typename SyncRandomAccessWriteDevice, typename ConstBufferSequence>
+inline std::size_t write_at(SyncRandomAccessWriteDevice& d,
+    uint64_t offset, const ConstBufferSequence& buffers,
+    asio::error_code& ec)
+{
+  return write_at(d, offset, buffers, transfer_all(), ec);
+}
+
+template <typename SyncRandomAccessWriteDevice, typename ConstBufferSequence,
+    typename CompletionCondition>
+inline std::size_t write_at(SyncRandomAccessWriteDevice& d,
+    uint64_t offset, const ConstBufferSequence& buffers,
+    CompletionCondition completion_condition)
+{
+  asio::error_code ec;
+  std::size_t bytes_transferred = write_at(d, offset, buffers,
+      ASIO_MOVE_CAST(CompletionCondition)(completion_condition), ec);
+  asio::detail::throw_error(ec, "write_at");
+  return bytes_transferred;
+}
+
+#if !defined(ASIO_NO_EXTENSIONS)
+#if !defined(ASIO_NO_IOSTREAM)
+
+template <typename SyncRandomAccessWriteDevice, typename Allocator,
+    typename CompletionCondition>
+std::size_t write_at(SyncRandomAccessWriteDevice& d,
+    uint64_t offset, asio::basic_streambuf<Allocator>& b,
+    CompletionCondition completion_condition, asio::error_code& ec)
+{
+  std::size_t bytes_transferred = write_at(d, offset, b.data(),
+      ASIO_MOVE_CAST(CompletionCondition)(completion_condition), ec);
+  b.consume(bytes_transferred);
+  return bytes_transferred;
+}
+
+template <typename SyncRandomAccessWriteDevice, typename Allocator>
+inline std::size_t write_at(SyncRandomAccessWriteDevice& d,
+    uint64_t offset, asio::basic_streambuf<Allocator>& b)
+{
+  asio::error_code ec;
+  std::size_t bytes_transferred = write_at(d, offset, b, transfer_all(), ec);
+  asio::detail::throw_error(ec, "write_at");
+  return bytes_transferred;
+}
+
+template <typename SyncRandomAccessWriteDevice, typename Allocator>
+inline std::size_t write_at(SyncRandomAccessWriteDevice& d,
+    uint64_t offset, asio::basic_streambuf<Allocator>& b,
+    asio::error_code& ec)
+{
+  return write_at(d, offset, b, transfer_all(), ec);
+}
+
+template <typename SyncRandomAccessWriteDevice, typename Allocator,
+    typename CompletionCondition>
+inline std::size_t write_at(SyncRandomAccessWriteDevice& d,
+    uint64_t offset, asio::basic_streambuf<Allocator>& b,
+    CompletionCondition completion_condition)
+{
+  asio::error_code ec;
+  std::size_t bytes_transferred = write_at(d, offset, b,
+      ASIO_MOVE_CAST(CompletionCondition)(completion_condition), ec);
+  asio::detail::throw_error(ec, "write_at");
+  return bytes_transferred;
+}
+
+#endif // !defined(ASIO_NO_IOSTREAM)
+#endif // !defined(ASIO_NO_EXTENSIONS)
+
+namespace detail
+{
+  template <typename AsyncRandomAccessWriteDevice,
+      typename ConstBufferSequence, typename ConstBufferIterator,
+      typename CompletionCondition, typename WriteHandler>
+  class write_at_op
+    : detail::base_from_completion_cond<CompletionCondition>
+  {
+  public:
+    write_at_op(AsyncRandomAccessWriteDevice& device,
+        uint64_t offset, const ConstBufferSequence& buffers,
+        CompletionCondition& completion_condition, WriteHandler& handler)
+      : detail::base_from_completion_cond<
+          CompletionCondition>(completion_condition),
+        device_(device),
+        offset_(offset),
+        buffers_(buffers),
+        start_(0),
+        handler_(ASIO_MOVE_CAST(WriteHandler)(handler))
+    {
+    }
+
+#if defined(ASIO_HAS_MOVE)
+    write_at_op(const write_at_op& other)
+      : detail::base_from_completion_cond<CompletionCondition>(other),
+        device_(other.device_),
+        offset_(other.offset_),
+        buffers_(other.buffers_),
+        start_(other.start_),
+        handler_(other.handler_)
+    {
+    }
+
+    write_at_op(write_at_op&& other)
+      : detail::base_from_completion_cond<CompletionCondition>(
+          ASIO_MOVE_CAST(detail::base_from_completion_cond<
+            CompletionCondition>)(other)),
+        device_(other.device_),
+        offset_(other.offset_),
+        buffers_(ASIO_MOVE_CAST(buffers_type)(other.buffers_)),
+        start_(other.start_),
+        handler_(ASIO_MOVE_CAST(WriteHandler)(other.handler_))
+    {
+    }
+#endif // defined(ASIO_HAS_MOVE)
+
+    void operator()(const asio::error_code& ec,
+        std::size_t bytes_transferred, int start = 0)
+    {
+      std::size_t max_size;
+      switch (start_ = start)
+      {
+        case 1:
+        max_size = this->check_for_completion(ec, buffers_.total_consumed());
+        do
+        {
+          {
+            ASIO_HANDLER_LOCATION((__FILE__, __LINE__, "async_write_at"));
+            device_.async_write_some_at(
+                offset_ + buffers_.total_consumed(), buffers_.prepare(max_size),
+                ASIO_MOVE_CAST(write_at_op)(*this));
+          }
+          return; default:
+          buffers_.consume(bytes_transferred);
+          if ((!ec && bytes_transferred == 0) || buffers_.empty())
+            break;
+          max_size = this->check_for_completion(ec, buffers_.total_consumed());
+        } while (max_size > 0);
+
+        handler_(ec, buffers_.total_consumed());
+      }
+    }
+
+  //private:
+    typedef asio::detail::consuming_buffers<const_buffer,
+        ConstBufferSequence, ConstBufferIterator> buffers_type;
+
+    AsyncRandomAccessWriteDevice& device_;
+    uint64_t offset_;
+    buffers_type buffers_;
+    int start_;
+    WriteHandler handler_;
+  };
+
+  template <typename AsyncRandomAccessWriteDevice,
+      typename ConstBufferSequence, typename ConstBufferIterator,
+      typename CompletionCondition, typename WriteHandler>
+  inline asio_handler_allocate_is_deprecated
+  asio_handler_allocate(std::size_t size,
+      write_at_op<AsyncRandomAccessWriteDevice, ConstBufferSequence,
+        ConstBufferIterator, CompletionCondition, WriteHandler>* this_handler)
+  {
+#if defined(ASIO_NO_DEPRECATED)
+    asio_handler_alloc_helpers::allocate(size, this_handler->handler_);
+    return asio_handler_allocate_is_no_longer_used();
+#else // defined(ASIO_NO_DEPRECATED)
+    return asio_handler_alloc_helpers::allocate(
+        size, this_handler->handler_);
+#endif // defined(ASIO_NO_DEPRECATED)
+  }
+
+  template <typename AsyncRandomAccessWriteDevice,
+      typename ConstBufferSequence, typename ConstBufferIterator,
+      typename CompletionCondition, typename WriteHandler>
+  inline asio_handler_deallocate_is_deprecated
+  asio_handler_deallocate(void* pointer, std::size_t size,
+      write_at_op<AsyncRandomAccessWriteDevice, ConstBufferSequence,
+        ConstBufferIterator, CompletionCondition, WriteHandler>* this_handler)
+  {
+    asio_handler_alloc_helpers::deallocate(
+        pointer, size, this_handler->handler_);
+#if defined(ASIO_NO_DEPRECATED)
+    return asio_handler_deallocate_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+  }
+
+  template <typename AsyncRandomAccessWriteDevice,
+      typename ConstBufferSequence, typename ConstBufferIterator,
+      typename CompletionCondition, typename WriteHandler>
+  inline bool asio_handler_is_continuation(
+      write_at_op<AsyncRandomAccessWriteDevice, ConstBufferSequence,
+        ConstBufferIterator, CompletionCondition, WriteHandler>* this_handler)
+  {
+    return this_handler->start_ == 0 ? true
+      : asio_handler_cont_helpers::is_continuation(
+          this_handler->handler_);
+  }
+
+  template <typename Function, typename AsyncRandomAccessWriteDevice,
+      typename ConstBufferSequence, typename ConstBufferIterator,
+      typename CompletionCondition, typename WriteHandler>
+  inline asio_handler_invoke_is_deprecated
+  asio_handler_invoke(Function& function,
+      write_at_op<AsyncRandomAccessWriteDevice, ConstBufferSequence,
+        ConstBufferIterator, CompletionCondition, WriteHandler>* this_handler)
+  {
+    asio_handler_invoke_helpers::invoke(
+        function, this_handler->handler_);
+#if defined(ASIO_NO_DEPRECATED)
+    return asio_handler_invoke_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+  }
+
+  template <typename Function, typename AsyncRandomAccessWriteDevice,
+      typename ConstBufferSequence, typename ConstBufferIterator,
+      typename CompletionCondition, typename WriteHandler>
+  inline asio_handler_invoke_is_deprecated
+  asio_handler_invoke(const Function& function,
+      write_at_op<AsyncRandomAccessWriteDevice, ConstBufferSequence,
+        ConstBufferIterator, CompletionCondition, WriteHandler>* this_handler)
+  {
+    asio_handler_invoke_helpers::invoke(
+        function, this_handler->handler_);
+#if defined(ASIO_NO_DEPRECATED)
+    return asio_handler_invoke_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+  }
+
+  template <typename AsyncRandomAccessWriteDevice,
+      typename ConstBufferSequence, typename ConstBufferIterator,
+      typename CompletionCondition, typename WriteHandler>
+  inline void start_write_at_buffer_sequence_op(AsyncRandomAccessWriteDevice& d,
+      uint64_t offset, const ConstBufferSequence& buffers,
+      const ConstBufferIterator&, CompletionCondition& completion_condition,
+      WriteHandler& handler)
+  {
+    detail::write_at_op<AsyncRandomAccessWriteDevice, ConstBufferSequence,
+      ConstBufferIterator, CompletionCondition, WriteHandler>(
+        d, offset, buffers, completion_condition, handler)(
+          asio::error_code(), 0, 1);
+  }
+
+  template <typename AsyncRandomAccessWriteDevice>
+  class initiate_async_write_at_buffer_sequence
+  {
+  public:
+    typedef typename AsyncRandomAccessWriteDevice::executor_type executor_type;
+
+    explicit initiate_async_write_at_buffer_sequence(
+        AsyncRandomAccessWriteDevice& device)
+      : device_(device)
+    {
+    }
+
+    executor_type get_executor() const ASIO_NOEXCEPT
+    {
+      return device_.get_executor();
+    }
+
+    template <typename WriteHandler, typename ConstBufferSequence,
+        typename CompletionCondition>
+    void operator()(ASIO_MOVE_ARG(WriteHandler) handler,
+        uint64_t offset, const ConstBufferSequence& buffers,
+        ASIO_MOVE_ARG(CompletionCondition) completion_cond) const
+    {
+      // If you get an error on the following line it means that your handler
+      // does not meet the documented type requirements for a WriteHandler.
+      ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check;
+
+      non_const_lvalue<WriteHandler> handler2(handler);
+      non_const_lvalue<CompletionCondition> completion_cond2(completion_cond);
+      start_write_at_buffer_sequence_op(device_, offset, buffers,
+          asio::buffer_sequence_begin(buffers),
+          completion_cond2.value, handler2.value);
+    }
+
+  private:
+    AsyncRandomAccessWriteDevice& device_;
+  };
+} // namespace detail
+
+#if !defined(GENERATING_DOCUMENTATION)
+
+template <typename AsyncRandomAccessWriteDevice,
+    typename ConstBufferSequence, typename ConstBufferIterator,
+    typename CompletionCondition, typename WriteHandler, typename Allocator>
+struct associated_allocator<
+    detail::write_at_op<AsyncRandomAccessWriteDevice, ConstBufferSequence,
+      ConstBufferIterator, CompletionCondition, WriteHandler>,
+    Allocator>
+{
+  typedef typename associated_allocator<WriteHandler, Allocator>::type type;
+
+  static type get(
+      const detail::write_at_op<AsyncRandomAccessWriteDevice,
+        ConstBufferSequence, ConstBufferIterator,
+        CompletionCondition, WriteHandler>& h,
+      const Allocator& a = Allocator()) ASIO_NOEXCEPT
+  {
+    return associated_allocator<WriteHandler, Allocator>::get(h.handler_, a);
+  }
+};
+
+template <typename AsyncRandomAccessWriteDevice,
+    typename ConstBufferSequence, typename ConstBufferIterator,
+    typename CompletionCondition, typename WriteHandler, typename Executor>
+struct associated_executor<
+    detail::write_at_op<AsyncRandomAccessWriteDevice, ConstBufferSequence,
+      ConstBufferIterator, CompletionCondition, WriteHandler>,
+    Executor>
+  : detail::associated_executor_forwarding_base<WriteHandler, Executor>
+{
+  typedef typename associated_executor<WriteHandler, Executor>::type type;
+
+  static type get(
+      const detail::write_at_op<AsyncRandomAccessWriteDevice,
+        ConstBufferSequence, ConstBufferIterator,
+        CompletionCondition, WriteHandler>& h,
+      const Executor& ex = Executor()) ASIO_NOEXCEPT
+  {
+    return associated_executor<WriteHandler, Executor>::get(h.handler_, ex);
+  }
+};
+
+#endif // !defined(GENERATING_DOCUMENTATION)
+
+template <typename AsyncRandomAccessWriteDevice,
+    typename ConstBufferSequence, typename CompletionCondition,
+    ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+      std::size_t)) WriteHandler>
+inline ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,
+    void (asio::error_code, std::size_t))
+async_write_at(AsyncRandomAccessWriteDevice& d,
+    uint64_t offset, const ConstBufferSequence& buffers,
+    CompletionCondition completion_condition,
+    ASIO_MOVE_ARG(WriteHandler) handler)
+{
+  return async_initiate<WriteHandler,
+    void (asio::error_code, std::size_t)>(
+      detail::initiate_async_write_at_buffer_sequence<
+        AsyncRandomAccessWriteDevice>(d),
+      handler, offset, buffers,
+      ASIO_MOVE_CAST(CompletionCondition)(completion_condition));
+}
+
+template <typename AsyncRandomAccessWriteDevice, typename ConstBufferSequence,
+    ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+      std::size_t)) WriteHandler>
+inline ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,
+    void (asio::error_code, std::size_t))
+async_write_at(AsyncRandomAccessWriteDevice& d,
+    uint64_t offset, const ConstBufferSequence& buffers,
+    ASIO_MOVE_ARG(WriteHandler) handler)
+{
+  return async_initiate<WriteHandler,
+    void (asio::error_code, std::size_t)>(
+      detail::initiate_async_write_at_buffer_sequence<
+        AsyncRandomAccessWriteDevice>(d),
+      handler, offset, buffers, transfer_all());
+}
+
+#if !defined(ASIO_NO_EXTENSIONS)
+#if !defined(ASIO_NO_IOSTREAM)
+
+namespace detail
+{
+  template <typename Allocator, typename WriteHandler>
+  class write_at_streambuf_op
+  {
+  public:
+    write_at_streambuf_op(
+        asio::basic_streambuf<Allocator>& streambuf,
+        WriteHandler& handler)
+      : streambuf_(streambuf),
+        handler_(ASIO_MOVE_CAST(WriteHandler)(handler))
+    {
+    }
+
+#if defined(ASIO_HAS_MOVE)
+    write_at_streambuf_op(const write_at_streambuf_op& other)
+      : streambuf_(other.streambuf_),
+        handler_(other.handler_)
+    {
+    }
+
+    write_at_streambuf_op(write_at_streambuf_op&& other)
+      : streambuf_(other.streambuf_),
+        handler_(ASIO_MOVE_CAST(WriteHandler)(other.handler_))
+    {
+    }
+#endif // defined(ASIO_HAS_MOVE)
+
+    void operator()(const asio::error_code& ec,
+        const std::size_t bytes_transferred)
+    {
+      streambuf_.consume(bytes_transferred);
+      handler_(ec, bytes_transferred);
+    }
+
+  //private:
+    asio::basic_streambuf<Allocator>& streambuf_;
+    WriteHandler handler_;
+  };
+
+  template <typename Allocator, typename WriteHandler>
+  inline asio_handler_allocate_is_deprecated
+  asio_handler_allocate(std::size_t size,
+      write_at_streambuf_op<Allocator, WriteHandler>* this_handler)
+  {
+#if defined(ASIO_NO_DEPRECATED)
+    asio_handler_alloc_helpers::allocate(size, this_handler->handler_);
+    return asio_handler_allocate_is_no_longer_used();
+#else // defined(ASIO_NO_DEPRECATED)
+    return asio_handler_alloc_helpers::allocate(
+        size, this_handler->handler_);
+#endif // defined(ASIO_NO_DEPRECATED)
+  }
+
+  template <typename Allocator, typename WriteHandler>
+  inline asio_handler_deallocate_is_deprecated
+  asio_handler_deallocate(void* pointer, std::size_t size,
+      write_at_streambuf_op<Allocator, WriteHandler>* this_handler)
+  {
+    asio_handler_alloc_helpers::deallocate(
+        pointer, size, this_handler->handler_);
+#if defined(ASIO_NO_DEPRECATED)
+    return asio_handler_deallocate_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+  }
+
+  template <typename Allocator, typename WriteHandler>
+  inline bool asio_handler_is_continuation(
+      write_at_streambuf_op<Allocator, WriteHandler>* this_handler)
+  {
+    return asio_handler_cont_helpers::is_continuation(
+        this_handler->handler_);
+  }
+
+  template <typename Function, typename Allocator, typename WriteHandler>
+  inline asio_handler_invoke_is_deprecated
+  asio_handler_invoke(Function& function,
+      write_at_streambuf_op<Allocator, WriteHandler>* this_handler)
+  {
+    asio_handler_invoke_helpers::invoke(
+        function, this_handler->handler_);
+#if defined(ASIO_NO_DEPRECATED)
+    return asio_handler_invoke_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+  }
+
+  template <typename Function, typename Allocator, typename WriteHandler>
+  inline asio_handler_invoke_is_deprecated
+  asio_handler_invoke(const Function& function,
+      write_at_streambuf_op<Allocator, WriteHandler>* this_handler)
+  {
+    asio_handler_invoke_helpers::invoke(
+        function, this_handler->handler_);
+#if defined(ASIO_NO_DEPRECATED)
+    return asio_handler_invoke_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+  }
+
+  template <typename AsyncRandomAccessWriteDevice>
+  class initiate_async_write_at_streambuf
+  {
+  public:
+    typedef typename AsyncRandomAccessWriteDevice::executor_type executor_type;
+
+    explicit initiate_async_write_at_streambuf(
+        AsyncRandomAccessWriteDevice& device)
+      : device_(device)
+    {
+    }
+
+    executor_type get_executor() const ASIO_NOEXCEPT
+    {
+      return device_.get_executor();
+    }
+
+    template <typename WriteHandler,
+        typename Allocator, typename CompletionCondition>
+    void operator()(ASIO_MOVE_ARG(WriteHandler) handler,
+        uint64_t offset, basic_streambuf<Allocator>* b,
+        ASIO_MOVE_ARG(CompletionCondition) completion_condition) const
+    {
+      // If you get an error on the following line it means that your handler
+      // does not meet the documented type requirements for a WriteHandler.
+      ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check;
+
+      non_const_lvalue<WriteHandler> handler2(handler);
+      async_write_at(device_, offset, b->data(),
+          ASIO_MOVE_CAST(CompletionCondition)(completion_condition),
+          write_at_streambuf_op<Allocator, typename decay<WriteHandler>::type>(
+            *b, handler2.value));
+    }
+
+  private:
+    AsyncRandomAccessWriteDevice& device_;
+  };
+} // namespace detail
+
+#if !defined(GENERATING_DOCUMENTATION)
+
+template <typename Allocator, typename WriteHandler, typename Allocator1>
+struct associated_allocator<
+    detail::write_at_streambuf_op<Allocator, WriteHandler>,
+    Allocator1>
+{
+  typedef typename associated_allocator<WriteHandler, Allocator1>::type type;
+
+  static type get(
+      const detail::write_at_streambuf_op<Allocator, WriteHandler>& h,
+      const Allocator1& a = Allocator1()) ASIO_NOEXCEPT
+  {
+    return associated_allocator<WriteHandler, Allocator1>::get(h.handler_, a);
+  }
+};
+
+template <typename Executor, typename WriteHandler, typename Executor1>
+struct associated_executor<
+    detail::write_at_streambuf_op<Executor, WriteHandler>,
+    Executor1>
+  : detail::associated_executor_forwarding_base<WriteHandler, Executor>
+{
+  typedef typename associated_executor<WriteHandler, Executor1>::type type;
+
+  static type get(
+      const detail::write_at_streambuf_op<Executor, WriteHandler>& h,
+      const Executor1& ex = Executor1()) ASIO_NOEXCEPT
+  {
+    return associated_executor<WriteHandler, Executor1>::get(h.handler_, ex);
+  }
+};
+
+#endif // !defined(GENERATING_DOCUMENTATION)
+
+template <typename AsyncRandomAccessWriteDevice,
+    typename Allocator, typename CompletionCondition,
+    ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+      std::size_t)) WriteHandler>
+inline ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,
+    void (asio::error_code, std::size_t))
+async_write_at(AsyncRandomAccessWriteDevice& d,
+    uint64_t offset, asio::basic_streambuf<Allocator>& b,
+    CompletionCondition completion_condition,
+    ASIO_MOVE_ARG(WriteHandler) handler)
+{
+  return async_initiate<WriteHandler,
+    void (asio::error_code, std::size_t)>(
+      detail::initiate_async_write_at_streambuf<
+        AsyncRandomAccessWriteDevice>(d),
+      handler, offset, &b,
+      ASIO_MOVE_CAST(CompletionCondition)(completion_condition));
+}
+
+template <typename AsyncRandomAccessWriteDevice, typename Allocator,
+    ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+      std::size_t)) WriteHandler>
+inline ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,
+    void (asio::error_code, std::size_t))
+async_write_at(AsyncRandomAccessWriteDevice& d,
+    uint64_t offset, asio::basic_streambuf<Allocator>& b,
+    ASIO_MOVE_ARG(WriteHandler) handler)
+{
+  return async_initiate<WriteHandler,
+    void (asio::error_code, std::size_t)>(
+      detail::initiate_async_write_at_streambuf<
+        AsyncRandomAccessWriteDevice>(d),
+      handler, offset, &b, transfer_all());
+}
+
+#endif // !defined(ASIO_NO_IOSTREAM)
+#endif // !defined(ASIO_NO_EXTENSIONS)
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IMPL_WRITE_AT_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/io_context.hpp b/link/modules/asio-standalone/asio/include/asio/io_context.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/io_context.hpp
@@ -0,0 +1,1530 @@
+//
+// io_context.hpp
+// ~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_IO_CONTEXT_HPP
+#define ASIO_IO_CONTEXT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <cstddef>
+#include <stdexcept>
+#include <typeinfo>
+#include "asio/async_result.hpp"
+#include "asio/detail/wrapped_handler.hpp"
+#include "asio/error_code.hpp"
+#include "asio/execution.hpp"
+#include "asio/execution_context.hpp"
+
+#if defined(ASIO_HAS_CHRONO)
+# include "asio/detail/chrono.hpp"
+#endif // defined(ASIO_HAS_CHRONO)
+
+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+# include "asio/detail/winsock_init.hpp"
+#elif defined(__sun) || defined(__QNX__) || defined(__hpux) || defined(_AIX) \
+  || defined(__osf__)
+# include "asio/detail/signal_init.hpp"
+#endif
+
+#if defined(ASIO_HAS_IOCP)
+# include "asio/detail/win_iocp_io_context.hpp"
+#else
+# include "asio/detail/scheduler.hpp"
+#endif
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+namespace detail {
+#if defined(ASIO_HAS_IOCP)
+  typedef win_iocp_io_context io_context_impl;
+  class win_iocp_overlapped_ptr;
+#else
+  typedef scheduler io_context_impl;
+#endif
+
+  struct io_context_bits
+  {
+    ASIO_STATIC_CONSTEXPR(unsigned int, blocking_never = 1);
+    ASIO_STATIC_CONSTEXPR(unsigned int, relationship_continuation = 2);
+    ASIO_STATIC_CONSTEXPR(unsigned int, outstanding_work_tracked = 4);
+  };
+} // namespace detail
+
+/// Provides core I/O functionality.
+/**
+ * The io_context class provides the core I/O functionality for users of the
+ * asynchronous I/O objects, including:
+ *
+ * @li asio::ip::tcp::socket
+ * @li asio::ip::tcp::acceptor
+ * @li asio::ip::udp::socket
+ * @li asio::deadline_timer.
+ *
+ * The io_context class also includes facilities intended for developers of
+ * custom asynchronous services.
+ *
+ * @par Thread Safety
+ * @e Distinct @e objects: Safe.@n
+ * @e Shared @e objects: Safe, with the specific exceptions of the restart()
+ * and notify_fork() functions. Calling restart() while there are unfinished
+ * run(), run_one(), run_for(), run_until(), poll() or poll_one() calls results
+ * in undefined behaviour. The notify_fork() function should not be called
+ * while any io_context function, or any function on an I/O object that is
+ * associated with the io_context, is being called in another thread.
+ *
+ * @par Concepts:
+ * Dispatcher.
+ *
+ * @par Synchronous and asynchronous operations
+ *
+ * Synchronous operations on I/O objects implicitly run the io_context object
+ * for an individual operation. The io_context functions run(), run_one(),
+ * run_for(), run_until(), poll() or poll_one() must be called for the
+ * io_context to perform asynchronous operations on behalf of a C++ program.
+ * Notification that an asynchronous operation has completed is delivered by
+ * invocation of the associated handler. Handlers are invoked only by a thread
+ * that is currently calling any overload of run(), run_one(), run_for(),
+ * run_until(), poll() or poll_one() for the io_context.
+ *
+ * @par Effect of exceptions thrown from handlers
+ *
+ * If an exception is thrown from a handler, the exception is allowed to
+ * propagate through the throwing thread's invocation of run(), run_one(),
+ * run_for(), run_until(), poll() or poll_one(). No other threads that are
+ * calling any of these functions are affected. It is then the responsibility
+ * of the application to catch the exception.
+ *
+ * After the exception has been caught, the run(), run_one(), run_for(),
+ * run_until(), poll() or poll_one() call may be restarted @em without the need
+ * for an intervening call to restart(). This allows the thread to rejoin the
+ * io_context object's thread pool without impacting any other threads in the
+ * pool.
+ *
+ * For example:
+ *
+ * @code
+ * asio::io_context io_context;
+ * ...
+ * for (;;)
+ * {
+ *   try
+ *   {
+ *     io_context.run();
+ *     break; // run() exited normally
+ *   }
+ *   catch (my_exception& e)
+ *   {
+ *     // Deal with exception as appropriate.
+ *   }
+ * }
+ * @endcode
+ *
+ * @par Submitting arbitrary tasks to the io_context
+ *
+ * To submit functions to the io_context, use the @ref asio::dispatch,
+ * @ref asio::post or @ref asio::defer free functions.
+ *
+ * For example:
+ *
+ * @code void my_task()
+ * {
+ *   ...
+ * }
+ *
+ * ...
+ *
+ * asio::io_context io_context;
+ *
+ * // Submit a function to the io_context.
+ * asio::post(io_context, my_task);
+ *
+ * // Submit a lambda object to the io_context.
+ * asio::post(io_context,
+ *     []()
+ *     {
+ *       ...
+ *     });
+ *
+ * // Run the io_context until it runs out of work.
+ * io_context.run(); @endcode
+ *
+ * @par Stopping the io_context from running out of work
+ *
+ * Some applications may need to prevent an io_context object's run() call from
+ * returning when there is no more work to do. For example, the io_context may
+ * be being run in a background thread that is launched prior to the
+ * application's asynchronous operations. The run() call may be kept running by
+ * creating an executor that tracks work against the io_context:
+ *
+ * @code asio::io_context io_context;
+ * auto work = asio::require(io_context.get_executor(),
+ *     asio::execution::outstanding_work.tracked);
+ * ... @endcode
+ *
+ * If using C++03, which lacks automatic variable type deduction, you may
+ * compute the return type of the require call:
+ *
+ * @code asio::io_context io_context;
+ * typename asio::require_result<
+ *     asio::io_context::executor_type,
+ *     asio::exeution::outstanding_work_t::tracked_t>
+ *   work = asio::require(io_context.get_executor(),
+ *     asio::execution::outstanding_work.tracked);
+ * ... @endcode
+ *
+ * or store the result in the type-erasing executor wrapper, any_io_executor:
+ *
+ * @code asio::io_context io_context;
+ * asio::any_io_executor work
+ *   = asio::require(io_context.get_executor(),
+ *       asio::execution::outstanding_work.tracked);
+ * ... @endcode
+ *
+ * To effect a shutdown, the application will then need to call the io_context
+ * object's stop() member function. This will cause the io_context run() call
+ * to return as soon as possible, abandoning unfinished operations and without
+ * permitting ready handlers to be dispatched.
+ *
+ * Alternatively, if the application requires that all operations and handlers
+ * be allowed to finish normally, store the work-tracking executor in an
+ * any_io_executor object, so that it may be explicitly reset.
+ *
+ * @code asio::io_context io_context;
+ * asio::any_io_executor work
+ *   = asio::require(io_context.get_executor(),
+ *       asio::execution::outstanding_work.tracked);
+ * ...
+ * work = asio::any_io_executor(); // Allow run() to exit. @endcode
+ */
+class io_context
+  : public execution_context
+{
+private:
+  typedef detail::io_context_impl impl_type;
+#if defined(ASIO_HAS_IOCP)
+  friend class detail::win_iocp_overlapped_ptr;
+#endif
+
+public:
+  template <typename Allocator, unsigned int Bits>
+  class basic_executor_type;
+
+  template <typename Allocator, unsigned int Bits>
+  friend class basic_executor_type;
+
+  /// Executor used to submit functions to an io_context.
+  typedef basic_executor_type<std::allocator<void>, 0> executor_type;
+
+#if !defined(ASIO_NO_DEPRECATED)
+  class work;
+  friend class work;
+#endif // !defined(ASIO_NO_DEPRECATED)
+
+  class service;
+
+#if !defined(ASIO_NO_EXTENSIONS) \
+  && !defined(ASIO_NO_TS_EXECUTORS)
+  class strand;
+#endif // !defined(ASIO_NO_EXTENSIONS)
+       //   && !defined(ASIO_NO_TS_EXECUTORS)
+
+  /// The type used to count the number of handlers executed by the context.
+  typedef std::size_t count_type;
+
+  /// Constructor.
+  ASIO_DECL io_context();
+
+  /// Constructor.
+  /**
+   * Construct with a hint about the required level of concurrency.
+   *
+   * @param concurrency_hint A suggestion to the implementation on how many
+   * threads it should allow to run simultaneously.
+   */
+  ASIO_DECL explicit io_context(int concurrency_hint);
+
+  /// Destructor.
+  /**
+   * On destruction, the io_context performs the following sequence of
+   * operations:
+   *
+   * @li For each service object @c svc in the io_context set, in reverse order
+   * of the beginning of service object lifetime, performs
+   * @c svc->shutdown().
+   *
+   * @li Uninvoked handler objects that were scheduled for deferred invocation
+   * on the io_context, or any associated strand, are destroyed.
+   *
+   * @li For each service object @c svc in the io_context set, in reverse order
+   * of the beginning of service object lifetime, performs
+   * <tt>delete static_cast<io_context::service*>(svc)</tt>.
+   *
+   * @note The destruction sequence described above permits programs to
+   * simplify their resource management by using @c shared_ptr<>. Where an
+   * object's lifetime is tied to the lifetime of a connection (or some other
+   * sequence of asynchronous operations), a @c shared_ptr to the object would
+   * be bound into the handlers for all asynchronous operations associated with
+   * it. This works as follows:
+   *
+   * @li When a single connection ends, all associated asynchronous operations
+   * complete. The corresponding handler objects are destroyed, and all
+   * @c shared_ptr references to the objects are destroyed.
+   *
+   * @li To shut down the whole program, the io_context function stop() is
+   * called to terminate any run() calls as soon as possible. The io_context
+   * destructor defined above destroys all handlers, causing all @c shared_ptr
+   * references to all connection objects to be destroyed.
+   */
+  ASIO_DECL ~io_context();
+
+  /// Obtains the executor associated with the io_context.
+  executor_type get_executor() ASIO_NOEXCEPT;
+
+  /// Run the io_context object's event processing loop.
+  /**
+   * The run() function blocks until all work has finished and there are no
+   * more handlers to be dispatched, or until the io_context has been stopped.
+   *
+   * Multiple threads may call the run() function to set up a pool of threads
+   * from which the io_context may execute handlers. All threads that are
+   * waiting in the pool are equivalent and the io_context may choose any one
+   * of them to invoke a handler.
+   *
+   * A normal exit from the run() function implies that the io_context object
+   * is stopped (the stopped() function returns @c true). Subsequent calls to
+   * run(), run_one(), poll() or poll_one() will return immediately unless there
+   * is a prior call to restart().
+   *
+   * @return The number of handlers that were executed.
+   *
+   * @note Calling the run() function from a thread that is currently calling
+   * one of run(), run_one(), run_for(), run_until(), poll() or poll_one() on
+   * the same io_context object may introduce the potential for deadlock. It is
+   * the caller's reponsibility to avoid this.
+   *
+   * The poll() function may also be used to dispatch ready handlers, but
+   * without blocking.
+   */
+  ASIO_DECL count_type run();
+
+#if !defined(ASIO_NO_DEPRECATED)
+  /// (Deprecated: Use non-error_code overload.) Run the io_context object's
+  /// event processing loop.
+  /**
+   * The run() function blocks until all work has finished and there are no
+   * more handlers to be dispatched, or until the io_context has been stopped.
+   *
+   * Multiple threads may call the run() function to set up a pool of threads
+   * from which the io_context may execute handlers. All threads that are
+   * waiting in the pool are equivalent and the io_context may choose any one
+   * of them to invoke a handler.
+   *
+   * A normal exit from the run() function implies that the io_context object
+   * is stopped (the stopped() function returns @c true). Subsequent calls to
+   * run(), run_one(), poll() or poll_one() will return immediately unless there
+   * is a prior call to restart().
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   *
+   * @return The number of handlers that were executed.
+   *
+   * @note Calling the run() function from a thread that is currently calling
+   * one of run(), run_one(), run_for(), run_until(), poll() or poll_one() on
+   * the same io_context object may introduce the potential for deadlock. It is
+   * the caller's reponsibility to avoid this.
+   *
+   * The poll() function may also be used to dispatch ready handlers, but
+   * without blocking.
+   */
+  ASIO_DECL count_type run(asio::error_code& ec);
+#endif // !defined(ASIO_NO_DEPRECATED)
+
+#if defined(ASIO_HAS_CHRONO) || defined(GENERATING_DOCUMENTATION)
+  /// Run the io_context object's event processing loop for a specified
+  /// duration.
+  /**
+   * The run_for() function blocks until all work has finished and there are no
+   * more handlers to be dispatched, until the io_context has been stopped, or
+   * until the specified duration has elapsed.
+   *
+   * @param rel_time The duration for which the call may block.
+   *
+   * @return The number of handlers that were executed.
+   */
+  template <typename Rep, typename Period>
+  std::size_t run_for(const chrono::duration<Rep, Period>& rel_time);
+
+  /// Run the io_context object's event processing loop until a specified time.
+  /**
+   * The run_until() function blocks until all work has finished and there are
+   * no more handlers to be dispatched, until the io_context has been stopped,
+   * or until the specified time has been reached.
+   *
+   * @param abs_time The time point until which the call may block.
+   *
+   * @return The number of handlers that were executed.
+   */
+  template <typename Clock, typename Duration>
+  std::size_t run_until(const chrono::time_point<Clock, Duration>& abs_time);
+#endif // defined(ASIO_HAS_CHRONO) || defined(GENERATING_DOCUMENTATION)
+
+  /// Run the io_context object's event processing loop to execute at most one
+  /// handler.
+  /**
+   * The run_one() function blocks until one handler has been dispatched, or
+   * until the io_context has been stopped.
+   *
+   * @return The number of handlers that were executed. A zero return value
+   * implies that the io_context object is stopped (the stopped() function
+   * returns @c true). Subsequent calls to run(), run_one(), poll() or
+   * poll_one() will return immediately unless there is a prior call to
+   * restart().
+   *
+   * @note Calling the run_one() function from a thread that is currently
+   * calling one of run(), run_one(), run_for(), run_until(), poll() or
+   * poll_one() on the same io_context object may introduce the potential for
+   * deadlock. It is the caller's reponsibility to avoid this.
+   */
+  ASIO_DECL count_type run_one();
+
+#if !defined(ASIO_NO_DEPRECATED)
+  /// (Deprecated: Use non-error_code overlaod.) Run the io_context object's
+  /// event processing loop to execute at most one handler.
+  /**
+   * The run_one() function blocks until one handler has been dispatched, or
+   * until the io_context has been stopped.
+   *
+   * @return The number of handlers that were executed. A zero return value
+   * implies that the io_context object is stopped (the stopped() function
+   * returns @c true). Subsequent calls to run(), run_one(), poll() or
+   * poll_one() will return immediately unless there is a prior call to
+   * restart().
+   *
+   * @return The number of handlers that were executed.
+   *
+   * @note Calling the run_one() function from a thread that is currently
+   * calling one of run(), run_one(), run_for(), run_until(), poll() or
+   * poll_one() on the same io_context object may introduce the potential for
+   * deadlock. It is the caller's reponsibility to avoid this.
+   */
+  ASIO_DECL count_type run_one(asio::error_code& ec);
+#endif // !defined(ASIO_NO_DEPRECATED)
+
+#if defined(ASIO_HAS_CHRONO) || defined(GENERATING_DOCUMENTATION)
+  /// Run the io_context object's event processing loop for a specified duration
+  /// to execute at most one handler.
+  /**
+   * The run_one_for() function blocks until one handler has been dispatched,
+   * until the io_context has been stopped, or until the specified duration has
+   * elapsed.
+   *
+   * @param rel_time The duration for which the call may block.
+   *
+   * @return The number of handlers that were executed.
+   */
+  template <typename Rep, typename Period>
+  std::size_t run_one_for(const chrono::duration<Rep, Period>& rel_time);
+
+  /// Run the io_context object's event processing loop until a specified time
+  /// to execute at most one handler.
+  /**
+   * The run_one_until() function blocks until one handler has been dispatched,
+   * until the io_context has been stopped, or until the specified time has
+   * been reached.
+   *
+   * @param abs_time The time point until which the call may block.
+   *
+   * @return The number of handlers that were executed.
+   */
+  template <typename Clock, typename Duration>
+  std::size_t run_one_until(
+      const chrono::time_point<Clock, Duration>& abs_time);
+#endif // defined(ASIO_HAS_CHRONO) || defined(GENERATING_DOCUMENTATION)
+
+  /// Run the io_context object's event processing loop to execute ready
+  /// handlers.
+  /**
+   * The poll() function runs handlers that are ready to run, without blocking,
+   * until the io_context has been stopped or there are no more ready handlers.
+   *
+   * @return The number of handlers that were executed.
+   */
+  ASIO_DECL count_type poll();
+
+#if !defined(ASIO_NO_DEPRECATED)
+  /// (Deprecated: Use non-error_code overload.) Run the io_context object's
+  /// event processing loop to execute ready handlers.
+  /**
+   * The poll() function runs handlers that are ready to run, without blocking,
+   * until the io_context has been stopped or there are no more ready handlers.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   *
+   * @return The number of handlers that were executed.
+   */
+  ASIO_DECL count_type poll(asio::error_code& ec);
+#endif // !defined(ASIO_NO_DEPRECATED)
+
+  /// Run the io_context object's event processing loop to execute one ready
+  /// handler.
+  /**
+   * The poll_one() function runs at most one handler that is ready to run,
+   * without blocking.
+   *
+   * @return The number of handlers that were executed.
+   */
+  ASIO_DECL count_type poll_one();
+
+#if !defined(ASIO_NO_DEPRECATED)
+  /// (Deprecated: Use non-error_code overload.) Run the io_context object's
+  /// event processing loop to execute one ready handler.
+  /**
+   * The poll_one() function runs at most one handler that is ready to run,
+   * without blocking.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   *
+   * @return The number of handlers that were executed.
+   */
+  ASIO_DECL count_type poll_one(asio::error_code& ec);
+#endif // !defined(ASIO_NO_DEPRECATED)
+
+  /// Stop the io_context object's event processing loop.
+  /**
+   * This function does not block, but instead simply signals the io_context to
+   * stop. All invocations of its run() or run_one() member functions should
+   * return as soon as possible. Subsequent calls to run(), run_one(), poll()
+   * or poll_one() will return immediately until restart() is called.
+   */
+  ASIO_DECL void stop();
+
+  /// Determine whether the io_context object has been stopped.
+  /**
+   * This function is used to determine whether an io_context object has been
+   * stopped, either through an explicit call to stop(), or due to running out
+   * of work. When an io_context object is stopped, calls to run(), run_one(),
+   * poll() or poll_one() will return immediately without invoking any
+   * handlers.
+   *
+   * @return @c true if the io_context object is stopped, otherwise @c false.
+   */
+  ASIO_DECL bool stopped() const;
+
+  /// Restart the io_context in preparation for a subsequent run() invocation.
+  /**
+   * This function must be called prior to any second or later set of
+   * invocations of the run(), run_one(), poll() or poll_one() functions when a
+   * previous invocation of these functions returned due to the io_context
+   * being stopped or running out of work. After a call to restart(), the
+   * io_context object's stopped() function will return @c false.
+   *
+   * This function must not be called while there are any unfinished calls to
+   * the run(), run_one(), poll() or poll_one() functions.
+   */
+  ASIO_DECL void restart();
+
+#if !defined(ASIO_NO_DEPRECATED)
+  /// (Deprecated: Use restart().) Reset the io_context in preparation for a
+  /// subsequent run() invocation.
+  /**
+   * This function must be called prior to any second or later set of
+   * invocations of the run(), run_one(), poll() or poll_one() functions when a
+   * previous invocation of these functions returned due to the io_context
+   * being stopped or running out of work. After a call to restart(), the
+   * io_context object's stopped() function will return @c false.
+   *
+   * This function must not be called while there are any unfinished calls to
+   * the run(), run_one(), poll() or poll_one() functions.
+   */
+  void reset();
+
+  /// (Deprecated: Use asio::dispatch().) Request the io_context to
+  /// invoke the given handler.
+  /**
+   * This function is used to ask the io_context to execute the given handler.
+   *
+   * The io_context guarantees that the handler will only be called in a thread
+   * in which the run(), run_one(), poll() or poll_one() member functions is
+   * currently being invoked. The handler may be executed inside this function
+   * if the guarantee can be met.
+   *
+   * @param handler The handler to be called. The io_context will make
+   * a copy of the handler object as required. The function signature of the
+   * handler must be: @code void handler(); @endcode
+   *
+   * @note This function throws an exception only if:
+   *
+   * @li the handler's @c asio_handler_allocate function; or
+   *
+   * @li the handler's copy constructor
+   *
+   * throws an exception.
+   */
+  template <typename LegacyCompletionHandler>
+  ASIO_INITFN_AUTO_RESULT_TYPE(LegacyCompletionHandler, void ())
+  dispatch(ASIO_MOVE_ARG(LegacyCompletionHandler) handler);
+
+  /// (Deprecated: Use asio::post().) Request the io_context to invoke
+  /// the given handler and return immediately.
+  /**
+   * This function is used to ask the io_context to execute the given handler,
+   * but without allowing the io_context to call the handler from inside this
+   * function.
+   *
+   * The io_context guarantees that the handler will only be called in a thread
+   * in which the run(), run_one(), poll() or poll_one() member functions is
+   * currently being invoked.
+   *
+   * @param handler The handler to be called. The io_context will make
+   * a copy of the handler object as required. The function signature of the
+   * handler must be: @code void handler(); @endcode
+   *
+   * @note This function throws an exception only if:
+   *
+   * @li the handler's @c asio_handler_allocate function; or
+   *
+   * @li the handler's copy constructor
+   *
+   * throws an exception.
+   */
+  template <typename LegacyCompletionHandler>
+  ASIO_INITFN_AUTO_RESULT_TYPE(LegacyCompletionHandler, void ())
+  post(ASIO_MOVE_ARG(LegacyCompletionHandler) handler);
+
+  /// (Deprecated: Use asio::bind_executor().) Create a new handler that
+  /// automatically dispatches the wrapped handler on the io_context.
+  /**
+   * This function is used to create a new handler function object that, when
+   * invoked, will automatically pass the wrapped handler to the io_context
+   * object's dispatch function.
+   *
+   * @param handler The handler to be wrapped. The io_context will make a copy
+   * of the handler object as required. The function signature of the handler
+   * must be: @code void handler(A1 a1, ... An an); @endcode
+   *
+   * @return A function object that, when invoked, passes the wrapped handler to
+   * the io_context object's dispatch function. Given a function object with the
+   * signature:
+   * @code R f(A1 a1, ... An an); @endcode
+   * If this function object is passed to the wrap function like so:
+   * @code io_context.wrap(f); @endcode
+   * then the return value is a function object with the signature
+   * @code void g(A1 a1, ... An an); @endcode
+   * that, when invoked, executes code equivalent to:
+   * @code io_context.dispatch(boost::bind(f, a1, ... an)); @endcode
+   */
+  template <typename Handler>
+#if defined(GENERATING_DOCUMENTATION)
+  unspecified
+#else
+  detail::wrapped_handler<io_context&, Handler>
+#endif
+  wrap(Handler handler);
+#endif // !defined(ASIO_NO_DEPRECATED)
+
+private:
+  io_context(const io_context&) ASIO_DELETED;
+  io_context& operator=(const io_context&) ASIO_DELETED;
+
+#if !defined(ASIO_NO_DEPRECATED)
+  struct initiate_dispatch;
+  struct initiate_post;
+#endif // !defined(ASIO_NO_DEPRECATED)
+
+  // Helper function to add the implementation.
+  ASIO_DECL impl_type& add_impl(impl_type* impl);
+
+  // Backwards compatible overload for use with services derived from
+  // io_context::service.
+  template <typename Service>
+  friend Service& use_service(io_context& ioc);
+
+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+  detail::winsock_init<> init_;
+#elif defined(__sun) || defined(__QNX__) || defined(__hpux) || defined(_AIX) \
+  || defined(__osf__)
+  detail::signal_init<> init_;
+#endif
+
+  // The implementation.
+  impl_type& impl_;
+};
+
+namespace detail {
+
+} // namespace detail
+
+/// Executor implementation type used to submit functions to an io_context.
+template <typename Allocator, unsigned int Bits>
+class io_context::basic_executor_type : detail::io_context_bits
+{
+public:
+  /// Copy constructor.
+  basic_executor_type(
+      const basic_executor_type& other) ASIO_NOEXCEPT
+    : io_context_(other.io_context_),
+      allocator_(other.allocator_),
+      bits_(other.bits_)
+  {
+    if (Bits & outstanding_work_tracked)
+      if (io_context_)
+        io_context_->impl_.work_started();
+  }
+
+#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+  /// Move constructor.
+  basic_executor_type(basic_executor_type&& other) ASIO_NOEXCEPT
+    : io_context_(other.io_context_),
+      allocator_(ASIO_MOVE_CAST(Allocator)(other.allocator_)),
+      bits_(other.bits_)
+  {
+    if (Bits & outstanding_work_tracked)
+      other.io_context_ = 0;
+  }
+#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+
+  /// Destructor.
+  ~basic_executor_type() ASIO_NOEXCEPT
+  {
+    if (Bits & outstanding_work_tracked)
+      if (io_context_)
+        io_context_->impl_.work_finished();
+  }
+
+  /// Assignment operator.
+  basic_executor_type& operator=(
+      const basic_executor_type& other) ASIO_NOEXCEPT;
+
+#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+  /// Move assignment operator.
+  basic_executor_type& operator=(
+      basic_executor_type&& other) ASIO_NOEXCEPT;
+#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+
+  /// Obtain an executor with the @c blocking.possibly property.
+  /**
+   * Do not call this function directly. It is intended for use with the
+   * asio::require customisation point.
+   *
+   * For example:
+   * @code auto ex1 = my_io_context.get_executor();
+   * auto ex2 = asio::require(ex1,
+   *     asio::execution::blocking.possibly); @endcode
+   */
+  ASIO_CONSTEXPR basic_executor_type require(
+      execution::blocking_t::possibly_t) const
+  {
+    return basic_executor_type(io_context_,
+        allocator_, bits_ & ~blocking_never);
+  }
+
+  /// Obtain an executor with the @c blocking.never property.
+  /**
+   * Do not call this function directly. It is intended for use with the
+   * asio::require customisation point.
+   *
+   * For example:
+   * @code auto ex1 = my_io_context.get_executor();
+   * auto ex2 = asio::require(ex1,
+   *     asio::execution::blocking.never); @endcode
+   */
+  ASIO_CONSTEXPR basic_executor_type require(
+      execution::blocking_t::never_t) const
+  {
+    return basic_executor_type(io_context_,
+        allocator_, bits_ | blocking_never);
+  }
+
+  /// Obtain an executor with the @c relationship.fork property.
+  /**
+   * Do not call this function directly. It is intended for use with the
+   * asio::require customisation point.
+   *
+   * For example:
+   * @code auto ex1 = my_io_context.get_executor();
+   * auto ex2 = asio::require(ex1,
+   *     asio::execution::relationship.fork); @endcode
+   */
+  ASIO_CONSTEXPR basic_executor_type require(
+      execution::relationship_t::fork_t) const
+  {
+    return basic_executor_type(io_context_,
+        allocator_, bits_ & ~relationship_continuation);
+  }
+
+  /// Obtain an executor with the @c relationship.continuation property.
+  /**
+   * Do not call this function directly. It is intended for use with the
+   * asio::require customisation point.
+   *
+   * For example:
+   * @code auto ex1 = my_io_context.get_executor();
+   * auto ex2 = asio::require(ex1,
+   *     asio::execution::relationship.continuation); @endcode
+   */
+  ASIO_CONSTEXPR basic_executor_type require(
+      execution::relationship_t::continuation_t) const
+  {
+    return basic_executor_type(io_context_,
+        allocator_, bits_ | relationship_continuation);
+  }
+
+  /// Obtain an executor with the @c outstanding_work.tracked property.
+  /**
+   * Do not call this function directly. It is intended for use with the
+   * asio::require customisation point.
+   *
+   * For example:
+   * @code auto ex1 = my_io_context.get_executor();
+   * auto ex2 = asio::require(ex1,
+   *     asio::execution::outstanding_work.tracked); @endcode
+   */
+  ASIO_CONSTEXPR basic_executor_type<Allocator,
+      ASIO_UNSPECIFIED(Bits | outstanding_work_tracked)>
+  require(execution::outstanding_work_t::tracked_t) const
+  {
+    return basic_executor_type<Allocator, Bits | outstanding_work_tracked>(
+        io_context_, allocator_, bits_);
+  }
+
+  /// Obtain an executor with the @c outstanding_work.untracked property.
+  /**
+   * Do not call this function directly. It is intended for use with the
+   * asio::require customisation point.
+   *
+   * For example:
+   * @code auto ex1 = my_io_context.get_executor();
+   * auto ex2 = asio::require(ex1,
+   *     asio::execution::outstanding_work.untracked); @endcode
+   */
+  ASIO_CONSTEXPR basic_executor_type<Allocator,
+      ASIO_UNSPECIFIED(Bits & ~outstanding_work_tracked)>
+  require(execution::outstanding_work_t::untracked_t) const
+  {
+    return basic_executor_type<Allocator, Bits & ~outstanding_work_tracked>(
+        io_context_, allocator_, bits_);
+  }
+
+  /// Obtain an executor with the specified @c allocator property.
+  /**
+   * Do not call this function directly. It is intended for use with the
+   * asio::require customisation point.
+   *
+   * For example:
+   * @code auto ex1 = my_io_context.get_executor();
+   * auto ex2 = asio::require(ex1,
+   *     asio::execution::allocator(my_allocator)); @endcode
+   */
+  template <typename OtherAllocator>
+  ASIO_CONSTEXPR basic_executor_type<OtherAllocator, Bits>
+  require(execution::allocator_t<OtherAllocator> a) const
+  {
+    return basic_executor_type<OtherAllocator, Bits>(
+        io_context_, a.value(), bits_);
+  }
+
+  /// Obtain an executor with the default @c allocator property.
+  /**
+   * Do not call this function directly. It is intended for use with the
+   * asio::require customisation point.
+   *
+   * For example:
+   * @code auto ex1 = my_io_context.get_executor();
+   * auto ex2 = asio::require(ex1,
+   *     asio::execution::allocator); @endcode
+   */
+  ASIO_CONSTEXPR basic_executor_type<std::allocator<void>, Bits>
+  require(execution::allocator_t<void>) const
+  {
+    return basic_executor_type<std::allocator<void>, Bits>(
+        io_context_, std::allocator<void>(), bits_);
+  }
+
+  /// Query the current value of the @c mapping property.
+  /**
+   * Do not call this function directly. It is intended for use with the
+   * asio::query customisation point.
+   *
+   * For example:
+   * @code auto ex = my_io_context.get_executor();
+   * if (asio::query(ex, asio::execution::mapping)
+   *       == asio::execution::mapping.thread)
+   *   ... @endcode
+   */
+  static ASIO_CONSTEXPR execution::mapping_t query(
+      execution::mapping_t) ASIO_NOEXCEPT
+  {
+    return execution::mapping.thread;
+  }
+
+  /// Query the current value of the @c context property.
+  /**
+   * Do not call this function directly. It is intended for use with the
+   * asio::query customisation point.
+   *
+   * For example:
+   * @code auto ex = my_io_context.get_executor();
+   * asio::io_context& ctx = asio::query(
+   *     ex, asio::execution::context); @endcode
+   */
+  io_context& query(execution::context_t) const ASIO_NOEXCEPT
+  {
+    return *io_context_;
+  }
+
+  /// Query the current value of the @c blocking property.
+  /**
+   * Do not call this function directly. It is intended for use with the
+   * asio::query customisation point.
+   *
+   * For example:
+   * @code auto ex = my_io_context.get_executor();
+   * if (asio::query(ex, asio::execution::blocking)
+   *       == asio::execution::blocking.always)
+   *   ... @endcode
+   */
+  ASIO_CONSTEXPR execution::blocking_t query(
+      execution::blocking_t) const ASIO_NOEXCEPT
+  {
+    return (bits_ & blocking_never)
+      ? execution::blocking_t(execution::blocking.never)
+      : execution::blocking_t(execution::blocking.possibly);
+  }
+
+  /// Query the current value of the @c relationship property.
+  /**
+   * Do not call this function directly. It is intended for use with the
+   * asio::query customisation point.
+   *
+   * For example:
+   * @code auto ex = my_io_context.get_executor();
+   * if (asio::query(ex, asio::execution::relationship)
+   *       == asio::execution::relationship.continuation)
+   *   ... @endcode
+   */
+  ASIO_CONSTEXPR execution::relationship_t query(
+      execution::relationship_t) const ASIO_NOEXCEPT
+  {
+    return (bits_ & relationship_continuation)
+      ? execution::relationship_t(execution::relationship.continuation)
+      : execution::relationship_t(execution::relationship.fork);
+  }
+
+  /// Query the current value of the @c outstanding_work property.
+  /**
+   * Do not call this function directly. It is intended for use with the
+   * asio::query customisation point.
+   *
+   * For example:
+   * @code auto ex = my_io_context.get_executor();
+   * if (asio::query(ex, asio::execution::outstanding_work)
+   *       == asio::execution::outstanding_work.tracked)
+   *   ... @endcode
+   */
+  static ASIO_CONSTEXPR execution::outstanding_work_t query(
+      execution::outstanding_work_t) ASIO_NOEXCEPT
+  {
+    return (Bits & outstanding_work_tracked)
+      ? execution::outstanding_work_t(execution::outstanding_work.tracked)
+      : execution::outstanding_work_t(execution::outstanding_work.untracked);
+  }
+
+  /// Query the current value of the @c allocator property.
+  /**
+   * Do not call this function directly. It is intended for use with the
+   * asio::query customisation point.
+   *
+   * For example:
+   * @code auto ex = my_io_context.get_executor();
+   * auto alloc = asio::query(ex,
+   *     asio::execution::allocator); @endcode
+   */
+  template <typename OtherAllocator>
+  ASIO_CONSTEXPR Allocator query(
+      execution::allocator_t<OtherAllocator>) const ASIO_NOEXCEPT
+  {
+    return allocator_;
+  }
+
+  /// Query the current value of the @c allocator property.
+  /**
+   * Do not call this function directly. It is intended for use with the
+   * asio::query customisation point.
+   *
+   * For example:
+   * @code auto ex = my_io_context.get_executor();
+   * auto alloc = asio::query(ex,
+   *     asio::execution::allocator); @endcode
+   */
+  ASIO_CONSTEXPR Allocator query(
+      execution::allocator_t<void>) const ASIO_NOEXCEPT
+  {
+    return allocator_;
+  }
+
+  /// Determine whether the io_context is running in the current thread.
+  /**
+   * @return @c true if the current thread is running the io_context. Otherwise
+   * returns @c false.
+   */
+  bool running_in_this_thread() const ASIO_NOEXCEPT;
+
+  /// Compare two executors for equality.
+  /**
+   * Two executors are equal if they refer to the same underlying io_context.
+   */
+  friend bool operator==(const basic_executor_type& a,
+      const basic_executor_type& b) ASIO_NOEXCEPT
+  {
+    return a.io_context_ == b.io_context_
+      && a.allocator_ == b.allocator_
+      && a.bits_ == b.bits_;
+  }
+
+  /// Compare two executors for inequality.
+  /**
+   * Two executors are equal if they refer to the same underlying io_context.
+   */
+  friend bool operator!=(const basic_executor_type& a,
+      const basic_executor_type& b) ASIO_NOEXCEPT
+  {
+    return a.io_context_ != b.io_context_
+      || a.allocator_ != b.allocator_
+      || a.bits_ != b.bits_;
+  }
+
+  /// Execution function.
+  /**
+   * Do not call this function directly. It is intended for use with the
+   * execution::execute customisation point.
+   *
+   * For example:
+   * @code auto ex = my_io_context.get_executor();
+   * execution::execute(ex, my_function_object); @endcode
+   */
+  template <typename Function>
+  void execute(ASIO_MOVE_ARG(Function) f) const;
+
+#if !defined(ASIO_NO_TS_EXECUTORS)
+  /// Obtain the underlying execution context.
+  io_context& context() const ASIO_NOEXCEPT;
+
+  /// Inform the io_context that it has some outstanding work to do.
+  /**
+   * This function is used to inform the io_context that some work has begun.
+   * This ensures that the io_context's run() and run_one() functions do not
+   * exit while the work is underway.
+   */
+  void on_work_started() const ASIO_NOEXCEPT;
+
+  /// Inform the io_context that some work is no longer outstanding.
+  /**
+   * This function is used to inform the io_context that some work has
+   * finished. Once the count of unfinished work reaches zero, the io_context
+   * is stopped and the run() and run_one() functions may exit.
+   */
+  void on_work_finished() const ASIO_NOEXCEPT;
+
+  /// Request the io_context to invoke the given function object.
+  /**
+   * This function is used to ask the io_context to execute the given function
+   * object. If the current thread is running the io_context, @c dispatch()
+   * executes the function before returning. Otherwise, the function will be
+   * scheduled to run on the io_context.
+   *
+   * @param f The function object to be called. The executor will make a copy
+   * of the handler object as required. The function signature of the function
+   * object must be: @code void function(); @endcode
+   *
+   * @param a An allocator that may be used by the executor to allocate the
+   * internal storage needed for function invocation.
+   */
+  template <typename Function, typename OtherAllocator>
+  void dispatch(ASIO_MOVE_ARG(Function) f,
+      const OtherAllocator& a) const;
+
+  /// Request the io_context to invoke the given function object.
+  /**
+   * This function is used to ask the io_context to execute the given function
+   * object. The function object will never be executed inside @c post().
+   * Instead, it will be scheduled to run on the io_context.
+   *
+   * @param f The function object to be called. The executor will make a copy
+   * of the handler object as required. The function signature of the function
+   * object must be: @code void function(); @endcode
+   *
+   * @param a An allocator that may be used by the executor to allocate the
+   * internal storage needed for function invocation.
+   */
+  template <typename Function, typename OtherAllocator>
+  void post(ASIO_MOVE_ARG(Function) f,
+      const OtherAllocator& a) const;
+
+  /// Request the io_context to invoke the given function object.
+  /**
+   * This function is used to ask the io_context to execute the given function
+   * object. The function object will never be executed inside @c defer().
+   * Instead, it will be scheduled to run on the io_context.
+   *
+   * If the current thread belongs to the io_context, @c defer() will delay
+   * scheduling the function object until the current thread returns control to
+   * the pool.
+   *
+   * @param f The function object to be called. The executor will make a copy
+   * of the handler object as required. The function signature of the function
+   * object must be: @code void function(); @endcode
+   *
+   * @param a An allocator that may be used by the executor to allocate the
+   * internal storage needed for function invocation.
+   */
+  template <typename Function, typename OtherAllocator>
+  void defer(ASIO_MOVE_ARG(Function) f,
+      const OtherAllocator& a) const;
+#endif // !defined(ASIO_NO_TS_EXECUTORS)
+
+private:
+  friend class io_context;
+  template <typename, unsigned int> friend class basic_executor_type;
+
+  // Constructor used by io_context::get_executor().
+  explicit basic_executor_type(io_context& i) ASIO_NOEXCEPT
+    : io_context_(&i),
+      allocator_(),
+      bits_(0)
+  {
+    if (Bits & outstanding_work_tracked)
+      io_context_->impl_.work_started();
+  }
+
+  // Constructor used by require().
+  basic_executor_type(io_context* i,
+      const Allocator& a, unsigned int bits) ASIO_NOEXCEPT
+    : io_context_(i),
+      allocator_(a),
+      bits_(bits)
+  {
+    if (Bits & outstanding_work_tracked)
+      if (io_context_)
+        io_context_->impl_.work_started();
+  }
+
+  // The underlying io_context.
+  io_context* io_context_;
+
+  // The allocator used for execution functions.
+  Allocator allocator_;
+
+  // The runtime-switched properties of the io_context executor.
+  unsigned int bits_;
+};
+
+#if !defined(ASIO_NO_DEPRECATED)
+/// (Deprecated: Use executor_work_guard.) Class to inform the io_context when
+/// it has work to do.
+/**
+ * The work class is used to inform the io_context when work starts and
+ * finishes. This ensures that the io_context object's run() function will not
+ * exit while work is underway, and that it does exit when there is no
+ * unfinished work remaining.
+ *
+ * The work class is copy-constructible so that it may be used as a data member
+ * in a handler class. It is not assignable.
+ */
+class io_context::work
+{
+public:
+  /// Constructor notifies the io_context that work is starting.
+  /**
+   * The constructor is used to inform the io_context that some work has begun.
+   * This ensures that the io_context object's run() function will not exit
+   * while the work is underway.
+   */
+  explicit work(asio::io_context& io_context);
+
+  /// Copy constructor notifies the io_context that work is starting.
+  /**
+   * The constructor is used to inform the io_context that some work has begun.
+   * This ensures that the io_context object's run() function will not exit
+   * while the work is underway.
+   */
+  work(const work& other);
+
+  /// Destructor notifies the io_context that the work is complete.
+  /**
+   * The destructor is used to inform the io_context that some work has
+   * finished. Once the count of unfinished work reaches zero, the io_context
+   * object's run() function is permitted to exit.
+   */
+  ~work();
+
+  /// Get the io_context associated with the work.
+  asio::io_context& get_io_context();
+
+private:
+  // Prevent assignment.
+  void operator=(const work& other);
+
+  // The io_context implementation.
+  detail::io_context_impl& io_context_impl_;
+};
+#endif // !defined(ASIO_NO_DEPRECATED)
+
+/// Base class for all io_context services.
+class io_context::service
+  : public execution_context::service
+{
+public:
+  /// Get the io_context object that owns the service.
+  asio::io_context& get_io_context();
+
+private:
+  /// Destroy all user-defined handler objects owned by the service.
+  ASIO_DECL virtual void shutdown();
+
+#if !defined(ASIO_NO_DEPRECATED)
+  /// (Deprecated: Use shutdown().) Destroy all user-defined handler objects
+  /// owned by the service.
+  ASIO_DECL virtual void shutdown_service();
+#endif // !defined(ASIO_NO_DEPRECATED)
+
+  /// Handle notification of a fork-related event to perform any necessary
+  /// housekeeping.
+  /**
+   * This function is not a pure virtual so that services only have to
+   * implement it if necessary. The default implementation does nothing.
+   */
+  ASIO_DECL virtual void notify_fork(
+      execution_context::fork_event event);
+
+#if !defined(ASIO_NO_DEPRECATED)
+  /// (Deprecated: Use notify_fork().) Handle notification of a fork-related
+  /// event to perform any necessary housekeeping.
+  /**
+   * This function is not a pure virtual so that services only have to
+   * implement it if necessary. The default implementation does nothing.
+   */
+  ASIO_DECL virtual void fork_service(
+      execution_context::fork_event event);
+#endif // !defined(ASIO_NO_DEPRECATED)
+
+protected:
+  /// Constructor.
+  /**
+   * @param owner The io_context object that owns the service.
+   */
+  ASIO_DECL service(asio::io_context& owner);
+
+  /// Destructor.
+  ASIO_DECL virtual ~service();
+};
+
+namespace detail {
+
+// Special service base class to keep classes header-file only.
+template <typename Type>
+class service_base
+  : public asio::io_context::service
+{
+public:
+  static asio::detail::service_id<Type> id;
+
+  // Constructor.
+  service_base(asio::io_context& io_context)
+    : asio::io_context::service(io_context)
+  {
+  }
+};
+
+template <typename Type>
+asio::detail::service_id<Type> service_base<Type>::id;
+
+} // namespace detail
+
+#if !defined(GENERATING_DOCUMENTATION)
+
+namespace traits {
+
+#if !defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)
+
+template <typename Allocator, unsigned int Bits>
+struct equality_comparable<
+    asio::io_context::basic_executor_type<Allocator, Bits>
+  >
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
+};
+
+#endif // !defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)
+
+#if !defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)
+
+template <typename Allocator, unsigned int Bits, typename Function>
+struct execute_member<
+    asio::io_context::basic_executor_type<Allocator, Bits>,
+    Function
+  >
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
+  typedef void result_type;
+};
+
+#endif // !defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)
+
+#if !defined(ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT)
+
+template <typename Allocator, unsigned int Bits>
+struct require_member<
+    asio::io_context::basic_executor_type<Allocator, Bits>,
+    asio::execution::blocking_t::possibly_t
+  >
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
+  typedef asio::io_context::basic_executor_type<
+      Allocator, Bits> result_type;
+};
+
+template <typename Allocator, unsigned int Bits>
+struct require_member<
+    asio::io_context::basic_executor_type<Allocator, Bits>,
+    asio::execution::blocking_t::never_t
+  >
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
+  typedef asio::io_context::basic_executor_type<
+      Allocator, Bits> result_type;
+};
+
+template <typename Allocator, unsigned int Bits>
+struct require_member<
+    asio::io_context::basic_executor_type<Allocator, Bits>,
+    asio::execution::relationship_t::fork_t
+  >
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
+  typedef asio::io_context::basic_executor_type<
+      Allocator, Bits> result_type;
+};
+
+template <typename Allocator, unsigned int Bits>
+struct require_member<
+    asio::io_context::basic_executor_type<Allocator, Bits>,
+    asio::execution::relationship_t::continuation_t
+  >
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
+  typedef asio::io_context::basic_executor_type<
+      Allocator, Bits> result_type;
+};
+
+template <typename Allocator, unsigned int Bits>
+struct require_member<
+    asio::io_context::basic_executor_type<Allocator, Bits>,
+    asio::execution::outstanding_work_t::tracked_t
+  > : asio::detail::io_context_bits
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
+  typedef asio::io_context::basic_executor_type<
+      Allocator, Bits | outstanding_work_tracked> result_type;
+};
+
+template <typename Allocator, unsigned int Bits>
+struct require_member<
+    asio::io_context::basic_executor_type<Allocator, Bits>,
+    asio::execution::outstanding_work_t::untracked_t
+  > : asio::detail::io_context_bits
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
+  typedef asio::io_context::basic_executor_type<
+      Allocator, Bits & ~outstanding_work_tracked> result_type;
+};
+
+template <typename Allocator, unsigned int Bits>
+struct require_member<
+    asio::io_context::basic_executor_type<Allocator, Bits>,
+    asio::execution::allocator_t<void>
+  >
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
+  typedef asio::io_context::basic_executor_type<
+      std::allocator<void>, Bits> result_type;
+};
+
+template <unsigned int Bits,
+    typename Allocator, typename OtherAllocator>
+struct require_member<
+    asio::io_context::basic_executor_type<Allocator, Bits>,
+    asio::execution::allocator_t<OtherAllocator>
+  >
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
+  typedef asio::io_context::basic_executor_type<
+      OtherAllocator, Bits> result_type;
+};
+
+#endif // !defined(ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT)
+
+#if !defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT)
+
+template <typename Allocator, unsigned int Bits, typename Property>
+struct query_static_constexpr_member<
+    asio::io_context::basic_executor_type<Allocator, Bits>,
+    Property,
+    typename asio::enable_if<
+      asio::is_convertible<
+        Property,
+        asio::execution::outstanding_work_t
+      >::value
+    >::type
+  > : asio::detail::io_context_bits
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
+  typedef asio::execution::outstanding_work_t result_type;
+
+  static ASIO_CONSTEXPR result_type value() ASIO_NOEXCEPT
+  {
+    return (Bits & outstanding_work_tracked)
+      ? execution::outstanding_work_t(execution::outstanding_work.tracked)
+      : execution::outstanding_work_t(execution::outstanding_work.untracked);
+  }
+};
+
+template <typename Allocator, unsigned int Bits, typename Property>
+struct query_static_constexpr_member<
+    asio::io_context::basic_executor_type<Allocator, Bits>,
+    Property,
+    typename asio::enable_if<
+      asio::is_convertible<
+        Property,
+        asio::execution::mapping_t
+      >::value
+    >::type
+  >
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
+  typedef asio::execution::mapping_t::thread_t result_type;
+
+  static ASIO_CONSTEXPR result_type value() ASIO_NOEXCEPT
+  {
+    return result_type();
+  }
+};
+
+#endif // !defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT)
+
+#if !defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT)
+
+template <typename Allocator, unsigned int Bits, typename Property>
+struct query_member<
+    asio::io_context::basic_executor_type<Allocator, Bits>,
+    Property,
+    typename asio::enable_if<
+      asio::is_convertible<
+        Property,
+        asio::execution::blocking_t
+      >::value
+    >::type
+  >
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
+  typedef asio::execution::blocking_t result_type;
+};
+
+template <typename Allocator, unsigned int Bits, typename Property>
+struct query_member<
+    asio::io_context::basic_executor_type<Allocator, Bits>,
+    Property,
+    typename asio::enable_if<
+      asio::is_convertible<
+        Property,
+        asio::execution::relationship_t
+      >::value
+    >::type
+  >
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
+  typedef asio::execution::relationship_t result_type;
+};
+
+template <typename Allocator, unsigned int Bits>
+struct query_member<
+    asio::io_context::basic_executor_type<Allocator, Bits>,
+    asio::execution::context_t
+  >
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
+  typedef asio::io_context& result_type;
+};
+
+template <typename Allocator, unsigned int Bits>
+struct query_member<
+    asio::io_context::basic_executor_type<Allocator, Bits>,
+    asio::execution::allocator_t<void>
+  >
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
+  typedef Allocator result_type;
+};
+
+template <typename Allocator, unsigned int Bits, typename OtherAllocator>
+struct query_member<
+    asio::io_context::basic_executor_type<Allocator, Bits>,
+    asio::execution::allocator_t<OtherAllocator>
+  >
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
+  typedef Allocator result_type;
+};
+
+#endif // !defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT)
+
+} // namespace traits
+
+#endif // !defined(GENERATING_DOCUMENTATION)
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/impl/io_context.hpp"
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/impl/io_context.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+// If both io_context.hpp and strand.hpp have been included, automatically
+// include the header file needed for the io_context::strand class.
+#if !defined(ASIO_NO_EXTENSIONS)
+# if defined(ASIO_STRAND_HPP)
+#  include "asio/io_context_strand.hpp"
+# endif // defined(ASIO_STRAND_HPP)
+#endif // !defined(ASIO_NO_EXTENSIONS)
+
+#endif // ASIO_IO_CONTEXT_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/io_context_strand.hpp b/link/modules/asio-standalone/asio/include/asio/io_context_strand.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/io_context_strand.hpp
@@ -0,0 +1,376 @@
+//
+// io_context_strand.hpp
+// ~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_IO_CONTEXT_STRAND_HPP
+#define ASIO_IO_CONTEXT_STRAND_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if !defined(ASIO_NO_EXTENSIONS) \
+  && !defined(ASIO_NO_TS_EXECUTORS)
+
+#include "asio/async_result.hpp"
+#include "asio/detail/handler_type_requirements.hpp"
+#include "asio/detail/strand_service.hpp"
+#include "asio/detail/wrapped_handler.hpp"
+#include "asio/io_context.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+/// Provides serialised handler execution.
+/**
+ * The io_context::strand class provides the ability to post and dispatch
+ * handlers with the guarantee that none of those handlers will execute
+ * concurrently.
+ *
+ * @par Order of handler invocation
+ * Given:
+ *
+ * @li a strand object @c s
+ *
+ * @li an object @c a meeting completion handler requirements
+ *
+ * @li an object @c a1 which is an arbitrary copy of @c a made by the
+ * implementation
+ *
+ * @li an object @c b meeting completion handler requirements
+ *
+ * @li an object @c b1 which is an arbitrary copy of @c b made by the
+ * implementation
+ *
+ * if any of the following conditions are true:
+ *
+ * @li @c s.post(a) happens-before @c s.post(b)
+ * 
+ * @li @c s.post(a) happens-before @c s.dispatch(b), where the latter is
+ * performed outside the strand
+ * 
+ * @li @c s.dispatch(a) happens-before @c s.post(b), where the former is
+ * performed outside the strand
+ * 
+ * @li @c s.dispatch(a) happens-before @c s.dispatch(b), where both are
+ * performed outside the strand
+ *   
+ * then @c asio_handler_invoke(a1, &a1) happens-before
+ * @c asio_handler_invoke(b1, &b1).
+ * 
+ * Note that in the following case:
+ * @code async_op_1(..., s.wrap(a));
+ * async_op_2(..., s.wrap(b)); @endcode
+ * the completion of the first async operation will perform @c s.dispatch(a),
+ * and the second will perform @c s.dispatch(b), but the order in which those
+ * are performed is unspecified. That is, you cannot state whether one
+ * happens-before the other. Therefore none of the above conditions are met and
+ * no ordering guarantee is made.
+ *
+ * @note The implementation makes no guarantee that handlers posted or
+ * dispatched through different @c strand objects will be invoked concurrently.
+ *
+ * @par Thread Safety
+ * @e Distinct @e objects: Safe.@n
+ * @e Shared @e objects: Safe.
+ *
+ * @par Concepts:
+ * Dispatcher.
+ */
+class io_context::strand
+{
+public:
+  /// Constructor.
+  /**
+   * Constructs the strand.
+   *
+   * @param io_context The io_context object that the strand will use to
+   * dispatch handlers that are ready to be run.
+   */
+  explicit strand(asio::io_context& io_context)
+    : service_(asio::use_service<
+        asio::detail::strand_service>(io_context))
+  {
+    service_.construct(impl_);
+  }
+
+  /// Destructor.
+  /**
+   * Destroys a strand.
+   *
+   * Handlers posted through the strand that have not yet been invoked will
+   * still be dispatched in a way that meets the guarantee of non-concurrency.
+   */
+  ~strand()
+  {
+  }
+
+  /// Obtain the underlying execution context.
+  asio::io_context& context() const ASIO_NOEXCEPT
+  {
+    return service_.get_io_context();
+  }
+
+  /// Inform the strand that it has some outstanding work to do.
+  /**
+   * The strand delegates this call to its underlying io_context.
+   */
+  void on_work_started() const ASIO_NOEXCEPT
+  {
+    context().get_executor().on_work_started();
+  }
+
+  /// Inform the strand that some work is no longer outstanding.
+  /**
+   * The strand delegates this call to its underlying io_context.
+   */
+  void on_work_finished() const ASIO_NOEXCEPT
+  {
+    context().get_executor().on_work_finished();
+  }
+
+  /// Request the strand to invoke the given function object.
+  /**
+   * This function is used to ask the strand to execute the given function
+   * object on its underlying io_context. The function object will be executed
+   * inside this function if the strand is not otherwise busy and if the
+   * underlying io_context's executor's @c dispatch() function is also able to
+   * execute the function before returning.
+   *
+   * @param f The function object to be called. The executor will make
+   * a copy of the handler object as required. The function signature of the
+   * function object must be: @code void function(); @endcode
+   *
+   * @param a An allocator that may be used by the executor to allocate the
+   * internal storage needed for function invocation.
+   */
+  template <typename Function, typename Allocator>
+  void dispatch(ASIO_MOVE_ARG(Function) f, const Allocator& a) const
+  {
+    typename decay<Function>::type tmp(ASIO_MOVE_CAST(Function)(f));
+    service_.dispatch(impl_, tmp);
+    (void)a;
+  }
+
+#if !defined(ASIO_NO_DEPRECATED)
+  /// (Deprecated: Use asio::dispatch().) Request the strand to invoke
+  /// the given handler.
+  /**
+   * This function is used to ask the strand to execute the given handler.
+   *
+   * The strand object guarantees that handlers posted or dispatched through
+   * the strand will not be executed concurrently. The handler may be executed
+   * inside this function if the guarantee can be met. If this function is
+   * called from within a handler that was posted or dispatched through the same
+   * strand, then the new handler will be executed immediately.
+   *
+   * The strand's guarantee is in addition to the guarantee provided by the
+   * underlying io_context. The io_context guarantees that the handler will only
+   * be called in a thread in which the io_context's run member function is
+   * currently being invoked.
+   *
+   * @param handler The handler to be called. The strand will make a copy of the
+   * handler object as required. The function signature of the handler must be:
+   * @code void handler(); @endcode
+   */
+  template <typename LegacyCompletionHandler>
+  ASIO_INITFN_AUTO_RESULT_TYPE(LegacyCompletionHandler, void ())
+  dispatch(ASIO_MOVE_ARG(LegacyCompletionHandler) handler)
+  {
+    return async_initiate<LegacyCompletionHandler, void ()>(
+        initiate_dispatch(), handler, this);
+  }
+#endif // !defined(ASIO_NO_DEPRECATED)
+
+  /// Request the strand to invoke the given function object.
+  /**
+   * This function is used to ask the executor to execute the given function
+   * object. The function object will never be executed inside this function.
+   * Instead, it will be scheduled to run by the underlying io_context.
+   *
+   * @param f The function object to be called. The executor will make
+   * a copy of the handler object as required. The function signature of the
+   * function object must be: @code void function(); @endcode
+   *
+   * @param a An allocator that may be used by the executor to allocate the
+   * internal storage needed for function invocation.
+   */
+  template <typename Function, typename Allocator>
+  void post(ASIO_MOVE_ARG(Function) f, const Allocator& a) const
+  {
+    typename decay<Function>::type tmp(ASIO_MOVE_CAST(Function)(f));
+    service_.post(impl_, tmp);
+    (void)a;
+  }
+
+#if !defined(ASIO_NO_DEPRECATED)
+  /// (Deprecated: Use asio::post().) Request the strand to invoke the
+  /// given handler and return immediately.
+  /**
+   * This function is used to ask the strand to execute the given handler, but
+   * without allowing the strand to call the handler from inside this function.
+   *
+   * The strand object guarantees that handlers posted or dispatched through
+   * the strand will not be executed concurrently. The strand's guarantee is in
+   * addition to the guarantee provided by the underlying io_context. The
+   * io_context guarantees that the handler will only be called in a thread in
+   * which the io_context's run member function is currently being invoked.
+   *
+   * @param handler The handler to be called. The strand will make a copy of the
+   * handler object as required. The function signature of the handler must be:
+   * @code void handler(); @endcode
+   */
+  template <typename LegacyCompletionHandler>
+  ASIO_INITFN_AUTO_RESULT_TYPE(LegacyCompletionHandler, void ())
+  post(ASIO_MOVE_ARG(LegacyCompletionHandler) handler)
+  {
+    return async_initiate<LegacyCompletionHandler, void ()>(
+        initiate_post(), handler, this);
+  }
+#endif // !defined(ASIO_NO_DEPRECATED)
+
+  /// Request the strand to invoke the given function object.
+  /**
+   * This function is used to ask the executor to execute the given function
+   * object. The function object will never be executed inside this function.
+   * Instead, it will be scheduled to run by the underlying io_context.
+   *
+   * @param f The function object to be called. The executor will make
+   * a copy of the handler object as required. The function signature of the
+   * function object must be: @code void function(); @endcode
+   *
+   * @param a An allocator that may be used by the executor to allocate the
+   * internal storage needed for function invocation.
+   */
+  template <typename Function, typename Allocator>
+  void defer(ASIO_MOVE_ARG(Function) f, const Allocator& a) const
+  {
+    typename decay<Function>::type tmp(ASIO_MOVE_CAST(Function)(f));
+    service_.post(impl_, tmp);
+    (void)a;
+  }
+
+#if !defined(ASIO_NO_DEPRECATED)
+  /// (Deprecated: Use asio::bind_executor().) Create a new handler that
+  /// automatically dispatches the wrapped handler on the strand.
+  /**
+   * This function is used to create a new handler function object that, when
+   * invoked, will automatically pass the wrapped handler to the strand's
+   * dispatch function.
+   *
+   * @param handler The handler to be wrapped. The strand will make a copy of
+   * the handler object as required. The function signature of the handler must
+   * be: @code void handler(A1 a1, ... An an); @endcode
+   *
+   * @return A function object that, when invoked, passes the wrapped handler to
+   * the strand's dispatch function. Given a function object with the signature:
+   * @code R f(A1 a1, ... An an); @endcode
+   * If this function object is passed to the wrap function like so:
+   * @code strand.wrap(f); @endcode
+   * then the return value is a function object with the signature
+   * @code void g(A1 a1, ... An an); @endcode
+   * that, when invoked, executes code equivalent to:
+   * @code strand.dispatch(boost::bind(f, a1, ... an)); @endcode
+   */
+  template <typename Handler>
+#if defined(GENERATING_DOCUMENTATION)
+  unspecified
+#else
+  detail::wrapped_handler<strand, Handler, detail::is_continuation_if_running>
+#endif
+  wrap(Handler handler)
+  {
+    return detail::wrapped_handler<io_context::strand, Handler,
+        detail::is_continuation_if_running>(*this, handler);
+  }
+#endif // !defined(ASIO_NO_DEPRECATED)
+
+  /// Determine whether the strand is running in the current thread.
+  /**
+   * @return @c true if the current thread is executing a handler that was
+   * submitted to the strand using post(), dispatch() or wrap(). Otherwise
+   * returns @c false.
+   */
+  bool running_in_this_thread() const ASIO_NOEXCEPT
+  {
+    return service_.running_in_this_thread(impl_);
+  }
+
+  /// Compare two strands for equality.
+  /**
+   * Two strands are equal if they refer to the same ordered, non-concurrent
+   * state.
+   */
+  friend bool operator==(const strand& a, const strand& b) ASIO_NOEXCEPT
+  {
+    return a.impl_ == b.impl_;
+  }
+
+  /// Compare two strands for inequality.
+  /**
+   * Two strands are equal if they refer to the same ordered, non-concurrent
+   * state.
+   */
+  friend bool operator!=(const strand& a, const strand& b) ASIO_NOEXCEPT
+  {
+    return a.impl_ != b.impl_;
+  }
+
+private:
+#if !defined(ASIO_NO_DEPRECATED)
+  struct initiate_dispatch
+  {
+    template <typename LegacyCompletionHandler>
+    void operator()(ASIO_MOVE_ARG(LegacyCompletionHandler) handler,
+        strand* self) const
+    {
+      // If you get an error on the following line it means that your
+      // handler does not meet the documented type requirements for a
+      // LegacyCompletionHandler.
+      ASIO_LEGACY_COMPLETION_HANDLER_CHECK(
+          LegacyCompletionHandler, handler) type_check;
+
+      detail::non_const_lvalue<LegacyCompletionHandler> handler2(handler);
+      self->service_.dispatch(self->impl_, handler2.value);
+    }
+  };
+
+  struct initiate_post
+  {
+    template <typename LegacyCompletionHandler>
+    void operator()(ASIO_MOVE_ARG(LegacyCompletionHandler) handler,
+        strand* self) const
+    {
+      // If you get an error on the following line it means that your
+      // handler does not meet the documented type requirements for a
+      // LegacyCompletionHandler.
+      ASIO_LEGACY_COMPLETION_HANDLER_CHECK(
+          LegacyCompletionHandler, handler) type_check;
+
+      detail::non_const_lvalue<LegacyCompletionHandler> handler2(handler);
+      self->service_.post(self->impl_, handler2.value);
+    }
+  };
+#endif // !defined(ASIO_NO_DEPRECATED)
+
+  asio::detail::strand_service& service_;
+  mutable asio::detail::strand_service::implementation_type impl_;
+};
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // !defined(ASIO_NO_EXTENSIONS)
+       //   && !defined(ASIO_NO_TS_EXECUTORS)
+
+#endif // ASIO_IO_CONTEXT_STRAND_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/io_service.hpp b/link/modules/asio-standalone/asio/include/asio/io_service.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/io_service.hpp
@@ -0,0 +1,33 @@
+//
+// io_service.hpp
+// ~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_IO_SERVICE_HPP
+#define ASIO_IO_SERVICE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/io_context.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+#if !defined(ASIO_NO_DEPRECATED)
+/// Typedef for backwards compatibility.
+typedef io_context io_service;
+#endif // !defined(ASIO_NO_DEPRECATED)
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IO_SERVICE_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/io_service_strand.hpp b/link/modules/asio-standalone/asio/include/asio/io_service_strand.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/io_service_strand.hpp
@@ -0,0 +1,20 @@
+//
+// io_service_strand.hpp
+// ~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_IO_SERVICE_STRAND_HPP
+#define ASIO_IO_SERVICE_STRAND_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/io_context_strand.hpp"
+
+#endif // ASIO_IO_SERVICE_STRAND_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/ip/address.hpp b/link/modules/asio-standalone/asio/include/asio/ip/address.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/ip/address.hpp
@@ -0,0 +1,268 @@
+//
+// ip/address.hpp
+// ~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_IP_ADDRESS_HPP
+#define ASIO_IP_ADDRESS_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <string>
+#include "asio/detail/throw_exception.hpp"
+#include "asio/detail/string_view.hpp"
+#include "asio/detail/type_traits.hpp"
+#include "asio/error_code.hpp"
+#include "asio/ip/address_v4.hpp"
+#include "asio/ip/address_v6.hpp"
+#include "asio/ip/bad_address_cast.hpp"
+
+#if !defined(ASIO_NO_IOSTREAM)
+# include <iosfwd>
+#endif // !defined(ASIO_NO_IOSTREAM)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace ip {
+
+/// Implements version-independent IP addresses.
+/**
+ * The asio::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.
+  ASIO_DECL address() ASIO_NOEXCEPT;
+
+  /// Construct an address from an IPv4 address.
+  ASIO_DECL address(
+      const asio::ip::address_v4& ipv4_address) ASIO_NOEXCEPT;
+
+  /// Construct an address from an IPv6 address.
+  ASIO_DECL address(
+      const asio::ip::address_v6& ipv6_address) ASIO_NOEXCEPT;
+
+  /// Copy constructor.
+  ASIO_DECL address(const address& other) ASIO_NOEXCEPT;
+
+#if defined(ASIO_HAS_MOVE)
+  /// Move constructor.
+  ASIO_DECL address(address&& other) ASIO_NOEXCEPT;
+#endif // defined(ASIO_HAS_MOVE)
+
+  /// Assign from another address.
+  ASIO_DECL address& operator=(const address& other) ASIO_NOEXCEPT;
+
+#if defined(ASIO_HAS_MOVE)
+  /// Move-assign from another address.
+  ASIO_DECL address& operator=(address&& other) ASIO_NOEXCEPT;
+#endif // defined(ASIO_HAS_MOVE)
+
+  /// Assign from an IPv4 address.
+  ASIO_DECL address& operator=(
+      const asio::ip::address_v4& ipv4_address) ASIO_NOEXCEPT;
+
+  /// Assign from an IPv6 address.
+  ASIO_DECL address& operator=(
+      const asio::ip::address_v6& ipv6_address) ASIO_NOEXCEPT;
+
+  /// Get whether the address is an IP version 4 address.
+  bool is_v4() const ASIO_NOEXCEPT
+  {
+    return type_ == ipv4;
+  }
+
+  /// Get whether the address is an IP version 6 address.
+  bool is_v6() const ASIO_NOEXCEPT
+  {
+    return type_ == ipv6;
+  }
+
+  /// Get the address as an IP version 4 address.
+  ASIO_DECL asio::ip::address_v4 to_v4() const;
+
+  /// Get the address as an IP version 6 address.
+  ASIO_DECL asio::ip::address_v6 to_v6() const;
+
+  /// Get the address as a string.
+  ASIO_DECL std::string to_string() const;
+
+#if !defined(ASIO_NO_DEPRECATED)
+  /// (Deprecated: Use other overload.) Get the address as a string.
+  ASIO_DECL std::string to_string(asio::error_code& ec) const;
+
+  /// (Deprecated: Use make_address().) Create an address from an IPv4 address
+  /// string in dotted decimal form, or from an IPv6 address in hexadecimal
+  /// notation.
+  static address from_string(const char* str);
+
+  /// (Deprecated: Use make_address().) Create an address from an IPv4 address
+  /// string in dotted decimal form, or from an IPv6 address in hexadecimal
+  /// notation.
+  static address from_string(const char* str, asio::error_code& ec);
+
+  /// (Deprecated: Use make_address().) Create an address from an IPv4 address
+  /// string in dotted decimal form, or from an IPv6 address in hexadecimal
+  /// notation.
+  static address from_string(const std::string& str);
+
+  /// (Deprecated: Use make_address().) Create an address from an IPv4 address
+  /// string in dotted decimal form, or from an IPv6 address in hexadecimal
+  /// notation.
+  static address from_string(
+      const std::string& str, asio::error_code& ec);
+#endif // !defined(ASIO_NO_DEPRECATED)
+
+  /// Determine whether the address is a loopback address.
+  ASIO_DECL bool is_loopback() const ASIO_NOEXCEPT;
+
+  /// Determine whether the address is unspecified.
+  ASIO_DECL bool is_unspecified() const ASIO_NOEXCEPT;
+
+  /// Determine whether the address is a multicast address.
+  ASIO_DECL bool is_multicast() const ASIO_NOEXCEPT;
+
+  /// Compare two addresses for equality.
+  ASIO_DECL friend bool operator==(const address& a1,
+      const address& a2) ASIO_NOEXCEPT;
+
+  /// Compare two addresses for inequality.
+  friend bool operator!=(const address& a1,
+      const address& a2) ASIO_NOEXCEPT
+  {
+    return !(a1 == a2);
+  }
+
+  /// Compare addresses for ordering.
+  ASIO_DECL friend bool operator<(const address& a1,
+      const address& a2) ASIO_NOEXCEPT;
+
+  /// Compare addresses for ordering.
+  friend bool operator>(const address& a1,
+      const address& a2) ASIO_NOEXCEPT
+  {
+    return a2 < a1;
+  }
+
+  /// Compare addresses for ordering.
+  friend bool operator<=(const address& a1,
+      const address& a2) ASIO_NOEXCEPT
+  {
+    return !(a2 < a1);
+  }
+
+  /// Compare addresses for ordering.
+  friend bool operator>=(const address& a1,
+      const address& a2) ASIO_NOEXCEPT
+  {
+    return !(a1 < a2);
+  }
+
+private:
+  // The type of the address.
+  enum { ipv4, ipv6 } type_;
+
+  // The underlying IPv4 address.
+  asio::ip::address_v4 ipv4_address_;
+
+  // The underlying IPv6 address.
+  asio::ip::address_v6 ipv6_address_;
+};
+
+/// Create an address from an IPv4 address string in dotted decimal form,
+/// or from an IPv6 address in hexadecimal notation.
+/**
+ * @relates address
+ */
+ASIO_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.
+/**
+ * @relates address
+ */
+ASIO_DECL address make_address(const char* str,
+    asio::error_code& ec) ASIO_NOEXCEPT;
+
+/// Create an address from an IPv4 address string in dotted decimal form,
+/// or from an IPv6 address in hexadecimal notation.
+/**
+ * @relates address
+ */
+ASIO_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.
+/**
+ * @relates address
+ */
+ASIO_DECL address make_address(const std::string& str,
+    asio::error_code& ec) ASIO_NOEXCEPT;
+
+#if defined(ASIO_HAS_STRING_VIEW) \
+  || defined(GENERATING_DOCUMENTATION)
+
+/// Create an address from an IPv4 address string in dotted decimal form,
+/// or from an IPv6 address in hexadecimal notation.
+/**
+ * @relates address
+ */
+ASIO_DECL address make_address(string_view str);
+
+/// Create an address from an IPv4 address string in dotted decimal form,
+/// or from an IPv6 address in hexadecimal notation.
+/**
+ * @relates address
+ */
+ASIO_DECL address make_address(string_view str,
+    asio::error_code& ec) ASIO_NOEXCEPT;
+
+#endif // defined(ASIO_HAS_STRING_VIEW)
+       //  || defined(GENERATING_DOCUMENTATION)
+
+#if !defined(ASIO_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 asio::ip::address
+ */
+template <typename Elem, typename Traits>
+std::basic_ostream<Elem, Traits>& operator<<(
+    std::basic_ostream<Elem, Traits>& os, const address& addr);
+
+#endif // !defined(ASIO_NO_IOSTREAM)
+
+} // namespace ip
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/ip/impl/address.hpp"
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/ip/impl/address.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // ASIO_IP_ADDRESS_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/ip/address_v4.hpp b/link/modules/asio-standalone/asio/include/asio/ip/address_v4.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/ip/address_v4.hpp
@@ -0,0 +1,335 @@
+//
+// ip/address_v4.hpp
+// ~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_IP_ADDRESS_V4_HPP
+#define ASIO_IP_ADDRESS_V4_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <string>
+#include "asio/detail/array.hpp"
+#include "asio/detail/cstdint.hpp"
+#include "asio/detail/socket_types.hpp"
+#include "asio/detail/string_view.hpp"
+#include "asio/detail/winsock_init.hpp"
+#include "asio/error_code.hpp"
+
+#if !defined(ASIO_NO_IOSTREAM)
+# include <iosfwd>
+#endif // !defined(ASIO_NO_IOSTREAM)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace ip {
+
+/// Implements IP version 4 style addresses.
+/**
+ * The asio::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:
+  /// The type used to represent an address as an unsigned integer.
+  typedef uint_least32_t uint_type;
+
+  /// The type used to represent an address as an array of bytes.
+  /**
+   * @note This type is defined in terms of the C++0x template @c std::array
+   * when it is available. Otherwise, it uses @c boost:array.
+   */
+#if defined(GENERATING_DOCUMENTATION)
+  typedef array<unsigned char, 4> bytes_type;
+#else
+  typedef asio::detail::array<unsigned char, 4> bytes_type;
+#endif
+
+  /// Default constructor.
+  address_v4() ASIO_NOEXCEPT
+  {
+    addr_.s_addr = 0;
+  }
+
+  /// Construct an address from raw bytes.
+  ASIO_DECL explicit address_v4(const bytes_type& bytes);
+
+  /// Construct an address from an unsigned integer in host byte order.
+  ASIO_DECL explicit address_v4(uint_type addr);
+
+  /// Copy constructor.
+  address_v4(const address_v4& other) ASIO_NOEXCEPT
+    : addr_(other.addr_)
+  {
+  }
+
+#if defined(ASIO_HAS_MOVE)
+  /// Move constructor.
+  address_v4(address_v4&& other) ASIO_NOEXCEPT
+    : addr_(other.addr_)
+  {
+  }
+#endif // defined(ASIO_HAS_MOVE)
+
+  /// Assign from another address.
+  address_v4& operator=(const address_v4& other) ASIO_NOEXCEPT
+  {
+    addr_ = other.addr_;
+    return *this;
+  }
+
+#if defined(ASIO_HAS_MOVE)
+  /// Move-assign from another address.
+  address_v4& operator=(address_v4&& other) ASIO_NOEXCEPT
+  {
+    addr_ = other.addr_;
+    return *this;
+  }
+#endif // defined(ASIO_HAS_MOVE)
+
+  /// Get the address in bytes, in network byte order.
+  ASIO_DECL bytes_type to_bytes() const ASIO_NOEXCEPT;
+
+  /// Get the address as an unsigned integer in host byte order
+  ASIO_DECL uint_type to_uint() const ASIO_NOEXCEPT;
+
+#if !defined(ASIO_NO_DEPRECATED)
+  /// Get the address as an unsigned long in host byte order
+  ASIO_DECL unsigned long to_ulong() const;
+#endif // !defined(ASIO_NO_DEPRECATED)
+
+  /// Get the address as a string in dotted decimal format.
+  ASIO_DECL std::string to_string() const;
+
+#if !defined(ASIO_NO_DEPRECATED)
+  /// (Deprecated: Use other overload.) Get the address as a string in dotted
+  /// decimal format.
+  ASIO_DECL std::string to_string(asio::error_code& ec) const;
+
+  /// (Deprecated: Use make_address_v4().) Create an address from an IP address
+  /// string in dotted decimal form.
+  static address_v4 from_string(const char* str);
+
+  /// (Deprecated: Use make_address_v4().) Create an address from an IP address
+  /// string in dotted decimal form.
+  static address_v4 from_string(
+      const char* str, asio::error_code& ec);
+
+  /// (Deprecated: Use make_address_v4().) Create an address from an IP address
+  /// string in dotted decimal form.
+  static address_v4 from_string(const std::string& str);
+
+  /// (Deprecated: Use make_address_v4().) Create an address from an IP address
+  /// string in dotted decimal form.
+  static address_v4 from_string(
+      const std::string& str, asio::error_code& ec);
+#endif // !defined(ASIO_NO_DEPRECATED)
+
+  /// Determine whether the address is a loopback address.
+  ASIO_DECL bool is_loopback() const ASIO_NOEXCEPT;
+
+  /// Determine whether the address is unspecified.
+  ASIO_DECL bool is_unspecified() const ASIO_NOEXCEPT;
+
+#if !defined(ASIO_NO_DEPRECATED)
+  /// (Deprecated: Use network_v4 class.) Determine whether the address is a
+  /// class A address.
+  ASIO_DECL bool is_class_a() const;
+
+  /// (Deprecated: Use network_v4 class.) Determine whether the address is a
+  /// class B address.
+  ASIO_DECL bool is_class_b() const;
+
+  /// (Deprecated: Use network_v4 class.) Determine whether the address is a
+  /// class C address.
+  ASIO_DECL bool is_class_c() const;
+#endif // !defined(ASIO_NO_DEPRECATED)
+
+  /// Determine whether the address is a multicast address.
+  ASIO_DECL bool is_multicast() const ASIO_NOEXCEPT;
+
+  /// Compare two addresses for equality.
+  friend bool operator==(const address_v4& a1,
+      const address_v4& a2) ASIO_NOEXCEPT
+  {
+    return a1.addr_.s_addr == a2.addr_.s_addr;
+  }
+
+  /// Compare two addresses for inequality.
+  friend bool operator!=(const address_v4& a1,
+      const address_v4& a2) ASIO_NOEXCEPT
+  {
+    return a1.addr_.s_addr != a2.addr_.s_addr;
+  }
+
+  /// Compare addresses for ordering.
+  friend bool operator<(const address_v4& a1,
+      const address_v4& a2) ASIO_NOEXCEPT
+  {
+    return a1.to_uint() < a2.to_uint();
+  }
+
+  /// Compare addresses for ordering.
+  friend bool operator>(const address_v4& a1,
+      const address_v4& a2) ASIO_NOEXCEPT
+  {
+    return a1.to_uint() > a2.to_uint();
+  }
+
+  /// Compare addresses for ordering.
+  friend bool operator<=(const address_v4& a1,
+      const address_v4& a2) ASIO_NOEXCEPT
+  {
+    return a1.to_uint() <= a2.to_uint();
+  }
+
+  /// Compare addresses for ordering.
+  friend bool operator>=(const address_v4& a1,
+      const address_v4& a2) ASIO_NOEXCEPT
+  {
+    return a1.to_uint() >= a2.to_uint();
+  }
+
+  /// Obtain an address object that represents any address.
+  static address_v4 any() ASIO_NOEXCEPT
+  {
+    return address_v4();
+  }
+
+  /// Obtain an address object that represents the loopback address.
+  static address_v4 loopback() ASIO_NOEXCEPT
+  {
+    return address_v4(0x7F000001);
+  }
+
+  /// Obtain an address object that represents the broadcast address.
+  static address_v4 broadcast() ASIO_NOEXCEPT
+  {
+    return address_v4(0xFFFFFFFF);
+  }
+
+#if !defined(ASIO_NO_DEPRECATED)
+  /// (Deprecated: Use network_v4 class.) Obtain an address object that
+  /// represents the broadcast address that corresponds to the specified
+  /// address and netmask.
+  ASIO_DECL static address_v4 broadcast(
+      const address_v4& addr, const address_v4& mask);
+
+  /// (Deprecated: Use network_v4 class.) Obtain the netmask that corresponds
+  /// to the address, based on its address class.
+  ASIO_DECL static address_v4 netmask(const address_v4& addr);
+#endif // !defined(ASIO_NO_DEPRECATED)
+
+private:
+  // The underlying IPv4 address.
+  asio::detail::in4_addr_type addr_;
+};
+
+/// Create an IPv4 address from raw bytes in network order.
+/**
+ * @relates address_v4
+ */
+inline address_v4 make_address_v4(const address_v4::bytes_type& bytes)
+{
+  return address_v4(bytes);
+}
+
+/// Create an IPv4 address from an unsigned integer in host byte order.
+/**
+ * @relates address_v4
+ */
+inline address_v4 make_address_v4(address_v4::uint_type addr)
+{
+  return address_v4(addr);
+}
+
+/// Create an IPv4 address from an IP address string in dotted decimal form.
+/**
+ * @relates address_v4
+ */
+ASIO_DECL address_v4 make_address_v4(const char* str);
+
+/// Create an IPv4 address from an IP address string in dotted decimal form.
+/**
+ * @relates address_v4
+ */
+ASIO_DECL address_v4 make_address_v4(const char* str,
+    asio::error_code& ec) ASIO_NOEXCEPT;
+
+/// Create an IPv4 address from an IP address string in dotted decimal form.
+/**
+ * @relates address_v4
+ */
+ASIO_DECL address_v4 make_address_v4(const std::string& str);
+
+/// Create an IPv4 address from an IP address string in dotted decimal form.
+/**
+ * @relates address_v4
+ */
+ASIO_DECL address_v4 make_address_v4(const std::string& str,
+    asio::error_code& ec) ASIO_NOEXCEPT;
+
+#if defined(ASIO_HAS_STRING_VIEW) \
+  || defined(GENERATING_DOCUMENTATION)
+
+/// Create an IPv4 address from an IP address string in dotted decimal form.
+/**
+ * @relates address_v4
+ */
+ASIO_DECL address_v4 make_address_v4(string_view str);
+
+/// Create an IPv4 address from an IP address string in dotted decimal form.
+/**
+ * @relates address_v4
+ */
+ASIO_DECL address_v4 make_address_v4(string_view str,
+    asio::error_code& ec) ASIO_NOEXCEPT;
+
+#endif // defined(ASIO_HAS_STRING_VIEW)
+       //  || defined(GENERATING_DOCUMENTATION)
+
+#if !defined(ASIO_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 asio::ip::address_v4
+ */
+template <typename Elem, typename Traits>
+std::basic_ostream<Elem, Traits>& operator<<(
+    std::basic_ostream<Elem, Traits>& os, const address_v4& addr);
+
+#endif // !defined(ASIO_NO_IOSTREAM)
+
+} // namespace ip
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/ip/impl/address_v4.hpp"
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/ip/impl/address_v4.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // ASIO_IP_ADDRESS_V4_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/ip/address_v4_iterator.hpp b/link/modules/asio-standalone/asio/include/asio/ip/address_v4_iterator.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/ip/address_v4_iterator.hpp
@@ -0,0 +1,162 @@
+//
+// ip/address_v4_iterator.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_IP_ADDRESS_V4_ITERATOR_HPP
+#define ASIO_IP_ADDRESS_V4_ITERATOR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/ip/address_v4.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace ip {
+
+template <typename> class basic_address_iterator;
+
+/// An input iterator that can be used for traversing IPv4 addresses.
+/**
+ * In addition to satisfying the input iterator requirements, this iterator
+ * also supports decrement.
+ *
+ * @par Thread Safety
+ * @e Distinct @e objects: Safe.@n
+ * @e Shared @e objects: Unsafe.
+ */
+template <> class basic_address_iterator<address_v4>
+{
+public:
+  /// The type of the elements pointed to by the iterator.
+  typedef address_v4 value_type;
+
+  /// Distance between two iterators.
+  typedef std::ptrdiff_t difference_type;
+
+  /// The type of a pointer to an element pointed to by the iterator.
+  typedef const address_v4* pointer;
+
+  /// The type of a reference to an element pointed to by the iterator.
+  typedef const address_v4& reference;
+
+  /// Denotes that the iterator satisfies the input iterator requirements.
+  typedef std::input_iterator_tag iterator_category;
+
+  /// Construct an iterator that points to the specified address.
+  basic_address_iterator(const address_v4& addr) ASIO_NOEXCEPT
+    : address_(addr)
+  {
+  }
+
+  /// Copy constructor.
+  basic_address_iterator(
+      const basic_address_iterator& other) ASIO_NOEXCEPT
+    : address_(other.address_)
+  {
+  }
+
+#if defined(ASIO_HAS_MOVE)
+  /// Move constructor.
+  basic_address_iterator(basic_address_iterator&& other) ASIO_NOEXCEPT
+    : address_(ASIO_MOVE_CAST(address_v4)(other.address_))
+  {
+  }
+#endif // defined(ASIO_HAS_MOVE)
+
+  /// Assignment operator.
+  basic_address_iterator& operator=(
+      const basic_address_iterator& other) ASIO_NOEXCEPT
+  {
+    address_ = other.address_;
+    return *this;
+  }
+
+#if defined(ASIO_HAS_MOVE)
+  /// Move assignment operator.
+  basic_address_iterator& operator=(
+      basic_address_iterator&& other) ASIO_NOEXCEPT
+  {
+    address_ = ASIO_MOVE_CAST(address_v4)(other.address_);
+    return *this;
+  }
+#endif // defined(ASIO_HAS_MOVE)
+
+  /// Dereference the iterator.
+  const address_v4& operator*() const ASIO_NOEXCEPT
+  {
+    return address_;
+  }
+
+  /// Dereference the iterator.
+  const address_v4* operator->() const ASIO_NOEXCEPT
+  {
+    return &address_;
+  }
+
+  /// Pre-increment operator.
+  basic_address_iterator& operator++() ASIO_NOEXCEPT
+  {
+    address_ = address_v4((address_.to_uint() + 1) & 0xFFFFFFFF);
+    return *this;
+  }
+
+  /// Post-increment operator.
+  basic_address_iterator operator++(int) ASIO_NOEXCEPT
+  {
+    basic_address_iterator tmp(*this);
+    ++*this;
+    return tmp;
+  }
+
+  /// Pre-decrement operator.
+  basic_address_iterator& operator--() ASIO_NOEXCEPT
+  {
+    address_ = address_v4((address_.to_uint() - 1) & 0xFFFFFFFF);
+    return *this;
+  }
+
+  /// Post-decrement operator.
+  basic_address_iterator operator--(int)
+  {
+    basic_address_iterator tmp(*this);
+    --*this;
+    return tmp;
+  }
+
+  /// Compare two addresses for equality.
+  friend bool operator==(const basic_address_iterator& a,
+      const basic_address_iterator& b)
+  {
+    return a.address_ == b.address_;
+  }
+
+  /// Compare two addresses for inequality.
+  friend bool operator!=(const basic_address_iterator& a,
+      const basic_address_iterator& b)
+  {
+    return a.address_ != b.address_;
+  }
+
+private:
+  address_v4 address_;
+};
+
+/// An input iterator that can be used for traversing IPv4 addresses.
+typedef basic_address_iterator<address_v4> address_v4_iterator;
+
+} // namespace ip
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IP_ADDRESS_V4_ITERATOR_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/ip/address_v4_range.hpp b/link/modules/asio-standalone/asio/include/asio/ip/address_v4_range.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/ip/address_v4_range.hpp
@@ -0,0 +1,134 @@
+//
+// ip/address_v4_range.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_IP_ADDRESS_V4_RANGE_HPP
+#define ASIO_IP_ADDRESS_V4_RANGE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/ip/address_v4_iterator.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace ip {
+
+template <typename> class basic_address_range;
+
+/// Represents a range of IPv4 addresses.
+/**
+ * @par Thread Safety
+ * @e Distinct @e objects: Safe.@n
+ * @e Shared @e objects: Unsafe.
+ */
+template <> class basic_address_range<address_v4>
+{
+public:
+  /// The type of an iterator that points into the range.
+  typedef basic_address_iterator<address_v4> iterator;
+
+  /// Construct an empty range.
+  basic_address_range() ASIO_NOEXCEPT
+    : begin_(address_v4()),
+      end_(address_v4())
+  {
+  }
+
+  /// Construct an range that represents the given range of addresses.
+  explicit basic_address_range(const iterator& first,
+      const iterator& last) ASIO_NOEXCEPT
+    : begin_(first),
+      end_(last)
+  {
+  }
+
+  /// Copy constructor.
+  basic_address_range(const basic_address_range& other) ASIO_NOEXCEPT
+    : begin_(other.begin_),
+      end_(other.end_)
+  {
+  }
+
+#if defined(ASIO_HAS_MOVE)
+  /// Move constructor.
+  basic_address_range(basic_address_range&& other) ASIO_NOEXCEPT
+    : begin_(ASIO_MOVE_CAST(iterator)(other.begin_)),
+      end_(ASIO_MOVE_CAST(iterator)(other.end_))
+  {
+  }
+#endif // defined(ASIO_HAS_MOVE)
+
+  /// Assignment operator.
+  basic_address_range& operator=(
+      const basic_address_range& other) ASIO_NOEXCEPT
+  {
+    begin_ = other.begin_;
+    end_ = other.end_;
+    return *this;
+  }
+
+#if defined(ASIO_HAS_MOVE)
+  /// Move assignment operator.
+  basic_address_range& operator=(
+      basic_address_range&& other) ASIO_NOEXCEPT
+  {
+    begin_ = ASIO_MOVE_CAST(iterator)(other.begin_);
+    end_ = ASIO_MOVE_CAST(iterator)(other.end_);
+    return *this;
+  }
+#endif // defined(ASIO_HAS_MOVE)
+
+  /// Obtain an iterator that points to the start of the range.
+  iterator begin() const ASIO_NOEXCEPT
+  {
+    return begin_;
+  }
+
+  /// Obtain an iterator that points to the end of the range.
+  iterator end() const ASIO_NOEXCEPT
+  {
+    return end_;
+  }
+
+  /// Determine whether the range is empty.
+  bool empty() const ASIO_NOEXCEPT
+  {
+    return size() == 0;
+  }
+
+  /// Return the size of the range.
+  std::size_t size() const ASIO_NOEXCEPT
+  {
+    return end_->to_uint() - begin_->to_uint();
+  }
+
+  /// Find an address in the range.
+  iterator find(const address_v4& addr) const ASIO_NOEXCEPT
+  {
+    return addr >= *begin_ && addr < *end_ ? iterator(addr) : end_;
+  }
+
+private:
+  iterator begin_;
+  iterator end_;
+};
+
+/// Represents a range of IPv4 addresses.
+typedef basic_address_range<address_v4> address_v4_range;
+
+} // namespace ip
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IP_ADDRESS_V4_RANGE_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/ip/address_v6.hpp b/link/modules/asio-standalone/asio/include/asio/ip/address_v6.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/ip/address_v6.hpp
@@ -0,0 +1,341 @@
+//
+// ip/address_v6.hpp
+// ~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_IP_ADDRESS_V6_HPP
+#define ASIO_IP_ADDRESS_V6_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <string>
+#include "asio/detail/array.hpp"
+#include "asio/detail/socket_types.hpp"
+#include "asio/detail/string_view.hpp"
+#include "asio/detail/winsock_init.hpp"
+#include "asio/error_code.hpp"
+#include "asio/ip/address_v4.hpp"
+
+#if !defined(ASIO_NO_IOSTREAM)
+# include <iosfwd>
+#endif // !defined(ASIO_NO_IOSTREAM)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace ip {
+
+template <typename> class basic_address_iterator;
+
+/// Implements IP version 6 style addresses.
+/**
+ * The asio::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:
+  /// The type used to represent an address as an array of bytes.
+  /**
+   * @note This type is defined in terms of the C++0x template @c std::array
+   * when it is available. Otherwise, it uses @c boost:array.
+   */
+#if defined(GENERATING_DOCUMENTATION)
+  typedef array<unsigned char, 16> bytes_type;
+#else
+  typedef asio::detail::array<unsigned char, 16> bytes_type;
+#endif
+
+  /// Default constructor.
+  ASIO_DECL address_v6() ASIO_NOEXCEPT;
+
+  /// Construct an address from raw bytes and scope ID.
+  ASIO_DECL explicit address_v6(const bytes_type& bytes,
+      unsigned long scope_id = 0);
+
+  /// Copy constructor.
+  ASIO_DECL address_v6(const address_v6& other) ASIO_NOEXCEPT;
+
+#if defined(ASIO_HAS_MOVE)
+  /// Move constructor.
+  ASIO_DECL address_v6(address_v6&& other) ASIO_NOEXCEPT;
+#endif // defined(ASIO_HAS_MOVE)
+
+  /// Assign from another address.
+  ASIO_DECL address_v6& operator=(
+      const address_v6& other) ASIO_NOEXCEPT;
+
+#if defined(ASIO_HAS_MOVE)
+  /// Move-assign from another address.
+  ASIO_DECL address_v6& operator=(address_v6&& other) ASIO_NOEXCEPT;
+#endif // defined(ASIO_HAS_MOVE)
+
+  /// The scope ID of the address.
+  /**
+   * Returns the scope ID associated with the IPv6 address.
+   */
+  unsigned long scope_id() const ASIO_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) ASIO_NOEXCEPT
+  {
+    scope_id_ = id;
+  }
+
+  /// Get the address in bytes, in network byte order.
+  ASIO_DECL bytes_type to_bytes() const ASIO_NOEXCEPT;
+
+  /// Get the address as a string.
+  ASIO_DECL std::string to_string() const;
+
+#if !defined(ASIO_NO_DEPRECATED)
+  /// (Deprecated: Use other overload.) Get the address as a string.
+  ASIO_DECL std::string to_string(asio::error_code& ec) const;
+
+  /// (Deprecated: Use make_address_v6().) Create an IPv6 address from an IP
+  /// address string.
+  static address_v6 from_string(const char* str);
+
+  /// (Deprecated: Use make_address_v6().) Create an IPv6 address from an IP
+  /// address string.
+  static address_v6 from_string(
+      const char* str, asio::error_code& ec);
+
+  /// (Deprecated: Use make_address_v6().) Create an IPv6 address from an IP
+  /// address string.
+  static address_v6 from_string(const std::string& str);
+
+  /// (Deprecated: Use make_address_v6().) Create an IPv6 address from an IP
+  /// address string.
+  static address_v6 from_string(
+      const std::string& str, asio::error_code& ec);
+
+  /// (Deprecated: Use make_address_v4().) Converts an IPv4-mapped or
+  /// IPv4-compatible address to an IPv4 address.
+  ASIO_DECL address_v4 to_v4() const;
+#endif // !defined(ASIO_NO_DEPRECATED)
+
+  /// Determine whether the address is a loopback address.
+  ASIO_DECL bool is_loopback() const ASIO_NOEXCEPT;
+
+  /// Determine whether the address is unspecified.
+  ASIO_DECL bool is_unspecified() const ASIO_NOEXCEPT;
+
+  /// Determine whether the address is link local.
+  ASIO_DECL bool is_link_local() const ASIO_NOEXCEPT;
+
+  /// Determine whether the address is site local.
+  ASIO_DECL bool is_site_local() const ASIO_NOEXCEPT;
+
+  /// Determine whether the address is a mapped IPv4 address.
+  ASIO_DECL bool is_v4_mapped() const ASIO_NOEXCEPT;
+
+#if !defined(ASIO_NO_DEPRECATED)
+  /// (Deprecated: No replacement.) Determine whether the address is an
+  /// IPv4-compatible address.
+  ASIO_DECL bool is_v4_compatible() const;
+#endif // !defined(ASIO_NO_DEPRECATED)
+
+  /// Determine whether the address is a multicast address.
+  ASIO_DECL bool is_multicast() const ASIO_NOEXCEPT;
+
+  /// Determine whether the address is a global multicast address.
+  ASIO_DECL bool is_multicast_global() const ASIO_NOEXCEPT;
+
+  /// Determine whether the address is a link-local multicast address.
+  ASIO_DECL bool is_multicast_link_local() const ASIO_NOEXCEPT;
+
+  /// Determine whether the address is a node-local multicast address.
+  ASIO_DECL bool is_multicast_node_local() const ASIO_NOEXCEPT;
+
+  /// Determine whether the address is a org-local multicast address.
+  ASIO_DECL bool is_multicast_org_local() const ASIO_NOEXCEPT;
+
+  /// Determine whether the address is a site-local multicast address.
+  ASIO_DECL bool is_multicast_site_local() const ASIO_NOEXCEPT;
+
+  /// Compare two addresses for equality.
+  ASIO_DECL friend bool operator==(const address_v6& a1,
+      const address_v6& a2) ASIO_NOEXCEPT;
+
+  /// Compare two addresses for inequality.
+  friend bool operator!=(const address_v6& a1,
+      const address_v6& a2) ASIO_NOEXCEPT
+  {
+    return !(a1 == a2);
+  }
+
+  /// Compare addresses for ordering.
+  ASIO_DECL friend bool operator<(const address_v6& a1,
+      const address_v6& a2) ASIO_NOEXCEPT;
+
+  /// Compare addresses for ordering.
+  friend bool operator>(const address_v6& a1,
+      const address_v6& a2) ASIO_NOEXCEPT
+  {
+    return a2 < a1;
+  }
+
+  /// Compare addresses for ordering.
+  friend bool operator<=(const address_v6& a1,
+      const address_v6& a2) ASIO_NOEXCEPT
+  {
+    return !(a2 < a1);
+  }
+
+  /// Compare addresses for ordering.
+  friend bool operator>=(const address_v6& a1,
+      const address_v6& a2) ASIO_NOEXCEPT
+  {
+    return !(a1 < a2);
+  }
+
+  /// Obtain an address object that represents any address.
+  static address_v6 any() ASIO_NOEXCEPT
+  {
+    return address_v6();
+  }
+
+  /// Obtain an address object that represents the loopback address.
+  ASIO_DECL static address_v6 loopback() ASIO_NOEXCEPT;
+
+#if !defined(ASIO_NO_DEPRECATED)
+  /// (Deprecated: Use make_address_v6().) Create an IPv4-mapped IPv6 address.
+  ASIO_DECL static address_v6 v4_mapped(const address_v4& addr);
+
+  /// (Deprecated: No replacement.) Create an IPv4-compatible IPv6 address.
+  ASIO_DECL static address_v6 v4_compatible(const address_v4& addr);
+#endif // !defined(ASIO_NO_DEPRECATED)
+
+private:
+  friend class basic_address_iterator<address_v6>;
+
+  // The underlying IPv6 address.
+  asio::detail::in6_addr_type addr_;
+
+  // The scope ID associated with the address.
+  unsigned long scope_id_;
+};
+
+/// Create an IPv6 address from raw bytes and scope ID.
+/**
+ * @relates address_v6
+ */
+inline address_v6 make_address_v6(const address_v6::bytes_type& bytes,
+    unsigned long scope_id = 0)
+{
+  return address_v6(bytes, scope_id);
+}
+
+/// Create an IPv6 address from an IP address string.
+/**
+ * @relates address_v6
+ */
+ASIO_DECL address_v6 make_address_v6(const char* str);
+
+/// Create an IPv6 address from an IP address string.
+/**
+ * @relates address_v6
+ */
+ASIO_DECL address_v6 make_address_v6(const char* str,
+    asio::error_code& ec) ASIO_NOEXCEPT;
+
+/// Createan IPv6 address from an IP address string.
+/**
+ * @relates address_v6
+ */
+ASIO_DECL address_v6 make_address_v6(const std::string& str);
+
+/// Create an IPv6 address from an IP address string.
+/**
+ * @relates address_v6
+ */
+ASIO_DECL address_v6 make_address_v6(const std::string& str,
+    asio::error_code& ec) ASIO_NOEXCEPT;
+
+#if defined(ASIO_HAS_STRING_VIEW) \
+  || defined(GENERATING_DOCUMENTATION)
+
+/// Create an IPv6 address from an IP address string.
+/**
+ * @relates address_v6
+ */
+ASIO_DECL address_v6 make_address_v6(string_view str);
+
+/// Create an IPv6 address from an IP address string.
+/**
+ * @relates address_v6
+ */
+ASIO_DECL address_v6 make_address_v6(string_view str,
+    asio::error_code& ec) ASIO_NOEXCEPT;
+
+#endif // defined(ASIO_HAS_STRING_VIEW)
+       //  || defined(GENERATING_DOCUMENTATION)
+
+/// Tag type used for distinguishing overloads that deal in IPv4-mapped IPv6
+/// addresses.
+enum v4_mapped_t { v4_mapped };
+
+/// Create an IPv4 address from a IPv4-mapped IPv6 address.
+/**
+ * @relates address_v4
+ */
+ASIO_DECL address_v4 make_address_v4(
+    v4_mapped_t, const address_v6& v6_addr);
+
+/// Create an IPv4-mapped IPv6 address from an IPv4 address.
+/**
+ * @relates address_v6
+ */
+ASIO_DECL address_v6 make_address_v6(
+    v4_mapped_t, const address_v4& v4_addr);
+
+#if !defined(ASIO_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 asio::ip::address_v6
+ */
+template <typename Elem, typename Traits>
+std::basic_ostream<Elem, Traits>& operator<<(
+    std::basic_ostream<Elem, Traits>& os, const address_v6& addr);
+
+#endif // !defined(ASIO_NO_IOSTREAM)
+
+} // namespace ip
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/ip/impl/address_v6.hpp"
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/ip/impl/address_v6.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // ASIO_IP_ADDRESS_V6_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/ip/address_v6_iterator.hpp b/link/modules/asio-standalone/asio/include/asio/ip/address_v6_iterator.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/ip/address_v6_iterator.hpp
@@ -0,0 +1,183 @@
+//
+// ip/address_v6_iterator.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//                         Oliver Kowalke (oliver dot kowalke at gmail 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 ASIO_IP_ADDRESS_V6_ITERATOR_HPP
+#define ASIO_IP_ADDRESS_V6_ITERATOR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/ip/address_v6.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace ip {
+
+template <typename> class basic_address_iterator;
+
+/// An input iterator that can be used for traversing IPv6 addresses.
+/**
+ * In addition to satisfying the input iterator requirements, this iterator
+ * also supports decrement.
+ *
+ * @par Thread Safety
+ * @e Distinct @e objects: Safe.@n
+ * @e Shared @e objects: Unsafe.
+ */
+template <> class basic_address_iterator<address_v6>
+{
+public:
+  /// The type of the elements pointed to by the iterator.
+  typedef address_v6 value_type;
+
+  /// Distance between two iterators.
+  typedef std::ptrdiff_t difference_type;
+
+  /// The type of a pointer to an element pointed to by the iterator.
+  typedef const address_v6* pointer;
+
+  /// The type of a reference to an element pointed to by the iterator.
+  typedef const address_v6& reference;
+
+  /// Denotes that the iterator satisfies the input iterator requirements.
+  typedef std::input_iterator_tag iterator_category;
+
+  /// Construct an iterator that points to the specified address.
+  basic_address_iterator(const address_v6& addr) ASIO_NOEXCEPT
+    : address_(addr)
+  {
+  }
+
+  /// Copy constructor.
+  basic_address_iterator(
+      const basic_address_iterator& other) ASIO_NOEXCEPT
+    : address_(other.address_)
+  {
+  }
+
+#if defined(ASIO_HAS_MOVE)
+  /// Move constructor.
+  basic_address_iterator(basic_address_iterator&& other) ASIO_NOEXCEPT
+    : address_(ASIO_MOVE_CAST(address_v6)(other.address_))
+  {
+  }
+#endif // defined(ASIO_HAS_MOVE)
+
+  /// Assignment operator.
+  basic_address_iterator& operator=(
+      const basic_address_iterator& other) ASIO_NOEXCEPT
+  {
+    address_ = other.address_;
+    return *this;
+  }
+
+#if defined(ASIO_HAS_MOVE)
+  /// Move assignment operator.
+  basic_address_iterator& operator=(
+      basic_address_iterator&& other) ASIO_NOEXCEPT
+  {
+    address_ = ASIO_MOVE_CAST(address_v6)(other.address_);
+    return *this;
+  }
+#endif // defined(ASIO_HAS_MOVE)
+
+  /// Dereference the iterator.
+  const address_v6& operator*() const ASIO_NOEXCEPT
+  {
+    return address_;
+  }
+
+  /// Dereference the iterator.
+  const address_v6* operator->() const ASIO_NOEXCEPT
+  {
+    return &address_;
+  }
+
+  /// Pre-increment operator.
+  basic_address_iterator& operator++() ASIO_NOEXCEPT
+  {
+    for (int i = 15; i >= 0; --i)
+    {
+      if (address_.addr_.s6_addr[i] < 0xFF)
+      {
+        ++address_.addr_.s6_addr[i];
+        break;
+      }
+
+      address_.addr_.s6_addr[i] = 0;
+    }
+
+    return *this;
+  }
+
+  /// Post-increment operator.
+  basic_address_iterator operator++(int) ASIO_NOEXCEPT
+  {
+    basic_address_iterator tmp(*this);
+    ++*this;
+    return tmp;
+  }
+
+  /// Pre-decrement operator.
+  basic_address_iterator& operator--() ASIO_NOEXCEPT
+  {
+    for (int i = 15; i >= 0; --i)
+    {
+      if (address_.addr_.s6_addr[i] > 0)
+      {
+        --address_.addr_.s6_addr[i];
+        break;
+      }
+
+      address_.addr_.s6_addr[i] = 0xFF;
+    }
+
+    return *this;
+  }
+
+  /// Post-decrement operator.
+  basic_address_iterator operator--(int)
+  {
+    basic_address_iterator tmp(*this);
+    --*this;
+    return tmp;
+  }
+
+  /// Compare two addresses for equality.
+  friend bool operator==(const basic_address_iterator& a,
+      const basic_address_iterator& b)
+  {
+    return a.address_ == b.address_;
+  }
+
+  /// Compare two addresses for inequality.
+  friend bool operator!=(const basic_address_iterator& a,
+      const basic_address_iterator& b)
+  {
+    return a.address_ != b.address_;
+  }
+
+private:
+  address_v6 address_;
+};
+
+/// An input iterator that can be used for traversing IPv6 addresses.
+typedef basic_address_iterator<address_v6> address_v6_iterator;
+
+} // namespace ip
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IP_ADDRESS_V6_ITERATOR_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/ip/address_v6_range.hpp b/link/modules/asio-standalone/asio/include/asio/ip/address_v6_range.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/ip/address_v6_range.hpp
@@ -0,0 +1,129 @@
+//
+// ip/address_v6_range.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//                         Oliver Kowalke (oliver dot kowalke at gmail 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 ASIO_IP_ADDRESS_V6_RANGE_HPP
+#define ASIO_IP_ADDRESS_V6_RANGE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/ip/address_v6_iterator.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace ip {
+
+template <typename> class basic_address_range;
+
+/// Represents a range of IPv6 addresses.
+/**
+ * @par Thread Safety
+ * @e Distinct @e objects: Safe.@n
+ * @e Shared @e objects: Unsafe.
+ */
+template <> class basic_address_range<address_v6>
+{
+public:
+  /// The type of an iterator that points into the range.
+  typedef basic_address_iterator<address_v6> iterator;
+
+  /// Construct an empty range.
+  basic_address_range() ASIO_NOEXCEPT
+    : begin_(address_v6()),
+      end_(address_v6())
+  {
+  }
+
+  /// Construct an range that represents the given range of addresses.
+  explicit basic_address_range(const iterator& first,
+      const iterator& last) ASIO_NOEXCEPT
+    : begin_(first),
+      end_(last)
+  {
+  }
+
+  /// Copy constructor.
+  basic_address_range(const basic_address_range& other) ASIO_NOEXCEPT
+    : begin_(other.begin_),
+      end_(other.end_)
+  {
+  }
+
+#if defined(ASIO_HAS_MOVE)
+  /// Move constructor.
+  basic_address_range(basic_address_range&& other) ASIO_NOEXCEPT
+    : begin_(ASIO_MOVE_CAST(iterator)(other.begin_)),
+      end_(ASIO_MOVE_CAST(iterator)(other.end_))
+  {
+  }
+#endif // defined(ASIO_HAS_MOVE)
+
+  /// Assignment operator.
+  basic_address_range& operator=(
+      const basic_address_range& other) ASIO_NOEXCEPT
+  {
+    begin_ = other.begin_;
+    end_ = other.end_;
+    return *this;
+  }
+
+#if defined(ASIO_HAS_MOVE)
+  /// Move assignment operator.
+  basic_address_range& operator=(
+      basic_address_range&& other) ASIO_NOEXCEPT
+  {
+    begin_ = ASIO_MOVE_CAST(iterator)(other.begin_);
+    end_ = ASIO_MOVE_CAST(iterator)(other.end_);
+    return *this;
+  }
+#endif // defined(ASIO_HAS_MOVE)
+
+  /// Obtain an iterator that points to the start of the range.
+  iterator begin() const ASIO_NOEXCEPT
+  {
+    return begin_;
+  }
+
+  /// Obtain an iterator that points to the end of the range.
+  iterator end() const ASIO_NOEXCEPT
+  {
+    return end_;
+  }
+
+  /// Determine whether the range is empty.
+  bool empty() const ASIO_NOEXCEPT
+  {
+    return begin_ == end_;
+  }
+
+  /// Find an address in the range.
+  iterator find(const address_v6& addr) const ASIO_NOEXCEPT
+  {
+    return addr >= *begin_ && addr < *end_ ? iterator(addr) : end_;
+  }
+
+private:
+  iterator begin_;
+  iterator end_;
+};
+
+/// Represents a range of IPv6 addresses.
+typedef basic_address_range<address_v6> address_v6_range;
+
+} // namespace ip
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IP_ADDRESS_V6_RANGE_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/ip/bad_address_cast.hpp b/link/modules/asio-standalone/asio/include/asio/ip/bad_address_cast.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/ip/bad_address_cast.hpp
@@ -0,0 +1,53 @@
+//
+// ip/bad_address_cast.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_IP_BAD_ADDRESS_CAST_HPP
+#define ASIO_IP_BAD_ADDRESS_CAST_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <typeinfo>
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace ip {
+
+/// Thrown to indicate a failed address conversion.
+class bad_address_cast :
+#if defined(ASIO_MSVC) && defined(_HAS_EXCEPTIONS) && !_HAS_EXCEPTIONS
+  public std::exception
+#else
+  public std::bad_cast
+#endif
+{
+public:
+  /// Default constructor.
+  bad_address_cast() {}
+
+  /// Destructor.
+  virtual ~bad_address_cast() ASIO_NOEXCEPT_OR_NOTHROW {}
+
+  /// Get the message associated with the exception.
+  virtual const char* what() const ASIO_NOEXCEPT_OR_NOTHROW
+  {
+    return "bad address cast";
+  }
+};
+
+} // namespace ip
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IP_ADDRESS_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/ip/basic_endpoint.hpp b/link/modules/asio-standalone/asio/include/asio/ip/basic_endpoint.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/ip/basic_endpoint.hpp
@@ -0,0 +1,264 @@
+//
+// ip/basic_endpoint.hpp
+// ~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_IP_BASIC_ENDPOINT_HPP
+#define ASIO_IP_BASIC_ENDPOINT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/ip/address.hpp"
+#include "asio/ip/detail/endpoint.hpp"
+
+#if !defined(ASIO_NO_IOSTREAM)
+# include <iosfwd>
+#endif // !defined(ASIO_NO_IOSTREAM)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace ip {
+
+/// Describes an endpoint for a version-independent IP socket.
+/**
+ * The asio::ip::basic_endpoint class template describes an endpoint that
+ * may be associated with a particular socket.
+ *
+ * @par Thread Safety
+ * @e Distinct @e objects: Safe.@n
+ * @e Shared @e objects: Unsafe.
+ *
+ * @par Concepts:
+ * Endpoint.
+ */
+template <typename InternetProtocol>
+class basic_endpoint
+{
+public:
+  /// The protocol type associated with the endpoint.
+  typedef InternetProtocol protocol_type;
+
+  /// The type of the endpoint structure. This type is dependent on the
+  /// underlying implementation of the socket layer.
+#if defined(GENERATING_DOCUMENTATION)
+  typedef implementation_defined data_type;
+#else
+  typedef asio::detail::socket_addr_type data_type;
+#endif
+
+  /// Default constructor.
+  basic_endpoint() ASIO_NOEXCEPT
+    : impl_()
+  {
+  }
+
+  /// Construct an endpoint using a port number, specified in the host's byte
+  /// order. The IP address will be the any address (i.e. INADDR_ANY or
+  /// in6addr_any). This constructor would typically be used for accepting new
+  /// connections.
+  /**
+   * @par Examples
+   * To initialise an IPv4 TCP endpoint for port 1234, use:
+   * @code
+   * asio::ip::tcp::endpoint ep(asio::ip::tcp::v4(), 1234);
+   * @endcode
+   *
+   * To specify an IPv6 UDP endpoint for port 9876, use:
+   * @code
+   * asio::ip::udp::endpoint ep(asio::ip::udp::v6(), 9876);
+   * @endcode
+   */
+  basic_endpoint(const InternetProtocol& internet_protocol,
+      unsigned short port_num) ASIO_NOEXCEPT
+    : impl_(internet_protocol.family(), port_num)
+  {
+  }
+
+  /// Construct an endpoint using a port number and an IP address. This
+  /// constructor may be used for accepting connections on a specific interface
+  /// or for making a connection to a remote endpoint.
+  basic_endpoint(const asio::ip::address& addr,
+      unsigned short port_num) ASIO_NOEXCEPT
+    : impl_(addr, port_num)
+  {
+  }
+
+  /// Copy constructor.
+  basic_endpoint(const basic_endpoint& other) ASIO_NOEXCEPT
+    : impl_(other.impl_)
+  {
+  }
+
+#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+  /// Move constructor.
+  basic_endpoint(basic_endpoint&& other) ASIO_NOEXCEPT
+    : impl_(other.impl_)
+  {
+  }
+#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+
+  /// Assign from another endpoint.
+  basic_endpoint& operator=(const basic_endpoint& other) ASIO_NOEXCEPT
+  {
+    impl_ = other.impl_;
+    return *this;
+  }
+
+#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+  /// Move-assign from another endpoint.
+  basic_endpoint& operator=(basic_endpoint&& other) ASIO_NOEXCEPT
+  {
+    impl_ = other.impl_;
+    return *this;
+  }
+#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+
+  /// The protocol associated with the endpoint.
+  protocol_type protocol() const ASIO_NOEXCEPT
+  {
+    if (impl_.is_v4())
+      return InternetProtocol::v4();
+    return InternetProtocol::v6();
+  }
+
+  /// Get the underlying endpoint in the native type.
+  data_type* data() ASIO_NOEXCEPT
+  {
+    return impl_.data();
+  }
+
+  /// Get the underlying endpoint in the native type.
+  const data_type* data() const ASIO_NOEXCEPT
+  {
+    return impl_.data();
+  }
+
+  /// Get the underlying size of the endpoint in the native type.
+  std::size_t size() const ASIO_NOEXCEPT
+  {
+    return impl_.size();
+  }
+
+  /// Set the underlying size of the endpoint in the native type.
+  void resize(std::size_t new_size)
+  {
+    impl_.resize(new_size);
+  }
+
+  /// Get the capacity of the endpoint in the native type.
+  std::size_t capacity() const ASIO_NOEXCEPT
+  {
+    return impl_.capacity();
+  }
+
+  /// Get the port associated with the endpoint. The port number is always in
+  /// the host's byte order.
+  unsigned short port() const ASIO_NOEXCEPT
+  {
+    return impl_.port();
+  }
+
+  /// Set the port associated with the endpoint. The port number is always in
+  /// the host's byte order.
+  void port(unsigned short port_num) ASIO_NOEXCEPT
+  {
+    impl_.port(port_num);
+  }
+
+  /// Get the IP address associated with the endpoint.
+  asio::ip::address address() const ASIO_NOEXCEPT
+  {
+    return impl_.address();
+  }
+
+  /// Set the IP address associated with the endpoint.
+  void address(const asio::ip::address& addr) ASIO_NOEXCEPT
+  {
+    impl_.address(addr);
+  }
+
+  /// Compare two endpoints for equality.
+  friend bool operator==(const basic_endpoint<InternetProtocol>& e1,
+      const basic_endpoint<InternetProtocol>& e2) ASIO_NOEXCEPT
+  {
+    return e1.impl_ == e2.impl_;
+  }
+
+  /// Compare two endpoints for inequality.
+  friend bool operator!=(const basic_endpoint<InternetProtocol>& e1,
+      const basic_endpoint<InternetProtocol>& e2) ASIO_NOEXCEPT
+  {
+    return !(e1 == e2);
+  }
+
+  /// Compare endpoints for ordering.
+  friend bool operator<(const basic_endpoint<InternetProtocol>& e1,
+      const basic_endpoint<InternetProtocol>& e2) ASIO_NOEXCEPT
+  {
+    return e1.impl_ < e2.impl_;
+  }
+
+  /// Compare endpoints for ordering.
+  friend bool operator>(const basic_endpoint<InternetProtocol>& e1,
+      const basic_endpoint<InternetProtocol>& e2) ASIO_NOEXCEPT
+  {
+    return e2.impl_ < e1.impl_;
+  }
+
+  /// Compare endpoints for ordering.
+  friend bool operator<=(const basic_endpoint<InternetProtocol>& e1,
+      const basic_endpoint<InternetProtocol>& e2) ASIO_NOEXCEPT
+  {
+    return !(e2 < e1);
+  }
+
+  /// Compare endpoints for ordering.
+  friend bool operator>=(const basic_endpoint<InternetProtocol>& e1,
+      const basic_endpoint<InternetProtocol>& e2) ASIO_NOEXCEPT
+  {
+    return !(e1 < e2);
+  }
+
+private:
+  // The underlying IP endpoint.
+  asio::ip::detail::endpoint impl_;
+};
+
+#if !defined(ASIO_NO_IOSTREAM)
+
+/// Output an endpoint as a string.
+/**
+ * Used to output a human-readable string for a specified endpoint.
+ *
+ * @param os The output stream to which the string will be written.
+ *
+ * @param endpoint The endpoint to be written.
+ *
+ * @return The output stream.
+ *
+ * @relates asio::ip::basic_endpoint
+ */
+template <typename Elem, typename Traits, typename InternetProtocol>
+std::basic_ostream<Elem, Traits>& operator<<(
+    std::basic_ostream<Elem, Traits>& os,
+    const basic_endpoint<InternetProtocol>& endpoint);
+
+#endif // !defined(ASIO_NO_IOSTREAM)
+
+} // namespace ip
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/ip/impl/basic_endpoint.hpp"
+
+#endif // ASIO_IP_BASIC_ENDPOINT_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/ip/basic_resolver.hpp b/link/modules/asio-standalone/asio/include/asio/ip/basic_resolver.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/ip/basic_resolver.hpp
@@ -0,0 +1,1030 @@
+//
+// ip/basic_resolver.hpp
+// ~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_IP_BASIC_RESOLVER_HPP
+#define ASIO_IP_BASIC_RESOLVER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <string>
+#include "asio/any_io_executor.hpp"
+#include "asio/async_result.hpp"
+#include "asio/detail/handler_type_requirements.hpp"
+#include "asio/detail/io_object_impl.hpp"
+#include "asio/detail/non_const_lvalue.hpp"
+#include "asio/detail/string_view.hpp"
+#include "asio/detail/throw_error.hpp"
+#include "asio/error.hpp"
+#include "asio/execution_context.hpp"
+#include "asio/ip/basic_resolver_iterator.hpp"
+#include "asio/ip/basic_resolver_query.hpp"
+#include "asio/ip/basic_resolver_results.hpp"
+#include "asio/ip/resolver_base.hpp"
+#if defined(ASIO_WINDOWS_RUNTIME)
+# include "asio/detail/winrt_resolver_service.hpp"
+#else
+# include "asio/detail/resolver_service.hpp"
+#endif
+
+#if defined(ASIO_HAS_MOVE)
+# include <utility>
+#endif // defined(ASIO_HAS_MOVE)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace ip {
+
+#if !defined(ASIO_IP_BASIC_RESOLVER_FWD_DECL)
+#define ASIO_IP_BASIC_RESOLVER_FWD_DECL
+
+// Forward declaration with defaulted arguments.
+template <typename InternetProtocol, typename Executor = any_io_executor>
+class basic_resolver;
+
+#endif // !defined(ASIO_IP_BASIC_RESOLVER_FWD_DECL)
+
+/// Provides endpoint resolution functionality.
+/**
+ * The basic_resolver class template provides the ability to resolve a query
+ * to a list of endpoints.
+ *
+ * @par Thread Safety
+ * @e Distinct @e objects: Safe.@n
+ * @e Shared @e objects: Unsafe.
+ */
+template <typename InternetProtocol, typename Executor>
+class basic_resolver
+  : public resolver_base
+{
+public:
+  /// The type of the executor associated with the object.
+  typedef Executor executor_type;
+
+  /// Rebinds the resolver type to another executor.
+  template <typename Executor1>
+  struct rebind_executor
+  {
+    /// The resolver type when rebound to the specified executor.
+    typedef basic_resolver<InternetProtocol, Executor1> other;
+  };
+
+  /// The protocol type.
+  typedef InternetProtocol protocol_type;
+
+  /// The endpoint type.
+  typedef typename InternetProtocol::endpoint endpoint_type;
+
+#if !defined(ASIO_NO_DEPRECATED)
+  /// (Deprecated.) The query type.
+  typedef basic_resolver_query<InternetProtocol> query;
+
+  /// (Deprecated.) The iterator type.
+  typedef basic_resolver_iterator<InternetProtocol> iterator;
+#endif // !defined(ASIO_NO_DEPRECATED)
+
+  /// The results type.
+  typedef basic_resolver_results<InternetProtocol> results_type;
+
+  /// Construct with executor.
+  /**
+   * This constructor creates a basic_resolver.
+   *
+   * @param ex The I/O executor that the resolver will use, by default, to
+   * dispatch handlers for any asynchronous operations performed on the
+   * resolver.
+   */
+  explicit basic_resolver(const executor_type& ex)
+    : impl_(ex)
+  {
+  }
+
+  /// Construct with execution context.
+  /**
+   * This constructor creates a basic_resolver.
+   *
+   * @param context An execution context which provides the I/O executor that
+   * the resolver will use, by default, to dispatch handlers for any
+   * asynchronous operations performed on the resolver.
+   */
+  template <typename ExecutionContext>
+  explicit basic_resolver(ExecutionContext& context,
+      typename enable_if<
+        is_convertible<ExecutionContext&, execution_context&>::value
+      >::type* = 0)
+    : impl_(context)
+  {
+  }
+
+#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+  /// Move-construct a basic_resolver from another.
+  /**
+   * This constructor moves a resolver from one object to another.
+   *
+   * @param other The other basic_resolver object from which the move will
+   * occur.
+   *
+   * @note Following the move, the moved-from object is in the same state as if
+   * constructed using the @c basic_resolver(const executor_type&) constructor.
+   */
+  basic_resolver(basic_resolver&& other)
+    : impl_(std::move(other.impl_))
+  {
+  }
+
+  /// Move-assign a basic_resolver from another.
+  /**
+   * This assignment operator moves a resolver from one object to another.
+   * Cancels any outstanding asynchronous operations associated with the target
+   * object.
+   *
+   * @param other The other basic_resolver object from which the move will
+   * occur.
+   *
+   * @note Following the move, the moved-from object is in the same state as if
+   * constructed using the @c basic_resolver(const executor_type&) constructor.
+   */
+  basic_resolver& operator=(basic_resolver&& other)
+  {
+    impl_ = std::move(other.impl_);
+    return *this;
+  }
+#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+
+  /// Destroys the resolver.
+  /**
+   * This function destroys the resolver, cancelling any outstanding
+   * asynchronous wait operations associated with the resolver as if by calling
+   * @c cancel.
+   */
+  ~basic_resolver()
+  {
+  }
+
+  /// Get the executor associated with the object.
+  executor_type get_executor() ASIO_NOEXCEPT
+  {
+    return impl_.get_executor();
+  }
+
+  /// Cancel any asynchronous operations that are waiting on the resolver.
+  /**
+   * This function forces the completion of any pending asynchronous
+   * operations on the host resolver. The handler for each cancelled operation
+   * will be invoked with the asio::error::operation_aborted error code.
+   */
+  void cancel()
+  {
+    return impl_.get_service().cancel(impl_.get_implementation());
+  }
+
+#if !defined(ASIO_NO_DEPRECATED)
+  /// (Deprecated: Use overload with separate host and service parameters.)
+  /// Perform forward resolution of a query to a list of entries.
+  /**
+   * This function is used to resolve a query into a list of endpoint entries.
+   *
+   * @param q A query object that determines what endpoints will be returned.
+   *
+   * @returns A range object representing the list of endpoint entries. A
+   * successful call to this function is guaranteed to return a non-empty
+   * range.
+   *
+   * @throws asio::system_error Thrown on failure.
+   */
+  results_type resolve(const query& q)
+  {
+    asio::error_code ec;
+    results_type r = impl_.get_service().resolve(
+        impl_.get_implementation(), q, ec);
+    asio::detail::throw_error(ec, "resolve");
+    return r;
+  }
+
+  /// (Deprecated: Use overload with separate host and service parameters.)
+  /// Perform forward resolution of a query to a list of entries.
+  /**
+   * This function is used to resolve a query into a list of endpoint entries.
+   *
+   * @param q A query object that determines what endpoints will be returned.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   *
+   * @returns A range object representing the list of endpoint entries. An
+   * empty range is returned if an error occurs. A successful call to this
+   * function is guaranteed to return a non-empty range.
+   */
+  results_type resolve(const query& q, asio::error_code& ec)
+  {
+    return impl_.get_service().resolve(impl_.get_implementation(), q, ec);
+  }
+#endif // !defined(ASIO_NO_DEPRECATED)
+
+  /// Perform forward resolution of a query to a list of entries.
+  /**
+   * This function is used to resolve host and service names into a list of
+   * endpoint entries.
+   *
+   * @param host A string identifying a location. May be a descriptive name or
+   * a numeric address string. If an empty string and the passive flag has been
+   * specified, the resolved endpoints are suitable for local service binding.
+   * If an empty string and passive is not specified, the resolved endpoints
+   * will use the loopback address.
+   *
+   * @param service A string identifying the requested service. This may be a
+   * descriptive name or a numeric string corresponding to a port number. May
+   * be an empty string, in which case all resolved endpoints will have a port
+   * number of 0.
+   *
+   * @returns A range object representing the list of endpoint entries. A
+   * successful call to this function is guaranteed to return a non-empty
+   * range.
+   *
+   * @throws asio::system_error Thrown on failure.
+   *
+   * @note On POSIX systems, host names may be locally defined in the file
+   * <tt>/etc/hosts</tt>. On Windows, host names may be defined in the file
+   * <tt>c:\\windows\\system32\\drivers\\etc\\hosts</tt>. Remote host name
+   * resolution is performed using DNS. Operating systems may use additional
+   * locations when resolving host names (such as NETBIOS names on Windows).
+   *
+   * On POSIX systems, service names are typically defined in the file
+   * <tt>/etc/services</tt>. On Windows, service names may be found in the file
+   * <tt>c:\\windows\\system32\\drivers\\etc\\services</tt>. Operating systems
+   * may use additional locations when resolving service names.
+   */
+  results_type resolve(ASIO_STRING_VIEW_PARAM host,
+      ASIO_STRING_VIEW_PARAM service)
+  {
+    return resolve(host, service, resolver_base::flags());
+  }
+
+  /// Perform forward resolution of a query to a list of entries.
+  /**
+   * This function is used to resolve host and service names into a list of
+   * endpoint entries.
+   *
+   * @param host A string identifying a location. May be a descriptive name or
+   * a numeric address string. If an empty string and the passive flag has been
+   * specified, the resolved endpoints are suitable for local service binding.
+   * If an empty string and passive is not specified, the resolved endpoints
+   * will use the loopback address.
+   *
+   * @param service A string identifying the requested service. This may be a
+   * descriptive name or a numeric string corresponding to a port number. May
+   * be an empty string, in which case all resolved endpoints will have a port
+   * number of 0.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   *
+   * @returns A range object representing the list of endpoint entries. An
+   * empty range is returned if an error occurs. A successful call to this
+   * function is guaranteed to return a non-empty range.
+   *
+   * @note On POSIX systems, host names may be locally defined in the file
+   * <tt>/etc/hosts</tt>. On Windows, host names may be defined in the file
+   * <tt>c:\\windows\\system32\\drivers\\etc\\hosts</tt>. Remote host name
+   * resolution is performed using DNS. Operating systems may use additional
+   * locations when resolving host names (such as NETBIOS names on Windows).
+   *
+   * On POSIX systems, service names are typically defined in the file
+   * <tt>/etc/services</tt>. On Windows, service names may be found in the file
+   * <tt>c:\\windows\\system32\\drivers\\etc\\services</tt>. Operating systems
+   * may use additional locations when resolving service names.
+   */
+  results_type resolve(ASIO_STRING_VIEW_PARAM host,
+      ASIO_STRING_VIEW_PARAM service, asio::error_code& ec)
+  {
+    return resolve(host, service, resolver_base::flags(), ec);
+  }
+
+  /// Perform forward resolution of a query to a list of entries.
+  /**
+   * This function is used to resolve host and service names into a list of
+   * endpoint entries.
+   *
+   * @param host A string identifying a location. May be a descriptive name or
+   * a numeric address string. If an empty string and the passive flag has been
+   * specified, the resolved endpoints are suitable for local service binding.
+   * If an empty string and passive is not specified, the resolved endpoints
+   * will use the loopback address.
+   *
+   * @param service A string identifying the requested service. This may be a
+   * descriptive name or a numeric string corresponding to a port number. May
+   * be an empty string, in which case all resolved endpoints will have a port
+   * number of 0.
+   *
+   * @param resolve_flags A set of flags that determine how name resolution
+   * should be performed. The default flags are suitable for communication with
+   * remote hosts. See the @ref resolver_base documentation for the set of
+   * available flags.
+   *
+   * @returns A range object representing the list of endpoint entries. A
+   * successful call to this function is guaranteed to return a non-empty
+   * range.
+   *
+   * @throws asio::system_error Thrown on failure.
+   *
+   * @note On POSIX systems, host names may be locally defined in the file
+   * <tt>/etc/hosts</tt>. On Windows, host names may be defined in the file
+   * <tt>c:\\windows\\system32\\drivers\\etc\\hosts</tt>. Remote host name
+   * resolution is performed using DNS. Operating systems may use additional
+   * locations when resolving host names (such as NETBIOS names on Windows).
+   *
+   * On POSIX systems, service names are typically defined in the file
+   * <tt>/etc/services</tt>. On Windows, service names may be found in the file
+   * <tt>c:\\windows\\system32\\drivers\\etc\\services</tt>. Operating systems
+   * may use additional locations when resolving service names.
+   */
+  results_type resolve(ASIO_STRING_VIEW_PARAM host,
+      ASIO_STRING_VIEW_PARAM service, resolver_base::flags resolve_flags)
+  {
+    asio::error_code ec;
+    basic_resolver_query<protocol_type> q(static_cast<std::string>(host),
+        static_cast<std::string>(service), resolve_flags);
+    results_type r = impl_.get_service().resolve(
+        impl_.get_implementation(), q, ec);
+    asio::detail::throw_error(ec, "resolve");
+    return r;
+  }
+
+  /// Perform forward resolution of a query to a list of entries.
+  /**
+   * This function is used to resolve host and service names into a list of
+   * endpoint entries.
+   *
+   * @param host A string identifying a location. May be a descriptive name or
+   * a numeric address string. If an empty string and the passive flag has been
+   * specified, the resolved endpoints are suitable for local service binding.
+   * If an empty string and passive is not specified, the resolved endpoints
+   * will use the loopback address.
+   *
+   * @param service A string identifying the requested service. This may be a
+   * descriptive name or a numeric string corresponding to a port number. May
+   * be an empty string, in which case all resolved endpoints will have a port
+   * number of 0.
+   *
+   * @param resolve_flags A set of flags that determine how name resolution
+   * should be performed. The default flags are suitable for communication with
+   * remote hosts. See the @ref resolver_base documentation for the set of
+   * available flags.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   *
+   * @returns A range object representing the list of endpoint entries. An
+   * empty range is returned if an error occurs. A successful call to this
+   * function is guaranteed to return a non-empty range.
+   *
+   * @note On POSIX systems, host names may be locally defined in the file
+   * <tt>/etc/hosts</tt>. On Windows, host names may be defined in the file
+   * <tt>c:\\windows\\system32\\drivers\\etc\\hosts</tt>. Remote host name
+   * resolution is performed using DNS. Operating systems may use additional
+   * locations when resolving host names (such as NETBIOS names on Windows).
+   *
+   * On POSIX systems, service names are typically defined in the file
+   * <tt>/etc/services</tt>. On Windows, service names may be found in the file
+   * <tt>c:\\windows\\system32\\drivers\\etc\\services</tt>. Operating systems
+   * may use additional locations when resolving service names.
+   */
+  results_type resolve(ASIO_STRING_VIEW_PARAM host,
+      ASIO_STRING_VIEW_PARAM service, resolver_base::flags resolve_flags,
+      asio::error_code& ec)
+  {
+    basic_resolver_query<protocol_type> q(static_cast<std::string>(host),
+        static_cast<std::string>(service), resolve_flags);
+    return impl_.get_service().resolve(impl_.get_implementation(), q, ec);
+  }
+
+  /// Perform forward resolution of a query to a list of entries.
+  /**
+   * This function is used to resolve host and service names into a list of
+   * endpoint entries.
+   *
+   * @param protocol A protocol object, normally representing either the IPv4 or
+   * IPv6 version of an internet protocol.
+   *
+   * @param host A string identifying a location. May be a descriptive name or
+   * a numeric address string. If an empty string and the passive flag has been
+   * specified, the resolved endpoints are suitable for local service binding.
+   * If an empty string and passive is not specified, the resolved endpoints
+   * will use the loopback address.
+   *
+   * @param service A string identifying the requested service. This may be a
+   * descriptive name or a numeric string corresponding to a port number. May
+   * be an empty string, in which case all resolved endpoints will have a port
+   * number of 0.
+   *
+   * @returns A range object representing the list of endpoint entries. A
+   * successful call to this function is guaranteed to return a non-empty
+   * range.
+   *
+   * @throws asio::system_error Thrown on failure.
+   *
+   * @note On POSIX systems, host names may be locally defined in the file
+   * <tt>/etc/hosts</tt>. On Windows, host names may be defined in the file
+   * <tt>c:\\windows\\system32\\drivers\\etc\\hosts</tt>. Remote host name
+   * resolution is performed using DNS. Operating systems may use additional
+   * locations when resolving host names (such as NETBIOS names on Windows).
+   *
+   * On POSIX systems, service names are typically defined in the file
+   * <tt>/etc/services</tt>. On Windows, service names may be found in the file
+   * <tt>c:\\windows\\system32\\drivers\\etc\\services</tt>. Operating systems
+   * may use additional locations when resolving service names.
+   */
+  results_type resolve(const protocol_type& protocol,
+      ASIO_STRING_VIEW_PARAM host, ASIO_STRING_VIEW_PARAM service)
+  {
+    return resolve(protocol, host, service, resolver_base::flags());
+  }
+
+  /// Perform forward resolution of a query to a list of entries.
+  /**
+   * This function is used to resolve host and service names into a list of
+   * endpoint entries.
+   *
+   * @param protocol A protocol object, normally representing either the IPv4 or
+   * IPv6 version of an internet protocol.
+   *
+   * @param host A string identifying a location. May be a descriptive name or
+   * a numeric address string. If an empty string and the passive flag has been
+   * specified, the resolved endpoints are suitable for local service binding.
+   * If an empty string and passive is not specified, the resolved endpoints
+   * will use the loopback address.
+   *
+   * @param service A string identifying the requested service. This may be a
+   * descriptive name or a numeric string corresponding to a port number. May
+   * be an empty string, in which case all resolved endpoints will have a port
+   * number of 0.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   *
+   * @returns A range object representing the list of endpoint entries. An
+   * empty range is returned if an error occurs. A successful call to this
+   * function is guaranteed to return a non-empty range.
+   *
+   * @note On POSIX systems, host names may be locally defined in the file
+   * <tt>/etc/hosts</tt>. On Windows, host names may be defined in the file
+   * <tt>c:\\windows\\system32\\drivers\\etc\\hosts</tt>. Remote host name
+   * resolution is performed using DNS. Operating systems may use additional
+   * locations when resolving host names (such as NETBIOS names on Windows).
+   *
+   * On POSIX systems, service names are typically defined in the file
+   * <tt>/etc/services</tt>. On Windows, service names may be found in the file
+   * <tt>c:\\windows\\system32\\drivers\\etc\\services</tt>. Operating systems
+   * may use additional locations when resolving service names.
+   */
+  results_type resolve(const protocol_type& protocol,
+      ASIO_STRING_VIEW_PARAM host, ASIO_STRING_VIEW_PARAM service,
+      asio::error_code& ec)
+  {
+    return resolve(protocol, host, service, resolver_base::flags(), ec);
+  }
+
+  /// Perform forward resolution of a query to a list of entries.
+  /**
+   * This function is used to resolve host and service names into a list of
+   * endpoint entries.
+   *
+   * @param protocol A protocol object, normally representing either the IPv4 or
+   * IPv6 version of an internet protocol.
+   *
+   * @param host A string identifying a location. May be a descriptive name or
+   * a numeric address string. If an empty string and the passive flag has been
+   * specified, the resolved endpoints are suitable for local service binding.
+   * If an empty string and passive is not specified, the resolved endpoints
+   * will use the loopback address.
+   *
+   * @param service A string identifying the requested service. This may be a
+   * descriptive name or a numeric string corresponding to a port number. May
+   * be an empty string, in which case all resolved endpoints will have a port
+   * number of 0.
+   *
+   * @param resolve_flags A set of flags that determine how name resolution
+   * should be performed. The default flags are suitable for communication with
+   * remote hosts. See the @ref resolver_base documentation for the set of
+   * available flags.
+   *
+   * @returns A range object representing the list of endpoint entries. A
+   * successful call to this function is guaranteed to return a non-empty
+   * range.
+   *
+   * @throws asio::system_error Thrown on failure.
+   *
+   * @note On POSIX systems, host names may be locally defined in the file
+   * <tt>/etc/hosts</tt>. On Windows, host names may be defined in the file
+   * <tt>c:\\windows\\system32\\drivers\\etc\\hosts</tt>. Remote host name
+   * resolution is performed using DNS. Operating systems may use additional
+   * locations when resolving host names (such as NETBIOS names on Windows).
+   *
+   * On POSIX systems, service names are typically defined in the file
+   * <tt>/etc/services</tt>. On Windows, service names may be found in the file
+   * <tt>c:\\windows\\system32\\drivers\\etc\\services</tt>. Operating systems
+   * may use additional locations when resolving service names.
+   */
+  results_type resolve(const protocol_type& protocol,
+      ASIO_STRING_VIEW_PARAM host, ASIO_STRING_VIEW_PARAM service,
+      resolver_base::flags resolve_flags)
+  {
+    asio::error_code ec;
+    basic_resolver_query<protocol_type> q(
+        protocol, static_cast<std::string>(host),
+        static_cast<std::string>(service), resolve_flags);
+    results_type r = impl_.get_service().resolve(
+        impl_.get_implementation(), q, ec);
+    asio::detail::throw_error(ec, "resolve");
+    return r;
+  }
+
+  /// Perform forward resolution of a query to a list of entries.
+  /**
+   * This function is used to resolve host and service names into a list of
+   * endpoint entries.
+   *
+   * @param protocol A protocol object, normally representing either the IPv4 or
+   * IPv6 version of an internet protocol.
+   *
+   * @param host A string identifying a location. May be a descriptive name or
+   * a numeric address string. If an empty string and the passive flag has been
+   * specified, the resolved endpoints are suitable for local service binding.
+   * If an empty string and passive is not specified, the resolved endpoints
+   * will use the loopback address.
+   *
+   * @param service A string identifying the requested service. This may be a
+   * descriptive name or a numeric string corresponding to a port number. May
+   * be an empty string, in which case all resolved endpoints will have a port
+   * number of 0.
+   *
+   * @param resolve_flags A set of flags that determine how name resolution
+   * should be performed. The default flags are suitable for communication with
+   * remote hosts. See the @ref resolver_base documentation for the set of
+   * available flags.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   *
+   * @returns A range object representing the list of endpoint entries. An
+   * empty range is returned if an error occurs. A successful call to this
+   * function is guaranteed to return a non-empty range.
+   *
+   * @note On POSIX systems, host names may be locally defined in the file
+   * <tt>/etc/hosts</tt>. On Windows, host names may be defined in the file
+   * <tt>c:\\windows\\system32\\drivers\\etc\\hosts</tt>. Remote host name
+   * resolution is performed using DNS. Operating systems may use additional
+   * locations when resolving host names (such as NETBIOS names on Windows).
+   *
+   * On POSIX systems, service names are typically defined in the file
+   * <tt>/etc/services</tt>. On Windows, service names may be found in the file
+   * <tt>c:\\windows\\system32\\drivers\\etc\\services</tt>. Operating systems
+   * may use additional locations when resolving service names.
+   */
+  results_type resolve(const protocol_type& protocol,
+      ASIO_STRING_VIEW_PARAM host, ASIO_STRING_VIEW_PARAM service,
+      resolver_base::flags resolve_flags, asio::error_code& ec)
+  {
+    basic_resolver_query<protocol_type> q(
+        protocol, static_cast<std::string>(host),
+        static_cast<std::string>(service), resolve_flags);
+    return impl_.get_service().resolve(impl_.get_implementation(), q, ec);
+  }
+
+#if !defined(ASIO_NO_DEPRECATED)
+  /// (Deprecated: Use overload with separate host and service parameters.)
+  /// Asynchronously perform forward resolution of a query to a list of entries.
+  /**
+   * This function is used to asynchronously resolve a query into a list of
+   * endpoint entries.
+   *
+   * @param q A query object that determines what endpoints will be returned.
+   *
+   * @param handler The handler to be called when the resolve operation
+   * completes. Copies will be made of the handler as required. The function
+   * signature of the handler must be:
+   * @code void handler(
+   *   const asio::error_code& error, // Result of operation.
+   *   resolver::results_type results // Resolved endpoints as a range.
+   * ); @endcode
+   * Regardless of whether the asynchronous operation completes immediately or
+   * not, the handler will not be invoked from within this function. On
+   * immediate completion, invocation of the handler will be performed in a
+   * manner equivalent to using asio::post().
+   *
+   * A successful resolve operation is guaranteed to pass a non-empty range to
+   * the handler.
+   */
+  template <
+      ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+        results_type)) ResolveHandler
+          ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
+  ASIO_INITFN_AUTO_RESULT_TYPE(ResolveHandler,
+      void (asio::error_code, results_type))
+  async_resolve(const query& q,
+      ASIO_MOVE_ARG(ResolveHandler) handler
+        ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
+  {
+    return asio::async_initiate<ResolveHandler,
+      void (asio::error_code, results_type)>(
+        initiate_async_resolve(this), handler, q);
+  }
+#endif // !defined(ASIO_NO_DEPRECATED)
+
+  /// Asynchronously perform forward resolution of a query to a list of entries.
+  /**
+   * This function is used to resolve host and service names into a list of
+   * endpoint entries.
+   *
+   * @param host A string identifying a location. May be a descriptive name or
+   * a numeric address string. If an empty string and the passive flag has been
+   * specified, the resolved endpoints are suitable for local service binding.
+   * If an empty string and passive is not specified, the resolved endpoints
+   * will use the loopback address.
+   *
+   * @param service A string identifying the requested service. This may be a
+   * descriptive name or a numeric string corresponding to a port number. May
+   * be an empty string, in which case all resolved endpoints will have a port
+   * number of 0.
+   *
+   * @param handler The handler to be called when the resolve operation
+   * completes. Copies will be made of the handler as required. The function
+   * signature of the handler must be:
+   * @code void handler(
+   *   const asio::error_code& error, // Result of operation.
+   *   resolver::results_type results // Resolved endpoints as a range.
+   * ); @endcode
+   * Regardless of whether the asynchronous operation completes immediately or
+   * not, the handler will not be invoked from within this function. On
+   * immediate completion, invocation of the handler will be performed in a
+   * manner equivalent to using asio::post().
+   *
+   * A successful resolve operation is guaranteed to pass a non-empty range to
+   * the handler.
+   *
+   * @note On POSIX systems, host names may be locally defined in the file
+   * <tt>/etc/hosts</tt>. On Windows, host names may be defined in the file
+   * <tt>c:\\windows\\system32\\drivers\\etc\\hosts</tt>. Remote host name
+   * resolution is performed using DNS. Operating systems may use additional
+   * locations when resolving host names (such as NETBIOS names on Windows).
+   *
+   * On POSIX systems, service names are typically defined in the file
+   * <tt>/etc/services</tt>. On Windows, service names may be found in the file
+   * <tt>c:\\windows\\system32\\drivers\\etc\\services</tt>. Operating systems
+   * may use additional locations when resolving service names.
+   */
+  template <
+      ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+        results_type)) ResolveHandler
+          ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
+  ASIO_INITFN_AUTO_RESULT_TYPE(ResolveHandler,
+      void (asio::error_code, results_type))
+  async_resolve(ASIO_STRING_VIEW_PARAM host,
+      ASIO_STRING_VIEW_PARAM service,
+      ASIO_MOVE_ARG(ResolveHandler) handler
+        ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
+  {
+    return async_resolve(host, service, resolver_base::flags(),
+        ASIO_MOVE_CAST(ResolveHandler)(handler));
+  }
+
+  /// Asynchronously perform forward resolution of a query to a list of entries.
+  /**
+   * This function is used to resolve host and service names into a list of
+   * endpoint entries.
+   *
+   * @param host A string identifying a location. May be a descriptive name or
+   * a numeric address string. If an empty string and the passive flag has been
+   * specified, the resolved endpoints are suitable for local service binding.
+   * If an empty string and passive is not specified, the resolved endpoints
+   * will use the loopback address.
+   *
+   * @param service A string identifying the requested service. This may be a
+   * descriptive name or a numeric string corresponding to a port number. May
+   * be an empty string, in which case all resolved endpoints will have a port
+   * number of 0.
+   *
+   * @param resolve_flags A set of flags that determine how name resolution
+   * should be performed. The default flags are suitable for communication with
+   * remote hosts. See the @ref resolver_base documentation for the set of
+   * available flags.
+   *
+   * @param handler The handler to be called when the resolve operation
+   * completes. Copies will be made of the handler as required. The function
+   * signature of the handler must be:
+   * @code void handler(
+   *   const asio::error_code& error, // Result of operation.
+   *   resolver::results_type results // Resolved endpoints as a range.
+   * ); @endcode
+   * Regardless of whether the asynchronous operation completes immediately or
+   * not, the handler will not be invoked from within this function. On
+   * immediate completion, invocation of the handler will be performed in a
+   * manner equivalent to using asio::post().
+   *
+   * A successful resolve operation is guaranteed to pass a non-empty range to
+   * the handler.
+   *
+   * @note On POSIX systems, host names may be locally defined in the file
+   * <tt>/etc/hosts</tt>. On Windows, host names may be defined in the file
+   * <tt>c:\\windows\\system32\\drivers\\etc\\hosts</tt>. Remote host name
+   * resolution is performed using DNS. Operating systems may use additional
+   * locations when resolving host names (such as NETBIOS names on Windows).
+   *
+   * On POSIX systems, service names are typically defined in the file
+   * <tt>/etc/services</tt>. On Windows, service names may be found in the file
+   * <tt>c:\\windows\\system32\\drivers\\etc\\services</tt>. Operating systems
+   * may use additional locations when resolving service names.
+   */
+  template <
+      ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+        results_type)) ResolveHandler
+          ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
+  ASIO_INITFN_AUTO_RESULT_TYPE(ResolveHandler,
+      void (asio::error_code, results_type))
+  async_resolve(ASIO_STRING_VIEW_PARAM host,
+      ASIO_STRING_VIEW_PARAM service,
+      resolver_base::flags resolve_flags,
+      ASIO_MOVE_ARG(ResolveHandler) handler
+        ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
+  {
+    basic_resolver_query<protocol_type> q(static_cast<std::string>(host),
+        static_cast<std::string>(service), resolve_flags);
+
+    return asio::async_initiate<ResolveHandler,
+      void (asio::error_code, results_type)>(
+        initiate_async_resolve(this), handler, q);
+  }
+
+  /// Asynchronously perform forward resolution of a query to a list of entries.
+  /**
+   * This function is used to resolve host and service names into a list of
+   * endpoint entries.
+   *
+   * @param protocol A protocol object, normally representing either the IPv4 or
+   * IPv6 version of an internet protocol.
+   *
+   * @param host A string identifying a location. May be a descriptive name or
+   * a numeric address string. If an empty string and the passive flag has been
+   * specified, the resolved endpoints are suitable for local service binding.
+   * If an empty string and passive is not specified, the resolved endpoints
+   * will use the loopback address.
+   *
+   * @param service A string identifying the requested service. This may be a
+   * descriptive name or a numeric string corresponding to a port number. May
+   * be an empty string, in which case all resolved endpoints will have a port
+   * number of 0.
+   *
+   * @param handler The handler to be called when the resolve operation
+   * completes. Copies will be made of the handler as required. The function
+   * signature of the handler must be:
+   * @code void handler(
+   *   const asio::error_code& error, // Result of operation.
+   *   resolver::results_type results // Resolved endpoints as a range.
+   * ); @endcode
+   * Regardless of whether the asynchronous operation completes immediately or
+   * not, the handler will not be invoked from within this function. On
+   * immediate completion, invocation of the handler will be performed in a
+   * manner equivalent to using asio::post().
+   *
+   * A successful resolve operation is guaranteed to pass a non-empty range to
+   * the handler.
+   *
+   * @note On POSIX systems, host names may be locally defined in the file
+   * <tt>/etc/hosts</tt>. On Windows, host names may be defined in the file
+   * <tt>c:\\windows\\system32\\drivers\\etc\\hosts</tt>. Remote host name
+   * resolution is performed using DNS. Operating systems may use additional
+   * locations when resolving host names (such as NETBIOS names on Windows).
+   *
+   * On POSIX systems, service names are typically defined in the file
+   * <tt>/etc/services</tt>. On Windows, service names may be found in the file
+   * <tt>c:\\windows\\system32\\drivers\\etc\\services</tt>. Operating systems
+   * may use additional locations when resolving service names.
+   */
+  template <
+      ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+        results_type)) ResolveHandler
+          ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
+  ASIO_INITFN_AUTO_RESULT_TYPE(ResolveHandler,
+      void (asio::error_code, results_type))
+  async_resolve(const protocol_type& protocol,
+      ASIO_STRING_VIEW_PARAM host, ASIO_STRING_VIEW_PARAM service,
+      ASIO_MOVE_ARG(ResolveHandler) handler
+        ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
+  {
+    return async_resolve(protocol, host, service, resolver_base::flags(),
+        ASIO_MOVE_CAST(ResolveHandler)(handler));
+  }
+
+  /// Asynchronously perform forward resolution of a query to a list of entries.
+  /**
+   * This function is used to resolve host and service names into a list of
+   * endpoint entries.
+   *
+   * @param protocol A protocol object, normally representing either the IPv4 or
+   * IPv6 version of an internet protocol.
+   *
+   * @param host A string identifying a location. May be a descriptive name or
+   * a numeric address string. If an empty string and the passive flag has been
+   * specified, the resolved endpoints are suitable for local service binding.
+   * If an empty string and passive is not specified, the resolved endpoints
+   * will use the loopback address.
+   *
+   * @param service A string identifying the requested service. This may be a
+   * descriptive name or a numeric string corresponding to a port number. May
+   * be an empty string, in which case all resolved endpoints will have a port
+   * number of 0.
+   *
+   * @param resolve_flags A set of flags that determine how name resolution
+   * should be performed. The default flags are suitable for communication with
+   * remote hosts. See the @ref resolver_base documentation for the set of
+   * available flags.
+   *
+   * @param handler The handler to be called when the resolve operation
+   * completes. Copies will be made of the handler as required. The function
+   * signature of the handler must be:
+   * @code void handler(
+   *   const asio::error_code& error, // Result of operation.
+   *   resolver::results_type results // Resolved endpoints as a range.
+   * ); @endcode
+   * Regardless of whether the asynchronous operation completes immediately or
+   * not, the handler will not be invoked from within this function. On
+   * immediate completion, invocation of the handler will be performed in a
+   * manner equivalent to using asio::post().
+   *
+   * A successful resolve operation is guaranteed to pass a non-empty range to
+   * the handler.
+   *
+   * @note On POSIX systems, host names may be locally defined in the file
+   * <tt>/etc/hosts</tt>. On Windows, host names may be defined in the file
+   * <tt>c:\\windows\\system32\\drivers\\etc\\hosts</tt>. Remote host name
+   * resolution is performed using DNS. Operating systems may use additional
+   * locations when resolving host names (such as NETBIOS names on Windows).
+   *
+   * On POSIX systems, service names are typically defined in the file
+   * <tt>/etc/services</tt>. On Windows, service names may be found in the file
+   * <tt>c:\\windows\\system32\\drivers\\etc\\services</tt>. Operating systems
+   * may use additional locations when resolving service names.
+   */
+  template <
+      ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+        results_type)) ResolveHandler
+          ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
+  ASIO_INITFN_AUTO_RESULT_TYPE(ResolveHandler,
+      void (asio::error_code, results_type))
+  async_resolve(const protocol_type& protocol,
+      ASIO_STRING_VIEW_PARAM host, ASIO_STRING_VIEW_PARAM service,
+      resolver_base::flags resolve_flags,
+      ASIO_MOVE_ARG(ResolveHandler) handler
+        ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
+  {
+    basic_resolver_query<protocol_type> q(
+        protocol, static_cast<std::string>(host),
+        static_cast<std::string>(service), resolve_flags);
+
+    return asio::async_initiate<ResolveHandler,
+      void (asio::error_code, results_type)>(
+        initiate_async_resolve(this), handler, q);
+  }
+
+  /// Perform reverse resolution of an endpoint to a list of entries.
+  /**
+   * This function is used to resolve an endpoint into a list of endpoint
+   * entries.
+   *
+   * @param e An endpoint object that determines what endpoints will be
+   * returned.
+   *
+   * @returns A range object representing the list of endpoint entries. A
+   * successful call to this function is guaranteed to return a non-empty
+   * range.
+   *
+   * @throws asio::system_error Thrown on failure.
+   */
+  results_type resolve(const endpoint_type& e)
+  {
+    asio::error_code ec;
+    results_type i = impl_.get_service().resolve(
+        impl_.get_implementation(), e, ec);
+    asio::detail::throw_error(ec, "resolve");
+    return i;
+  }
+
+  /// Perform reverse resolution of an endpoint to a list of entries.
+  /**
+   * This function is used to resolve an endpoint into a list of endpoint
+   * entries.
+   *
+   * @param e An endpoint object that determines what endpoints will be
+   * returned.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   *
+   * @returns A range object representing the list of endpoint entries. An
+   * empty range is returned if an error occurs. A successful call to this
+   * function is guaranteed to return a non-empty range.
+   */
+  results_type resolve(const endpoint_type& e, asio::error_code& ec)
+  {
+    return impl_.get_service().resolve(impl_.get_implementation(), e, ec);
+  }
+
+  /// Asynchronously perform reverse resolution of an endpoint to a list of
+  /// entries.
+  /**
+   * This function is used to asynchronously resolve an endpoint into a list of
+   * endpoint entries.
+   *
+   * @param e An endpoint object that determines what endpoints will be
+   * returned.
+   *
+   * @param handler The handler to be called when the resolve operation
+   * completes. Copies will be made of the handler as required. The function
+   * signature of the handler must be:
+   * @code void handler(
+   *   const asio::error_code& error, // Result of operation.
+   *   resolver::results_type results // Resolved endpoints as a range.
+   * ); @endcode
+   * Regardless of whether the asynchronous operation completes immediately or
+   * not, the handler will not be invoked from within this function. On
+   * immediate completion, invocation of the handler will be performed in a
+   * manner equivalent to using asio::post().
+   *
+   * A successful resolve operation is guaranteed to pass a non-empty range to
+   * the handler.
+   */
+  template <
+      ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+        results_type)) ResolveHandler
+          ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
+  ASIO_INITFN_AUTO_RESULT_TYPE(ResolveHandler,
+      void (asio::error_code, results_type))
+  async_resolve(const endpoint_type& e,
+      ASIO_MOVE_ARG(ResolveHandler) handler
+        ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
+  {
+    return asio::async_initiate<ResolveHandler,
+      void (asio::error_code, results_type)>(
+        initiate_async_resolve(this), handler, e);
+  }
+
+private:
+  // Disallow copying and assignment.
+  basic_resolver(const basic_resolver&) ASIO_DELETED;
+  basic_resolver& operator=(const basic_resolver&) ASIO_DELETED;
+
+  class initiate_async_resolve
+  {
+  public:
+    typedef Executor executor_type;
+
+    explicit initiate_async_resolve(basic_resolver* self)
+      : self_(self)
+    {
+    }
+
+    executor_type get_executor() const ASIO_NOEXCEPT
+    {
+      return self_->get_executor();
+    }
+
+    template <typename ResolveHandler, typename Query>
+    void operator()(ASIO_MOVE_ARG(ResolveHandler) handler,
+        const Query& q) const
+    {
+      // If you get an error on the following line it means that your handler
+      // does not meet the documented type requirements for a ResolveHandler.
+      ASIO_RESOLVE_HANDLER_CHECK(
+          ResolveHandler, handler, results_type) type_check;
+
+      asio::detail::non_const_lvalue<ResolveHandler> handler2(handler);
+      self_->impl_.get_service().async_resolve(
+          self_->impl_.get_implementation(), q,
+          handler2.value, self_->impl_.get_executor());
+    }
+
+  private:
+    basic_resolver* self_;
+  };
+
+# if defined(ASIO_WINDOWS_RUNTIME)
+  asio::detail::io_object_impl<
+    asio::detail::winrt_resolver_service<InternetProtocol>,
+    Executor> impl_;
+# else
+  asio::detail::io_object_impl<
+    asio::detail::resolver_service<InternetProtocol>,
+    Executor> impl_;
+# endif
+};
+
+} // namespace ip
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IP_BASIC_RESOLVER_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/ip/basic_resolver_entry.hpp b/link/modules/asio-standalone/asio/include/asio/ip/basic_resolver_entry.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/ip/basic_resolver_entry.hpp
@@ -0,0 +1,113 @@
+//
+// ip/basic_resolver_entry.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_IP_BASIC_RESOLVER_ENTRY_HPP
+#define ASIO_IP_BASIC_RESOLVER_ENTRY_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <string>
+#include "asio/detail/string_view.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace ip {
+
+/// An entry produced by a resolver.
+/**
+ * The asio::ip::basic_resolver_entry class template describes an entry
+ * as returned by a resolver.
+ *
+ * @par Thread Safety
+ * @e Distinct @e objects: Safe.@n
+ * @e Shared @e objects: Unsafe.
+ */
+template <typename InternetProtocol>
+class basic_resolver_entry
+{
+public:
+  /// The protocol type associated with the endpoint entry.
+  typedef InternetProtocol protocol_type;
+
+  /// The endpoint type associated with the endpoint entry.
+  typedef typename InternetProtocol::endpoint endpoint_type;
+
+  /// Default constructor.
+  basic_resolver_entry()
+  {
+  }
+
+  /// Construct with specified endpoint, host name and service name.
+  basic_resolver_entry(const endpoint_type& ep,
+      ASIO_STRING_VIEW_PARAM host, ASIO_STRING_VIEW_PARAM service)
+    : endpoint_(ep),
+      host_name_(static_cast<std::string>(host)),
+      service_name_(static_cast<std::string>(service))
+  {
+  }
+
+  /// Get the endpoint associated with the entry.
+  endpoint_type endpoint() const
+  {
+    return endpoint_;
+  }
+
+  /// Convert to the endpoint associated with the entry.
+  operator endpoint_type() const
+  {
+    return endpoint_;
+  }
+
+  /// Get the host name associated with the entry.
+  std::string host_name() const
+  {
+    return host_name_;
+  }
+
+  /// Get the host name associated with the entry.
+  template <class Allocator>
+  std::basic_string<char, std::char_traits<char>, Allocator> host_name(
+      const Allocator& alloc = Allocator()) const
+  {
+    return std::basic_string<char, std::char_traits<char>, Allocator>(
+        host_name_.c_str(), alloc);
+  }
+
+  /// Get the service name associated with the entry.
+  std::string service_name() const
+  {
+    return service_name_;
+  }
+
+  /// Get the service name associated with the entry.
+  template <class Allocator>
+  std::basic_string<char, std::char_traits<char>, Allocator> service_name(
+      const Allocator& alloc = Allocator()) const
+  {
+    return std::basic_string<char, std::char_traits<char>, Allocator>(
+        service_name_.c_str(), alloc);
+  }
+
+private:
+  endpoint_type endpoint_;
+  std::string host_name_;
+  std::string service_name_;
+};
+
+} // namespace ip
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IP_BASIC_RESOLVER_ENTRY_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/ip/basic_resolver_iterator.hpp b/link/modules/asio-standalone/asio/include/asio/ip/basic_resolver_iterator.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/ip/basic_resolver_iterator.hpp
@@ -0,0 +1,192 @@
+//
+// ip/basic_resolver_iterator.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_IP_BASIC_RESOLVER_ITERATOR_HPP
+#define ASIO_IP_BASIC_RESOLVER_ITERATOR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <cstddef>
+#include <cstring>
+#include <iterator>
+#include <string>
+#include <vector>
+#include "asio/detail/memory.hpp"
+#include "asio/detail/socket_ops.hpp"
+#include "asio/detail/socket_types.hpp"
+#include "asio/ip/basic_resolver_entry.hpp"
+
+#if defined(ASIO_WINDOWS_RUNTIME)
+# include "asio/detail/winrt_utils.hpp"
+#endif // defined(ASIO_WINDOWS_RUNTIME)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace ip {
+
+/// An iterator over the entries produced by a resolver.
+/**
+ * The asio::ip::basic_resolver_iterator class template is used to define
+ * iterators over the results returned by a resolver.
+ *
+ * The iterator's value_type, obtained when the iterator is dereferenced, is:
+ * @code const basic_resolver_entry<InternetProtocol> @endcode
+ *
+ * @par Thread Safety
+ * @e Distinct @e objects: Safe.@n
+ * @e Shared @e objects: Unsafe.
+ */
+template <typename InternetProtocol>
+class basic_resolver_iterator
+{
+public:
+  /// The type used for the distance between two iterators.
+  typedef std::ptrdiff_t difference_type;
+
+  /// The type of the value pointed to by the iterator.
+  typedef basic_resolver_entry<InternetProtocol> value_type;
+
+  /// The type of the result of applying operator->() to the iterator.
+  typedef const basic_resolver_entry<InternetProtocol>* pointer;
+
+  /// The type of the result of applying operator*() to the iterator.
+  typedef const basic_resolver_entry<InternetProtocol>& reference;
+
+  /// The iterator category.
+  typedef std::forward_iterator_tag iterator_category;
+
+  /// Default constructor creates an end iterator.
+  basic_resolver_iterator()
+    : index_(0)
+  {
+  }
+
+  /// Copy constructor.
+  basic_resolver_iterator(const basic_resolver_iterator& other)
+    : values_(other.values_),
+      index_(other.index_)
+  {
+  }
+
+#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+  /// Move constructor.
+  basic_resolver_iterator(basic_resolver_iterator&& other)
+    : values_(ASIO_MOVE_CAST(values_ptr_type)(other.values_)),
+      index_(other.index_)
+  {
+    other.index_ = 0;
+  }
+#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+
+  /// Assignment operator.
+  basic_resolver_iterator& operator=(const basic_resolver_iterator& other)
+  {
+    values_ = other.values_;
+    index_ = other.index_;
+    return *this;
+  }
+
+#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+  /// Move-assignment operator.
+  basic_resolver_iterator& operator=(basic_resolver_iterator&& other)
+  {
+    if (this != &other)
+    {
+      values_ = ASIO_MOVE_CAST(values_ptr_type)(other.values_);
+      index_ = other.index_;
+      other.index_ = 0;
+    }
+
+    return *this;
+  }
+#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+
+  /// Dereference an iterator.
+  const basic_resolver_entry<InternetProtocol>& operator*() const
+  {
+    return dereference();
+  }
+
+  /// Dereference an iterator.
+  const basic_resolver_entry<InternetProtocol>* operator->() const
+  {
+    return &dereference();
+  }
+
+  /// Increment operator (prefix).
+  basic_resolver_iterator& operator++()
+  {
+    increment();
+    return *this;
+  }
+
+  /// Increment operator (postfix).
+  basic_resolver_iterator operator++(int)
+  {
+    basic_resolver_iterator tmp(*this);
+    ++*this;
+    return tmp;
+  }
+
+  /// Test two iterators for equality.
+  friend bool operator==(const basic_resolver_iterator& a,
+      const basic_resolver_iterator& b)
+  {
+    return a.equal(b);
+  }
+
+  /// Test two iterators for inequality.
+  friend bool operator!=(const basic_resolver_iterator& a,
+      const basic_resolver_iterator& b)
+  {
+    return !a.equal(b);
+  }
+
+protected:
+  void increment()
+  {
+    if (++index_ == values_->size())
+    {
+      // Reset state to match a default constructed end iterator.
+      values_.reset();
+      index_ = 0;
+    }
+  }
+
+  bool equal(const basic_resolver_iterator& other) const
+  {
+    if (!values_ && !other.values_)
+      return true;
+    if (values_ != other.values_)
+      return false;
+    return index_ == other.index_;
+  }
+
+  const basic_resolver_entry<InternetProtocol>& dereference() const
+  {
+    return (*values_)[index_];
+  }
+
+  typedef std::vector<basic_resolver_entry<InternetProtocol> > values_type;
+  typedef asio::detail::shared_ptr<values_type> values_ptr_type;
+  values_ptr_type values_;
+  std::size_t index_;
+};
+
+} // namespace ip
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IP_BASIC_RESOLVER_ITERATOR_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/ip/basic_resolver_query.hpp b/link/modules/asio-standalone/asio/include/asio/ip/basic_resolver_query.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/ip/basic_resolver_query.hpp
@@ -0,0 +1,244 @@
+//
+// ip/basic_resolver_query.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_IP_BASIC_RESOLVER_QUERY_HPP
+#define ASIO_IP_BASIC_RESOLVER_QUERY_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <string>
+#include "asio/detail/socket_ops.hpp"
+#include "asio/ip/resolver_query_base.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace ip {
+
+/// An query to be passed to a resolver.
+/**
+ * The asio::ip::basic_resolver_query class template describes a query
+ * that can be passed to a resolver.
+ *
+ * @par Thread Safety
+ * @e Distinct @e objects: Safe.@n
+ * @e Shared @e objects: Unsafe.
+ */
+template <typename InternetProtocol>
+class basic_resolver_query
+  : public resolver_query_base
+{
+public:
+  /// The protocol type associated with the endpoint query.
+  typedef InternetProtocol protocol_type;
+
+  /// Construct with specified service name for any protocol.
+  /**
+   * This constructor is typically used to perform name resolution for local
+   * service binding.
+   *
+   * @param service A string identifying the requested service. This may be a
+   * descriptive name or a numeric string corresponding to a port number.
+   *
+   * @param resolve_flags A set of flags that determine how name resolution
+   * should be performed. The default flags are suitable for local service
+   * binding.
+   *
+   * @note On POSIX systems, service names are typically defined in the file
+   * <tt>/etc/services</tt>. On Windows, service names may be found in the file
+   * <tt>c:\\windows\\system32\\drivers\\etc\\services</tt>. Operating systems
+   * may use additional locations when resolving service names.
+   */
+  basic_resolver_query(const std::string& service,
+      resolver_query_base::flags resolve_flags = passive | address_configured)
+    : hints_(),
+      host_name_(),
+      service_name_(service)
+  {
+    typename InternetProtocol::endpoint endpoint;
+    hints_.ai_flags = static_cast<int>(resolve_flags);
+    hints_.ai_family = PF_UNSPEC;
+    hints_.ai_socktype = endpoint.protocol().type();
+    hints_.ai_protocol = endpoint.protocol().protocol();
+    hints_.ai_addrlen = 0;
+    hints_.ai_canonname = 0;
+    hints_.ai_addr = 0;
+    hints_.ai_next = 0;
+  }
+
+  /// Construct with specified service name for a given protocol.
+  /**
+   * This constructor is typically used to perform name resolution for local
+   * service binding with a specific protocol version.
+   *
+   * @param protocol A protocol object, normally representing either the IPv4 or
+   * IPv6 version of an internet protocol.
+   *
+   * @param service A string identifying the requested service. This may be a
+   * descriptive name or a numeric string corresponding to a port number.
+   *
+   * @param resolve_flags A set of flags that determine how name resolution
+   * should be performed. The default flags are suitable for local service
+   * binding.
+   *
+   * @note On POSIX systems, service names are typically defined in the file
+   * <tt>/etc/services</tt>. On Windows, service names may be found in the file
+   * <tt>c:\\windows\\system32\\drivers\\etc\\services</tt>. Operating systems
+   * may use additional locations when resolving service names.
+   */
+  basic_resolver_query(const protocol_type& protocol,
+      const std::string& service,
+      resolver_query_base::flags resolve_flags = passive | address_configured)
+    : hints_(),
+      host_name_(),
+      service_name_(service)
+  {
+    hints_.ai_flags = static_cast<int>(resolve_flags);
+    hints_.ai_family = protocol.family();
+    hints_.ai_socktype = protocol.type();
+    hints_.ai_protocol = protocol.protocol();
+    hints_.ai_addrlen = 0;
+    hints_.ai_canonname = 0;
+    hints_.ai_addr = 0;
+    hints_.ai_next = 0;
+  }
+
+  /// Construct with specified host name and service name for any protocol.
+  /**
+   * This constructor is typically used to perform name resolution for
+   * communication with remote hosts.
+   *
+   * @param host A string identifying a location. May be a descriptive name or
+   * a numeric address string. If an empty string and the passive flag has been
+   * specified, the resolved endpoints are suitable for local service binding.
+   * If an empty string and passive is not specified, the resolved endpoints
+   * will use the loopback address.
+   *
+   * @param service A string identifying the requested service. This may be a
+   * descriptive name or a numeric string corresponding to a port number. May
+   * be an empty string, in which case all resolved endpoints will have a port
+   * number of 0.
+   *
+   * @param resolve_flags A set of flags that determine how name resolution
+   * should be performed. The default flags are suitable for communication with
+   * remote hosts.
+   *
+   * @note On POSIX systems, host names may be locally defined in the file
+   * <tt>/etc/hosts</tt>. On Windows, host names may be defined in the file
+   * <tt>c:\\windows\\system32\\drivers\\etc\\hosts</tt>. Remote host name
+   * resolution is performed using DNS. Operating systems may use additional
+   * locations when resolving host names (such as NETBIOS names on Windows).
+   *
+   * On POSIX systems, service names are typically defined in the file
+   * <tt>/etc/services</tt>. On Windows, service names may be found in the file
+   * <tt>c:\\windows\\system32\\drivers\\etc\\services</tt>. Operating systems
+   * may use additional locations when resolving service names.
+   */
+  basic_resolver_query(const std::string& host, const std::string& service,
+      resolver_query_base::flags resolve_flags = address_configured)
+    : hints_(),
+      host_name_(host),
+      service_name_(service)
+  {
+    typename InternetProtocol::endpoint endpoint;
+    hints_.ai_flags = static_cast<int>(resolve_flags);
+    hints_.ai_family = ASIO_OS_DEF(AF_UNSPEC);
+    hints_.ai_socktype = endpoint.protocol().type();
+    hints_.ai_protocol = endpoint.protocol().protocol();
+    hints_.ai_addrlen = 0;
+    hints_.ai_canonname = 0;
+    hints_.ai_addr = 0;
+    hints_.ai_next = 0;
+  }
+
+  /// Construct with specified host name and service name for a given protocol.
+  /**
+   * This constructor is typically used to perform name resolution for
+   * communication with remote hosts.
+   *
+   * @param protocol A protocol object, normally representing either the IPv4 or
+   * IPv6 version of an internet protocol.
+   *
+   * @param host A string identifying a location. May be a descriptive name or
+   * a numeric address string. If an empty string and the passive flag has been
+   * specified, the resolved endpoints are suitable for local service binding.
+   * If an empty string and passive is not specified, the resolved endpoints
+   * will use the loopback address.
+   *
+   * @param service A string identifying the requested service. This may be a
+   * descriptive name or a numeric string corresponding to a port number. May
+   * be an empty string, in which case all resolved endpoints will have a port
+   * number of 0.
+   *
+   * @param resolve_flags A set of flags that determine how name resolution
+   * should be performed. The default flags are suitable for communication with
+   * remote hosts.
+   *
+   * @note On POSIX systems, host names may be locally defined in the file
+   * <tt>/etc/hosts</tt>. On Windows, host names may be defined in the file
+   * <tt>c:\\windows\\system32\\drivers\\etc\\hosts</tt>. Remote host name
+   * resolution is performed using DNS. Operating systems may use additional
+   * locations when resolving host names (such as NETBIOS names on Windows).
+   *
+   * On POSIX systems, service names are typically defined in the file
+   * <tt>/etc/services</tt>. On Windows, service names may be found in the file
+   * <tt>c:\\windows\\system32\\drivers\\etc\\services</tt>. Operating systems
+   * may use additional locations when resolving service names.
+   */
+  basic_resolver_query(const protocol_type& protocol,
+      const std::string& host, const std::string& service,
+      resolver_query_base::flags resolve_flags = address_configured)
+    : hints_(),
+      host_name_(host),
+      service_name_(service)
+  {
+    hints_.ai_flags = static_cast<int>(resolve_flags);
+    hints_.ai_family = protocol.family();
+    hints_.ai_socktype = protocol.type();
+    hints_.ai_protocol = protocol.protocol();
+    hints_.ai_addrlen = 0;
+    hints_.ai_canonname = 0;
+    hints_.ai_addr = 0;
+    hints_.ai_next = 0;
+  }
+
+  /// Get the hints associated with the query.
+  const asio::detail::addrinfo_type& hints() const
+  {
+    return hints_;
+  }
+
+  /// Get the host name associated with the query.
+  std::string host_name() const
+  {
+    return host_name_;
+  }
+
+  /// Get the service name associated with the query.
+  std::string service_name() const
+  {
+    return service_name_;
+  }
+
+private:
+  asio::detail::addrinfo_type hints_;
+  std::string host_name_;
+  std::string service_name_;
+};
+
+} // namespace ip
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IP_BASIC_RESOLVER_QUERY_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/ip/basic_resolver_results.hpp b/link/modules/asio-standalone/asio/include/asio/ip/basic_resolver_results.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/ip/basic_resolver_results.hpp
@@ -0,0 +1,311 @@
+//
+// ip/basic_resolver_results.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_IP_BASIC_RESOLVER_RESULTS_HPP
+#define ASIO_IP_BASIC_RESOLVER_RESULTS_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <cstddef>
+#include <cstring>
+#include "asio/detail/socket_ops.hpp"
+#include "asio/detail/socket_types.hpp"
+#include "asio/ip/basic_resolver_iterator.hpp"
+
+#if defined(ASIO_WINDOWS_RUNTIME)
+# include "asio/detail/winrt_utils.hpp"
+#endif // defined(ASIO_WINDOWS_RUNTIME)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace ip {
+
+/// A range of entries produced by a resolver.
+/**
+ * The asio::ip::basic_resolver_results class template is used to define
+ * a range over the results returned by a resolver.
+ *
+ * The iterator's value_type, obtained when a results iterator is dereferenced,
+ * is: @code const basic_resolver_entry<InternetProtocol> @endcode
+ *
+ * @note For backward compatibility, basic_resolver_results is derived from
+ * basic_resolver_iterator. This derivation is deprecated.
+ *
+ * @par Thread Safety
+ * @e Distinct @e objects: Safe.@n
+ * @e Shared @e objects: Unsafe.
+ */
+template <typename InternetProtocol>
+class basic_resolver_results
+#if !defined(ASIO_NO_DEPRECATED)
+  : public basic_resolver_iterator<InternetProtocol>
+#else // !defined(ASIO_NO_DEPRECATED)
+  : private basic_resolver_iterator<InternetProtocol>
+#endif // !defined(ASIO_NO_DEPRECATED)
+{
+public:
+  /// The protocol type associated with the results.
+  typedef InternetProtocol protocol_type;
+
+  /// The endpoint type associated with the results.
+  typedef typename protocol_type::endpoint endpoint_type;
+
+  /// The type of a value in the results range.
+  typedef basic_resolver_entry<protocol_type> value_type;
+
+  /// The type of a const reference to a value in the range.
+  typedef const value_type& const_reference;
+
+  /// The type of a non-const reference to a value in the range.
+  typedef value_type& reference;
+
+  /// The type of an iterator into the range.
+  typedef basic_resolver_iterator<protocol_type> const_iterator;
+
+  /// The type of an iterator into the range.
+  typedef const_iterator iterator;
+
+  /// Type used to represent the distance between two iterators in the range.
+  typedef std::ptrdiff_t difference_type;
+
+  /// Type used to represent a count of the elements in the range.
+  typedef std::size_t size_type;
+
+  /// Default constructor creates an empty range.
+  basic_resolver_results()
+  {
+  }
+
+  /// Copy constructor.
+  basic_resolver_results(const basic_resolver_results& other)
+    : basic_resolver_iterator<InternetProtocol>(other)
+  {
+  }
+
+#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+  /// Move constructor.
+  basic_resolver_results(basic_resolver_results&& other)
+    : basic_resolver_iterator<InternetProtocol>(
+        ASIO_MOVE_CAST(basic_resolver_results)(other))
+  {
+  }
+#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+
+  /// Assignment operator.
+  basic_resolver_results& operator=(const basic_resolver_results& other)
+  {
+    basic_resolver_iterator<InternetProtocol>::operator=(other);
+    return *this;
+  }
+
+#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+  /// Move-assignment operator.
+  basic_resolver_results& operator=(basic_resolver_results&& other)
+  {
+    basic_resolver_iterator<InternetProtocol>::operator=(
+        ASIO_MOVE_CAST(basic_resolver_results)(other));
+    return *this;
+  }
+#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+
+#if !defined(GENERATING_DOCUMENTATION)
+  // Create results from an addrinfo list returned by getaddrinfo.
+  static basic_resolver_results create(
+      asio::detail::addrinfo_type* address_info,
+      const std::string& host_name, const std::string& service_name)
+  {
+    basic_resolver_results results;
+    if (!address_info)
+      return results;
+
+    std::string actual_host_name = host_name;
+    if (address_info->ai_canonname)
+      actual_host_name = address_info->ai_canonname;
+
+    results.values_.reset(new values_type);
+
+    while (address_info)
+    {
+      if (address_info->ai_family == ASIO_OS_DEF(AF_INET)
+          || address_info->ai_family == ASIO_OS_DEF(AF_INET6))
+      {
+        using namespace std; // For memcpy.
+        typename InternetProtocol::endpoint endpoint;
+        endpoint.resize(static_cast<std::size_t>(address_info->ai_addrlen));
+        memcpy(endpoint.data(), address_info->ai_addr,
+            address_info->ai_addrlen);
+        results.values_->push_back(
+            basic_resolver_entry<InternetProtocol>(endpoint,
+              actual_host_name, service_name));
+      }
+      address_info = address_info->ai_next;
+    }
+
+    return results;
+  }
+
+  // Create results from an endpoint, host name and service name.
+  static basic_resolver_results create(const endpoint_type& endpoint,
+      const std::string& host_name, const std::string& service_name)
+  {
+    basic_resolver_results results;
+    results.values_.reset(new values_type);
+    results.values_->push_back(
+        basic_resolver_entry<InternetProtocol>(
+          endpoint, host_name, service_name));
+    return results;
+  }
+
+  // Create results from a sequence of endpoints, host and service name.
+  template <typename EndpointIterator>
+  static basic_resolver_results create(
+      EndpointIterator begin, EndpointIterator end,
+      const std::string& host_name, const std::string& service_name)
+  {
+    basic_resolver_results results;
+    if (begin != end)
+    {
+      results.values_.reset(new values_type);
+      for (EndpointIterator ep_iter = begin; ep_iter != end; ++ep_iter)
+      {
+        results.values_->push_back(
+            basic_resolver_entry<InternetProtocol>(
+              *ep_iter, host_name, service_name));
+      }
+    }
+    return results;
+  }
+
+# if defined(ASIO_WINDOWS_RUNTIME)
+  // Create results from a Windows Runtime list of EndpointPair objects.
+  static basic_resolver_results create(
+      Windows::Foundation::Collections::IVectorView<
+        Windows::Networking::EndpointPair^>^ endpoints,
+      const asio::detail::addrinfo_type& hints,
+      const std::string& host_name, const std::string& service_name)
+  {
+    basic_resolver_results results;
+    if (endpoints->Size)
+    {
+      results.values_.reset(new values_type);
+      for (unsigned int i = 0; i < endpoints->Size; ++i)
+      {
+        auto pair = endpoints->GetAt(i);
+
+        if (hints.ai_family == ASIO_OS_DEF(AF_INET)
+            && pair->RemoteHostName->Type
+              != Windows::Networking::HostNameType::Ipv4)
+          continue;
+
+        if (hints.ai_family == ASIO_OS_DEF(AF_INET6)
+            && pair->RemoteHostName->Type
+              != Windows::Networking::HostNameType::Ipv6)
+          continue;
+
+        results.values_->push_back(
+            basic_resolver_entry<InternetProtocol>(
+              typename InternetProtocol::endpoint(
+                ip::make_address(
+                  asio::detail::winrt_utils::string(
+                    pair->RemoteHostName->CanonicalName)),
+                asio::detail::winrt_utils::integer(
+                  pair->RemoteServiceName)),
+              host_name, service_name));
+      }
+    }
+    return results;
+  }
+# endif // defined(ASIO_WINDOWS_RUNTIME)
+#endif // !defined(GENERATING_DOCUMENTATION)
+
+  /// Get the number of entries in the results range.
+  size_type size() const ASIO_NOEXCEPT
+  {
+    return this->values_ ? this->values_->size() : 0;
+  }
+
+  /// Get the maximum number of entries permitted in a results range.
+  size_type max_size() const ASIO_NOEXCEPT
+  {
+    return this->values_ ? this->values_->max_size() : values_type().max_size();
+  }
+
+  /// Determine whether the results range is empty.
+  bool empty() const ASIO_NOEXCEPT
+  {
+    return this->values_ ? this->values_->empty() : true;
+  }
+
+  /// Obtain a begin iterator for the results range.
+  const_iterator begin() const
+  {
+    basic_resolver_results tmp(*this);
+    tmp.index_ = 0;
+    return ASIO_MOVE_CAST(basic_resolver_results)(tmp);
+  }
+
+  /// Obtain an end iterator for the results range.
+  const_iterator end() const
+  {
+    return const_iterator();
+  }
+
+  /// Obtain a begin iterator for the results range.
+  const_iterator cbegin() const
+  {
+    return begin();
+  }
+
+  /// Obtain an end iterator for the results range.
+  const_iterator cend() const
+  {
+    return end();
+  }
+
+  /// Swap the results range with another.
+  void swap(basic_resolver_results& that) ASIO_NOEXCEPT
+  {
+    if (this != &that)
+    {
+      this->values_.swap(that.values_);
+      std::size_t index = this->index_;
+      this->index_ = that.index_;
+      that.index_ = index;
+    }
+  }
+
+  /// Test two iterators for equality.
+  friend bool operator==(const basic_resolver_results& a,
+      const basic_resolver_results& b)
+  {
+    return a.equal(b);
+  }
+
+  /// Test two iterators for inequality.
+  friend bool operator!=(const basic_resolver_results& a,
+      const basic_resolver_results& b)
+  {
+    return !a.equal(b);
+  }
+
+private:
+  typedef std::vector<basic_resolver_entry<InternetProtocol> > values_type;
+};
+
+} // namespace ip
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IP_BASIC_RESOLVER_RESULTS_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/ip/detail/endpoint.hpp b/link/modules/asio-standalone/asio/include/asio/ip/detail/endpoint.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/ip/detail/endpoint.hpp
@@ -0,0 +1,141 @@
+//
+// ip/detail/endpoint.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_IP_DETAIL_ENDPOINT_HPP
+#define ASIO_IP_DETAIL_ENDPOINT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <string>
+#include "asio/detail/socket_types.hpp"
+#include "asio/detail/winsock_init.hpp"
+#include "asio/error_code.hpp"
+#include "asio/ip/address.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace ip {
+namespace detail {
+
+// Helper class for implementating an IP endpoint.
+class endpoint
+{
+public:
+  // Default constructor.
+  ASIO_DECL endpoint() ASIO_NOEXCEPT;
+
+  // Construct an endpoint using a family and port number.
+  ASIO_DECL endpoint(int family,
+      unsigned short port_num) ASIO_NOEXCEPT;
+
+  // Construct an endpoint using an address and port number.
+  ASIO_DECL endpoint(const asio::ip::address& addr,
+      unsigned short port_num) ASIO_NOEXCEPT;
+
+  // Copy constructor.
+  endpoint(const endpoint& other) ASIO_NOEXCEPT
+    : data_(other.data_)
+  {
+  }
+
+  // Assign from another endpoint.
+  endpoint& operator=(const endpoint& other) ASIO_NOEXCEPT
+  {
+    data_ = other.data_;
+    return *this;
+  }
+
+  // Get the underlying endpoint in the native type.
+  asio::detail::socket_addr_type* data() ASIO_NOEXCEPT
+  {
+    return &data_.base;
+  }
+
+  // Get the underlying endpoint in the native type.
+  const asio::detail::socket_addr_type* data() const ASIO_NOEXCEPT
+  {
+    return &data_.base;
+  }
+
+  // Get the underlying size of the endpoint in the native type.
+  std::size_t size() const ASIO_NOEXCEPT
+  {
+    if (is_v4())
+      return sizeof(asio::detail::sockaddr_in4_type);
+    else
+      return sizeof(asio::detail::sockaddr_in6_type);
+  }
+
+  // Set the underlying size of the endpoint in the native type.
+  ASIO_DECL void resize(std::size_t new_size);
+
+  // Get the capacity of the endpoint in the native type.
+  std::size_t capacity() const ASIO_NOEXCEPT
+  {
+    return sizeof(data_);
+  }
+
+  // Get the port associated with the endpoint.
+  ASIO_DECL unsigned short port() const ASIO_NOEXCEPT;
+
+  // Set the port associated with the endpoint.
+  ASIO_DECL void port(unsigned short port_num) ASIO_NOEXCEPT;
+
+  // Get the IP address associated with the endpoint.
+  ASIO_DECL asio::ip::address address() const ASIO_NOEXCEPT;
+
+  // Set the IP address associated with the endpoint.
+  ASIO_DECL void address(
+      const asio::ip::address& addr) ASIO_NOEXCEPT;
+
+  // Compare two endpoints for equality.
+  ASIO_DECL friend bool operator==(const endpoint& e1,
+      const endpoint& e2) ASIO_NOEXCEPT;
+
+  // Compare endpoints for ordering.
+  ASIO_DECL friend bool operator<(const endpoint& e1,
+      const endpoint& e2) ASIO_NOEXCEPT;
+
+  // Determine whether the endpoint is IPv4.
+  bool is_v4() const ASIO_NOEXCEPT
+  {
+    return data_.base.sa_family == ASIO_OS_DEF(AF_INET);
+  }
+
+#if !defined(ASIO_NO_IOSTREAM)
+  // Convert to a string.
+  ASIO_DECL std::string to_string() const;
+#endif // !defined(ASIO_NO_IOSTREAM)
+
+private:
+  // The underlying IP socket address.
+  union data_union
+  {
+    asio::detail::socket_addr_type base;
+    asio::detail::sockaddr_in4_type v4;
+    asio::detail::sockaddr_in6_type v6;
+  } data_;
+};
+
+} // namespace detail
+} // namespace ip
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/ip/detail/impl/endpoint.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // ASIO_IP_DETAIL_ENDPOINT_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/ip/detail/impl/endpoint.ipp b/link/modules/asio-standalone/asio/include/asio/ip/detail/impl/endpoint.ipp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/ip/detail/impl/endpoint.ipp
@@ -0,0 +1,199 @@
+//
+// ip/detail/impl/endpoint.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_IP_DETAIL_IMPL_ENDPOINT_IPP
+#define ASIO_IP_DETAIL_IMPL_ENDPOINT_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <cstring>
+#if !defined(ASIO_NO_IOSTREAM)
+# include <sstream>
+#endif // !defined(ASIO_NO_IOSTREAM)
+#include "asio/detail/socket_ops.hpp"
+#include "asio/detail/throw_error.hpp"
+#include "asio/error.hpp"
+#include "asio/ip/detail/endpoint.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace ip {
+namespace detail {
+
+endpoint::endpoint() ASIO_NOEXCEPT
+  : data_()
+{
+  data_.v4.sin_family = ASIO_OS_DEF(AF_INET);
+  data_.v4.sin_port = 0;
+  data_.v4.sin_addr.s_addr = ASIO_OS_DEF(INADDR_ANY);
+}
+
+endpoint::endpoint(int family, unsigned short port_num) ASIO_NOEXCEPT
+  : data_()
+{
+  using namespace std; // For memcpy.
+  if (family == ASIO_OS_DEF(AF_INET))
+  {
+    data_.v4.sin_family = ASIO_OS_DEF(AF_INET);
+    data_.v4.sin_port =
+      asio::detail::socket_ops::host_to_network_short(port_num);
+    data_.v4.sin_addr.s_addr = ASIO_OS_DEF(INADDR_ANY);
+  }
+  else
+  {
+    data_.v6.sin6_family = ASIO_OS_DEF(AF_INET6);
+    data_.v6.sin6_port =
+      asio::detail::socket_ops::host_to_network_short(port_num);
+    data_.v6.sin6_flowinfo = 0;
+    data_.v6.sin6_addr.s6_addr[0] = 0; data_.v6.sin6_addr.s6_addr[1] = 0;
+    data_.v6.sin6_addr.s6_addr[2] = 0; data_.v6.sin6_addr.s6_addr[3] = 0;
+    data_.v6.sin6_addr.s6_addr[4] = 0; data_.v6.sin6_addr.s6_addr[5] = 0;
+    data_.v6.sin6_addr.s6_addr[6] = 0; data_.v6.sin6_addr.s6_addr[7] = 0;
+    data_.v6.sin6_addr.s6_addr[8] = 0; data_.v6.sin6_addr.s6_addr[9] = 0;
+    data_.v6.sin6_addr.s6_addr[10] = 0; data_.v6.sin6_addr.s6_addr[11] = 0;
+    data_.v6.sin6_addr.s6_addr[12] = 0; data_.v6.sin6_addr.s6_addr[13] = 0;
+    data_.v6.sin6_addr.s6_addr[14] = 0; data_.v6.sin6_addr.s6_addr[15] = 0;
+    data_.v6.sin6_scope_id = 0;
+  }
+}
+
+endpoint::endpoint(const asio::ip::address& addr,
+    unsigned short port_num) ASIO_NOEXCEPT
+  : data_()
+{
+  using namespace std; // For memcpy.
+  if (addr.is_v4())
+  {
+    data_.v4.sin_family = ASIO_OS_DEF(AF_INET);
+    data_.v4.sin_port =
+      asio::detail::socket_ops::host_to_network_short(port_num);
+    data_.v4.sin_addr.s_addr =
+      asio::detail::socket_ops::host_to_network_long(
+        addr.to_v4().to_uint());
+  }
+  else
+  {
+    data_.v6.sin6_family = ASIO_OS_DEF(AF_INET6);
+    data_.v6.sin6_port =
+      asio::detail::socket_ops::host_to_network_short(port_num);
+    data_.v6.sin6_flowinfo = 0;
+    asio::ip::address_v6 v6_addr = addr.to_v6();
+    asio::ip::address_v6::bytes_type bytes = v6_addr.to_bytes();
+    memcpy(data_.v6.sin6_addr.s6_addr, bytes.data(), 16);
+    data_.v6.sin6_scope_id =
+      static_cast<asio::detail::u_long_type>(
+        v6_addr.scope_id());
+  }
+}
+
+void endpoint::resize(std::size_t new_size)
+{
+  if (new_size > sizeof(asio::detail::sockaddr_storage_type))
+  {
+    asio::error_code ec(asio::error::invalid_argument);
+    asio::detail::throw_error(ec);
+  }
+}
+
+unsigned short endpoint::port() const ASIO_NOEXCEPT
+{
+  if (is_v4())
+  {
+    return asio::detail::socket_ops::network_to_host_short(
+        data_.v4.sin_port);
+  }
+  else
+  {
+    return asio::detail::socket_ops::network_to_host_short(
+        data_.v6.sin6_port);
+  }
+}
+
+void endpoint::port(unsigned short port_num) ASIO_NOEXCEPT
+{
+  if (is_v4())
+  {
+    data_.v4.sin_port
+      = asio::detail::socket_ops::host_to_network_short(port_num);
+  }
+  else
+  {
+    data_.v6.sin6_port
+      = asio::detail::socket_ops::host_to_network_short(port_num);
+  }
+}
+
+asio::ip::address endpoint::address() const ASIO_NOEXCEPT
+{
+  using namespace std; // For memcpy.
+  if (is_v4())
+  {
+    return asio::ip::address_v4(
+        asio::detail::socket_ops::network_to_host_long(
+          data_.v4.sin_addr.s_addr));
+  }
+  else
+  {
+    asio::ip::address_v6::bytes_type bytes;
+#if defined(ASIO_HAS_STD_ARRAY)
+    memcpy(bytes.data(), data_.v6.sin6_addr.s6_addr, 16);
+#else // defined(ASIO_HAS_STD_ARRAY)
+    memcpy(bytes.elems, data_.v6.sin6_addr.s6_addr, 16);
+#endif // defined(ASIO_HAS_STD_ARRAY)
+    return asio::ip::address_v6(bytes, data_.v6.sin6_scope_id);
+  }
+}
+
+void endpoint::address(const asio::ip::address& addr) ASIO_NOEXCEPT
+{
+  endpoint tmp_endpoint(addr, port());
+  data_ = tmp_endpoint.data_;
+}
+
+bool operator==(const endpoint& e1, const endpoint& e2) ASIO_NOEXCEPT
+{
+  return e1.address() == e2.address() && e1.port() == e2.port();
+}
+
+bool operator<(const endpoint& e1, const endpoint& e2) ASIO_NOEXCEPT
+{
+  if (e1.address() < e2.address())
+    return true;
+  if (e1.address() != e2.address())
+    return false;
+  return e1.port() < e2.port();
+}
+
+#if !defined(ASIO_NO_IOSTREAM)
+std::string endpoint::to_string() const
+{
+  std::ostringstream tmp_os;
+  tmp_os.imbue(std::locale::classic());
+  if (is_v4())
+    tmp_os << address();
+  else
+    tmp_os << '[' << address() << ']';
+  tmp_os << ':' << port();
+
+  return tmp_os.str();
+}
+#endif // !defined(ASIO_NO_IOSTREAM)
+
+} // namespace detail
+} // namespace ip
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IP_DETAIL_IMPL_ENDPOINT_IPP
diff --git a/link/modules/asio-standalone/asio/include/asio/ip/detail/socket_option.hpp b/link/modules/asio-standalone/asio/include/asio/ip/detail/socket_option.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/ip/detail/socket_option.hpp
@@ -0,0 +1,566 @@
+//
+// detail/socket_option.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_IP_DETAIL_SOCKET_OPTION_HPP
+#define ASIO_IP_DETAIL_SOCKET_OPTION_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <cstddef>
+#include <cstring>
+#include <stdexcept>
+#include "asio/detail/socket_ops.hpp"
+#include "asio/detail/socket_types.hpp"
+#include "asio/detail/throw_exception.hpp"
+#include "asio/ip/address.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace ip {
+namespace detail {
+namespace socket_option {
+
+// Helper template for implementing multicast enable loopback options.
+template <int IPv4_Level, int IPv4_Name, int IPv6_Level, int IPv6_Name>
+class multicast_enable_loopback
+{
+public:
+#if defined(__sun) || defined(__osf__)
+  typedef unsigned char ipv4_value_type;
+  typedef unsigned char ipv6_value_type;
+#elif defined(_AIX) || defined(__hpux) || defined(__QNXNTO__) 
+  typedef unsigned char ipv4_value_type;
+  typedef unsigned int ipv6_value_type;
+#else
+  typedef int ipv4_value_type;
+  typedef int ipv6_value_type;
+#endif
+
+  // Default constructor.
+  multicast_enable_loopback()
+    : ipv4_value_(0),
+      ipv6_value_(0)
+  {
+  }
+
+  // Construct with a specific option value.
+  explicit multicast_enable_loopback(bool v)
+    : ipv4_value_(v ? 1 : 0),
+      ipv6_value_(v ? 1 : 0)
+  {
+  }
+
+  // Set the value of the boolean.
+  multicast_enable_loopback& operator=(bool v)
+  {
+    ipv4_value_ = v ? 1 : 0;
+    ipv6_value_ = v ? 1 : 0;
+    return *this;
+  }
+
+  // Get the current value of the boolean.
+  bool value() const
+  {
+    return !!ipv4_value_;
+  }
+
+  // Convert to bool.
+  operator bool() const
+  {
+    return !!ipv4_value_;
+  }
+
+  // Test for false.
+  bool operator!() const
+  {
+    return !ipv4_value_;
+  }
+
+  // Get the level of the socket option.
+  template <typename Protocol>
+  int level(const Protocol& protocol) const
+  {
+    if (protocol.family() == PF_INET6)
+      return IPv6_Level;
+    return IPv4_Level;
+  }
+
+  // Get the name of the socket option.
+  template <typename Protocol>
+  int name(const Protocol& protocol) const
+  {
+    if (protocol.family() == PF_INET6)
+      return IPv6_Name;
+    return IPv4_Name;
+  }
+
+  // Get the address of the boolean data.
+  template <typename Protocol>
+  void* data(const Protocol& protocol)
+  {
+    if (protocol.family() == PF_INET6)
+      return &ipv6_value_;
+    return &ipv4_value_;
+  }
+
+  // Get the address of the boolean data.
+  template <typename Protocol>
+  const void* data(const Protocol& protocol) const
+  {
+    if (protocol.family() == PF_INET6)
+      return &ipv6_value_;
+    return &ipv4_value_;
+  }
+
+  // Get the size of the boolean data.
+  template <typename Protocol>
+  std::size_t size(const Protocol& protocol) const
+  {
+    if (protocol.family() == PF_INET6)
+      return sizeof(ipv6_value_);
+    return sizeof(ipv4_value_);
+  }
+
+  // Set the size of the boolean data.
+  template <typename Protocol>
+  void resize(const Protocol& protocol, std::size_t s)
+  {
+    if (protocol.family() == PF_INET6)
+    {
+      if (s != sizeof(ipv6_value_))
+      {
+        std::length_error ex("multicast_enable_loopback socket option resize");
+        asio::detail::throw_exception(ex);
+      }
+      ipv4_value_ = ipv6_value_ ? 1 : 0;
+    }
+    else
+    {
+      if (s != sizeof(ipv4_value_))
+      {
+        std::length_error ex("multicast_enable_loopback socket option resize");
+        asio::detail::throw_exception(ex);
+      }
+      ipv6_value_ = ipv4_value_ ? 1 : 0;
+    }
+  }
+
+private:
+  ipv4_value_type ipv4_value_;
+  ipv6_value_type ipv6_value_;
+};
+
+// Helper template for implementing unicast hops options.
+template <int IPv4_Level, int IPv4_Name, int IPv6_Level, int IPv6_Name>
+class unicast_hops
+{
+public:
+  // Default constructor.
+  unicast_hops()
+    : value_(0)
+  {
+  }
+
+  // Construct with a specific option value.
+  explicit unicast_hops(int v)
+    : value_(v)
+  {
+  }
+
+  // Set the value of the option.
+  unicast_hops& operator=(int v)
+  {
+    value_ = v;
+    return *this;
+  }
+
+  // Get the current value of the option.
+  int value() const
+  {
+    return value_;
+  }
+
+  // Get the level of the socket option.
+  template <typename Protocol>
+  int level(const Protocol& protocol) const
+  {
+    if (protocol.family() == PF_INET6)
+      return IPv6_Level;
+    return IPv4_Level;
+  }
+
+  // Get the name of the socket option.
+  template <typename Protocol>
+  int name(const Protocol& protocol) const
+  {
+    if (protocol.family() == PF_INET6)
+      return IPv6_Name;
+    return IPv4_Name;
+  }
+
+  // Get the address of the data.
+  template <typename Protocol>
+  int* data(const Protocol&)
+  {
+    return &value_;
+  }
+
+  // Get the address of the data.
+  template <typename Protocol>
+  const int* data(const Protocol&) const
+  {
+    return &value_;
+  }
+
+  // Get the size of the data.
+  template <typename Protocol>
+  std::size_t size(const Protocol&) const
+  {
+    return sizeof(value_);
+  }
+
+  // Set the size of the data.
+  template <typename Protocol>
+  void resize(const Protocol&, std::size_t s)
+  {
+    if (s != sizeof(value_))
+    {
+      std::length_error ex("unicast hops socket option resize");
+      asio::detail::throw_exception(ex);
+    }
+#if defined(__hpux)
+    if (value_ < 0)
+      value_ = value_ & 0xFF;
+#endif
+  }
+
+private:
+  int value_;
+};
+
+// Helper template for implementing multicast hops options.
+template <int IPv4_Level, int IPv4_Name, int IPv6_Level, int IPv6_Name>
+class multicast_hops
+{
+public:
+#if defined(ASIO_WINDOWS) && defined(UNDER_CE)
+  typedef int ipv4_value_type;
+#else
+  typedef unsigned char ipv4_value_type;
+#endif
+  typedef int ipv6_value_type;
+
+  // Default constructor.
+  multicast_hops()
+    : ipv4_value_(0),
+      ipv6_value_(0)
+  {
+  }
+
+  // Construct with a specific option value.
+  explicit multicast_hops(int v)
+  {
+    if (v < 0 || v > 255)
+    {
+      std::out_of_range ex("multicast hops value out of range");
+      asio::detail::throw_exception(ex);
+    }
+    ipv4_value_ = (ipv4_value_type)v;
+    ipv6_value_ = v;
+  }
+
+  // Set the value of the option.
+  multicast_hops& operator=(int v)
+  {
+    if (v < 0 || v > 255)
+    {
+      std::out_of_range ex("multicast hops value out of range");
+      asio::detail::throw_exception(ex);
+    }
+    ipv4_value_ = (ipv4_value_type)v;
+    ipv6_value_ = v;
+    return *this;
+  }
+
+  // Get the current value of the option.
+  int value() const
+  {
+    return ipv6_value_;
+  }
+
+  // Get the level of the socket option.
+  template <typename Protocol>
+  int level(const Protocol& protocol) const
+  {
+    if (protocol.family() == PF_INET6)
+      return IPv6_Level;
+    return IPv4_Level;
+  }
+
+  // Get the name of the socket option.
+  template <typename Protocol>
+  int name(const Protocol& protocol) const
+  {
+    if (protocol.family() == PF_INET6)
+      return IPv6_Name;
+    return IPv4_Name;
+  }
+
+  // Get the address of the data.
+  template <typename Protocol>
+  void* data(const Protocol& protocol)
+  {
+    if (protocol.family() == PF_INET6)
+      return &ipv6_value_;
+    return &ipv4_value_;
+  }
+
+  // Get the address of the data.
+  template <typename Protocol>
+  const void* data(const Protocol& protocol) const
+  {
+    if (protocol.family() == PF_INET6)
+      return &ipv6_value_;
+    return &ipv4_value_;
+  }
+
+  // Get the size of the data.
+  template <typename Protocol>
+  std::size_t size(const Protocol& protocol) const
+  {
+    if (protocol.family() == PF_INET6)
+      return sizeof(ipv6_value_);
+    return sizeof(ipv4_value_);
+  }
+
+  // Set the size of the data.
+  template <typename Protocol>
+  void resize(const Protocol& protocol, std::size_t s)
+  {
+    if (protocol.family() == PF_INET6)
+    {
+      if (s != sizeof(ipv6_value_))
+      {
+        std::length_error ex("multicast hops socket option resize");
+        asio::detail::throw_exception(ex);
+      }
+      if (ipv6_value_ < 0)
+        ipv4_value_ = 0;
+      else if (ipv6_value_ > 255)
+        ipv4_value_ = 255;
+      else
+        ipv4_value_ = (ipv4_value_type)ipv6_value_;
+    }
+    else
+    {
+      if (s != sizeof(ipv4_value_))
+      {
+        std::length_error ex("multicast hops socket option resize");
+        asio::detail::throw_exception(ex);
+      }
+      ipv6_value_ = ipv4_value_;
+    }
+  }
+
+private:
+  ipv4_value_type ipv4_value_;
+  ipv6_value_type ipv6_value_;
+};
+
+// Helper template for implementing ip_mreq-based options.
+template <int IPv4_Level, int IPv4_Name, int IPv6_Level, int IPv6_Name>
+class multicast_request
+{
+public:
+  // Default constructor.
+  multicast_request()
+    : ipv4_value_(), // Zero-initialisation gives the "any" address.
+      ipv6_value_() // Zero-initialisation gives the "any" address.
+  {
+  }
+
+  // Construct with multicast address only.
+  explicit multicast_request(const address& multicast_address)
+    : ipv4_value_(), // Zero-initialisation gives the "any" address.
+      ipv6_value_() // Zero-initialisation gives the "any" address.
+  {
+    if (multicast_address.is_v6())
+    {
+      using namespace std; // For memcpy.
+      address_v6 ipv6_address = multicast_address.to_v6();
+      address_v6::bytes_type bytes = ipv6_address.to_bytes();
+      memcpy(ipv6_value_.ipv6mr_multiaddr.s6_addr, bytes.data(), 16);
+      ipv6_value_.ipv6mr_interface = ipv6_address.scope_id();
+    }
+    else
+    {
+      ipv4_value_.imr_multiaddr.s_addr =
+        asio::detail::socket_ops::host_to_network_long(
+            multicast_address.to_v4().to_uint());
+      ipv4_value_.imr_interface.s_addr =
+        asio::detail::socket_ops::host_to_network_long(
+            address_v4::any().to_uint());
+    }
+  }
+
+  // Construct with multicast address and IPv4 address specifying an interface.
+  explicit multicast_request(const address_v4& multicast_address,
+      const address_v4& network_interface = address_v4::any())
+    : ipv6_value_() // Zero-initialisation gives the "any" address.
+  {
+    ipv4_value_.imr_multiaddr.s_addr =
+      asio::detail::socket_ops::host_to_network_long(
+          multicast_address.to_uint());
+    ipv4_value_.imr_interface.s_addr =
+      asio::detail::socket_ops::host_to_network_long(
+          network_interface.to_uint());
+  }
+
+  // Construct with multicast address and IPv6 network interface index.
+  explicit multicast_request(
+      const address_v6& multicast_address,
+      unsigned long network_interface = 0)
+    : ipv4_value_() // Zero-initialisation gives the "any" address.
+  {
+    using namespace std; // For memcpy.
+    address_v6::bytes_type bytes = multicast_address.to_bytes();
+    memcpy(ipv6_value_.ipv6mr_multiaddr.s6_addr, bytes.data(), 16);
+    if (network_interface)
+      ipv6_value_.ipv6mr_interface = network_interface;
+    else
+      ipv6_value_.ipv6mr_interface = multicast_address.scope_id();
+  }
+
+  // Get the level of the socket option.
+  template <typename Protocol>
+  int level(const Protocol& protocol) const
+  {
+    if (protocol.family() == PF_INET6)
+      return IPv6_Level;
+    return IPv4_Level;
+  }
+
+  // Get the name of the socket option.
+  template <typename Protocol>
+  int name(const Protocol& protocol) const
+  {
+    if (protocol.family() == PF_INET6)
+      return IPv6_Name;
+    return IPv4_Name;
+  }
+
+  // Get the address of the option data.
+  template <typename Protocol>
+  const void* data(const Protocol& protocol) const
+  {
+    if (protocol.family() == PF_INET6)
+      return &ipv6_value_;
+    return &ipv4_value_;
+  }
+
+  // Get the size of the option data.
+  template <typename Protocol>
+  std::size_t size(const Protocol& protocol) const
+  {
+    if (protocol.family() == PF_INET6)
+      return sizeof(ipv6_value_);
+    return sizeof(ipv4_value_);
+  }
+
+private:
+  asio::detail::in4_mreq_type ipv4_value_;
+  asio::detail::in6_mreq_type ipv6_value_;
+};
+
+// Helper template for implementing options that specify a network interface.
+template <int IPv4_Level, int IPv4_Name, int IPv6_Level, int IPv6_Name>
+class network_interface
+{
+public:
+  // Default constructor.
+  network_interface()
+  {
+    ipv4_value_.s_addr =
+      asio::detail::socket_ops::host_to_network_long(
+          address_v4::any().to_uint());
+    ipv6_value_ = 0;
+  }
+
+  // Construct with IPv4 interface.
+  explicit network_interface(const address_v4& ipv4_interface)
+  {
+    ipv4_value_.s_addr =
+      asio::detail::socket_ops::host_to_network_long(
+          ipv4_interface.to_uint());
+    ipv6_value_ = 0;
+  }
+
+  // Construct with IPv6 interface.
+  explicit network_interface(unsigned int ipv6_interface)
+  {
+    ipv4_value_.s_addr =
+      asio::detail::socket_ops::host_to_network_long(
+          address_v4::any().to_uint());
+    ipv6_value_ = ipv6_interface;
+  }
+
+  // Get the level of the socket option.
+  template <typename Protocol>
+  int level(const Protocol& protocol) const
+  {
+    if (protocol.family() == PF_INET6)
+      return IPv6_Level;
+    return IPv4_Level;
+  }
+
+  // Get the name of the socket option.
+  template <typename Protocol>
+  int name(const Protocol& protocol) const
+  {
+    if (protocol.family() == PF_INET6)
+      return IPv6_Name;
+    return IPv4_Name;
+  }
+
+  // Get the address of the option data.
+  template <typename Protocol>
+  const void* data(const Protocol& protocol) const
+  {
+    if (protocol.family() == PF_INET6)
+      return &ipv6_value_;
+    return &ipv4_value_;
+  }
+
+  // Get the size of the option data.
+  template <typename Protocol>
+  std::size_t size(const Protocol& protocol) const
+  {
+    if (protocol.family() == PF_INET6)
+      return sizeof(ipv6_value_);
+    return sizeof(ipv4_value_);
+  }
+
+private:
+  asio::detail::in4_addr_type ipv4_value_;
+  unsigned int ipv6_value_;
+};
+
+} // namespace socket_option
+} // namespace detail
+} // namespace ip
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IP_DETAIL_SOCKET_OPTION_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/ip/host_name.hpp b/link/modules/asio-standalone/asio/include/asio/ip/host_name.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/ip/host_name.hpp
@@ -0,0 +1,42 @@
+//
+// ip/host_name.hpp
+// ~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_IP_HOST_NAME_HPP
+#define ASIO_IP_HOST_NAME_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <string>
+#include "asio/error_code.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace ip {
+
+/// Get the current host name.
+ASIO_DECL std::string host_name();
+
+/// Get the current host name.
+ASIO_DECL std::string host_name(asio::error_code& ec);
+
+} // namespace ip
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/ip/impl/host_name.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // ASIO_IP_HOST_NAME_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/ip/icmp.hpp b/link/modules/asio-standalone/asio/include/asio/ip/icmp.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/ip/icmp.hpp
@@ -0,0 +1,115 @@
+//
+// ip/icmp.hpp
+// ~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_IP_ICMP_HPP
+#define ASIO_IP_ICMP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/socket_types.hpp"
+#include "asio/basic_raw_socket.hpp"
+#include "asio/ip/basic_endpoint.hpp"
+#include "asio/ip/basic_resolver.hpp"
+#include "asio/ip/basic_resolver_iterator.hpp"
+#include "asio/ip/basic_resolver_query.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace ip {
+
+/// Encapsulates the flags needed for ICMP.
+/**
+ * The asio::ip::icmp class contains flags necessary for ICMP sockets.
+ *
+ * @par Thread Safety
+ * @e Distinct @e objects: Safe.@n
+ * @e Shared @e objects: Safe.
+ *
+ * @par Concepts:
+ * Protocol, InternetProtocol.
+ */
+class icmp
+{
+public:
+  /// The type of a ICMP endpoint.
+  typedef basic_endpoint<icmp> endpoint;
+
+  /// Construct to represent the IPv4 ICMP protocol.
+  static icmp v4() ASIO_NOEXCEPT
+  {
+    return icmp(ASIO_OS_DEF(IPPROTO_ICMP),
+        ASIO_OS_DEF(AF_INET));
+  }
+
+  /// Construct to represent the IPv6 ICMP protocol.
+  static icmp v6() ASIO_NOEXCEPT
+  {
+    return icmp(ASIO_OS_DEF(IPPROTO_ICMPV6),
+        ASIO_OS_DEF(AF_INET6));
+  }
+
+  /// Obtain an identifier for the type of the protocol.
+  int type() const ASIO_NOEXCEPT
+  {
+    return ASIO_OS_DEF(SOCK_RAW);
+  }
+
+  /// Obtain an identifier for the protocol.
+  int protocol() const ASIO_NOEXCEPT
+  {
+    return protocol_;
+  }
+
+  /// Obtain an identifier for the protocol family.
+  int family() const ASIO_NOEXCEPT
+  {
+    return family_;
+  }
+
+  /// The ICMP socket type.
+  typedef basic_raw_socket<icmp> socket;
+
+  /// The ICMP resolver type.
+  typedef basic_resolver<icmp> resolver;
+
+  /// Compare two protocols for equality.
+  friend bool operator==(const icmp& p1, const icmp& p2)
+  {
+    return p1.protocol_ == p2.protocol_ && p1.family_ == p2.family_;
+  }
+
+  /// Compare two protocols for inequality.
+  friend bool operator!=(const icmp& p1, const icmp& p2)
+  {
+    return p1.protocol_ != p2.protocol_ || p1.family_ != p2.family_;
+  }
+
+private:
+  // Construct with a specific family.
+  explicit icmp(int protocol_id, int protocol_family) ASIO_NOEXCEPT
+    : protocol_(protocol_id),
+      family_(protocol_family)
+  {
+  }
+
+  int protocol_;
+  int family_;
+};
+
+} // namespace ip
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IP_ICMP_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/ip/impl/address.hpp b/link/modules/asio-standalone/asio/include/asio/ip/impl/address.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/ip/impl/address.hpp
@@ -0,0 +1,67 @@
+//
+// ip/impl/address.hpp
+// ~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_IP_IMPL_ADDRESS_HPP
+#define ASIO_IP_IMPL_ADDRESS_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#if !defined(ASIO_NO_IOSTREAM)
+
+#include "asio/detail/throw_error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace ip {
+
+#if !defined(ASIO_NO_DEPRECATED)
+
+inline address address::from_string(const char* str)
+{
+  return asio::ip::make_address(str);
+}
+
+inline address address::from_string(
+    const char* str, asio::error_code& ec)
+{
+  return asio::ip::make_address(str, ec);
+}
+
+inline address address::from_string(const std::string& str)
+{
+  return asio::ip::make_address(str);
+}
+
+inline address address::from_string(
+    const std::string& str, asio::error_code& ec)
+{
+  return asio::ip::make_address(str, ec);
+}
+
+#endif // !defined(ASIO_NO_DEPRECATED)
+
+template <typename Elem, typename Traits>
+std::basic_ostream<Elem, Traits>& operator<<(
+    std::basic_ostream<Elem, Traits>& os, const address& addr)
+{
+  return os << addr.to_string().c_str();
+}
+
+} // namespace ip
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // !defined(ASIO_NO_IOSTREAM)
+
+#endif // ASIO_IP_IMPL_ADDRESS_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/ip/impl/address.ipp b/link/modules/asio-standalone/asio/include/asio/ip/impl/address.ipp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/ip/impl/address.ipp
@@ -0,0 +1,239 @@
+//
+// ip/impl/address.ipp
+// ~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_IP_IMPL_ADDRESS_IPP
+#define ASIO_IP_IMPL_ADDRESS_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <typeinfo>
+#include "asio/detail/throw_error.hpp"
+#include "asio/detail/throw_exception.hpp"
+#include "asio/error.hpp"
+#include "asio/ip/address.hpp"
+#include "asio/ip/bad_address_cast.hpp"
+#include "asio/system_error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace ip {
+
+address::address() ASIO_NOEXCEPT
+  : type_(ipv4),
+    ipv4_address_(),
+    ipv6_address_()
+{
+}
+
+address::address(
+    const asio::ip::address_v4& ipv4_address) ASIO_NOEXCEPT
+  : type_(ipv4),
+    ipv4_address_(ipv4_address),
+    ipv6_address_()
+{
+}
+
+address::address(
+    const asio::ip::address_v6& ipv6_address) ASIO_NOEXCEPT
+  : type_(ipv6),
+    ipv4_address_(),
+    ipv6_address_(ipv6_address)
+{
+}
+
+address::address(const address& other) ASIO_NOEXCEPT
+  : type_(other.type_),
+    ipv4_address_(other.ipv4_address_),
+    ipv6_address_(other.ipv6_address_)
+{
+}
+
+#if defined(ASIO_HAS_MOVE)
+address::address(address&& other) ASIO_NOEXCEPT
+  : type_(other.type_),
+    ipv4_address_(other.ipv4_address_),
+    ipv6_address_(other.ipv6_address_)
+{
+}
+#endif // defined(ASIO_HAS_MOVE)
+
+address& address::operator=(const address& other) ASIO_NOEXCEPT
+{
+  type_ = other.type_;
+  ipv4_address_ = other.ipv4_address_;
+  ipv6_address_ = other.ipv6_address_;
+  return *this;
+}
+
+#if defined(ASIO_HAS_MOVE)
+address& address::operator=(address&& other) ASIO_NOEXCEPT
+{
+  type_ = other.type_;
+  ipv4_address_ = other.ipv4_address_;
+  ipv6_address_ = other.ipv6_address_;
+  return *this;
+}
+#endif // defined(ASIO_HAS_MOVE)
+
+address& address::operator=(
+    const asio::ip::address_v4& ipv4_address) ASIO_NOEXCEPT
+{
+  type_ = ipv4;
+  ipv4_address_ = ipv4_address;
+  ipv6_address_ = asio::ip::address_v6();
+  return *this;
+}
+
+address& address::operator=(
+    const asio::ip::address_v6& ipv6_address) ASIO_NOEXCEPT
+{
+  type_ = ipv6;
+  ipv4_address_ = asio::ip::address_v4();
+  ipv6_address_ = ipv6_address;
+  return *this;
+}
+
+address make_address(const char* str)
+{
+  asio::error_code ec;
+  address addr = make_address(str, ec);
+  asio::detail::throw_error(ec);
+  return addr;
+}
+
+address make_address(const char* str,
+    asio::error_code& ec) ASIO_NOEXCEPT
+{
+  asio::ip::address_v6 ipv6_address =
+    asio::ip::make_address_v6(str, ec);
+  if (!ec)
+    return address(ipv6_address);
+
+  asio::ip::address_v4 ipv4_address =
+    asio::ip::make_address_v4(str, ec);
+  if (!ec)
+    return address(ipv4_address);
+
+  return address();
+}
+
+address make_address(const std::string& str)
+{
+  return make_address(str.c_str());
+}
+
+address make_address(const std::string& str,
+    asio::error_code& ec) ASIO_NOEXCEPT
+{
+  return make_address(str.c_str(), ec);
+}
+
+#if defined(ASIO_HAS_STRING_VIEW)
+
+address make_address(string_view str)
+{
+  return make_address(static_cast<std::string>(str));
+}
+
+address make_address(string_view str,
+    asio::error_code& ec) ASIO_NOEXCEPT
+{
+  return make_address(static_cast<std::string>(str), ec);
+}
+
+#endif // defined(ASIO_HAS_STRING_VIEW)
+
+asio::ip::address_v4 address::to_v4() const
+{
+  if (type_ != ipv4)
+  {
+    bad_address_cast ex;
+    asio::detail::throw_exception(ex);
+  }
+  return ipv4_address_;
+}
+
+asio::ip::address_v6 address::to_v6() const
+{
+  if (type_ != ipv6)
+  {
+    bad_address_cast ex;
+    asio::detail::throw_exception(ex);
+  }
+  return ipv6_address_;
+}
+
+std::string address::to_string() const
+{
+  if (type_ == ipv6)
+    return ipv6_address_.to_string();
+  return ipv4_address_.to_string();
+}
+
+#if !defined(ASIO_NO_DEPRECATED)
+std::string address::to_string(asio::error_code& ec) const
+{
+  if (type_ == ipv6)
+    return ipv6_address_.to_string(ec);
+  return ipv4_address_.to_string(ec);
+}
+#endif // !defined(ASIO_NO_DEPRECATED)
+
+bool address::is_loopback() const ASIO_NOEXCEPT
+{
+  return (type_ == ipv4)
+    ? ipv4_address_.is_loopback()
+    : ipv6_address_.is_loopback();
+}
+
+bool address::is_unspecified() const ASIO_NOEXCEPT
+{
+  return (type_ == ipv4)
+    ? ipv4_address_.is_unspecified()
+    : ipv6_address_.is_unspecified();
+}
+
+bool address::is_multicast() const ASIO_NOEXCEPT
+{
+  return (type_ == ipv4)
+    ? ipv4_address_.is_multicast()
+    : ipv6_address_.is_multicast();
+}
+
+bool operator==(const address& a1, const address& a2) ASIO_NOEXCEPT
+{
+  if (a1.type_ != a2.type_)
+    return false;
+  if (a1.type_ == address::ipv6)
+    return a1.ipv6_address_ == a2.ipv6_address_;
+  return a1.ipv4_address_ == a2.ipv4_address_;
+}
+
+bool operator<(const address& a1, const address& a2) ASIO_NOEXCEPT
+{
+  if (a1.type_ < a2.type_)
+    return true;
+  if (a1.type_ > a2.type_)
+    return false;
+  if (a1.type_ == address::ipv6)
+    return a1.ipv6_address_ < a2.ipv6_address_;
+  return a1.ipv4_address_ < a2.ipv4_address_;
+}
+
+} // namespace ip
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IP_IMPL_ADDRESS_IPP
diff --git a/link/modules/asio-standalone/asio/include/asio/ip/impl/address_v4.hpp b/link/modules/asio-standalone/asio/include/asio/ip/impl/address_v4.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/ip/impl/address_v4.hpp
@@ -0,0 +1,67 @@
+//
+// ip/impl/address_v4.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_IP_IMPL_ADDRESS_V4_HPP
+#define ASIO_IP_IMPL_ADDRESS_V4_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#if !defined(ASIO_NO_IOSTREAM)
+
+#include "asio/detail/throw_error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace ip {
+
+#if !defined(ASIO_NO_DEPRECATED)
+
+inline address_v4 address_v4::from_string(const char* str)
+{
+  return asio::ip::make_address_v4(str);
+}
+
+inline address_v4 address_v4::from_string(
+    const char* str, asio::error_code& ec)
+{
+  return asio::ip::make_address_v4(str, ec);
+}
+
+inline address_v4 address_v4::from_string(const std::string& str)
+{
+  return asio::ip::make_address_v4(str);
+}
+
+inline address_v4 address_v4::from_string(
+    const std::string& str, asio::error_code& ec)
+{
+  return asio::ip::make_address_v4(str, ec);
+}
+
+#endif // !defined(ASIO_NO_DEPRECATED)
+
+template <typename Elem, typename Traits>
+std::basic_ostream<Elem, Traits>& operator<<(
+    std::basic_ostream<Elem, Traits>& os, const address_v4& addr)
+{
+  return os << addr.to_string().c_str();
+}
+
+} // namespace ip
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // !defined(ASIO_NO_IOSTREAM)
+
+#endif // ASIO_IP_IMPL_ADDRESS_V4_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/ip/impl/address_v4.ipp b/link/modules/asio-standalone/asio/include/asio/ip/impl/address_v4.ipp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/ip/impl/address_v4.ipp
@@ -0,0 +1,210 @@
+//
+// ip/impl/address_v4.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_IP_IMPL_ADDRESS_V4_IPP
+#define ASIO_IP_IMPL_ADDRESS_V4_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <climits>
+#include <limits>
+#include <stdexcept>
+#include "asio/error.hpp"
+#include "asio/detail/socket_ops.hpp"
+#include "asio/detail/throw_error.hpp"
+#include "asio/detail/throw_exception.hpp"
+#include "asio/ip/address_v4.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace ip {
+
+address_v4::address_v4(const address_v4::bytes_type& bytes)
+{
+#if UCHAR_MAX > 0xFF
+  if (bytes[0] > 0xFF || bytes[1] > 0xFF
+      || bytes[2] > 0xFF || bytes[3] > 0xFF)
+  {
+    std::out_of_range ex("address_v4 from bytes_type");
+    asio::detail::throw_exception(ex);
+  }
+#endif // UCHAR_MAX > 0xFF
+
+  using namespace std; // For memcpy.
+  memcpy(&addr_.s_addr, bytes.data(), 4);
+}
+
+address_v4::address_v4(address_v4::uint_type addr)
+{
+  if ((std::numeric_limits<uint_type>::max)() > 0xFFFFFFFF)
+  {
+    std::out_of_range ex("address_v4 from unsigned integer");
+    asio::detail::throw_exception(ex);
+  }
+
+  addr_.s_addr = asio::detail::socket_ops::host_to_network_long(
+      static_cast<asio::detail::u_long_type>(addr));
+}
+
+address_v4::bytes_type address_v4::to_bytes() const ASIO_NOEXCEPT
+{
+  using namespace std; // For memcpy.
+  bytes_type bytes;
+#if defined(ASIO_HAS_STD_ARRAY)
+  memcpy(bytes.data(), &addr_.s_addr, 4);
+#else // defined(ASIO_HAS_STD_ARRAY)
+  memcpy(bytes.elems, &addr_.s_addr, 4);
+#endif // defined(ASIO_HAS_STD_ARRAY)
+  return bytes;
+}
+
+address_v4::uint_type address_v4::to_uint() const ASIO_NOEXCEPT
+{
+  return asio::detail::socket_ops::network_to_host_long(addr_.s_addr);
+}
+
+#if !defined(ASIO_NO_DEPRECATED)
+unsigned long address_v4::to_ulong() const
+{
+  return asio::detail::socket_ops::network_to_host_long(addr_.s_addr);
+}
+#endif // !defined(ASIO_NO_DEPRECATED)
+
+std::string address_v4::to_string() const
+{
+  asio::error_code ec;
+  char addr_str[asio::detail::max_addr_v4_str_len];
+  const char* addr =
+    asio::detail::socket_ops::inet_ntop(
+        ASIO_OS_DEF(AF_INET), &addr_, addr_str,
+        asio::detail::max_addr_v4_str_len, 0, ec);
+  if (addr == 0)
+    asio::detail::throw_error(ec);
+  return addr;
+}
+
+#if !defined(ASIO_NO_DEPRECATED)
+std::string address_v4::to_string(asio::error_code& ec) const
+{
+  char addr_str[asio::detail::max_addr_v4_str_len];
+  const char* addr =
+    asio::detail::socket_ops::inet_ntop(
+        ASIO_OS_DEF(AF_INET), &addr_, addr_str,
+        asio::detail::max_addr_v4_str_len, 0, ec);
+  if (addr == 0)
+    return std::string();
+  return addr;
+}
+#endif // !defined(ASIO_NO_DEPRECATED)
+
+bool address_v4::is_loopback() const ASIO_NOEXCEPT
+{
+  return (to_uint() & 0xFF000000) == 0x7F000000;
+}
+
+bool address_v4::is_unspecified() const ASIO_NOEXCEPT
+{
+  return to_uint() == 0;
+}
+
+#if !defined(ASIO_NO_DEPRECATED)
+bool address_v4::is_class_a() const
+{
+  return (to_uint() & 0x80000000) == 0;
+}
+
+bool address_v4::is_class_b() const
+{
+  return (to_uint() & 0xC0000000) == 0x80000000;
+}
+
+bool address_v4::is_class_c() const
+{
+  return (to_uint() & 0xE0000000) == 0xC0000000;
+}
+#endif // !defined(ASIO_NO_DEPRECATED)
+
+bool address_v4::is_multicast() const ASIO_NOEXCEPT
+{
+  return (to_uint() & 0xF0000000) == 0xE0000000;
+}
+
+#if !defined(ASIO_NO_DEPRECATED)
+address_v4 address_v4::broadcast(const address_v4& addr, const address_v4& mask)
+{
+  return address_v4(addr.to_uint() | (mask.to_uint() ^ 0xFFFFFFFF));
+}
+
+address_v4 address_v4::netmask(const address_v4& addr)
+{
+  if (addr.is_class_a())
+    return address_v4(0xFF000000);
+  if (addr.is_class_b())
+    return address_v4(0xFFFF0000);
+  if (addr.is_class_c())
+    return address_v4(0xFFFFFF00);
+  return address_v4(0xFFFFFFFF);
+}
+#endif // !defined(ASIO_NO_DEPRECATED)
+
+address_v4 make_address_v4(const char* str)
+{
+  asio::error_code ec;
+  address_v4 addr = make_address_v4(str, ec);
+  asio::detail::throw_error(ec);
+  return addr;
+}
+
+address_v4 make_address_v4(const char* str,
+    asio::error_code& ec) ASIO_NOEXCEPT
+{
+  address_v4::bytes_type bytes;
+  if (asio::detail::socket_ops::inet_pton(
+        ASIO_OS_DEF(AF_INET), str, &bytes, 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,
+    asio::error_code& ec) ASIO_NOEXCEPT
+{
+  return make_address_v4(str.c_str(), ec);
+}
+
+#if defined(ASIO_HAS_STRING_VIEW)
+
+address_v4 make_address_v4(string_view str)
+{
+  return make_address_v4(static_cast<std::string>(str));
+}
+
+address_v4 make_address_v4(string_view str,
+    asio::error_code& ec) ASIO_NOEXCEPT
+{
+  return make_address_v4(static_cast<std::string>(str), ec);
+}
+
+#endif // defined(ASIO_HAS_STRING_VIEW)
+
+} // namespace ip
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IP_IMPL_ADDRESS_V4_IPP
diff --git a/link/modules/asio-standalone/asio/include/asio/ip/impl/address_v6.hpp b/link/modules/asio-standalone/asio/include/asio/ip/impl/address_v6.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/ip/impl/address_v6.hpp
@@ -0,0 +1,67 @@
+//
+// ip/impl/address_v6.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_IP_IMPL_ADDRESS_V6_HPP
+#define ASIO_IP_IMPL_ADDRESS_V6_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#if !defined(ASIO_NO_IOSTREAM)
+
+#include "asio/detail/throw_error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace ip {
+
+#if !defined(ASIO_NO_DEPRECATED)
+
+inline address_v6 address_v6::from_string(const char* str)
+{
+  return asio::ip::make_address_v6(str);
+}
+
+inline address_v6 address_v6::from_string(
+    const char* str, asio::error_code& ec)
+{
+  return asio::ip::make_address_v6(str, ec);
+}
+
+inline address_v6 address_v6::from_string(const std::string& str)
+{
+  return asio::ip::make_address_v6(str);
+}
+
+inline address_v6 address_v6::from_string(
+    const std::string& str, asio::error_code& ec)
+{
+  return asio::ip::make_address_v6(str, ec);
+}
+
+#endif // !defined(ASIO_NO_DEPRECATED)
+
+template <typename Elem, typename Traits>
+std::basic_ostream<Elem, Traits>& operator<<(
+    std::basic_ostream<Elem, Traits>& os, const address_v6& addr)
+{
+  return os << addr.to_string().c_str();
+}
+
+} // namespace ip
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // !defined(ASIO_NO_IOSTREAM)
+
+#endif // ASIO_IP_IMPL_ADDRESS_V6_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/ip/impl/address_v6.ipp b/link/modules/asio-standalone/asio/include/asio/ip/impl/address_v6.ipp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/ip/impl/address_v6.ipp
@@ -0,0 +1,350 @@
+//
+// ip/impl/address_v6.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_IP_IMPL_ADDRESS_V6_IPP
+#define ASIO_IP_IMPL_ADDRESS_V6_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <cstring>
+#include <stdexcept>
+#include <typeinfo>
+#include "asio/detail/socket_ops.hpp"
+#include "asio/detail/throw_error.hpp"
+#include "asio/detail/throw_exception.hpp"
+#include "asio/error.hpp"
+#include "asio/ip/address_v6.hpp"
+#include "asio/ip/bad_address_cast.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace ip {
+
+address_v6::address_v6() ASIO_NOEXCEPT
+  : addr_(),
+    scope_id_(0)
+{
+}
+
+address_v6::address_v6(const address_v6::bytes_type& bytes,
+    unsigned long scope)
+  : scope_id_(scope)
+{
+#if UCHAR_MAX > 0xFF
+  for (std::size_t i = 0; i < bytes.size(); ++i)
+  {
+    if (bytes[i] > 0xFF)
+    {
+      std::out_of_range ex("address_v6 from bytes_type");
+      asio::detail::throw_exception(ex);
+    }
+  }
+#endif // UCHAR_MAX > 0xFF
+
+  using namespace std; // For memcpy.
+  memcpy(addr_.s6_addr, bytes.data(), 16);
+}
+
+address_v6::address_v6(const address_v6& other) ASIO_NOEXCEPT
+  : addr_(other.addr_),
+    scope_id_(other.scope_id_)
+{
+}
+
+#if defined(ASIO_HAS_MOVE)
+address_v6::address_v6(address_v6&& other) ASIO_NOEXCEPT
+  : addr_(other.addr_),
+    scope_id_(other.scope_id_)
+{
+}
+#endif // defined(ASIO_HAS_MOVE)
+
+address_v6& address_v6::operator=(const address_v6& other) ASIO_NOEXCEPT
+{
+  addr_ = other.addr_;
+  scope_id_ = other.scope_id_;
+  return *this;
+}
+
+#if defined(ASIO_HAS_MOVE)
+address_v6& address_v6::operator=(address_v6&& other) ASIO_NOEXCEPT
+{
+  addr_ = other.addr_;
+  scope_id_ = other.scope_id_;
+  return *this;
+}
+#endif // defined(ASIO_HAS_MOVE)
+
+address_v6::bytes_type address_v6::to_bytes() const ASIO_NOEXCEPT
+{
+  using namespace std; // For memcpy.
+  bytes_type bytes;
+#if defined(ASIO_HAS_STD_ARRAY)
+  memcpy(bytes.data(), addr_.s6_addr, 16);
+#else // defined(ASIO_HAS_STD_ARRAY)
+  memcpy(bytes.elems, addr_.s6_addr, 16);
+#endif // defined(ASIO_HAS_STD_ARRAY)
+  return bytes;
+}
+
+std::string address_v6::to_string() const
+{
+  asio::error_code ec;
+  char addr_str[asio::detail::max_addr_v6_str_len];
+  const char* addr =
+    asio::detail::socket_ops::inet_ntop(
+        ASIO_OS_DEF(AF_INET6), &addr_, addr_str,
+        asio::detail::max_addr_v6_str_len, scope_id_, ec);
+  if (addr == 0)
+    asio::detail::throw_error(ec);
+  return addr;
+}
+
+#if !defined(ASIO_NO_DEPRECATED)
+std::string address_v6::to_string(asio::error_code& ec) const
+{
+  char addr_str[asio::detail::max_addr_v6_str_len];
+  const char* addr =
+    asio::detail::socket_ops::inet_ntop(
+        ASIO_OS_DEF(AF_INET6), &addr_, addr_str,
+        asio::detail::max_addr_v6_str_len, scope_id_, ec);
+  if (addr == 0)
+    return std::string();
+  return addr;
+}
+
+address_v4 address_v6::to_v4() const
+{
+  if (!is_v4_mapped() && !is_v4_compatible())
+  {
+    bad_address_cast ex;
+    asio::detail::throw_exception(ex);
+  }
+
+  address_v4::bytes_type v4_bytes = { { addr_.s6_addr[12],
+    addr_.s6_addr[13], addr_.s6_addr[14], addr_.s6_addr[15] } };
+  return address_v4(v4_bytes);
+}
+#endif // !defined(ASIO_NO_DEPRECATED)
+
+bool address_v6::is_loopback() const ASIO_NOEXCEPT
+{
+  return ((addr_.s6_addr[0] == 0) && (addr_.s6_addr[1] == 0)
+      && (addr_.s6_addr[2] == 0) && (addr_.s6_addr[3] == 0)
+      && (addr_.s6_addr[4] == 0) && (addr_.s6_addr[5] == 0)
+      && (addr_.s6_addr[6] == 0) && (addr_.s6_addr[7] == 0)
+      && (addr_.s6_addr[8] == 0) && (addr_.s6_addr[9] == 0)
+      && (addr_.s6_addr[10] == 0) && (addr_.s6_addr[11] == 0)
+      && (addr_.s6_addr[12] == 0) && (addr_.s6_addr[13] == 0)
+      && (addr_.s6_addr[14] == 0) && (addr_.s6_addr[15] == 1));
+}
+
+bool address_v6::is_unspecified() const ASIO_NOEXCEPT
+{
+  return ((addr_.s6_addr[0] == 0) && (addr_.s6_addr[1] == 0)
+      && (addr_.s6_addr[2] == 0) && (addr_.s6_addr[3] == 0)
+      && (addr_.s6_addr[4] == 0) && (addr_.s6_addr[5] == 0)
+      && (addr_.s6_addr[6] == 0) && (addr_.s6_addr[7] == 0)
+      && (addr_.s6_addr[8] == 0) && (addr_.s6_addr[9] == 0)
+      && (addr_.s6_addr[10] == 0) && (addr_.s6_addr[11] == 0)
+      && (addr_.s6_addr[12] == 0) && (addr_.s6_addr[13] == 0)
+      && (addr_.s6_addr[14] == 0) && (addr_.s6_addr[15] == 0));
+}
+
+bool address_v6::is_link_local() const ASIO_NOEXCEPT
+{
+  return ((addr_.s6_addr[0] == 0xfe) && ((addr_.s6_addr[1] & 0xc0) == 0x80));
+}
+
+bool address_v6::is_site_local() const ASIO_NOEXCEPT
+{
+  return ((addr_.s6_addr[0] == 0xfe) && ((addr_.s6_addr[1] & 0xc0) == 0xc0));
+}
+
+bool address_v6::is_v4_mapped() const ASIO_NOEXCEPT
+{
+  return ((addr_.s6_addr[0] == 0) && (addr_.s6_addr[1] == 0)
+      && (addr_.s6_addr[2] == 0) && (addr_.s6_addr[3] == 0)
+      && (addr_.s6_addr[4] == 0) && (addr_.s6_addr[5] == 0)
+      && (addr_.s6_addr[6] == 0) && (addr_.s6_addr[7] == 0)
+      && (addr_.s6_addr[8] == 0) && (addr_.s6_addr[9] == 0)
+      && (addr_.s6_addr[10] == 0xff) && (addr_.s6_addr[11] == 0xff));
+}
+
+#if !defined(ASIO_NO_DEPRECATED)
+bool address_v6::is_v4_compatible() const
+{
+  return ((addr_.s6_addr[0] == 0) && (addr_.s6_addr[1] == 0)
+      && (addr_.s6_addr[2] == 0) && (addr_.s6_addr[3] == 0)
+      && (addr_.s6_addr[4] == 0) && (addr_.s6_addr[5] == 0)
+      && (addr_.s6_addr[6] == 0) && (addr_.s6_addr[7] == 0)
+      && (addr_.s6_addr[8] == 0) && (addr_.s6_addr[9] == 0)
+      && (addr_.s6_addr[10] == 0) && (addr_.s6_addr[11] == 0)
+      && !((addr_.s6_addr[12] == 0)
+        && (addr_.s6_addr[13] == 0)
+        && (addr_.s6_addr[14] == 0)
+        && ((addr_.s6_addr[15] == 0) || (addr_.s6_addr[15] == 1))));
+}
+#endif // !defined(ASIO_NO_DEPRECATED)
+
+bool address_v6::is_multicast() const ASIO_NOEXCEPT
+{
+  return (addr_.s6_addr[0] == 0xff);
+}
+
+bool address_v6::is_multicast_global() const ASIO_NOEXCEPT
+{
+  return ((addr_.s6_addr[0] == 0xff) && ((addr_.s6_addr[1] & 0x0f) == 0x0e));
+}
+
+bool address_v6::is_multicast_link_local() const ASIO_NOEXCEPT
+{
+  return ((addr_.s6_addr[0] == 0xff) && ((addr_.s6_addr[1] & 0x0f) == 0x02));
+}
+
+bool address_v6::is_multicast_node_local() const ASIO_NOEXCEPT
+{
+  return ((addr_.s6_addr[0] == 0xff) && ((addr_.s6_addr[1] & 0x0f) == 0x01));
+}
+
+bool address_v6::is_multicast_org_local() const ASIO_NOEXCEPT
+{
+  return ((addr_.s6_addr[0] == 0xff) && ((addr_.s6_addr[1] & 0x0f) == 0x08));
+}
+
+bool address_v6::is_multicast_site_local() const ASIO_NOEXCEPT
+{
+  return ((addr_.s6_addr[0] == 0xff) && ((addr_.s6_addr[1] & 0x0f) == 0x05));
+}
+
+bool operator==(const address_v6& a1, const address_v6& a2) ASIO_NOEXCEPT
+{
+  using namespace std; // For memcmp.
+  return memcmp(&a1.addr_, &a2.addr_,
+      sizeof(asio::detail::in6_addr_type)) == 0
+    && a1.scope_id_ == a2.scope_id_;
+}
+
+bool operator<(const address_v6& a1, const address_v6& a2) ASIO_NOEXCEPT
+{
+  using namespace std; // For memcmp.
+  int memcmp_result = memcmp(&a1.addr_, &a2.addr_,
+      sizeof(asio::detail::in6_addr_type));
+  if (memcmp_result < 0)
+    return true;
+  if (memcmp_result > 0)
+    return false;
+  return a1.scope_id_ < a2.scope_id_;
+}
+
+address_v6 address_v6::loopback() ASIO_NOEXCEPT
+{
+  address_v6 tmp;
+  tmp.addr_.s6_addr[15] = 1;
+  return tmp;
+}
+
+#if !defined(ASIO_NO_DEPRECATED)
+address_v6 address_v6::v4_mapped(const address_v4& addr)
+{
+  address_v4::bytes_type v4_bytes = addr.to_bytes();
+  bytes_type v6_bytes = { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF,
+    v4_bytes[0], v4_bytes[1], v4_bytes[2], v4_bytes[3] } };
+  return address_v6(v6_bytes);
+}
+
+address_v6 address_v6::v4_compatible(const address_v4& addr)
+{
+  address_v4::bytes_type v4_bytes = addr.to_bytes();
+  bytes_type v6_bytes = { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    v4_bytes[0], v4_bytes[1], v4_bytes[2], v4_bytes[3] } };
+  return address_v6(v6_bytes);
+}
+#endif // !defined(ASIO_NO_DEPRECATED)
+
+address_v6 make_address_v6(const char* str)
+{
+  asio::error_code ec;
+  address_v6 addr = make_address_v6(str, ec);
+  asio::detail::throw_error(ec);
+  return addr;
+}
+
+address_v6 make_address_v6(const char* str,
+    asio::error_code& ec) ASIO_NOEXCEPT
+{
+  address_v6::bytes_type bytes;
+  unsigned long scope_id = 0;
+  if (asio::detail::socket_ops::inet_pton(
+        ASIO_OS_DEF(AF_INET6), str, &bytes[0], &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,
+    asio::error_code& ec) ASIO_NOEXCEPT
+{
+  return make_address_v6(str.c_str(), ec);
+}
+
+#if defined(ASIO_HAS_STRING_VIEW)
+
+address_v6 make_address_v6(string_view str)
+{
+  return make_address_v6(static_cast<std::string>(str));
+}
+
+address_v6 make_address_v6(string_view str,
+    asio::error_code& ec) ASIO_NOEXCEPT
+{
+  return make_address_v6(static_cast<std::string>(str), ec);
+}
+
+#endif // defined(ASIO_HAS_STRING_VIEW)
+
+address_v4 make_address_v4(
+    v4_mapped_t, const address_v6& v6_addr)
+{
+  if (!v6_addr.is_v4_mapped())
+  {
+    bad_address_cast ex;
+    asio::detail::throw_exception(ex);
+  }
+
+  address_v6::bytes_type v6_bytes = v6_addr.to_bytes();
+  address_v4::bytes_type v4_bytes = { { v6_bytes[12],
+    v6_bytes[13], v6_bytes[14], v6_bytes[15] } };
+  return address_v4(v4_bytes);
+}
+
+address_v6 make_address_v6(
+    v4_mapped_t, const address_v4& v4_addr)
+{
+  address_v4::bytes_type v4_bytes = v4_addr.to_bytes();
+  address_v6::bytes_type v6_bytes = { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0xFF, 0xFF, v4_bytes[0], v4_bytes[1], v4_bytes[2], v4_bytes[3] } };
+  return address_v6(v6_bytes);
+}
+
+} // namespace ip
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IP_IMPL_ADDRESS_V6_IPP
diff --git a/link/modules/asio-standalone/asio/include/asio/ip/impl/basic_endpoint.hpp b/link/modules/asio-standalone/asio/include/asio/ip/impl/basic_endpoint.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/ip/impl/basic_endpoint.hpp
@@ -0,0 +1,43 @@
+//
+// ip/impl/basic_endpoint.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_IP_IMPL_BASIC_ENDPOINT_HPP
+#define ASIO_IP_IMPL_BASIC_ENDPOINT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#if !defined(ASIO_NO_IOSTREAM)
+
+#include "asio/detail/throw_error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace ip {
+
+template <typename Elem, typename Traits, typename InternetProtocol>
+std::basic_ostream<Elem, Traits>& operator<<(
+    std::basic_ostream<Elem, Traits>& os,
+    const basic_endpoint<InternetProtocol>& endpoint)
+{
+  asio::ip::detail::endpoint tmp_ep(endpoint.address(), endpoint.port());
+  return os << tmp_ep.to_string().c_str();
+}
+
+} // namespace ip
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // !defined(ASIO_NO_IOSTREAM)
+
+#endif // ASIO_IP_IMPL_BASIC_ENDPOINT_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/ip/impl/host_name.ipp b/link/modules/asio-standalone/asio/include/asio/ip/impl/host_name.ipp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/ip/impl/host_name.ipp
@@ -0,0 +1,54 @@
+//
+// ip/impl/host_name.ipp
+// ~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_IP_IMPL_HOST_NAME_IPP
+#define ASIO_IP_IMPL_HOST_NAME_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/socket_ops.hpp"
+#include "asio/detail/throw_error.hpp"
+#include "asio/detail/winsock_init.hpp"
+#include "asio/ip/host_name.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace ip {
+
+std::string host_name()
+{
+  char name[1024];
+  asio::error_code ec;
+  if (asio::detail::socket_ops::gethostname(name, sizeof(name), ec) != 0)
+  {
+    asio::detail::throw_error(ec);
+    return std::string();
+  }
+  return std::string(name);
+}
+
+std::string host_name(asio::error_code& ec)
+{
+  char name[1024];
+  if (asio::detail::socket_ops::gethostname(name, sizeof(name), ec) != 0)
+    return std::string();
+  return std::string(name);
+}
+
+} // namespace ip
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IP_IMPL_HOST_NAME_IPP
diff --git a/link/modules/asio-standalone/asio/include/asio/ip/impl/network_v4.hpp b/link/modules/asio-standalone/asio/include/asio/ip/impl/network_v4.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/ip/impl/network_v4.hpp
@@ -0,0 +1,54 @@
+//
+// ip/impl/network_v4.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2014 Oliver Kowalke (oliver dot kowalke at gmail 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 ASIO_IP_IMPL_NETWORK_V4_HPP
+#define ASIO_IP_IMPL_NETWORK_V4_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#if !defined(ASIO_NO_IOSTREAM)
+
+#include "asio/detail/throw_error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace ip {
+
+template <typename Elem, typename Traits>
+std::basic_ostream<Elem, Traits>& operator<<(
+    std::basic_ostream<Elem, Traits>& os, const network_v4& addr)
+{
+  asio::error_code ec;
+  std::string s = addr.to_string(ec);
+  if (ec)
+  {
+    if (os.exceptions() & std::basic_ostream<Elem, Traits>::failbit)
+      asio::detail::throw_error(ec);
+    else
+      os.setstate(std::basic_ostream<Elem, Traits>::failbit);
+  }
+  else
+    for (std::string::iterator i = s.begin(); i != s.end(); ++i)
+      os << os.widen(*i);
+  return os;
+}
+
+} // namespace ip
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // !defined(ASIO_NO_IOSTREAM)
+
+#endif // ASIO_IP_IMPL_NETWORK_V4_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/ip/impl/network_v4.ipp b/link/modules/asio-standalone/asio/include/asio/ip/impl/network_v4.ipp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/ip/impl/network_v4.ipp
@@ -0,0 +1,216 @@
+//
+// ip/impl/network_v4.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2014 Oliver Kowalke (oliver dot kowalke at gmail 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 ASIO_IP_IMPL_NETWORK_V4_IPP
+#define ASIO_IP_IMPL_NETWORK_V4_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <climits>
+#include <cstdio>
+#include <cstdlib>
+#include <stdexcept>
+#include "asio/error.hpp"
+#include "asio/detail/throw_error.hpp"
+#include "asio/detail/throw_exception.hpp"
+#include "asio/ip/network_v4.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace ip {
+
+network_v4::network_v4(const address_v4& addr, unsigned short prefix_len)
+  : address_(addr),
+    prefix_length_(prefix_len)
+{
+  if (prefix_len > 32)
+  {
+    std::out_of_range ex("prefix length too large");
+    asio::detail::throw_exception(ex);
+  }
+}
+
+network_v4::network_v4(const address_v4& addr, const address_v4& mask)
+  : address_(addr),
+    prefix_length_(0)
+{
+  address_v4::bytes_type mask_bytes = mask.to_bytes();
+  bool finished = false;
+  for (std::size_t i = 0; i < mask_bytes.size(); ++i)
+  {
+    if (finished)
+    {
+      if (mask_bytes[i])
+      {
+        std::invalid_argument ex("non-contiguous netmask");
+        asio::detail::throw_exception(ex);
+      }
+      continue;
+    }
+    else
+    {
+      switch (mask_bytes[i])
+      {
+      case 255:
+        prefix_length_ += 8;
+        break;
+      case 254: // prefix_length_ += 7
+        prefix_length_ += 1;
+      case 252: // prefix_length_ += 6
+        prefix_length_ += 1;
+      case 248: // prefix_length_ += 5
+        prefix_length_ += 1;
+      case 240: // prefix_length_ += 4
+        prefix_length_ += 1;
+      case 224: // prefix_length_ += 3
+        prefix_length_ += 1;
+      case 192: // prefix_length_ += 2
+        prefix_length_ += 1;
+      case 128: // prefix_length_ += 1
+        prefix_length_ += 1;
+      case 0:   // nbits += 0
+        finished = true;
+        break;
+      default:
+        std::out_of_range ex("non-contiguous netmask");
+        asio::detail::throw_exception(ex);
+      }
+    }
+  }
+}
+
+address_v4 network_v4::netmask() const ASIO_NOEXCEPT
+{
+  uint32_t nmbits = 0xffffffff;
+  if (prefix_length_ == 0)
+    nmbits = 0;
+  else
+    nmbits = nmbits << (32 - prefix_length_);
+  return address_v4(nmbits);
+}
+
+address_v4_range network_v4::hosts() const ASIO_NOEXCEPT
+{
+  return is_host()
+    ? address_v4_range(address_, address_v4(address_.to_uint() + 1))
+    : address_v4_range(address_v4(network().to_uint() + 1), broadcast());
+}
+
+bool network_v4::is_subnet_of(const network_v4& other) const
+{
+  if (other.prefix_length_ >= prefix_length_)
+    return false; // Only real subsets are allowed.
+  const network_v4 me(address_, other.prefix_length_);
+  return other.canonical() == me.canonical();
+}
+
+std::string network_v4::to_string() const
+{
+  asio::error_code ec;
+  std::string addr = to_string(ec);
+  asio::detail::throw_error(ec);
+  return addr;
+}
+
+std::string network_v4::to_string(asio::error_code& ec) const
+{
+  using namespace std; // For sprintf.
+  ec = asio::error_code();
+  char prefix_len[16];
+#if defined(ASIO_HAS_SECURE_RTL)
+  sprintf_s(prefix_len, sizeof(prefix_len), "/%u", prefix_length_);
+#else // defined(ASIO_HAS_SECURE_RTL)
+  sprintf(prefix_len, "/%u", prefix_length_);
+#endif // defined(ASIO_HAS_SECURE_RTL)
+  return address_.to_string() + prefix_len;
+}
+
+network_v4 make_network_v4(const char* str)
+{
+  return make_network_v4(std::string(str));
+}
+
+network_v4 make_network_v4(const char* str, asio::error_code& ec)
+{
+  return make_network_v4(std::string(str), ec);
+}
+
+network_v4 make_network_v4(const std::string& str)
+{
+  asio::error_code ec;
+  network_v4 net = make_network_v4(str, ec);
+  asio::detail::throw_error(ec);
+  return net;
+}
+
+network_v4 make_network_v4(const std::string& str,
+    asio::error_code& ec)
+{
+  std::string::size_type pos = str.find_first_of("/");
+
+  if (pos == std::string::npos)
+  {
+    ec = asio::error::invalid_argument;
+    return network_v4();
+  }
+
+  if (pos == str.size() - 1)
+  {
+    ec = asio::error::invalid_argument;
+    return network_v4();
+  }
+
+  std::string::size_type end = str.find_first_not_of("0123456789", pos + 1);
+  if (end != std::string::npos)
+  {
+    ec = asio::error::invalid_argument;
+    return network_v4();
+  }
+
+  const address_v4 addr = make_address_v4(str.substr(0, pos), ec);
+  if (ec)
+    return network_v4();
+
+  const int prefix_len = std::atoi(str.substr(pos + 1).c_str());
+  if (prefix_len < 0 || prefix_len > 32)
+  {
+    ec = asio::error::invalid_argument;
+    return network_v4();
+  }
+
+  return network_v4(addr, static_cast<unsigned short>(prefix_len));
+}
+
+#if defined(ASIO_HAS_STRING_VIEW)
+
+network_v4 make_network_v4(string_view str)
+{
+  return make_network_v4(static_cast<std::string>(str));
+}
+
+network_v4 make_network_v4(string_view str,
+    asio::error_code& ec)
+{
+  return make_network_v4(static_cast<std::string>(str), ec);
+}
+
+#endif // defined(ASIO_HAS_STRING_VIEW)
+
+} // namespace ip
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IP_IMPL_NETWORK_V4_IPP
diff --git a/link/modules/asio-standalone/asio/include/asio/ip/impl/network_v6.hpp b/link/modules/asio-standalone/asio/include/asio/ip/impl/network_v6.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/ip/impl/network_v6.hpp
@@ -0,0 +1,53 @@
+//
+// ip/impl/network_v6.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_IP_IMPL_NETWORK_V6_HPP
+#define ASIO_IP_IMPL_NETWORK_V6_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#if !defined(ASIO_NO_IOSTREAM)
+
+#include "asio/detail/throw_error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace ip {
+
+template <typename Elem, typename Traits>
+std::basic_ostream<Elem, Traits>& operator<<(
+    std::basic_ostream<Elem, Traits>& os, const network_v6& addr)
+{
+  asio::error_code ec;
+  std::string s = addr.to_string(ec);
+  if (ec)
+  {
+    if (os.exceptions() & std::basic_ostream<Elem, Traits>::failbit)
+      asio::detail::throw_error(ec);
+    else
+      os.setstate(std::basic_ostream<Elem, Traits>::failbit);
+  }
+  else
+    for (std::string::iterator i = s.begin(); i != s.end(); ++i)
+      os << os.widen(*i);
+  return os;
+}
+
+} // namespace ip
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // !defined(ASIO_NO_IOSTREAM)
+
+#endif // ASIO_IP_IMPL_NETWORK_V6_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/ip/impl/network_v6.ipp b/link/modules/asio-standalone/asio/include/asio/ip/impl/network_v6.ipp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/ip/impl/network_v6.ipp
@@ -0,0 +1,185 @@
+//
+// ip/impl/network_v6.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2014 Oliver Kowalke (oliver dot kowalke at gmail 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 ASIO_IP_IMPL_NETWORK_V6_IPP
+#define ASIO_IP_IMPL_NETWORK_V6_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <climits>
+#include <cstdio>
+#include <cstdlib>
+#include <stdexcept>
+#include "asio/error.hpp"
+#include "asio/detail/throw_error.hpp"
+#include "asio/detail/throw_exception.hpp"
+#include "asio/ip/network_v6.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace ip {
+
+network_v6::network_v6(const address_v6& addr, unsigned short prefix_len)
+  : address_(addr),
+    prefix_length_(prefix_len)
+{
+  if (prefix_len > 128)
+  {
+    std::out_of_range ex("prefix length too large");
+    asio::detail::throw_exception(ex);
+  }
+}
+
+ASIO_DECL address_v6 network_v6::network() const ASIO_NOEXCEPT
+{
+  address_v6::bytes_type bytes(address_.to_bytes());
+  for (std::size_t i = 0; i < 16; ++i)
+  {
+    if (prefix_length_ <= i * 8)
+      bytes[i] = 0;
+    else if (prefix_length_ < (i + 1) * 8)
+      bytes[i] &= 0xFF00 >> (prefix_length_ % 8);
+  }
+  return address_v6(bytes, address_.scope_id());
+}
+
+address_v6_range network_v6::hosts() const ASIO_NOEXCEPT
+{
+  address_v6::bytes_type begin_bytes(address_.to_bytes());
+  address_v6::bytes_type end_bytes(address_.to_bytes());
+  for (std::size_t i = 0; i < 16; ++i)
+  {
+    if (prefix_length_ <= i * 8)
+    {
+      begin_bytes[i] = 0;
+      end_bytes[i] = 0xFF;
+    }
+    else if (prefix_length_ < (i + 1) * 8)
+    {
+      begin_bytes[i] &= 0xFF00 >> (prefix_length_ % 8);
+      end_bytes[i] |= 0xFF >> (prefix_length_ % 8);
+    }
+  }
+  return address_v6_range(
+      address_v6_iterator(address_v6(begin_bytes, address_.scope_id())),
+      ++address_v6_iterator(address_v6(end_bytes, address_.scope_id())));
+}
+
+bool network_v6::is_subnet_of(const network_v6& other) const
+{
+  if (other.prefix_length_ >= prefix_length_)
+    return false; // Only real subsets are allowed.
+  const network_v6 me(address_, other.prefix_length_);
+  return other.canonical() == me.canonical();
+}
+
+std::string network_v6::to_string() const
+{
+  asio::error_code ec;
+  std::string addr = to_string(ec);
+  asio::detail::throw_error(ec);
+  return addr;
+}
+
+std::string network_v6::to_string(asio::error_code& ec) const
+{
+  using namespace std; // For sprintf.
+  ec = asio::error_code();
+  char prefix_len[16];
+#if defined(ASIO_HAS_SECURE_RTL)
+  sprintf_s(prefix_len, sizeof(prefix_len), "/%u", prefix_length_);
+#else // defined(ASIO_HAS_SECURE_RTL)
+  sprintf(prefix_len, "/%u", prefix_length_);
+#endif // defined(ASIO_HAS_SECURE_RTL)
+  return address_.to_string() + prefix_len;
+}
+
+network_v6 make_network_v6(const char* str)
+{
+  return make_network_v6(std::string(str));
+}
+
+network_v6 make_network_v6(const char* str, asio::error_code& ec)
+{
+  return make_network_v6(std::string(str), ec);
+}
+
+network_v6 make_network_v6(const std::string& str)
+{
+  asio::error_code ec;
+  network_v6 net = make_network_v6(str, ec);
+  asio::detail::throw_error(ec);
+  return net;
+}
+
+network_v6 make_network_v6(const std::string& str,
+    asio::error_code& ec)
+{
+  std::string::size_type pos = str.find_first_of("/");
+
+  if (pos == std::string::npos)
+  {
+    ec = asio::error::invalid_argument;
+    return network_v6();
+  }
+
+  if (pos == str.size() - 1)
+  {
+    ec = asio::error::invalid_argument;
+    return network_v6();
+  }
+
+  std::string::size_type end = str.find_first_not_of("0123456789", pos + 1);
+  if (end != std::string::npos)
+  {
+    ec = asio::error::invalid_argument;
+    return network_v6();
+  }
+
+  const address_v6 addr = make_address_v6(str.substr(0, pos), ec);
+  if (ec)
+    return network_v6();
+
+  const int prefix_len = std::atoi(str.substr(pos + 1).c_str());
+  if (prefix_len < 0 || prefix_len > 128)
+  {
+    ec = asio::error::invalid_argument;
+    return network_v6();
+  }
+
+  return network_v6(addr, static_cast<unsigned short>(prefix_len));
+}
+
+#if defined(ASIO_HAS_STRING_VIEW)
+
+network_v6 make_network_v6(string_view str)
+{
+  return make_network_v6(static_cast<std::string>(str));
+}
+
+network_v6 make_network_v6(string_view str,
+    asio::error_code& ec)
+{
+  return make_network_v6(static_cast<std::string>(str), ec);
+}
+
+#endif // defined(ASIO_HAS_STRING_VIEW)
+
+} // namespace ip
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IP_IMPL_NETWORK_V6_IPP
diff --git a/link/modules/asio-standalone/asio/include/asio/ip/multicast.hpp b/link/modules/asio-standalone/asio/include/asio/ip/multicast.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/ip/multicast.hpp
@@ -0,0 +1,191 @@
+//
+// ip/multicast.hpp
+// ~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_IP_MULTICAST_HPP
+#define ASIO_IP_MULTICAST_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <cstddef>
+#include "asio/ip/detail/socket_option.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace ip {
+namespace multicast {
+
+/// Socket option to join a multicast group on a specified interface.
+/**
+ * Implements the IPPROTO_IP/IP_ADD_MEMBERSHIP socket option.
+ *
+ * @par Examples
+ * Setting the option to join a multicast group:
+ * @code
+ * asio::ip::udp::socket socket(my_context);
+ * ...
+ * asio::ip::address multicast_address =
+ *   asio::ip::address::from_string("225.0.0.1");
+ * asio::ip::multicast::join_group option(multicast_address);
+ * socket.set_option(option);
+ * @endcode
+ *
+ * @par Concepts:
+ * SettableSocketOption.
+ */
+#if defined(GENERATING_DOCUMENTATION)
+typedef implementation_defined join_group;
+#else
+typedef asio::ip::detail::socket_option::multicast_request<
+  ASIO_OS_DEF(IPPROTO_IP),
+  ASIO_OS_DEF(IP_ADD_MEMBERSHIP),
+  ASIO_OS_DEF(IPPROTO_IPV6),
+  ASIO_OS_DEF(IPV6_JOIN_GROUP)> join_group;
+#endif
+
+/// Socket option to leave a multicast group on a specified interface.
+/**
+ * Implements the IPPROTO_IP/IP_DROP_MEMBERSHIP socket option.
+ *
+ * @par Examples
+ * Setting the option to leave a multicast group:
+ * @code
+ * asio::ip::udp::socket socket(my_context);
+ * ...
+ * asio::ip::address multicast_address =
+ *   asio::ip::address::from_string("225.0.0.1");
+ * asio::ip::multicast::leave_group option(multicast_address);
+ * socket.set_option(option);
+ * @endcode
+ *
+ * @par Concepts:
+ * SettableSocketOption.
+ */
+#if defined(GENERATING_DOCUMENTATION)
+typedef implementation_defined leave_group;
+#else
+typedef asio::ip::detail::socket_option::multicast_request<
+  ASIO_OS_DEF(IPPROTO_IP),
+  ASIO_OS_DEF(IP_DROP_MEMBERSHIP),
+  ASIO_OS_DEF(IPPROTO_IPV6),
+  ASIO_OS_DEF(IPV6_LEAVE_GROUP)> leave_group;
+#endif
+
+/// Socket option for local interface to use for outgoing multicast packets.
+/**
+ * Implements the IPPROTO_IP/IP_MULTICAST_IF socket option.
+ *
+ * @par Examples
+ * Setting the option:
+ * @code
+ * asio::ip::udp::socket socket(my_context);
+ * ...
+ * asio::ip::address_v4 local_interface =
+ *   asio::ip::address_v4::from_string("1.2.3.4");
+ * asio::ip::multicast::outbound_interface option(local_interface);
+ * socket.set_option(option);
+ * @endcode
+ *
+ * @par Concepts:
+ * SettableSocketOption.
+ */
+#if defined(GENERATING_DOCUMENTATION)
+typedef implementation_defined outbound_interface;
+#else
+typedef asio::ip::detail::socket_option::network_interface<
+  ASIO_OS_DEF(IPPROTO_IP),
+  ASIO_OS_DEF(IP_MULTICAST_IF),
+  ASIO_OS_DEF(IPPROTO_IPV6),
+  ASIO_OS_DEF(IPV6_MULTICAST_IF)> outbound_interface;
+#endif
+
+/// Socket option for time-to-live associated with outgoing multicast packets.
+/**
+ * Implements the IPPROTO_IP/IP_MULTICAST_TTL socket option.
+ *
+ * @par Examples
+ * Setting the option:
+ * @code
+ * asio::ip::udp::socket socket(my_context);
+ * ...
+ * asio::ip::multicast::hops option(4);
+ * socket.set_option(option);
+ * @endcode
+ *
+ * @par
+ * Getting the current option value:
+ * @code
+ * asio::ip::udp::socket socket(my_context);
+ * ...
+ * asio::ip::multicast::hops option;
+ * socket.get_option(option);
+ * int ttl = option.value();
+ * @endcode
+ *
+ * @par Concepts:
+ * GettableSocketOption, SettableSocketOption.
+ */
+#if defined(GENERATING_DOCUMENTATION)
+typedef implementation_defined hops;
+#else
+typedef asio::ip::detail::socket_option::multicast_hops<
+  ASIO_OS_DEF(IPPROTO_IP),
+  ASIO_OS_DEF(IP_MULTICAST_TTL),
+  ASIO_OS_DEF(IPPROTO_IPV6),
+  ASIO_OS_DEF(IPV6_MULTICAST_HOPS)> hops;
+#endif
+
+/// Socket option determining whether outgoing multicast packets will be
+/// received on the same socket if it is a member of the multicast group.
+/**
+ * Implements the IPPROTO_IP/IP_MULTICAST_LOOP socket option.
+ *
+ * @par Examples
+ * Setting the option:
+ * @code
+ * asio::ip::udp::socket socket(my_context);
+ * ...
+ * asio::ip::multicast::enable_loopback option(true);
+ * socket.set_option(option);
+ * @endcode
+ *
+ * @par
+ * Getting the current option value:
+ * @code
+ * asio::ip::udp::socket socket(my_context);
+ * ...
+ * asio::ip::multicast::enable_loopback option;
+ * socket.get_option(option);
+ * bool is_set = option.value();
+ * @endcode
+ *
+ * @par Concepts:
+ * GettableSocketOption, SettableSocketOption.
+ */
+#if defined(GENERATING_DOCUMENTATION)
+typedef implementation_defined enable_loopback;
+#else
+typedef asio::ip::detail::socket_option::multicast_enable_loopback<
+  ASIO_OS_DEF(IPPROTO_IP),
+  ASIO_OS_DEF(IP_MULTICAST_LOOP),
+  ASIO_OS_DEF(IPPROTO_IPV6),
+  ASIO_OS_DEF(IPV6_MULTICAST_LOOP)> enable_loopback;
+#endif
+
+} // namespace multicast
+} // namespace ip
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IP_MULTICAST_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/ip/network_v4.hpp b/link/modules/asio-standalone/asio/include/asio/ip/network_v4.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/ip/network_v4.hpp
@@ -0,0 +1,261 @@
+//
+// ip/network_v4.hpp
+// ~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2014 Oliver Kowalke (oliver dot kowalke at gmail 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 ASIO_IP_NETWORK_V4_HPP
+#define ASIO_IP_NETWORK_V4_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <string>
+#include "asio/detail/string_view.hpp"
+#include "asio/error_code.hpp"
+#include "asio/ip/address_v4_range.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace ip {
+
+/// Represents an IPv4 network.
+/**
+ * The asio::ip::network_v4 class provides the ability to use and
+ * manipulate IP version 4 networks.
+ *
+ * @par Thread Safety
+ * @e Distinct @e objects: Safe.@n
+ * @e Shared @e objects: Unsafe.
+ */
+class network_v4
+{
+public:
+  /// Default constructor.
+  network_v4() ASIO_NOEXCEPT
+    : address_(),
+      prefix_length_(0)
+  {
+  }
+
+  /// Construct a network based on the specified address and prefix length.
+  ASIO_DECL network_v4(const address_v4& addr,
+      unsigned short prefix_len);
+
+  /// Construct network based on the specified address and netmask.
+  ASIO_DECL network_v4(const address_v4& addr,
+      const address_v4& mask);
+
+  /// Copy constructor.
+  network_v4(const network_v4& other) ASIO_NOEXCEPT
+    : address_(other.address_),
+      prefix_length_(other.prefix_length_)
+  {
+  }
+
+#if defined(ASIO_HAS_MOVE)
+  /// Move constructor.
+  network_v4(network_v4&& other) ASIO_NOEXCEPT
+    : address_(ASIO_MOVE_CAST(address_v4)(other.address_)),
+      prefix_length_(other.prefix_length_)
+  {
+  }
+#endif // defined(ASIO_HAS_MOVE)
+
+  /// Assign from another network.
+  network_v4& operator=(const network_v4& other) ASIO_NOEXCEPT
+  {
+    address_ = other.address_;
+    prefix_length_ = other.prefix_length_;
+    return *this;
+  }
+
+#if defined(ASIO_HAS_MOVE)
+  /// Move-assign from another network.
+  network_v4& operator=(network_v4&& other) ASIO_NOEXCEPT
+  {
+    address_ = ASIO_MOVE_CAST(address_v4)(other.address_);
+    prefix_length_ = other.prefix_length_;
+    return *this;
+  }
+#endif // defined(ASIO_HAS_MOVE)
+
+  /// Obtain the address object specified when the network object was created.
+  address_v4 address() const ASIO_NOEXCEPT
+  {
+    return address_;
+  }
+
+  /// Obtain the prefix length that was specified when the network object was
+  /// created.
+  unsigned short prefix_length() const ASIO_NOEXCEPT
+  {
+    return prefix_length_;
+  }
+
+  /// Obtain the netmask that was specified when the network object was created.
+  ASIO_DECL address_v4 netmask() const ASIO_NOEXCEPT;
+
+  /// Obtain an address object that represents the network address.
+  address_v4 network() const ASIO_NOEXCEPT
+  {
+    return address_v4(address_.to_uint() & netmask().to_uint());
+  }
+
+  /// Obtain an address object that represents the network's broadcast address.
+  address_v4 broadcast() const ASIO_NOEXCEPT
+  {
+    return address_v4(network().to_uint() | (netmask().to_uint() ^ 0xFFFFFFFF));
+  }
+
+  /// Obtain an address range corresponding to the hosts in the network.
+  ASIO_DECL address_v4_range hosts() const ASIO_NOEXCEPT;
+
+  /// Obtain the true network address, omitting any host bits.
+  network_v4 canonical() const ASIO_NOEXCEPT
+  {
+    return network_v4(network(), netmask());
+  }
+
+  /// Test if network is a valid host address.
+  bool is_host() const ASIO_NOEXCEPT
+  {
+    return prefix_length_ == 32;
+  }
+
+  /// Test if a network is a real subnet of another network.
+  ASIO_DECL bool is_subnet_of(const network_v4& other) const;
+
+  /// Get the network as an address in dotted decimal format.
+  ASIO_DECL std::string to_string() const;
+
+  /// Get the network as an address in dotted decimal format.
+  ASIO_DECL std::string to_string(asio::error_code& ec) const;
+
+  /// Compare two networks for equality.
+  friend bool operator==(const network_v4& a, const network_v4& b)
+  {
+    return a.address_ == b.address_ && a.prefix_length_ == b.prefix_length_;
+  }
+
+  /// Compare two networks for inequality.
+  friend bool operator!=(const network_v4& a, const network_v4& b)
+  {
+    return !(a == b);
+  }
+
+private:
+  address_v4 address_;
+  unsigned short prefix_length_;
+};
+
+/// Create an IPv4 network from an address and prefix length.
+/**
+ * @relates address_v4
+ */
+inline network_v4 make_network_v4(
+    const address_v4& addr, unsigned short prefix_len)
+{
+  return network_v4(addr, prefix_len);
+}
+
+/// Create an IPv4 network from an address and netmask.
+/**
+ * @relates address_v4
+ */
+inline network_v4 make_network_v4(
+    const address_v4& addr, const address_v4& mask)
+{
+  return network_v4(addr, mask);
+}
+
+/// Create an IPv4 network from a string containing IP address and prefix
+/// length.
+/**
+ * @relates network_v4
+ */
+ASIO_DECL network_v4 make_network_v4(const char* str);
+
+/// Create an IPv4 network from a string containing IP address and prefix
+/// length.
+/**
+ * @relates network_v4
+ */
+ASIO_DECL network_v4 make_network_v4(
+    const char* str, asio::error_code& ec);
+
+/// Create an IPv4 network from a string containing IP address and prefix
+/// length.
+/**
+ * @relates network_v4
+ */
+ASIO_DECL network_v4 make_network_v4(const std::string& str);
+
+/// Create an IPv4 network from a string containing IP address and prefix
+/// length.
+/**
+ * @relates network_v4
+ */
+ASIO_DECL network_v4 make_network_v4(
+    const std::string& str, asio::error_code& ec);
+
+#if defined(ASIO_HAS_STRING_VIEW) \
+  || defined(GENERATING_DOCUMENTATION)
+
+/// Create an IPv4 network from a string containing IP address and prefix
+/// length.
+/**
+ * @relates network_v4
+ */
+ASIO_DECL network_v4 make_network_v4(string_view str);
+
+/// Create an IPv4 network from a string containing IP address and prefix
+/// length.
+/**
+ * @relates network_v4
+ */
+ASIO_DECL network_v4 make_network_v4(
+    string_view str, asio::error_code& ec);
+
+#endif // defined(ASIO_HAS_STRING_VIEW)
+       //  || defined(GENERATING_DOCUMENTATION)
+
+#if !defined(ASIO_NO_IOSTREAM)
+
+/// Output a network as a string.
+/**
+ * Used to output a human-readable string for a specified network.
+ *
+ * @param os The output stream to which the string will be written.
+ *
+ * @param net The network to be written.
+ *
+ * @return The output stream.
+ *
+ * @relates asio::ip::address_v4
+ */
+template <typename Elem, typename Traits>
+std::basic_ostream<Elem, Traits>& operator<<(
+    std::basic_ostream<Elem, Traits>& os, const network_v4& net);
+
+#endif // !defined(ASIO_NO_IOSTREAM)
+
+} // namespace ip
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/ip/impl/network_v4.hpp"
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/ip/impl/network_v4.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // ASIO_IP_NETWORK_V4_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/ip/network_v6.hpp b/link/modules/asio-standalone/asio/include/asio/ip/network_v6.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/ip/network_v6.hpp
@@ -0,0 +1,235 @@
+//
+// ip/network_v6.hpp
+// ~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2014 Oliver Kowalke (oliver dot kowalke at gmail 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 ASIO_IP_NETWORK_V6_HPP
+#define ASIO_IP_NETWORK_V6_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <string>
+#include "asio/detail/string_view.hpp"
+#include "asio/error_code.hpp"
+#include "asio/ip/address_v6_range.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace ip {
+
+/// Represents an IPv6 network.
+/**
+ * The asio::ip::network_v6 class provides the ability to use and
+ * manipulate IP version 6 networks.
+ *
+ * @par Thread Safety
+ * @e Distinct @e objects: Safe.@n
+ * @e Shared @e objects: Unsafe.
+ */
+class network_v6
+{
+public:
+  /// Default constructor.
+  network_v6() ASIO_NOEXCEPT
+    : address_(),
+      prefix_length_(0)
+  {
+  }
+
+  /// Construct a network based on the specified address and prefix length.
+  ASIO_DECL network_v6(const address_v6& addr,
+      unsigned short prefix_len);
+
+  /// Copy constructor.
+  network_v6(const network_v6& other) ASIO_NOEXCEPT
+    : address_(other.address_),
+      prefix_length_(other.prefix_length_)
+  {
+  }
+
+#if defined(ASIO_HAS_MOVE)
+  /// Move constructor.
+  network_v6(network_v6&& other) ASIO_NOEXCEPT
+    : address_(ASIO_MOVE_CAST(address_v6)(other.address_)),
+      prefix_length_(other.prefix_length_)
+  {
+  }
+#endif // defined(ASIO_HAS_MOVE)
+
+  /// Assign from another network.
+  network_v6& operator=(const network_v6& other) ASIO_NOEXCEPT
+  {
+    address_ = other.address_;
+    prefix_length_ = other.prefix_length_;
+    return *this;
+  }
+
+#if defined(ASIO_HAS_MOVE)
+  /// Move-assign from another network.
+  network_v6& operator=(network_v6&& other) ASIO_NOEXCEPT
+  {
+    address_ = ASIO_MOVE_CAST(address_v6)(other.address_);
+    prefix_length_ = other.prefix_length_;
+    return *this;
+  }
+#endif // defined(ASIO_HAS_MOVE)
+
+  /// Obtain the address object specified when the network object was created.
+  address_v6 address() const ASIO_NOEXCEPT
+  {
+    return address_;
+  }
+
+  /// Obtain the prefix length that was specified when the network object was
+  /// created.
+  unsigned short prefix_length() const ASIO_NOEXCEPT
+  {
+    return prefix_length_;
+  }
+
+  /// Obtain an address object that represents the network address.
+  ASIO_DECL address_v6 network() const ASIO_NOEXCEPT;
+
+  /// Obtain an address range corresponding to the hosts in the network.
+  ASIO_DECL address_v6_range hosts() const ASIO_NOEXCEPT;
+
+  /// Obtain the true network address, omitting any host bits.
+  network_v6 canonical() const ASIO_NOEXCEPT
+  {
+    return network_v6(network(), prefix_length());
+  }
+
+  /// Test if network is a valid host address.
+  bool is_host() const ASIO_NOEXCEPT
+  {
+    return prefix_length_ == 128;
+  }
+
+  /// Test if a network is a real subnet of another network.
+  ASIO_DECL bool is_subnet_of(const network_v6& other) const;
+
+  /// Get the network as an address in dotted decimal format.
+  ASIO_DECL std::string to_string() const;
+
+  /// Get the network as an address in dotted decimal format.
+  ASIO_DECL std::string to_string(asio::error_code& ec) const;
+
+  /// Compare two networks for equality.
+  friend bool operator==(const network_v6& a, const network_v6& b)
+  {
+    return a.address_ == b.address_ && a.prefix_length_ == b.prefix_length_;
+  }
+
+  /// Compare two networks for inequality.
+  friend bool operator!=(const network_v6& a, const network_v6& b)
+  {
+    return !(a == b);
+  }
+
+private:
+  address_v6 address_;
+  unsigned short prefix_length_;
+};
+
+/// Create an IPv6 network from an address and prefix length.
+/**
+ * @relates address_v6
+ */
+inline network_v6 make_network_v6(
+    const address_v6& addr, unsigned short prefix_len)
+{
+  return network_v6(addr, prefix_len);
+}
+
+/// Create an IPv6 network from a string containing IP address and prefix
+/// length.
+/**
+ * @relates network_v6
+ */
+ASIO_DECL network_v6 make_network_v6(const char* str);
+
+/// Create an IPv6 network from a string containing IP address and prefix
+/// length.
+/**
+ * @relates network_v6
+ */
+ASIO_DECL network_v6 make_network_v6(
+    const char* str, asio::error_code& ec);
+
+/// Create an IPv6 network from a string containing IP address and prefix
+/// length.
+/**
+ * @relates network_v6
+ */
+ASIO_DECL network_v6 make_network_v6(const std::string& str);
+
+/// Create an IPv6 network from a string containing IP address and prefix
+/// length.
+/**
+ * @relates network_v6
+ */
+ASIO_DECL network_v6 make_network_v6(
+    const std::string& str, asio::error_code& ec);
+
+#if defined(ASIO_HAS_STRING_VIEW) \
+  || defined(GENERATING_DOCUMENTATION)
+
+/// Create an IPv6 network from a string containing IP address and prefix
+/// length.
+/**
+ * @relates network_v6
+ */
+ASIO_DECL network_v6 make_network_v6(string_view str);
+
+/// Create an IPv6 network from a string containing IP address and prefix
+/// length.
+/**
+ * @relates network_v6
+ */
+ASIO_DECL network_v6 make_network_v6(
+    string_view str, asio::error_code& ec);
+
+#endif // defined(ASIO_HAS_STRING_VIEW)
+       //  || defined(GENERATING_DOCUMENTATION)
+
+#if !defined(ASIO_NO_IOSTREAM)
+
+/// Output a network as a string.
+/**
+ * Used to output a human-readable string for a specified network.
+ *
+ * @param os The output stream to which the string will be written.
+ *
+ * @param net The network to be written.
+ *
+ * @return The output stream.
+ *
+ * @relates asio::ip::address_v6
+ */
+template <typename Elem, typename Traits>
+std::basic_ostream<Elem, Traits>& operator<<(
+    std::basic_ostream<Elem, Traits>& os, const network_v6& net);
+
+#endif // !defined(ASIO_NO_IOSTREAM)
+
+} // namespace ip
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/ip/impl/network_v6.hpp"
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/ip/impl/network_v6.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // ASIO_IP_NETWORK_V6_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/ip/resolver_base.hpp b/link/modules/asio-standalone/asio/include/asio/ip/resolver_base.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/ip/resolver_base.hpp
@@ -0,0 +1,129 @@
+//
+// ip/resolver_base.hpp
+// ~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_IP_RESOLVER_BASE_HPP
+#define ASIO_IP_RESOLVER_BASE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/socket_types.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace ip {
+
+/// The resolver_base class is used as a base for the basic_resolver class
+/// templates to provide a common place to define the flag constants.
+class resolver_base
+{
+public:
+#if defined(GENERATING_DOCUMENTATION)
+  /// A bitmask type (C++ Std [lib.bitmask.types]).
+  typedef unspecified flags;
+
+  /// Determine the canonical name of the host specified in the query.
+  static const flags canonical_name = implementation_defined;
+
+  /// Indicate that returned endpoint is intended for use as a locally bound
+  /// socket endpoint.
+  static const flags passive = implementation_defined;
+
+  /// Host name should be treated as a numeric string defining an IPv4 or IPv6
+  /// address and no name resolution should be attempted.
+  static const flags numeric_host = implementation_defined;
+
+  /// Service name should be treated as a numeric string defining a port number
+  /// and no name resolution should be attempted.
+  static const flags numeric_service = implementation_defined;
+
+  /// If the query protocol family is specified as IPv6, return IPv4-mapped
+  /// IPv6 addresses on finding no IPv6 addresses.
+  static const flags v4_mapped = implementation_defined;
+
+  /// If used with v4_mapped, return all matching IPv6 and IPv4 addresses.
+  static const flags all_matching = implementation_defined;
+
+  /// Only return IPv4 addresses if a non-loopback IPv4 address is configured
+  /// for the system. Only return IPv6 addresses if a non-loopback IPv6 address
+  /// is configured for the system.
+  static const flags address_configured = implementation_defined;
+#else
+  enum flags
+  {
+    canonical_name = ASIO_OS_DEF(AI_CANONNAME),
+    passive = ASIO_OS_DEF(AI_PASSIVE),
+    numeric_host = ASIO_OS_DEF(AI_NUMERICHOST),
+    numeric_service = ASIO_OS_DEF(AI_NUMERICSERV),
+    v4_mapped = ASIO_OS_DEF(AI_V4MAPPED),
+    all_matching = ASIO_OS_DEF(AI_ALL),
+    address_configured = ASIO_OS_DEF(AI_ADDRCONFIG)
+  };
+
+  // Implement bitmask operations as shown in C++ Std [lib.bitmask.types].
+
+  friend flags operator&(flags x, flags y)
+  {
+    return static_cast<flags>(
+        static_cast<unsigned int>(x) & static_cast<unsigned int>(y));
+  }
+
+  friend flags operator|(flags x, flags y)
+  {
+    return static_cast<flags>(
+        static_cast<unsigned int>(x) | static_cast<unsigned int>(y));
+  }
+
+  friend flags operator^(flags x, flags y)
+  {
+    return static_cast<flags>(
+        static_cast<unsigned int>(x) ^ static_cast<unsigned int>(y));
+  }
+
+  friend flags operator~(flags x)
+  {
+    return static_cast<flags>(~static_cast<unsigned int>(x));
+  }
+
+  friend flags& operator&=(flags& x, flags y)
+  {
+    x = x & y;
+    return x;
+  }
+
+  friend flags& operator|=(flags& x, flags y)
+  {
+    x = x | y;
+    return x;
+  }
+
+  friend flags& operator^=(flags& x, flags y)
+  {
+    x = x ^ y;
+    return x;
+  }
+#endif
+
+protected:
+  /// Protected destructor to prevent deletion through this type.
+  ~resolver_base()
+  {
+  }
+};
+
+} // namespace ip
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IP_RESOLVER_BASE_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/ip/resolver_query_base.hpp b/link/modules/asio-standalone/asio/include/asio/ip/resolver_query_base.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/ip/resolver_query_base.hpp
@@ -0,0 +1,43 @@
+//
+// ip/resolver_query_base.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_IP_RESOLVER_QUERY_BASE_HPP
+#define ASIO_IP_RESOLVER_QUERY_BASE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/ip/resolver_base.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace ip {
+
+/// The resolver_query_base class is used as a base for the
+/// basic_resolver_query class templates to provide a common place to define
+/// the flag constants.
+class resolver_query_base : public resolver_base
+{
+protected:
+  /// Protected destructor to prevent deletion through this type.
+  ~resolver_query_base()
+  {
+  }
+};
+
+} // namespace ip
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IP_RESOLVER_QUERY_BASE_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/ip/tcp.hpp b/link/modules/asio-standalone/asio/include/asio/ip/tcp.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/ip/tcp.hpp
@@ -0,0 +1,155 @@
+//
+// ip/tcp.hpp
+// ~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_IP_TCP_HPP
+#define ASIO_IP_TCP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/basic_socket_acceptor.hpp"
+#include "asio/basic_socket_iostream.hpp"
+#include "asio/basic_stream_socket.hpp"
+#include "asio/detail/socket_option.hpp"
+#include "asio/detail/socket_types.hpp"
+#include "asio/ip/basic_endpoint.hpp"
+#include "asio/ip/basic_resolver.hpp"
+#include "asio/ip/basic_resolver_iterator.hpp"
+#include "asio/ip/basic_resolver_query.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace ip {
+
+/// Encapsulates the flags needed for TCP.
+/**
+ * The asio::ip::tcp class contains flags necessary for TCP sockets.
+ *
+ * @par Thread Safety
+ * @e Distinct @e objects: Safe.@n
+ * @e Shared @e objects: Safe.
+ *
+ * @par Concepts:
+ * Protocol, InternetProtocol.
+ */
+class tcp
+{
+public:
+  /// The type of a TCP endpoint.
+  typedef basic_endpoint<tcp> endpoint;
+
+  /// Construct to represent the IPv4 TCP protocol.
+  static tcp v4() ASIO_NOEXCEPT
+  {
+    return tcp(ASIO_OS_DEF(AF_INET));
+  }
+
+  /// Construct to represent the IPv6 TCP protocol.
+  static tcp v6() ASIO_NOEXCEPT
+  {
+    return tcp(ASIO_OS_DEF(AF_INET6));
+  }
+
+  /// Obtain an identifier for the type of the protocol.
+  int type() const ASIO_NOEXCEPT
+  {
+    return ASIO_OS_DEF(SOCK_STREAM);
+  }
+
+  /// Obtain an identifier for the protocol.
+  int protocol() const ASIO_NOEXCEPT
+  {
+    return ASIO_OS_DEF(IPPROTO_TCP);
+  }
+
+  /// Obtain an identifier for the protocol family.
+  int family() const ASIO_NOEXCEPT
+  {
+    return family_;
+  }
+
+  /// The TCP socket type.
+  typedef basic_stream_socket<tcp> socket;
+
+  /// The TCP acceptor type.
+  typedef basic_socket_acceptor<tcp> acceptor;
+
+  /// The TCP resolver type.
+  typedef basic_resolver<tcp> resolver;
+
+#if !defined(ASIO_NO_IOSTREAM)
+  /// The TCP iostream type.
+  typedef basic_socket_iostream<tcp> iostream;
+#endif // !defined(ASIO_NO_IOSTREAM)
+
+  /// Socket option for disabling the Nagle algorithm.
+  /**
+   * Implements the IPPROTO_TCP/TCP_NODELAY socket option.
+   *
+   * @par Examples
+   * Setting the option:
+   * @code
+   * asio::ip::tcp::socket socket(my_context);
+   * ...
+   * asio::ip::tcp::no_delay option(true);
+   * socket.set_option(option);
+   * @endcode
+   *
+   * @par
+   * Getting the current option value:
+   * @code
+   * asio::ip::tcp::socket socket(my_context);
+   * ...
+   * asio::ip::tcp::no_delay option;
+   * socket.get_option(option);
+   * bool is_set = option.value();
+   * @endcode
+   *
+   * @par Concepts:
+   * Socket_Option, Boolean_Socket_Option.
+   */
+#if defined(GENERATING_DOCUMENTATION)
+  typedef implementation_defined no_delay;
+#else
+  typedef asio::detail::socket_option::boolean<
+    ASIO_OS_DEF(IPPROTO_TCP), ASIO_OS_DEF(TCP_NODELAY)> no_delay;
+#endif
+
+  /// Compare two protocols for equality.
+  friend bool operator==(const tcp& p1, const tcp& p2)
+  {
+    return p1.family_ == p2.family_;
+  }
+
+  /// Compare two protocols for inequality.
+  friend bool operator!=(const tcp& p1, const tcp& p2)
+  {
+    return p1.family_ != p2.family_;
+  }
+
+private:
+  // Construct with a specific family.
+  explicit tcp(int protocol_family) ASIO_NOEXCEPT
+    : family_(protocol_family)
+  {
+  }
+
+  int family_;
+};
+
+} // namespace ip
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IP_TCP_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/ip/udp.hpp b/link/modules/asio-standalone/asio/include/asio/ip/udp.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/ip/udp.hpp
@@ -0,0 +1,111 @@
+//
+// ip/udp.hpp
+// ~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_IP_UDP_HPP
+#define ASIO_IP_UDP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/basic_datagram_socket.hpp"
+#include "asio/detail/socket_types.hpp"
+#include "asio/ip/basic_endpoint.hpp"
+#include "asio/ip/basic_resolver.hpp"
+#include "asio/ip/basic_resolver_iterator.hpp"
+#include "asio/ip/basic_resolver_query.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace ip {
+
+/// Encapsulates the flags needed for UDP.
+/**
+ * The asio::ip::udp class contains flags necessary for UDP sockets.
+ *
+ * @par Thread Safety
+ * @e Distinct @e objects: Safe.@n
+ * @e Shared @e objects: Safe.
+ *
+ * @par Concepts:
+ * Protocol, InternetProtocol.
+ */
+class udp
+{
+public:
+  /// The type of a UDP endpoint.
+  typedef basic_endpoint<udp> endpoint;
+
+  /// Construct to represent the IPv4 UDP protocol.
+  static udp v4() ASIO_NOEXCEPT
+  {
+    return udp(ASIO_OS_DEF(AF_INET));
+  }
+
+  /// Construct to represent the IPv6 UDP protocol.
+  static udp v6() ASIO_NOEXCEPT
+  {
+    return udp(ASIO_OS_DEF(AF_INET6));
+  }
+
+  /// Obtain an identifier for the type of the protocol.
+  int type() const ASIO_NOEXCEPT
+  {
+    return ASIO_OS_DEF(SOCK_DGRAM);
+  }
+
+  /// Obtain an identifier for the protocol.
+  int protocol() const ASIO_NOEXCEPT
+  {
+    return ASIO_OS_DEF(IPPROTO_UDP);
+  }
+
+  /// Obtain an identifier for the protocol family.
+  int family() const ASIO_NOEXCEPT
+  {
+    return family_;
+  }
+
+  /// The UDP socket type.
+  typedef basic_datagram_socket<udp> socket;
+
+  /// The UDP resolver type.
+  typedef basic_resolver<udp> resolver;
+
+  /// Compare two protocols for equality.
+  friend bool operator==(const udp& p1, const udp& p2)
+  {
+    return p1.family_ == p2.family_;
+  }
+
+  /// Compare two protocols for inequality.
+  friend bool operator!=(const udp& p1, const udp& p2)
+  {
+    return p1.family_ != p2.family_;
+  }
+
+private:
+  // Construct with a specific family.
+  explicit udp(int protocol_family) ASIO_NOEXCEPT
+    : family_(protocol_family)
+  {
+  }
+
+  int family_;
+};
+
+} // namespace ip
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IP_UDP_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/ip/unicast.hpp b/link/modules/asio-standalone/asio/include/asio/ip/unicast.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/ip/unicast.hpp
@@ -0,0 +1,70 @@
+//
+// ip/unicast.hpp
+// ~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_IP_UNICAST_HPP
+#define ASIO_IP_UNICAST_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <cstddef>
+#include "asio/ip/detail/socket_option.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace ip {
+namespace unicast {
+
+/// Socket option for time-to-live associated with outgoing unicast packets.
+/**
+ * Implements the IPPROTO_IP/IP_UNICAST_TTL socket option.
+ *
+ * @par Examples
+ * Setting the option:
+ * @code
+ * asio::ip::udp::socket socket(my_context);
+ * ...
+ * asio::ip::unicast::hops option(4);
+ * socket.set_option(option);
+ * @endcode
+ *
+ * @par
+ * Getting the current option value:
+ * @code
+ * asio::ip::udp::socket socket(my_context);
+ * ...
+ * asio::ip::unicast::hops option;
+ * socket.get_option(option);
+ * int ttl = option.value();
+ * @endcode
+ *
+ * @par Concepts:
+ * GettableSocketOption, SettableSocketOption.
+ */
+#if defined(GENERATING_DOCUMENTATION)
+typedef implementation_defined hops;
+#else
+typedef asio::ip::detail::socket_option::unicast_hops<
+  ASIO_OS_DEF(IPPROTO_IP),
+  ASIO_OS_DEF(IP_TTL),
+  ASIO_OS_DEF(IPPROTO_IPV6),
+  ASIO_OS_DEF(IPV6_UNICAST_HOPS)> hops;
+#endif
+
+} // namespace unicast
+} // namespace ip
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IP_UNICAST_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/ip/v6_only.hpp b/link/modules/asio-standalone/asio/include/asio/ip/v6_only.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/ip/v6_only.hpp
@@ -0,0 +1,69 @@
+//
+// ip/v6_only.hpp
+// ~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_IP_V6_ONLY_HPP
+#define ASIO_IP_V6_ONLY_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/socket_option.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace ip {
+
+/// Socket option for determining whether an IPv6 socket supports IPv6
+/// communication only.
+/**
+ * Implements the IPPROTO_IPV6/IP_V6ONLY socket option.
+ *
+ * @par Examples
+ * Setting the option:
+ * @code
+ * asio::ip::tcp::socket socket(my_context);
+ * ...
+ * asio::ip::v6_only option(true);
+ * socket.set_option(option);
+ * @endcode
+ *
+ * @par
+ * Getting the current option value:
+ * @code
+ * asio::ip::tcp::socket socket(my_context);
+ * ...
+ * asio::ip::v6_only option;
+ * socket.get_option(option);
+ * bool v6_only = option.value();
+ * @endcode
+ *
+ * @par Concepts:
+ * GettableSocketOption, SettableSocketOption.
+ */
+#if defined(GENERATING_DOCUMENTATION)
+typedef implementation_defined v6_only;
+#elif defined(IPV6_V6ONLY)
+typedef asio::detail::socket_option::boolean<
+    IPPROTO_IPV6, IPV6_V6ONLY> v6_only;
+#else
+typedef asio::detail::socket_option::boolean<
+    asio::detail::custom_socket_option_level,
+    asio::detail::always_fail_option> v6_only;
+#endif
+
+} // namespace ip
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IP_V6_ONLY_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/is_applicable_property.hpp b/link/modules/asio-standalone/asio/include/asio/is_applicable_property.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/is_applicable_property.hpp
@@ -0,0 +1,61 @@
+//
+// is_applicable_property.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_IS_APPLICABLE_PROPERTY_HPP
+#define ASIO_IS_APPLICABLE_PROPERTY_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/type_traits.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename T, typename Property, typename = void>
+struct is_applicable_property_trait : false_type
+{
+};
+
+#if defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+template <typename T, typename Property>
+struct is_applicable_property_trait<T, Property,
+  typename void_type<
+    typename enable_if<
+      !!Property::template is_applicable_property_v<T>
+    >::type
+  >::type> : true_type
+{
+};
+
+#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+} // namespace detail
+
+template <typename T, typename Property, typename = void>
+struct is_applicable_property :
+  detail::is_applicable_property_trait<T, Property>
+{
+};
+
+#if defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+template <typename T, typename Property>
+ASIO_CONSTEXPR const bool is_applicable_property_v
+  = is_applicable_property<T, Property>::value;
+
+#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+} // namespace asio
+
+#endif // ASIO_IS_APPLICABLE_PROPERTY_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/is_executor.hpp b/link/modules/asio-standalone/asio/include/asio/is_executor.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/is_executor.hpp
@@ -0,0 +1,46 @@
+//
+// is_executor.hpp
+// ~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_IS_EXECUTOR_HPP
+#define ASIO_IS_EXECUTOR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/is_executor.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+/// The is_executor trait detects whether a type T meets the Executor type
+/// requirements.
+/**
+ * Class template @c is_executor is a UnaryTypeTrait that is derived from @c
+ * true_type if the type @c T meets the syntactic requirements for Executor,
+ * otherwise @c false_type.
+ */
+template <typename T>
+struct is_executor
+#if defined(GENERATING_DOCUMENTATION)
+  : integral_constant<bool, automatically_determined>
+#else // defined(GENERATING_DOCUMENTATION)
+  : asio::detail::is_executor<T>
+#endif // defined(GENERATING_DOCUMENTATION)
+{
+};
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IS_EXECUTOR_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/is_read_buffered.hpp b/link/modules/asio-standalone/asio/include/asio/is_read_buffered.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/is_read_buffered.hpp
@@ -0,0 +1,59 @@
+//
+// is_read_buffered.hpp
+// ~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_IS_READ_BUFFERED_HPP
+#define ASIO_IS_READ_BUFFERED_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/buffered_read_stream_fwd.hpp"
+#include "asio/buffered_stream_fwd.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+namespace detail {
+
+template <typename Stream>
+char is_read_buffered_helper(buffered_stream<Stream>* s);
+
+template <typename Stream>
+char is_read_buffered_helper(buffered_read_stream<Stream>* s);
+
+struct is_read_buffered_big_type { char data[10]; };
+is_read_buffered_big_type is_read_buffered_helper(...);
+
+} // namespace detail
+
+/// The is_read_buffered class is a traits class that may be used to determine
+/// whether a stream type supports buffering of read data.
+template <typename Stream>
+class is_read_buffered
+{
+public:
+#if defined(GENERATING_DOCUMENTATION)
+  /// The value member is true only if the Stream type supports buffering of
+  /// read data.
+  static const bool value;
+#else
+  ASIO_STATIC_CONSTANT(bool,
+      value = sizeof(detail::is_read_buffered_helper((Stream*)0)) == 1);
+#endif
+};
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IS_READ_BUFFERED_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/is_write_buffered.hpp b/link/modules/asio-standalone/asio/include/asio/is_write_buffered.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/is_write_buffered.hpp
@@ -0,0 +1,59 @@
+//
+// is_write_buffered.hpp
+// ~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_IS_WRITE_BUFFERED_HPP
+#define ASIO_IS_WRITE_BUFFERED_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/buffered_stream_fwd.hpp"
+#include "asio/buffered_write_stream_fwd.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+namespace detail {
+
+template <typename Stream>
+char is_write_buffered_helper(buffered_stream<Stream>* s);
+
+template <typename Stream>
+char is_write_buffered_helper(buffered_write_stream<Stream>* s);
+
+struct is_write_buffered_big_type { char data[10]; };
+is_write_buffered_big_type is_write_buffered_helper(...);
+
+} // namespace detail
+
+/// The is_write_buffered class is a traits class that may be used to determine
+/// whether a stream type supports buffering of written data.
+template <typename Stream>
+class is_write_buffered
+{
+public:
+#if defined(GENERATING_DOCUMENTATION)
+  /// The value member is true only if the Stream type supports buffering of
+  /// written data.
+  static const bool value;
+#else
+  ASIO_STATIC_CONSTANT(bool,
+      value = sizeof(detail::is_write_buffered_helper((Stream*)0)) == 1);
+#endif
+};
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IS_WRITE_BUFFERED_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/local/basic_endpoint.hpp b/link/modules/asio-standalone/asio/include/asio/local/basic_endpoint.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/local/basic_endpoint.hpp
@@ -0,0 +1,247 @@
+//
+// local/basic_endpoint.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Derived from a public domain implementation written by Daniel Casimiro.
+//
+// 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 ASIO_LOCAL_BASIC_ENDPOINT_HPP
+#define ASIO_LOCAL_BASIC_ENDPOINT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_LOCAL_SOCKETS) \
+  || defined(GENERATING_DOCUMENTATION)
+
+#include "asio/local/detail/endpoint.hpp"
+
+#if !defined(ASIO_NO_IOSTREAM)
+# include <iosfwd>
+#endif // !defined(ASIO_NO_IOSTREAM)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace local {
+
+/// Describes an endpoint for a UNIX socket.
+/**
+ * The asio::local::basic_endpoint class template describes an endpoint
+ * that may be associated with a particular UNIX socket.
+ *
+ * @par Thread Safety
+ * @e Distinct @e objects: Safe.@n
+ * @e Shared @e objects: Unsafe.
+ *
+ * @par Concepts:
+ * Endpoint.
+ */
+template <typename Protocol>
+class basic_endpoint
+{
+public:
+  /// The protocol type associated with the endpoint.
+  typedef Protocol protocol_type;
+
+  /// The type of the endpoint structure. This type is dependent on the
+  /// underlying implementation of the socket layer.
+#if defined(GENERATING_DOCUMENTATION)
+  typedef implementation_defined data_type;
+#else
+  typedef asio::detail::socket_addr_type data_type;
+#endif
+
+  /// Default constructor.
+  basic_endpoint() ASIO_NOEXCEPT
+  {
+  }
+
+  /// Construct an endpoint using the specified path name.
+  basic_endpoint(const char* path_name)
+    : impl_(path_name)
+  {
+  }
+
+  /// Construct an endpoint using the specified path name.
+  basic_endpoint(const std::string& path_name)
+    : impl_(path_name)
+  {
+  }
+
+  #if defined(ASIO_HAS_STRING_VIEW)
+  /// Construct an endpoint using the specified path name.
+  basic_endpoint(string_view path_name)
+    : impl_(path_name)
+  {
+  }
+  #endif // defined(ASIO_HAS_STRING_VIEW)
+
+  /// Copy constructor.
+  basic_endpoint(const basic_endpoint& other)
+    : impl_(other.impl_)
+  {
+  }
+
+#if defined(ASIO_HAS_MOVE)
+  /// Move constructor.
+  basic_endpoint(basic_endpoint&& other)
+    : impl_(other.impl_)
+  {
+  }
+#endif // defined(ASIO_HAS_MOVE)
+
+  /// Assign from another endpoint.
+  basic_endpoint& operator=(const basic_endpoint& other)
+  {
+    impl_ = other.impl_;
+    return *this;
+  }
+
+#if defined(ASIO_HAS_MOVE)
+  /// Move-assign from another endpoint.
+  basic_endpoint& operator=(basic_endpoint&& other)
+  {
+    impl_ = other.impl_;
+    return *this;
+  }
+#endif // defined(ASIO_HAS_MOVE)
+
+  /// The protocol associated with the endpoint.
+  protocol_type protocol() const
+  {
+    return protocol_type();
+  }
+
+  /// Get the underlying endpoint in the native type.
+  data_type* data()
+  {
+    return impl_.data();
+  }
+
+  /// Get the underlying endpoint in the native type.
+  const data_type* data() const
+  {
+    return impl_.data();
+  }
+
+  /// Get the underlying size of the endpoint in the native type.
+  std::size_t size() const
+  {
+    return impl_.size();
+  }
+
+  /// Set the underlying size of the endpoint in the native type.
+  void resize(std::size_t new_size)
+  {
+    impl_.resize(new_size);
+  }
+
+  /// Get the capacity of the endpoint in the native type.
+  std::size_t capacity() const
+  {
+    return impl_.capacity();
+  }
+
+  /// Get the path associated with the endpoint.
+  std::string path() const
+  {
+    return impl_.path();
+  }
+
+  /// Set the path associated with the endpoint.
+  void path(const char* p)
+  {
+    impl_.path(p);
+  }
+
+  /// Set the path associated with the endpoint.
+  void path(const std::string& p)
+  {
+    impl_.path(p);
+  }
+
+  /// Compare two endpoints for equality.
+  friend bool operator==(const basic_endpoint<Protocol>& e1,
+      const basic_endpoint<Protocol>& e2)
+  {
+    return e1.impl_ == e2.impl_;
+  }
+
+  /// Compare two endpoints for inequality.
+  friend bool operator!=(const basic_endpoint<Protocol>& e1,
+      const basic_endpoint<Protocol>& e2)
+  {
+    return !(e1.impl_ == e2.impl_);
+  }
+
+  /// Compare endpoints for ordering.
+  friend bool operator<(const basic_endpoint<Protocol>& e1,
+      const basic_endpoint<Protocol>& e2)
+  {
+    return e1.impl_ < e2.impl_;
+  }
+
+  /// Compare endpoints for ordering.
+  friend bool operator>(const basic_endpoint<Protocol>& e1,
+      const basic_endpoint<Protocol>& e2)
+  {
+    return e2.impl_ < e1.impl_;
+  }
+
+  /// Compare endpoints for ordering.
+  friend bool operator<=(const basic_endpoint<Protocol>& e1,
+      const basic_endpoint<Protocol>& e2)
+  {
+    return !(e2 < e1);
+  }
+
+  /// Compare endpoints for ordering.
+  friend bool operator>=(const basic_endpoint<Protocol>& e1,
+      const basic_endpoint<Protocol>& e2)
+  {
+    return !(e1 < e2);
+  }
+
+private:
+  // The underlying UNIX domain endpoint.
+  asio::local::detail::endpoint impl_;
+};
+
+/// Output an endpoint as a string.
+/**
+ * Used to output a human-readable string for a specified endpoint.
+ *
+ * @param os The output stream to which the string will be written.
+ *
+ * @param endpoint The endpoint to be written.
+ *
+ * @return The output stream.
+ *
+ * @relates asio::local::basic_endpoint
+ */
+template <typename Elem, typename Traits, typename Protocol>
+std::basic_ostream<Elem, Traits>& operator<<(
+    std::basic_ostream<Elem, Traits>& os,
+    const basic_endpoint<Protocol>& endpoint)
+{
+  os << endpoint.path();
+  return os;
+}
+
+} // namespace local
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_LOCAL_SOCKETS)
+       //   || defined(GENERATING_DOCUMENTATION)
+
+#endif // ASIO_LOCAL_BASIC_ENDPOINT_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/local/connect_pair.hpp b/link/modules/asio-standalone/asio/include/asio/local/connect_pair.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/local/connect_pair.hpp
@@ -0,0 +1,101 @@
+//
+// local/connect_pair.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_LOCAL_CONNECT_PAIR_HPP
+#define ASIO_LOCAL_CONNECT_PAIR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_LOCAL_SOCKETS) \
+  || defined(GENERATING_DOCUMENTATION)
+
+#include "asio/basic_socket.hpp"
+#include "asio/detail/socket_ops.hpp"
+#include "asio/detail/throw_error.hpp"
+#include "asio/error.hpp"
+#include "asio/local/basic_endpoint.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace local {
+
+/// Create a pair of connected sockets.
+template <typename Protocol, typename Executor1, typename Executor2>
+void connect_pair(basic_socket<Protocol, Executor1>& socket1,
+    basic_socket<Protocol, Executor2>& socket2);
+
+/// Create a pair of connected sockets.
+template <typename Protocol, typename Executor1, typename Executor2>
+ASIO_SYNC_OP_VOID connect_pair(basic_socket<Protocol, Executor1>& socket1,
+    basic_socket<Protocol, Executor2>& socket2, asio::error_code& ec);
+
+template <typename Protocol, typename Executor1, typename Executor2>
+inline void connect_pair(basic_socket<Protocol, Executor1>& socket1,
+    basic_socket<Protocol, Executor2>& socket2)
+{
+  asio::error_code ec;
+  connect_pair(socket1, socket2, ec);
+  asio::detail::throw_error(ec, "connect_pair");
+}
+
+template <typename Protocol, typename Executor1, typename Executor2>
+inline ASIO_SYNC_OP_VOID connect_pair(
+    basic_socket<Protocol, Executor1>& socket1,
+    basic_socket<Protocol, Executor2>& socket2, asio::error_code& ec)
+{
+  // Check that this function is only being used with a UNIX domain socket.
+  asio::local::basic_endpoint<Protocol>* tmp
+    = static_cast<typename Protocol::endpoint*>(0);
+  (void)tmp;
+
+  Protocol protocol;
+  asio::detail::socket_type sv[2];
+  if (asio::detail::socket_ops::socketpair(protocol.family(),
+        protocol.type(), protocol.protocol(), sv, ec)
+      == asio::detail::socket_error_retval)
+    ASIO_SYNC_OP_VOID_RETURN(ec);
+
+  socket1.assign(protocol, sv[0], ec);
+  if (ec)
+  {
+    asio::error_code temp_ec;
+    asio::detail::socket_ops::state_type state[2] = { 0, 0 };
+    asio::detail::socket_ops::close(sv[0], state[0], true, temp_ec);
+    asio::detail::socket_ops::close(sv[1], state[1], true, temp_ec);
+    ASIO_SYNC_OP_VOID_RETURN(ec);
+  }
+
+  socket2.assign(protocol, sv[1], ec);
+  if (ec)
+  {
+    asio::error_code temp_ec;
+    socket1.close(temp_ec);
+    asio::detail::socket_ops::state_type state = 0;
+    asio::detail::socket_ops::close(sv[1], state, true, temp_ec);
+    ASIO_SYNC_OP_VOID_RETURN(ec);
+  }
+
+  ASIO_SYNC_OP_VOID_RETURN(ec);
+}
+
+} // namespace local
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_LOCAL_SOCKETS)
+       //   || defined(GENERATING_DOCUMENTATION)
+
+#endif // ASIO_LOCAL_CONNECT_PAIR_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/local/datagram_protocol.hpp b/link/modules/asio-standalone/asio/include/asio/local/datagram_protocol.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/local/datagram_protocol.hpp
@@ -0,0 +1,80 @@
+//
+// local/datagram_protocol.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_LOCAL_DATAGRAM_PROTOCOL_HPP
+#define ASIO_LOCAL_DATAGRAM_PROTOCOL_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_LOCAL_SOCKETS) \
+  || defined(GENERATING_DOCUMENTATION)
+
+#include "asio/basic_datagram_socket.hpp"
+#include "asio/detail/socket_types.hpp"
+#include "asio/local/basic_endpoint.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace local {
+
+/// Encapsulates the flags needed for datagram-oriented UNIX sockets.
+/**
+ * The asio::local::datagram_protocol class contains flags necessary for
+ * datagram-oriented UNIX domain sockets.
+ *
+ * @par Thread Safety
+ * @e Distinct @e objects: Safe.@n
+ * @e Shared @e objects: Safe.
+ *
+ * @par Concepts:
+ * Protocol.
+ */
+class datagram_protocol
+{
+public:
+  /// Obtain an identifier for the type of the protocol.
+  int type() const ASIO_NOEXCEPT
+  {
+    return SOCK_DGRAM;
+  }
+
+  /// Obtain an identifier for the protocol.
+  int protocol() const ASIO_NOEXCEPT
+  {
+    return 0;
+  }
+
+  /// Obtain an identifier for the protocol family.
+  int family() const ASIO_NOEXCEPT
+  {
+    return AF_UNIX;
+  }
+
+  /// The type of a UNIX domain endpoint.
+  typedef basic_endpoint<datagram_protocol> endpoint;
+
+  /// The UNIX domain socket type.
+  typedef basic_datagram_socket<datagram_protocol> socket;
+};
+
+} // namespace local
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_LOCAL_SOCKETS)
+       //   || defined(GENERATING_DOCUMENTATION)
+
+#endif // ASIO_LOCAL_DATAGRAM_PROTOCOL_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/local/detail/endpoint.hpp b/link/modules/asio-standalone/asio/include/asio/local/detail/endpoint.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/local/detail/endpoint.hpp
@@ -0,0 +1,139 @@
+//
+// local/detail/endpoint.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Derived from a public domain implementation written by Daniel Casimiro.
+//
+// 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 ASIO_LOCAL_DETAIL_ENDPOINT_HPP
+#define ASIO_LOCAL_DETAIL_ENDPOINT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_LOCAL_SOCKETS)
+
+#include <cstddef>
+#include <string>
+#include "asio/detail/socket_types.hpp"
+#include "asio/detail/string_view.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace local {
+namespace detail {
+
+// Helper class for implementing a UNIX domain endpoint.
+class endpoint
+{
+public:
+  // Default constructor.
+  ASIO_DECL endpoint();
+
+  // Construct an endpoint using the specified path name.
+  ASIO_DECL endpoint(const char* path_name);
+
+  // Construct an endpoint using the specified path name.
+  ASIO_DECL endpoint(const std::string& path_name);
+
+  #if defined(ASIO_HAS_STRING_VIEW)
+  // Construct an endpoint using the specified path name.
+  ASIO_DECL endpoint(string_view path_name);
+  #endif // defined(ASIO_HAS_STRING_VIEW)
+
+  // Copy constructor.
+  endpoint(const endpoint& other)
+    : data_(other.data_),
+      path_length_(other.path_length_)
+  {
+  }
+
+  // Assign from another endpoint.
+  endpoint& operator=(const endpoint& other)
+  {
+    data_ = other.data_;
+    path_length_ = other.path_length_;
+    return *this;
+  }
+
+  // Get the underlying endpoint in the native type.
+  asio::detail::socket_addr_type* data()
+  {
+    return &data_.base;
+  }
+
+  // Get the underlying endpoint in the native type.
+  const asio::detail::socket_addr_type* data() const
+  {
+    return &data_.base;
+  }
+
+  // Get the underlying size of the endpoint in the native type.
+  std::size_t size() const
+  {
+    return path_length_
+      + offsetof(asio::detail::sockaddr_un_type, sun_path);
+  }
+
+  // Set the underlying size of the endpoint in the native type.
+  ASIO_DECL void resize(std::size_t size);
+
+  // Get the capacity of the endpoint in the native type.
+  std::size_t capacity() const
+  {
+    return sizeof(asio::detail::sockaddr_un_type);
+  }
+
+  // Get the path associated with the endpoint.
+  ASIO_DECL std::string path() const;
+
+  // Set the path associated with the endpoint.
+  ASIO_DECL void path(const char* p);
+
+  // Set the path associated with the endpoint.
+  ASIO_DECL void path(const std::string& p);
+
+  // Compare two endpoints for equality.
+  ASIO_DECL friend bool operator==(
+      const endpoint& e1, const endpoint& e2);
+
+  // Compare endpoints for ordering.
+  ASIO_DECL friend bool operator<(
+      const endpoint& e1, const endpoint& e2);
+
+private:
+  // The underlying UNIX socket address.
+  union data_union
+  {
+    asio::detail::socket_addr_type base;
+    asio::detail::sockaddr_un_type local;
+  } data_;
+
+  // The length of the path associated with the endpoint.
+  std::size_t path_length_;
+
+  // Initialise with a specified path.
+  ASIO_DECL void init(const char* path, std::size_t path_length);
+};
+
+} // namespace detail
+} // namespace local
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/local/detail/impl/endpoint.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // defined(ASIO_HAS_LOCAL_SOCKETS)
+
+#endif // ASIO_LOCAL_DETAIL_ENDPOINT_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/local/detail/impl/endpoint.ipp b/link/modules/asio-standalone/asio/include/asio/local/detail/impl/endpoint.ipp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/local/detail/impl/endpoint.ipp
@@ -0,0 +1,136 @@
+//
+// local/detail/impl/endpoint.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Derived from a public domain implementation written by Daniel Casimiro.
+//
+// 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 ASIO_LOCAL_DETAIL_IMPL_ENDPOINT_IPP
+#define ASIO_LOCAL_DETAIL_IMPL_ENDPOINT_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_LOCAL_SOCKETS)
+
+#include <cstring>
+#include "asio/detail/socket_ops.hpp"
+#include "asio/detail/throw_error.hpp"
+#include "asio/error.hpp"
+#include "asio/local/detail/endpoint.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace local {
+namespace detail {
+
+endpoint::endpoint()
+{
+  init("", 0);
+}
+
+endpoint::endpoint(const char* path_name)
+{
+  using namespace std; // For strlen.
+  init(path_name, strlen(path_name));
+}
+
+endpoint::endpoint(const std::string& path_name)
+{
+  init(path_name.data(), path_name.length());
+}
+
+#if defined(ASIO_HAS_STRING_VIEW)
+endpoint::endpoint(string_view path_name)
+{
+  init(path_name.data(), path_name.length());
+}
+#endif // defined(ASIO_HAS_STRING_VIEW)
+
+void endpoint::resize(std::size_t new_size)
+{
+  if (new_size > sizeof(asio::detail::sockaddr_un_type))
+  {
+    asio::error_code ec(asio::error::invalid_argument);
+    asio::detail::throw_error(ec);
+  }
+  else if (new_size == 0)
+  {
+    path_length_ = 0;
+  }
+  else
+  {
+    path_length_ = new_size
+      - offsetof(asio::detail::sockaddr_un_type, sun_path);
+
+    // The path returned by the operating system may be NUL-terminated.
+    if (path_length_ > 0 && data_.local.sun_path[path_length_ - 1] == 0)
+      --path_length_;
+  }
+}
+
+std::string endpoint::path() const
+{
+  return std::string(data_.local.sun_path, path_length_);
+}
+
+void endpoint::path(const char* p)
+{
+  using namespace std; // For strlen.
+  init(p, strlen(p));
+}
+
+void endpoint::path(const std::string& p)
+{
+  init(p.data(), p.length());
+}
+
+bool operator==(const endpoint& e1, const endpoint& e2)
+{
+  return e1.path() == e2.path();
+}
+
+bool operator<(const endpoint& e1, const endpoint& e2)
+{
+  return e1.path() < e2.path();
+}
+
+void endpoint::init(const char* path_name, std::size_t path_length)
+{
+  if (path_length > sizeof(data_.local.sun_path) - 1)
+  {
+    // The buffer is not large enough to store this address.
+    asio::error_code ec(asio::error::name_too_long);
+    asio::detail::throw_error(ec);
+  }
+
+  using namespace std; // For memcpy.
+  data_.local = asio::detail::sockaddr_un_type();
+  data_.local.sun_family = AF_UNIX;
+  if (path_length > 0)
+    memcpy(data_.local.sun_path, path_name, path_length);
+  path_length_ = path_length;
+
+  // NUL-terminate normal path names. Names that start with a NUL are in the
+  // UNIX domain protocol's "abstract namespace" and are not NUL-terminated.
+  if (path_length > 0 && data_.local.sun_path[0] == 0)
+    data_.local.sun_path[path_length] = 0;
+}
+
+} // namespace detail
+} // namespace local
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_LOCAL_SOCKETS)
+
+#endif // ASIO_LOCAL_DETAIL_IMPL_ENDPOINT_IPP
diff --git a/link/modules/asio-standalone/asio/include/asio/local/stream_protocol.hpp b/link/modules/asio-standalone/asio/include/asio/local/stream_protocol.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/local/stream_protocol.hpp
@@ -0,0 +1,90 @@
+//
+// local/stream_protocol.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_LOCAL_STREAM_PROTOCOL_HPP
+#define ASIO_LOCAL_STREAM_PROTOCOL_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_LOCAL_SOCKETS) \
+  || defined(GENERATING_DOCUMENTATION)
+
+#include "asio/basic_socket_acceptor.hpp"
+#include "asio/basic_socket_iostream.hpp"
+#include "asio/basic_stream_socket.hpp"
+#include "asio/detail/socket_types.hpp"
+#include "asio/local/basic_endpoint.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace local {
+
+/// Encapsulates the flags needed for stream-oriented UNIX sockets.
+/**
+ * The asio::local::stream_protocol class contains flags necessary for
+ * stream-oriented UNIX domain sockets.
+ *
+ * @par Thread Safety
+ * @e Distinct @e objects: Safe.@n
+ * @e Shared @e objects: Safe.
+ *
+ * @par Concepts:
+ * Protocol.
+ */
+class stream_protocol
+{
+public:
+  /// Obtain an identifier for the type of the protocol.
+  int type() const ASIO_NOEXCEPT
+  {
+    return SOCK_STREAM;
+  }
+
+  /// Obtain an identifier for the protocol.
+  int protocol() const ASIO_NOEXCEPT
+  {
+    return 0;
+  }
+
+  /// Obtain an identifier for the protocol family.
+  int family() const ASIO_NOEXCEPT
+  {
+    return AF_UNIX;
+  }
+
+  /// The type of a UNIX domain endpoint.
+  typedef basic_endpoint<stream_protocol> endpoint;
+
+  /// The UNIX domain socket type.
+  typedef basic_stream_socket<stream_protocol> socket;
+
+  /// The UNIX domain acceptor type.
+  typedef basic_socket_acceptor<stream_protocol> acceptor;
+
+#if !defined(ASIO_NO_IOSTREAM)
+  /// The UNIX domain iostream type.
+  typedef basic_socket_iostream<stream_protocol> iostream;
+#endif // !defined(ASIO_NO_IOSTREAM)
+};
+
+} // namespace local
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_LOCAL_SOCKETS)
+       //   || defined(GENERATING_DOCUMENTATION)
+
+#endif // ASIO_LOCAL_STREAM_PROTOCOL_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/multiple_exceptions.hpp b/link/modules/asio-standalone/asio/include/asio/multiple_exceptions.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/multiple_exceptions.hpp
@@ -0,0 +1,58 @@
+//
+// multiple_exceptions.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_MULTIPLE_EXCEPTIONS_HPP
+#define ASIO_MULTIPLE_EXCEPTIONS_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <exception>
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+#if defined(ASIO_HAS_STD_EXCEPTION_PTR) \
+  || defined(GENERATING_DOCUMENTATION)
+
+/// Exception thrown when there are multiple pending exceptions to rethrow.
+class multiple_exceptions
+  : public std::exception
+{
+public:
+  /// Constructor.
+  ASIO_DECL multiple_exceptions(
+      std::exception_ptr first) ASIO_NOEXCEPT;
+
+  /// Obtain message associated with exception.
+  ASIO_DECL virtual const char* what() const
+    ASIO_NOEXCEPT_OR_NOTHROW;
+
+  /// Obtain a pointer to the first exception.
+  ASIO_DECL std::exception_ptr first_exception() const;
+
+private:
+  std::exception_ptr first_;
+};
+
+#endif // defined(ASIO_HAS_STD_EXCEPTION_PTR)
+       //   || defined(GENERATING_DOCUMENTATION)
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/impl/multiple_exceptions.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // ASIO_MULTIPLE_EXCEPTIONS_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/packaged_task.hpp b/link/modules/asio-standalone/asio/include/asio/packaged_task.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/packaged_task.hpp
@@ -0,0 +1,126 @@
+//
+// packaged_task.hpp
+// ~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_PACKAGED_TASK_HPP
+#define ASIO_PACKAGED_TASK_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/future.hpp"
+
+#if defined(ASIO_HAS_STD_FUTURE_CLASS) \
+  || defined(GENERATING_DOCUMENTATION)
+
+#include "asio/async_result.hpp"
+#include "asio/detail/type_traits.hpp"
+#include "asio/detail/variadic_templates.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+#if defined(ASIO_HAS_VARIADIC_TEMPLATES) \
+  || defined(GENERATING_DOCUMENTATION)
+
+/// Partial specialisation of @c async_result for @c std::packaged_task.
+template <typename Result, typename... Args, typename Signature>
+class async_result<std::packaged_task<Result(Args...)>, Signature>
+{
+public:
+  /// The packaged task is the concrete completion handler type.
+  typedef std::packaged_task<Result(Args...)> completion_handler_type;
+
+  /// The return type of the initiating function is the future obtained from
+  /// the packaged task.
+  typedef std::future<Result> return_type;
+
+  /// The constructor extracts the future from the packaged task.
+  explicit async_result(completion_handler_type& h)
+    : future_(h.get_future())
+  {
+  }
+
+  /// Returns the packaged task's future.
+  return_type get()
+  {
+    return std::move(future_);
+  }
+
+private:
+  return_type future_;
+};
+
+#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+      //   || defined(GENERATING_DOCUMENTATION)
+
+template <typename Result, typename Signature>
+struct async_result<std::packaged_task<Result()>, Signature>
+{
+  typedef std::packaged_task<Result()> completion_handler_type;
+  typedef std::future<Result> return_type;
+
+  explicit async_result(completion_handler_type& h)
+    : future_(h.get_future())
+  {
+  }
+
+  return_type get()
+  {
+    return std::move(future_);
+  }
+
+private:
+  return_type future_;
+};
+
+#define ASIO_PRIVATE_ASYNC_RESULT_DEF(n) \
+  template <typename Result, \
+    ASIO_VARIADIC_TPARAMS(n), typename Signature> \
+  class async_result< \
+    std::packaged_task<Result(ASIO_VARIADIC_TARGS(n))>, Signature> \
+  { \
+  public: \
+    typedef std::packaged_task< \
+      Result(ASIO_VARIADIC_TARGS(n))> \
+        completion_handler_type; \
+  \
+    typedef std::future<Result> return_type; \
+  \
+    explicit async_result(completion_handler_type& h) \
+      : future_(h.get_future()) \
+    { \
+    } \
+  \
+    return_type get() \
+    { \
+      return std::move(future_); \
+    } \
+  \
+  private: \
+    return_type future_; \
+  }; \
+  /**/
+  ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_ASYNC_RESULT_DEF)
+#undef ASIO_PRIVATE_ASYNC_RESULT_DEF
+
+#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+       //   || defined(GENERATING_DOCUMENTATION)
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_STD_FUTURE_CLASS)
+       //   || defined(GENERATING_DOCUMENTATION)
+
+#endif // ASIO_PACKAGED_TASK_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/placeholders.hpp b/link/modules/asio-standalone/asio/include/asio/placeholders.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/placeholders.hpp
@@ -0,0 +1,151 @@
+//
+// placeholders.hpp
+// ~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_PLACEHOLDERS_HPP
+#define ASIO_PLACEHOLDERS_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_BOOST_BIND)
+# include <boost/bind/arg.hpp>
+#endif // defined(ASIO_HAS_BOOST_BIND)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace placeholders {
+
+#if defined(GENERATING_DOCUMENTATION)
+
+/// An argument placeholder, for use with boost::bind(), that corresponds to
+/// the error argument of a handler for any of the asynchronous functions.
+unspecified error;
+
+/// An argument placeholder, for use with boost::bind(), that corresponds to
+/// the bytes_transferred argument of a handler for asynchronous functions such
+/// as asio::basic_stream_socket::async_write_some or
+/// asio::async_write.
+unspecified bytes_transferred;
+
+/// An argument placeholder, for use with boost::bind(), that corresponds to
+/// the iterator argument of a handler for asynchronous functions such as
+/// asio::async_connect.
+unspecified iterator;
+
+/// An argument placeholder, for use with boost::bind(), that corresponds to
+/// the results argument of a handler for asynchronous functions such as
+/// asio::basic_resolver::async_resolve.
+unspecified results;
+
+/// An argument placeholder, for use with boost::bind(), that corresponds to
+/// the results argument of a handler for asynchronous functions such as
+/// asio::async_connect.
+unspecified endpoint;
+
+/// An argument placeholder, for use with boost::bind(), that corresponds to
+/// the signal_number argument of a handler for asynchronous functions such as
+/// asio::signal_set::async_wait.
+unspecified signal_number;
+
+#elif defined(ASIO_HAS_BOOST_BIND)
+# if defined(__BORLANDC__) || defined(__GNUC__)
+
+inline boost::arg<1> error()
+{
+  return boost::arg<1>();
+}
+
+inline boost::arg<2> bytes_transferred()
+{
+  return boost::arg<2>();
+}
+
+inline boost::arg<2> iterator()
+{
+  return boost::arg<2>();
+}
+
+inline boost::arg<2> results()
+{
+  return boost::arg<2>();
+}
+
+inline boost::arg<2> endpoint()
+{
+  return boost::arg<2>();
+}
+
+inline boost::arg<2> signal_number()
+{
+  return boost::arg<2>();
+}
+
+# else
+
+namespace detail
+{
+  template <int Number>
+  struct placeholder
+  {
+    static boost::arg<Number>& get()
+    {
+      static boost::arg<Number> result;
+      return result;
+    }
+  };
+}
+
+#  if defined(ASIO_MSVC) && (ASIO_MSVC < 1400)
+
+static boost::arg<1>& error
+  = asio::placeholders::detail::placeholder<1>::get();
+static boost::arg<2>& bytes_transferred
+  = asio::placeholders::detail::placeholder<2>::get();
+static boost::arg<2>& iterator
+  = asio::placeholders::detail::placeholder<2>::get();
+static boost::arg<2>& results
+  = asio::placeholders::detail::placeholder<2>::get();
+static boost::arg<2>& endpoint
+  = asio::placeholders::detail::placeholder<2>::get();
+static boost::arg<2>& signal_number
+  = asio::placeholders::detail::placeholder<2>::get();
+
+#  else
+
+namespace
+{
+  boost::arg<1>& error
+    = asio::placeholders::detail::placeholder<1>::get();
+  boost::arg<2>& bytes_transferred
+    = asio::placeholders::detail::placeholder<2>::get();
+  boost::arg<2>& iterator
+    = asio::placeholders::detail::placeholder<2>::get();
+  boost::arg<2>& results
+    = asio::placeholders::detail::placeholder<2>::get();
+  boost::arg<2>& endpoint
+    = asio::placeholders::detail::placeholder<2>::get();
+  boost::arg<2>& signal_number
+    = asio::placeholders::detail::placeholder<2>::get();
+} // namespace
+
+#  endif
+# endif
+#endif
+
+} // namespace placeholders
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_PLACEHOLDERS_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/posix/basic_descriptor.hpp b/link/modules/asio-standalone/asio/include/asio/posix/basic_descriptor.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/posix/basic_descriptor.hpp
@@ -0,0 +1,697 @@
+//
+// posix/basic_descriptor.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_POSIX_BASIC_DESCRIPTOR_HPP
+#define ASIO_POSIX_BASIC_DESCRIPTOR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_POSIX_STREAM_DESCRIPTOR) \
+  || defined(GENERATING_DOCUMENTATION)
+
+#include "asio/any_io_executor.hpp"
+#include "asio/async_result.hpp"
+#include "asio/detail/handler_type_requirements.hpp"
+#include "asio/detail/io_object_impl.hpp"
+#include "asio/detail/non_const_lvalue.hpp"
+#include "asio/detail/reactive_descriptor_service.hpp"
+#include "asio/detail/throw_error.hpp"
+#include "asio/error.hpp"
+#include "asio/execution_context.hpp"
+#include "asio/posix/descriptor_base.hpp"
+
+#if defined(ASIO_HAS_MOVE)
+# include <utility>
+#endif // defined(ASIO_HAS_MOVE)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace posix {
+
+/// Provides POSIX descriptor functionality.
+/**
+ * The posix::basic_descriptor class template provides the ability to wrap a
+ * POSIX descriptor.
+ *
+ * @par Thread Safety
+ * @e Distinct @e objects: Safe.@n
+ * @e Shared @e objects: Unsafe.
+ */
+template <typename Executor = any_io_executor>
+class basic_descriptor
+  : public descriptor_base
+{
+public:
+  /// The type of the executor associated with the object.
+  typedef Executor executor_type;
+
+  /// Rebinds the descriptor type to another executor.
+  template <typename Executor1>
+  struct rebind_executor
+  {
+    /// The descriptor type when rebound to the specified executor.
+    typedef basic_descriptor<Executor1> other;
+  };
+
+  /// The native representation of a descriptor.
+#if defined(GENERATING_DOCUMENTATION)
+  typedef implementation_defined native_handle_type;
+#else
+  typedef detail::reactive_descriptor_service::native_handle_type
+    native_handle_type;
+#endif
+
+  /// A descriptor is always the lowest layer.
+  typedef basic_descriptor lowest_layer_type;
+
+  /// Construct a descriptor without opening it.
+  /**
+   * This constructor creates a descriptor without opening it.
+   *
+   * @param ex The I/O executor that the descriptor will use, by default, to
+   * dispatch handlers for any asynchronous operations performed on the
+   * descriptor.
+   */
+  explicit basic_descriptor(const executor_type& ex)
+    : impl_(ex)
+  {
+  }
+
+  /// Construct a descriptor without opening it.
+  /**
+   * This constructor creates a descriptor without opening it.
+   *
+   * @param context An execution context which provides the I/O executor that
+   * the descriptor will use, by default, to dispatch handlers for any
+   * asynchronous operations performed on the descriptor.
+   */
+  template <typename ExecutionContext>
+  explicit basic_descriptor(ExecutionContext& context,
+      typename enable_if<
+        is_convertible<ExecutionContext&, execution_context&>::value
+      >::type* = 0)
+    : impl_(context)
+  {
+  }
+
+  /// Construct a descriptor on an existing native descriptor.
+  /**
+   * This constructor creates a descriptor object to hold an existing native
+   * descriptor.
+   *
+   * @param ex The I/O executor that the descriptor will use, by default, to
+   * dispatch handlers for any asynchronous operations performed on the
+   * descriptor.
+   *
+   * @param native_descriptor A native descriptor.
+   *
+   * @throws asio::system_error Thrown on failure.
+   */
+  basic_descriptor(const executor_type& ex,
+      const native_handle_type& native_descriptor)
+    : impl_(ex)
+  {
+    asio::error_code ec;
+    impl_.get_service().assign(impl_.get_implementation(),
+        native_descriptor, ec);
+    asio::detail::throw_error(ec, "assign");
+  }
+
+  /// Construct a descriptor on an existing native descriptor.
+  /**
+   * This constructor creates a descriptor object to hold an existing native
+   * descriptor.
+   *
+   * @param context An execution context which provides the I/O executor that
+   * the descriptor will use, by default, to dispatch handlers for any
+   * asynchronous operations performed on the descriptor.
+   *
+   * @param native_descriptor A native descriptor.
+   *
+   * @throws asio::system_error Thrown on failure.
+   */
+  template <typename ExecutionContext>
+  basic_descriptor(ExecutionContext& context,
+      const native_handle_type& native_descriptor,
+      typename enable_if<
+        is_convertible<ExecutionContext&, execution_context&>::value
+      >::type* = 0)
+    : impl_(context)
+  {
+    asio::error_code ec;
+    impl_.get_service().assign(impl_.get_implementation(),
+        native_descriptor, ec);
+    asio::detail::throw_error(ec, "assign");
+  }
+
+#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+  /// Move-construct a descriptor from another.
+  /**
+   * This constructor moves a descriptor from one object to another.
+   *
+   * @param other The other descriptor object from which the move will
+   * occur.
+   *
+   * @note Following the move, the moved-from object is in the same state as if
+   * constructed using the @c basic_descriptor(const executor_type&)
+   * constructor.
+   */
+  basic_descriptor(basic_descriptor&& other) ASIO_NOEXCEPT
+    : impl_(std::move(other.impl_))
+  {
+  }
+
+  /// Move-assign a descriptor from another.
+  /**
+   * This assignment operator moves a descriptor from one object to another.
+   *
+   * @param other The other descriptor object from which the move will
+   * occur.
+   *
+   * @note Following the move, the moved-from object is in the same state as if
+   * constructed using the @c basic_descriptor(const executor_type&)
+   * constructor.
+   */
+  basic_descriptor& operator=(basic_descriptor&& other)
+  {
+    impl_ = std::move(other.impl_);
+    return *this;
+  }
+#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+
+  /// Get the executor associated with the object.
+  executor_type get_executor() ASIO_NOEXCEPT
+  {
+    return impl_.get_executor();
+  }
+
+  /// Get a reference to the lowest layer.
+  /**
+   * This function returns a reference to the lowest layer in a stack of
+   * layers. Since a descriptor cannot contain any further layers, it
+   * simply returns a reference to itself.
+   *
+   * @return A reference to the lowest layer in the stack of layers. Ownership
+   * is not transferred to the caller.
+   */
+  lowest_layer_type& lowest_layer()
+  {
+    return *this;
+  }
+
+  /// Get a const reference to the lowest layer.
+  /**
+   * This function returns a const reference to the lowest layer in a stack of
+   * layers. Since a descriptor cannot contain any further layers, it
+   * simply returns a reference to itself.
+   *
+   * @return A const reference to the lowest layer in the stack of layers.
+   * Ownership is not transferred to the caller.
+   */
+  const lowest_layer_type& lowest_layer() const
+  {
+    return *this;
+  }
+
+  /// Assign an existing native descriptor to the descriptor.
+  /*
+   * This function opens the descriptor to hold an existing native descriptor.
+   *
+   * @param native_descriptor A native descriptor.
+   *
+   * @throws asio::system_error Thrown on failure.
+   */
+  void assign(const native_handle_type& native_descriptor)
+  {
+    asio::error_code ec;
+    impl_.get_service().assign(impl_.get_implementation(),
+        native_descriptor, ec);
+    asio::detail::throw_error(ec, "assign");
+  }
+
+  /// Assign an existing native descriptor to the descriptor.
+  /*
+   * This function opens the descriptor to hold an existing native descriptor.
+   *
+   * @param native_descriptor A native descriptor.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   */
+  ASIO_SYNC_OP_VOID assign(const native_handle_type& native_descriptor,
+      asio::error_code& ec)
+  {
+    impl_.get_service().assign(
+        impl_.get_implementation(), native_descriptor, ec);
+    ASIO_SYNC_OP_VOID_RETURN(ec);
+  }
+
+  /// Determine whether the descriptor is open.
+  bool is_open() const
+  {
+    return impl_.get_service().is_open(impl_.get_implementation());
+  }
+
+  /// Close the descriptor.
+  /**
+   * This function is used to close the descriptor. Any asynchronous read or
+   * write operations will be cancelled immediately, and will complete with the
+   * asio::error::operation_aborted error.
+   *
+   * @throws asio::system_error Thrown on failure. Note that, even if
+   * the function indicates an error, the underlying descriptor is closed.
+   */
+  void close()
+  {
+    asio::error_code ec;
+    impl_.get_service().close(impl_.get_implementation(), ec);
+    asio::detail::throw_error(ec, "close");
+  }
+
+  /// Close the descriptor.
+  /**
+   * This function is used to close the descriptor. Any asynchronous read or
+   * write operations will be cancelled immediately, and will complete with the
+   * asio::error::operation_aborted error.
+   *
+   * @param ec Set to indicate what error occurred, if any. Note that, even if
+   * the function indicates an error, the underlying descriptor is closed.
+   */
+  ASIO_SYNC_OP_VOID close(asio::error_code& ec)
+  {
+    impl_.get_service().close(impl_.get_implementation(), ec);
+    ASIO_SYNC_OP_VOID_RETURN(ec);
+  }
+
+  /// Get the native descriptor representation.
+  /**
+   * This function may be used to obtain the underlying representation of the
+   * descriptor. This is intended to allow access to native descriptor
+   * functionality that is not otherwise provided.
+   */
+  native_handle_type native_handle()
+  {
+    return impl_.get_service().native_handle(impl_.get_implementation());
+  }
+
+  /// Release ownership of the native descriptor implementation.
+  /**
+   * This function may be used to obtain the underlying representation of the
+   * descriptor. After calling this function, @c is_open() returns false. The
+   * caller is responsible for closing the descriptor.
+   *
+   * All outstanding asynchronous read or write operations will finish
+   * immediately, and the handlers for cancelled operations will be passed the
+   * asio::error::operation_aborted error.
+   */
+  native_handle_type release()
+  {
+    return impl_.get_service().release(impl_.get_implementation());
+  }
+
+  /// Cancel all asynchronous operations associated with the descriptor.
+  /**
+   * This function causes all outstanding asynchronous read or write operations
+   * to finish immediately, and the handlers for cancelled operations will be
+   * passed the asio::error::operation_aborted error.
+   *
+   * @throws asio::system_error Thrown on failure.
+   */
+  void cancel()
+  {
+    asio::error_code ec;
+    impl_.get_service().cancel(impl_.get_implementation(), ec);
+    asio::detail::throw_error(ec, "cancel");
+  }
+
+  /// Cancel all asynchronous operations associated with the descriptor.
+  /**
+   * This function causes all outstanding asynchronous read or write operations
+   * to finish immediately, and the handlers for cancelled operations will be
+   * passed the asio::error::operation_aborted error.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   */
+  ASIO_SYNC_OP_VOID cancel(asio::error_code& ec)
+  {
+    impl_.get_service().cancel(impl_.get_implementation(), ec);
+    ASIO_SYNC_OP_VOID_RETURN(ec);
+  }
+
+  /// Perform an IO control command on the descriptor.
+  /**
+   * This function is used to execute an IO control command on the descriptor.
+   *
+   * @param command The IO control command to be performed on the descriptor.
+   *
+   * @throws asio::system_error Thrown on failure.
+   *
+   * @sa IoControlCommand @n
+   * asio::posix::descriptor_base::bytes_readable @n
+   * asio::posix::descriptor_base::non_blocking_io
+   *
+   * @par Example
+   * Getting the number of bytes ready to read:
+   * @code
+   * asio::posix::stream_descriptor descriptor(my_context);
+   * ...
+   * asio::posix::stream_descriptor::bytes_readable command;
+   * descriptor.io_control(command);
+   * std::size_t bytes_readable = command.get();
+   * @endcode
+   */
+  template <typename IoControlCommand>
+  void io_control(IoControlCommand& command)
+  {
+    asio::error_code ec;
+    impl_.get_service().io_control(impl_.get_implementation(), command, ec);
+    asio::detail::throw_error(ec, "io_control");
+  }
+
+  /// Perform an IO control command on the descriptor.
+  /**
+   * This function is used to execute an IO control command on the descriptor.
+   *
+   * @param command The IO control command to be performed on the descriptor.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   *
+   * @sa IoControlCommand @n
+   * asio::posix::descriptor_base::bytes_readable @n
+   * asio::posix::descriptor_base::non_blocking_io
+   *
+   * @par Example
+   * Getting the number of bytes ready to read:
+   * @code
+   * asio::posix::stream_descriptor descriptor(my_context);
+   * ...
+   * asio::posix::stream_descriptor::bytes_readable command;
+   * asio::error_code ec;
+   * descriptor.io_control(command, ec);
+   * if (ec)
+   * {
+   *   // An error occurred.
+   * }
+   * std::size_t bytes_readable = command.get();
+   * @endcode
+   */
+  template <typename IoControlCommand>
+  ASIO_SYNC_OP_VOID io_control(IoControlCommand& command,
+      asio::error_code& ec)
+  {
+    impl_.get_service().io_control(impl_.get_implementation(), command, ec);
+    ASIO_SYNC_OP_VOID_RETURN(ec);
+  }
+
+  /// Gets the non-blocking mode of the descriptor.
+  /**
+   * @returns @c true if the descriptor's synchronous operations will fail with
+   * asio::error::would_block if they are unable to perform the requested
+   * operation immediately. If @c false, synchronous operations will block
+   * until complete.
+   *
+   * @note The non-blocking mode has no effect on the behaviour of asynchronous
+   * operations. Asynchronous operations will never fail with the error
+   * asio::error::would_block.
+   */
+  bool non_blocking() const
+  {
+    return impl_.get_service().non_blocking(impl_.get_implementation());
+  }
+
+  /// Sets the non-blocking mode of the descriptor.
+  /**
+   * @param mode If @c true, the descriptor's synchronous operations will fail
+   * with asio::error::would_block if they are unable to perform the
+   * requested operation immediately. If @c false, synchronous operations will
+   * block until complete.
+   *
+   * @throws asio::system_error Thrown on failure.
+   *
+   * @note The non-blocking mode has no effect on the behaviour of asynchronous
+   * operations. Asynchronous operations will never fail with the error
+   * asio::error::would_block.
+   */
+  void non_blocking(bool mode)
+  {
+    asio::error_code ec;
+    impl_.get_service().non_blocking(impl_.get_implementation(), mode, ec);
+    asio::detail::throw_error(ec, "non_blocking");
+  }
+
+  /// Sets the non-blocking mode of the descriptor.
+  /**
+   * @param mode If @c true, the descriptor's synchronous operations will fail
+   * with asio::error::would_block if they are unable to perform the
+   * requested operation immediately. If @c false, synchronous operations will
+   * block until complete.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   *
+   * @note The non-blocking mode has no effect on the behaviour of asynchronous
+   * operations. Asynchronous operations will never fail with the error
+   * asio::error::would_block.
+   */
+  ASIO_SYNC_OP_VOID non_blocking(
+      bool mode, asio::error_code& ec)
+  {
+    impl_.get_service().non_blocking(impl_.get_implementation(), mode, ec);
+    ASIO_SYNC_OP_VOID_RETURN(ec);
+  }
+
+  /// Gets the non-blocking mode of the native descriptor implementation.
+  /**
+   * This function is used to retrieve the non-blocking mode of the underlying
+   * native descriptor. This mode has no effect on the behaviour of the
+   * descriptor object's synchronous operations.
+   *
+   * @returns @c true if the underlying descriptor is in non-blocking mode and
+   * direct system calls may fail with asio::error::would_block (or the
+   * equivalent system error).
+   *
+   * @note The current non-blocking mode is cached by the descriptor object.
+   * Consequently, the return value may be incorrect if the non-blocking mode
+   * was set directly on the native descriptor.
+   */
+  bool native_non_blocking() const
+  {
+    return impl_.get_service().native_non_blocking(
+        impl_.get_implementation());
+  }
+
+  /// Sets the non-blocking mode of the native descriptor implementation.
+  /**
+   * This function is used to modify the non-blocking mode of the underlying
+   * native descriptor. It has no effect on the behaviour of the descriptor
+   * object's synchronous operations.
+   *
+   * @param mode If @c true, the underlying descriptor is put into non-blocking
+   * mode and direct system calls may fail with asio::error::would_block
+   * (or the equivalent system error).
+   *
+   * @throws asio::system_error Thrown on failure. If the @c mode is
+   * @c false, but the current value of @c non_blocking() is @c true, this
+   * function fails with asio::error::invalid_argument, as the
+   * combination does not make sense.
+   */
+  void native_non_blocking(bool mode)
+  {
+    asio::error_code ec;
+    impl_.get_service().native_non_blocking(
+        impl_.get_implementation(), mode, ec);
+    asio::detail::throw_error(ec, "native_non_blocking");
+  }
+
+  /// Sets the non-blocking mode of the native descriptor implementation.
+  /**
+   * This function is used to modify the non-blocking mode of the underlying
+   * native descriptor. It has no effect on the behaviour of the descriptor
+   * object's synchronous operations.
+   *
+   * @param mode If @c true, the underlying descriptor is put into non-blocking
+   * mode and direct system calls may fail with asio::error::would_block
+   * (or the equivalent system error).
+   *
+   * @param ec Set to indicate what error occurred, if any. If the @c mode is
+   * @c false, but the current value of @c non_blocking() is @c true, this
+   * function fails with asio::error::invalid_argument, as the
+   * combination does not make sense.
+   */
+  ASIO_SYNC_OP_VOID native_non_blocking(
+      bool mode, asio::error_code& ec)
+  {
+    impl_.get_service().native_non_blocking(
+        impl_.get_implementation(), mode, ec);
+    ASIO_SYNC_OP_VOID_RETURN(ec);
+  }
+
+  /// Wait for the descriptor to become ready to read, ready to write, or to
+  /// have pending error conditions.
+  /**
+   * This function is used to perform a blocking wait for a descriptor to enter
+   * a ready to read, write or error condition state.
+   *
+   * @param w Specifies the desired descriptor state.
+   *
+   * @par Example
+   * Waiting for a descriptor to become readable.
+   * @code
+   * asio::posix::stream_descriptor descriptor(my_context);
+   * ...
+   * descriptor.wait(asio::posix::stream_descriptor::wait_read);
+   * @endcode
+   */
+  void wait(wait_type w)
+  {
+    asio::error_code ec;
+    impl_.get_service().wait(impl_.get_implementation(), w, ec);
+    asio::detail::throw_error(ec, "wait");
+  }
+
+  /// Wait for the descriptor to become ready to read, ready to write, or to
+  /// have pending error conditions.
+  /**
+   * This function is used to perform a blocking wait for a descriptor to enter
+   * a ready to read, write or error condition state.
+   *
+   * @param w Specifies the desired descriptor state.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   *
+   * @par Example
+   * Waiting for a descriptor to become readable.
+   * @code
+   * asio::posix::stream_descriptor descriptor(my_context);
+   * ...
+   * asio::error_code ec;
+   * descriptor.wait(asio::posix::stream_descriptor::wait_read, ec);
+   * @endcode
+   */
+  ASIO_SYNC_OP_VOID wait(wait_type w, asio::error_code& ec)
+  {
+    impl_.get_service().wait(impl_.get_implementation(), w, ec);
+    ASIO_SYNC_OP_VOID_RETURN(ec);
+  }
+
+  /// Asynchronously wait for the descriptor to become ready to read, ready to
+  /// write, or to have pending error conditions.
+  /**
+   * This function is used to perform an asynchronous wait for a descriptor to
+   * enter a ready to read, write or error condition state.
+   *
+   * @param w Specifies the desired descriptor state.
+   *
+   * @param handler The handler to be called when the wait operation completes.
+   * Copies will be made of the handler as required. The function signature of
+   * the handler must be:
+   * @code void handler(
+   *   const asio::error_code& error // Result of operation
+   * ); @endcode
+   * Regardless of whether the asynchronous operation completes immediately or
+   * not, the handler will not be invoked from within this function. On
+   * immediate completion, invocation of the handler will be performed in a
+   * manner equivalent to using asio::post().
+   *
+   * @par Example
+   * @code
+   * void wait_handler(const asio::error_code& error)
+   * {
+   *   if (!error)
+   *   {
+   *     // Wait succeeded.
+   *   }
+   * }
+   *
+   * ...
+   *
+   * asio::posix::stream_descriptor descriptor(my_context);
+   * ...
+   * descriptor.async_wait(
+   *     asio::posix::stream_descriptor::wait_read,
+   *     wait_handler);
+   * @endcode
+   */
+  template <
+      ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code))
+        WaitHandler ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
+  ASIO_INITFN_AUTO_RESULT_TYPE(WaitHandler,
+      void (asio::error_code))
+  async_wait(wait_type w,
+      ASIO_MOVE_ARG(WaitHandler) handler
+        ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
+  {
+    return async_initiate<WaitHandler, void (asio::error_code)>(
+        initiate_async_wait(this), handler, w);
+  }
+
+protected:
+  /// Protected destructor to prevent deletion through this type.
+  /**
+   * This function destroys the descriptor, cancelling any outstanding
+   * asynchronous wait operations associated with the descriptor as if by
+   * calling @c cancel.
+   */
+  ~basic_descriptor()
+  {
+  }
+
+  detail::io_object_impl<detail::reactive_descriptor_service, Executor> impl_;
+
+private:
+  // Disallow copying and assignment.
+  basic_descriptor(const basic_descriptor&) ASIO_DELETED;
+  basic_descriptor& operator=(const basic_descriptor&) ASIO_DELETED;
+
+  class initiate_async_wait
+  {
+  public:
+    typedef Executor executor_type;
+
+    explicit initiate_async_wait(basic_descriptor* self)
+      : self_(self)
+    {
+    }
+
+    executor_type get_executor() const ASIO_NOEXCEPT
+    {
+      return self_->get_executor();
+    }
+
+    template <typename WaitHandler>
+    void operator()(ASIO_MOVE_ARG(WaitHandler) handler, wait_type w) const
+    {
+      // If you get an error on the following line it means that your handler
+      // does not meet the documented type requirements for a WaitHandler.
+      ASIO_WAIT_HANDLER_CHECK(WaitHandler, handler) type_check;
+
+      detail::non_const_lvalue<WaitHandler> handler2(handler);
+      self_->impl_.get_service().async_wait(
+          self_->impl_.get_implementation(), w,
+          handler2.value, self_->impl_.get_executor());
+    }
+
+  private:
+    basic_descriptor* self_;
+  };
+};
+
+} // namespace posix
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_POSIX_STREAM_DESCRIPTOR)
+       //   || defined(GENERATING_DOCUMENTATION)
+
+#endif // ASIO_POSIX_BASIC_DESCRIPTOR_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/posix/basic_stream_descriptor.hpp b/link/modules/asio-standalone/asio/include/asio/posix/basic_stream_descriptor.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/posix/basic_stream_descriptor.hpp
@@ -0,0 +1,470 @@
+//
+// posix/basic_stream_descriptor.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_POSIX_BASIC_STREAM_DESCRIPTOR_HPP
+#define ASIO_POSIX_BASIC_STREAM_DESCRIPTOR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/posix/descriptor.hpp"
+
+#if defined(ASIO_HAS_POSIX_STREAM_DESCRIPTOR) \
+  || defined(GENERATING_DOCUMENTATION)
+
+namespace asio {
+namespace posix {
+
+/// Provides stream-oriented descriptor functionality.
+/**
+ * The posix::basic_stream_descriptor class template provides asynchronous and
+ * blocking stream-oriented descriptor functionality.
+ *
+ * @par Thread Safety
+ * @e Distinct @e objects: Safe.@n
+ * @e Shared @e objects: Unsafe.
+ *
+ * @par Concepts:
+ * AsyncReadStream, AsyncWriteStream, Stream, SyncReadStream, SyncWriteStream.
+ */
+template <typename Executor = any_io_executor>
+class basic_stream_descriptor
+  : public basic_descriptor<Executor>
+{
+public:
+  /// The type of the executor associated with the object.
+  typedef Executor executor_type;
+
+  /// Rebinds the descriptor type to another executor.
+  template <typename Executor1>
+  struct rebind_executor
+  {
+    /// The descriptor type when rebound to the specified executor.
+    typedef basic_stream_descriptor<Executor1> other;
+  };
+
+  /// The native representation of a descriptor.
+  typedef typename basic_descriptor<Executor>::native_handle_type
+    native_handle_type;
+
+  /// Construct a stream descriptor without opening it.
+  /**
+   * This constructor creates a stream descriptor without opening it. The
+   * descriptor needs to be opened and then connected or accepted before data
+   * can be sent or received on it.
+   *
+   * @param ex The I/O executor that the descriptor will use, by default, to
+   * dispatch handlers for any asynchronous operations performed on the
+   * descriptor.
+   */
+  explicit basic_stream_descriptor(const executor_type& ex)
+    : basic_descriptor<Executor>(ex)
+  {
+  }
+
+  /// Construct a stream descriptor without opening it.
+  /**
+   * This constructor creates a stream descriptor without opening it. The
+   * descriptor needs to be opened and then connected or accepted before data
+   * can be sent or received on it.
+   *
+   * @param context An execution context which provides the I/O executor that
+   * the descriptor will use, by default, to dispatch handlers for any
+   * asynchronous operations performed on the descriptor.
+   */
+  template <typename ExecutionContext>
+  explicit basic_stream_descriptor(ExecutionContext& context,
+      typename enable_if<
+        is_convertible<ExecutionContext&, execution_context&>::value
+      >::type* = 0)
+    : basic_descriptor<Executor>(context)
+  {
+  }
+
+  /// Construct a stream descriptor on an existing native descriptor.
+  /**
+   * This constructor creates a stream descriptor object to hold an existing
+   * native descriptor.
+   *
+   * @param ex The I/O executor that the descriptor will use, by default, to
+   * dispatch handlers for any asynchronous operations performed on the
+   * descriptor.
+   *
+   * @param native_descriptor The new underlying descriptor implementation.
+   *
+   * @throws asio::system_error Thrown on failure.
+   */
+  basic_stream_descriptor(const executor_type& ex,
+      const native_handle_type& native_descriptor)
+    : basic_descriptor<Executor>(ex, native_descriptor)
+  {
+  }
+
+  /// Construct a stream descriptor on an existing native descriptor.
+  /**
+   * This constructor creates a stream descriptor object to hold an existing
+   * native descriptor.
+   *
+   * @param context An execution context which provides the I/O executor that
+   * the descriptor will use, by default, to dispatch handlers for any
+   * asynchronous operations performed on the descriptor.
+   *
+   * @param native_descriptor The new underlying descriptor implementation.
+   *
+   * @throws asio::system_error Thrown on failure.
+   */
+  template <typename ExecutionContext>
+  basic_stream_descriptor(ExecutionContext& context,
+      const native_handle_type& native_descriptor,
+      typename enable_if<
+        is_convertible<ExecutionContext&, execution_context&>::value
+      >::type* = 0)
+    : basic_descriptor<Executor>(context, native_descriptor)
+  {
+  }
+
+#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+  /// Move-construct a stream descriptor from another.
+  /**
+   * This constructor moves a stream descriptor from one object to another.
+   *
+   * @param other The other stream descriptor object from which the move
+   * will occur.
+   *
+   * @note Following the move, the moved-from object is in the same state as if
+   * constructed using the @c basic_stream_descriptor(const executor_type&)
+   * constructor.
+   */
+  basic_stream_descriptor(basic_stream_descriptor&& other) ASIO_NOEXCEPT
+    : descriptor(std::move(other))
+  {
+  }
+
+  /// Move-assign a stream descriptor from another.
+  /**
+   * This assignment operator moves a stream descriptor from one object to
+   * another.
+   *
+   * @param other The other stream descriptor object from which the move
+   * will occur.
+   *
+   * @note Following the move, the moved-from object is in the same state as if
+   * constructed using the @c basic_stream_descriptor(const executor_type&)
+   * constructor.
+   */
+  basic_stream_descriptor& operator=(basic_stream_descriptor&& other)
+  {
+    descriptor::operator=(std::move(other));
+    return *this;
+  }
+#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+
+  /// Write some data to the descriptor.
+  /**
+   * This function is used to write data to the stream descriptor. The function
+   * call will block until one or more bytes of the data has been written
+   * successfully, or until an error occurs.
+   *
+   * @param buffers One or more data buffers to be written to the descriptor.
+   *
+   * @returns The number of bytes written.
+   *
+   * @throws asio::system_error Thrown on failure. An error code of
+   * asio::error::eof indicates that the connection was closed by the
+   * peer.
+   *
+   * @note The write_some operation may not transmit all of the data to the
+   * peer. Consider using the @ref write function if you need to ensure that
+   * all data is written before the blocking operation completes.
+   *
+   * @par Example
+   * To write a single data buffer use the @ref buffer function as follows:
+   * @code
+   * descriptor.write_some(asio::buffer(data, size));
+   * @endcode
+   * See the @ref buffer documentation for information on writing multiple
+   * buffers in one go, and how to use it with arrays, boost::array or
+   * std::vector.
+   */
+  template <typename ConstBufferSequence>
+  std::size_t write_some(const ConstBufferSequence& buffers)
+  {
+    asio::error_code ec;
+    std::size_t s = this->impl_.get_service().write_some(
+        this->impl_.get_implementation(), buffers, ec);
+    asio::detail::throw_error(ec, "write_some");
+    return s;
+  }
+
+  /// Write some data to the descriptor.
+  /**
+   * This function is used to write data to the stream descriptor. The function
+   * call will block until one or more bytes of the data has been written
+   * successfully, or until an error occurs.
+   *
+   * @param buffers One or more data buffers to be written to the descriptor.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   *
+   * @returns The number of bytes written. Returns 0 if an error occurred.
+   *
+   * @note The write_some operation may not transmit all of the data to the
+   * peer. Consider using the @ref write function if you need to ensure that
+   * all data is written before the blocking operation completes.
+   */
+  template <typename ConstBufferSequence>
+  std::size_t write_some(const ConstBufferSequence& buffers,
+      asio::error_code& ec)
+  {
+    return this->impl_.get_service().write_some(
+        this->impl_.get_implementation(), buffers, ec);
+  }
+
+  /// Start an asynchronous write.
+  /**
+   * This function is used to asynchronously write data to the stream
+   * descriptor. The function call always returns immediately.
+   *
+   * @param buffers One or more data buffers to be written to the descriptor.
+   * Although the buffers object may be copied as necessary, ownership of the
+   * underlying memory blocks is retained by the caller, which must guarantee
+   * that they remain valid until the handler is called.
+   *
+   * @param handler The handler to be called when the write operation completes.
+   * Copies will be made of the handler as required. The function signature of
+   * the handler must be:
+   * @code void handler(
+   *   const asio::error_code& error, // Result of operation.
+   *   std::size_t bytes_transferred           // Number of bytes written.
+   * ); @endcode
+   * Regardless of whether the asynchronous operation completes immediately or
+   * not, the handler will not be invoked from within this function. On
+   * immediate completion, invocation of the handler will be performed in a
+   * manner equivalent to using asio::post().
+   *
+   * @note The write operation may not transmit all of the data to the peer.
+   * Consider using the @ref async_write function if you need to ensure that all
+   * data is written before the asynchronous operation completes.
+   *
+   * @par Example
+   * To write a single data buffer use the @ref buffer function as follows:
+   * @code
+   * descriptor.async_write_some(asio::buffer(data, size), handler);
+   * @endcode
+   * See the @ref buffer documentation for information on writing multiple
+   * buffers in one go, and how to use it with arrays, boost::array or
+   * std::vector.
+   */
+  template <typename ConstBufferSequence,
+      ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+        std::size_t)) WriteHandler
+          ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
+  ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,
+      void (asio::error_code, std::size_t))
+  async_write_some(const ConstBufferSequence& buffers,
+      ASIO_MOVE_ARG(WriteHandler) handler
+        ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
+  {
+    return async_initiate<WriteHandler,
+      void (asio::error_code, std::size_t)>(
+        initiate_async_write_some(this), handler, buffers);
+  }
+
+  /// Read some data from the descriptor.
+  /**
+   * This function is used to read data from the stream descriptor. The function
+   * call will block until one or more bytes of data has been read successfully,
+   * or until an error occurs.
+   *
+   * @param buffers One or more buffers into which the data will be read.
+   *
+   * @returns The number of bytes read.
+   *
+   * @throws asio::system_error Thrown on failure. An error code of
+   * asio::error::eof indicates that the connection was closed by the
+   * peer.
+   *
+   * @note The read_some operation may not read all of the requested number of
+   * bytes. Consider using the @ref read function if you need to ensure that
+   * the requested amount of data is read before the blocking operation
+   * completes.
+   *
+   * @par Example
+   * To read into a single data buffer use the @ref buffer function as follows:
+   * @code
+   * descriptor.read_some(asio::buffer(data, size));
+   * @endcode
+   * See the @ref buffer documentation for information on reading into multiple
+   * buffers in one go, and how to use it with arrays, boost::array or
+   * std::vector.
+   */
+  template <typename MutableBufferSequence>
+  std::size_t read_some(const MutableBufferSequence& buffers)
+  {
+    asio::error_code ec;
+    std::size_t s = this->impl_.get_service().read_some(
+        this->impl_.get_implementation(), buffers, ec);
+    asio::detail::throw_error(ec, "read_some");
+    return s;
+  }
+
+  /// Read some data from the descriptor.
+  /**
+   * This function is used to read data from the stream descriptor. The function
+   * call will block until one or more bytes of data has been read successfully,
+   * or until an error occurs.
+   *
+   * @param buffers One or more buffers into which the data will be read.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   *
+   * @returns The number of bytes read. Returns 0 if an error occurred.
+   *
+   * @note The read_some operation may not read all of the requested number of
+   * bytes. Consider using the @ref read function if you need to ensure that
+   * the requested amount of data is read before the blocking operation
+   * completes.
+   */
+  template <typename MutableBufferSequence>
+  std::size_t read_some(const MutableBufferSequence& buffers,
+      asio::error_code& ec)
+  {
+    return this->impl_.get_service().read_some(
+        this->impl_.get_implementation(), buffers, ec);
+  }
+
+  /// Start an asynchronous read.
+  /**
+   * This function is used to asynchronously read data from the stream
+   * descriptor. The function call always returns immediately.
+   *
+   * @param buffers One or more buffers into which the data will be read.
+   * Although the buffers object may be copied as necessary, ownership of the
+   * underlying memory blocks is retained by the caller, which must guarantee
+   * that they remain valid until the handler is called.
+   *
+   * @param handler The handler to be called when the read operation completes.
+   * Copies will be made of the handler as required. The function signature of
+   * the handler must be:
+   * @code void handler(
+   *   const asio::error_code& error, // Result of operation.
+   *   std::size_t bytes_transferred           // Number of bytes read.
+   * ); @endcode
+   * Regardless of whether the asynchronous operation completes immediately or
+   * not, the handler will not be invoked from within this function. On
+   * immediate completion, invocation of the handler will be performed in a
+   * manner equivalent to using asio::post().
+   *
+   * @note The read operation may not read all of the requested number of bytes.
+   * Consider using the @ref async_read function if you need to ensure that the
+   * requested amount of data is read before the asynchronous operation
+   * completes.
+   *
+   * @par Example
+   * To read into a single data buffer use the @ref buffer function as follows:
+   * @code
+   * descriptor.async_read_some(asio::buffer(data, size), handler);
+   * @endcode
+   * See the @ref buffer documentation for information on reading into multiple
+   * buffers in one go, and how to use it with arrays, boost::array or
+   * std::vector.
+   */
+  template <typename MutableBufferSequence,
+      ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+        std::size_t)) ReadHandler
+          ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
+  ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,
+      void (asio::error_code, std::size_t))
+  async_read_some(const MutableBufferSequence& buffers,
+      ASIO_MOVE_ARG(ReadHandler) handler
+        ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
+  {
+    return async_initiate<ReadHandler,
+      void (asio::error_code, std::size_t)>(
+        initiate_async_read_some(this), handler, buffers);
+  }
+
+private:
+  class initiate_async_write_some
+  {
+  public:
+    typedef Executor executor_type;
+
+    explicit initiate_async_write_some(basic_stream_descriptor* self)
+      : self_(self)
+    {
+    }
+
+    executor_type get_executor() const ASIO_NOEXCEPT
+    {
+      return self_->get_executor();
+    }
+
+    template <typename WriteHandler, typename ConstBufferSequence>
+    void operator()(ASIO_MOVE_ARG(WriteHandler) handler,
+        const ConstBufferSequence& buffers) const
+    {
+      // If you get an error on the following line it means that your handler
+      // does not meet the documented type requirements for a WriteHandler.
+      ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check;
+
+      detail::non_const_lvalue<WriteHandler> handler2(handler);
+      self_->impl_.get_service().async_write_some(
+          self_->impl_.get_implementation(), buffers,
+          handler2.value, self_->impl_.get_executor());
+    }
+
+  private:
+    basic_stream_descriptor* self_;
+  };
+
+  class initiate_async_read_some
+  {
+  public:
+    typedef Executor executor_type;
+
+    explicit initiate_async_read_some(basic_stream_descriptor* self)
+      : self_(self)
+    {
+    }
+
+    executor_type get_executor() const ASIO_NOEXCEPT
+    {
+      return self_->get_executor();
+    }
+
+    template <typename ReadHandler, typename MutableBufferSequence>
+    void operator()(ASIO_MOVE_ARG(ReadHandler) handler,
+        const MutableBufferSequence& buffers) const
+    {
+      // If you get an error on the following line it means that your handler
+      // does not meet the documented type requirements for a ReadHandler.
+      ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
+
+      detail::non_const_lvalue<ReadHandler> handler2(handler);
+      self_->impl_.get_service().async_read_some(
+          self_->impl_.get_implementation(), buffers,
+          handler2.value, self_->impl_.get_executor());
+    }
+
+  private:
+    basic_stream_descriptor* self_;
+  };
+};
+
+} // namespace posix
+} // namespace asio
+
+#endif // defined(ASIO_HAS_POSIX_STREAM_DESCRIPTOR)
+       //   || defined(GENERATING_DOCUMENTATION)
+
+#endif // ASIO_POSIX_BASIC_STREAM_DESCRIPTOR_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/posix/descriptor.hpp b/link/modules/asio-standalone/asio/include/asio/posix/descriptor.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/posix/descriptor.hpp
@@ -0,0 +1,37 @@
+//
+// posix/descriptor.hpp
+// ~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_POSIX_DESCRIPTOR_HPP
+#define ASIO_POSIX_DESCRIPTOR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_POSIX_STREAM_DESCRIPTOR) \
+  || defined(GENERATING_DOCUMENTATION)
+
+#include "asio/posix/basic_descriptor.hpp"
+
+namespace asio {
+namespace posix {
+
+/// Typedef for the typical usage of basic_descriptor.
+typedef basic_descriptor<> descriptor;
+
+} // namespace posix
+} // namespace asio
+
+#endif // defined(ASIO_HAS_POSIX_STREAM_DESCRIPTOR)
+       // || defined(GENERATING_DOCUMENTATION)
+
+#endif // ASIO_POSIX_DESCRIPTOR_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/posix/descriptor_base.hpp b/link/modules/asio-standalone/asio/include/asio/posix/descriptor_base.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/posix/descriptor_base.hpp
@@ -0,0 +1,90 @@
+//
+// posix/descriptor_base.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_POSIX_DESCRIPTOR_BASE_HPP
+#define ASIO_POSIX_DESCRIPTOR_BASE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_POSIX_STREAM_DESCRIPTOR) \
+  || defined(GENERATING_DOCUMENTATION)
+
+#include "asio/detail/io_control.hpp"
+#include "asio/detail/socket_option.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace posix {
+
+/// The descriptor_base class is used as a base for the descriptor class as a
+/// place to define the associated IO control commands.
+class descriptor_base
+{
+public:
+  /// Wait types.
+  /**
+   * For use with descriptor::wait() and descriptor::async_wait().
+   */
+  enum wait_type
+  {
+    /// Wait for a descriptor to become ready to read.
+    wait_read,
+
+    /// Wait for a descriptor to become ready to write.
+    wait_write,
+
+    /// Wait for a descriptor to have error conditions pending.
+    wait_error
+  };
+
+  /// IO control command to get the amount of data that can be read without
+  /// blocking.
+  /**
+   * Implements the FIONREAD IO control command.
+   *
+   * @par Example
+   * @code
+   * asio::posix::stream_descriptor descriptor(my_context);
+   * ...
+   * asio::descriptor_base::bytes_readable command(true);
+   * descriptor.io_control(command);
+   * std::size_t bytes_readable = command.get();
+   * @endcode
+   *
+   * @par Concepts:
+   * IoControlCommand.
+   */
+#if defined(GENERATING_DOCUMENTATION)
+  typedef implementation_defined bytes_readable;
+#else
+  typedef asio::detail::io_control::bytes_readable bytes_readable;
+#endif
+
+protected:
+  /// Protected destructor to prevent deletion through this type.
+  ~descriptor_base()
+  {
+  }
+};
+
+} // namespace posix
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_POSIX_STREAM_DESCRIPTOR)
+       //   || defined(GENERATING_DOCUMENTATION)
+
+#endif // ASIO_POSIX_DESCRIPTOR_BASE_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/posix/stream_descriptor.hpp b/link/modules/asio-standalone/asio/include/asio/posix/stream_descriptor.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/posix/stream_descriptor.hpp
@@ -0,0 +1,37 @@
+//
+// posix/stream_descriptor.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_POSIX_STREAM_DESCRIPTOR_HPP
+#define ASIO_POSIX_STREAM_DESCRIPTOR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_POSIX_STREAM_DESCRIPTOR) \
+  || defined(GENERATING_DOCUMENTATION)
+
+#include "asio/posix/basic_stream_descriptor.hpp"
+
+namespace asio {
+namespace posix {
+
+/// Typedef for the typical usage of a stream-oriented descriptor.
+typedef basic_stream_descriptor<> stream_descriptor;
+
+} // namespace posix
+} // namespace asio
+
+#endif // defined(ASIO_HAS_POSIX_STREAM_DESCRIPTOR)
+       //   || defined(GENERATING_DOCUMENTATION)
+
+#endif // ASIO_POSIX_STREAM_DESCRIPTOR_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/post.hpp b/link/modules/asio-standalone/asio/include/asio/post.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/post.hpp
@@ -0,0 +1,126 @@
+//
+// post.hpp
+// ~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_POST_HPP
+#define ASIO_POST_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/async_result.hpp"
+#include "asio/detail/type_traits.hpp"
+#include "asio/execution_context.hpp"
+#include "asio/execution/executor.hpp"
+#include "asio/is_executor.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+/// Submits a completion token or function object for execution.
+/**
+ * This function submits an object for execution using the object's associated
+ * executor. The function object is queued for execution, and is never called
+ * from the current thread prior to returning from <tt>post()</tt>.
+ *
+ * The use of @c post(), rather than @ref defer(), indicates the caller's
+ * preference that the function object be eagerly queued for execution.
+ *
+ * This function has the following effects:
+ *
+ * @li Constructs a function object handler of type @c Handler, initialized
+ * with <tt>handler(forward<CompletionToken>(token))</tt>.
+ *
+ * @li Constructs an object @c result of type <tt>async_result<Handler></tt>,
+ * initializing the object as <tt>result(handler)</tt>.
+ *
+ * @li Obtains the handler's associated executor object @c ex by performing
+ * <tt>get_associated_executor(handler)</tt>.
+ *
+ * @li Obtains the handler's associated allocator object @c alloc by performing
+ * <tt>get_associated_allocator(handler)</tt>.
+ *
+ * @li Performs <tt>ex.post(std::move(handler), alloc)</tt>.
+ *
+ * @li Returns <tt>result.get()</tt>.
+ */
+template <ASIO_COMPLETION_TOKEN_FOR(void()) CompletionToken>
+ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void()) post(
+    ASIO_MOVE_ARG(CompletionToken) token);
+
+/// Submits a completion token or function object for execution.
+/**
+ * This function submits an object for execution using the specified executor.
+ * The function object is queued for execution, and is never called from the
+ * current thread prior to returning from <tt>post()</tt>.
+ *
+ * The use of @c post(), rather than @ref defer(), indicates the caller's
+ * preference that the function object be eagerly queued for execution.
+ *
+ * This function has the following effects:
+ *
+ * @li Constructs a function object handler of type @c Handler, initialized
+ * with <tt>handler(forward<CompletionToken>(token))</tt>.
+ *
+ * @li Constructs an object @c result of type <tt>async_result<Handler></tt>,
+ * initializing the object as <tt>result(handler)</tt>.
+ *
+ * @li Obtains the handler's associated executor object @c ex1 by performing
+ * <tt>get_associated_executor(handler)</tt>.
+ *
+ * @li Creates a work object @c w by performing <tt>make_work(ex1)</tt>.
+ *
+ * @li Obtains the handler's associated allocator object @c alloc by performing
+ * <tt>get_associated_allocator(handler)</tt>.
+ *
+ * @li Constructs a function object @c f with a function call operator that
+ * performs <tt>ex1.dispatch(std::move(handler), alloc)</tt> followed by
+ * <tt>w.reset()</tt>.
+ *
+ * @li Performs <tt>Executor(ex).post(std::move(f), alloc)</tt>.
+ *
+ * @li Returns <tt>result.get()</tt>.
+ */
+template <typename Executor,
+    ASIO_COMPLETION_TOKEN_FOR(void()) CompletionToken
+      ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(Executor)>
+ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void()) post(
+    const Executor& ex,
+    ASIO_MOVE_ARG(CompletionToken) token
+      ASIO_DEFAULT_COMPLETION_TOKEN(Executor),
+    typename enable_if<
+      execution::is_executor<Executor>::value || is_executor<Executor>::value
+    >::type* = 0);
+
+/// Submits a completion token or function object for execution.
+/**
+ * @returns <tt>post(ctx.get_executor(), forward<CompletionToken>(token))</tt>.
+ */
+template <typename ExecutionContext,
+    ASIO_COMPLETION_TOKEN_FOR(void()) CompletionToken
+      ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(
+        typename ExecutionContext::executor_type)>
+ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void()) post(
+    ExecutionContext& ctx,
+    ASIO_MOVE_ARG(CompletionToken) token
+      ASIO_DEFAULT_COMPLETION_TOKEN(
+        typename ExecutionContext::executor_type),
+    typename enable_if<is_convertible<
+      ExecutionContext&, execution_context&>::value>::type* = 0);
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/impl/post.hpp"
+
+#endif // ASIO_POST_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/prefer.hpp b/link/modules/asio-standalone/asio/include/asio/prefer.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/prefer.hpp
@@ -0,0 +1,656 @@
+//
+// prefer.hpp
+// ~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_PREFER_HPP
+#define ASIO_PREFER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/type_traits.hpp"
+#include "asio/is_applicable_property.hpp"
+#include "asio/traits/prefer_free.hpp"
+#include "asio/traits/prefer_member.hpp"
+#include "asio/traits/require_free.hpp"
+#include "asio/traits/require_member.hpp"
+#include "asio/traits/static_require.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+#if defined(GENERATING_DOCUMENTATION)
+
+namespace asio {
+
+/// A customisation point that attempts to apply a property to an object.
+/**
+ * The name <tt>prefer</tt> denotes a customisation point object. The
+ * expression <tt>asio::prefer(E, P0, Pn...)</tt> for some subexpressions
+ * <tt>E</tt> and <tt>P0</tt>, and where <tt>Pn...</tt> represents <tt>N</tt>
+ * subexpressions (where <tt>N</tt> is 0 or more, and with types <tt>T =
+ * decay_t<decltype(E)></tt> and <tt>Prop0 = decay_t<decltype(P0)></tt>) is
+ * expression-equivalent to:
+ *
+ * @li If <tt>is_applicable_property_v<T, Prop0> && Prop0::is_preferable</tt> is
+ *   not a well-formed constant expression with value <tt>true</tt>,
+ *   <tt>asio::prefer(E, P0, Pn...)</tt> is ill-formed.
+ *
+ * @li Otherwise, <tt>E</tt> if <tt>N == 0</tt> and the expression
+ *   <tt>Prop0::template static_query_v<T> == Prop0::value()</tt> is a
+ *   well-formed constant expression with value <tt>true</tt>.
+ *
+ * @li Otherwise, <tt>(E).require(P0)</tt> if <tt>N == 0</tt> and the expression
+ *   <tt>(E).require(P0)</tt> is a valid expression.
+ *
+ * @li Otherwise, <tt>require(E, P0)</tt> if <tt>N == 0</tt> and the expression
+ *   <tt>require(E, P0)</tt> is a valid expression with overload resolution
+ *   performed in a context that does not include the declaration of the
+ *   <tt>require</tt> customization point object.
+ *
+ * @li Otherwise, <tt>(E).prefer(P0)</tt> if <tt>N == 0</tt> and the expression
+ *   <tt>(E).prefer(P0)</tt> is a valid expression.
+ *
+ * @li Otherwise, <tt>prefer(E, P0)</tt> if <tt>N == 0</tt> and the expression
+ *   <tt>prefer(E, P0)</tt> is a valid expression with overload resolution
+ *   performed in a context that does not include the declaration of the
+ *   <tt>prefer</tt> customization point object.
+ *
+ * @li Otherwise, <tt>E</tt> if <tt>N == 0</tt>.
+ *
+ * @li Otherwise,
+ *   <tt>asio::prefer(asio::prefer(E, P0), Pn...)</tt>
+ *   if <tt>N > 0</tt> and the expression
+ *   <tt>asio::prefer(asio::prefer(E, P0), Pn...)</tt>
+ *   is a valid expression.
+ *
+ * @li Otherwise, <tt>asio::prefer(E, P0, Pn...)</tt> is ill-formed.
+ */
+inline constexpr unspecified prefer = unspecified;
+
+/// A type trait that determines whether a @c prefer expression is well-formed.
+/**
+ * Class template @c can_prefer is a trait that is derived from
+ * @c true_type if the expression <tt>asio::prefer(std::declval<T>(),
+ * std::declval<Properties>()...)</tt> is well formed; otherwise @c false_type.
+ */
+template <typename T, typename... Properties>
+struct can_prefer :
+  integral_constant<bool, automatically_determined>
+{
+};
+
+/// A type trait that determines whether a @c prefer expression will not throw.
+/**
+ * Class template @c is_nothrow_prefer is a trait that is derived from
+ * @c true_type if the expression <tt>asio::prefer(std::declval<T>(),
+ * std::declval<Properties>()...)</tt> is @c noexcept; otherwise @c false_type.
+ */
+template <typename T, typename... Properties>
+struct is_nothrow_prefer :
+  integral_constant<bool, automatically_determined>
+{
+};
+
+/// A type trait that determines the result type of a @c prefer expression.
+/**
+ * Class template @c prefer_result is a trait that determines the result
+ * type of the expression <tt>asio::prefer(std::declval<T>(),
+ * std::declval<Properties>()...)</tt>.
+ */
+template <typename T, typename... Properties>
+struct prefer_result
+{
+  /// The result of the @c prefer expression.
+  typedef automatically_determined type;
+};
+
+} // namespace asio
+
+#else // defined(GENERATING_DOCUMENTATION)
+
+namespace asio_prefer_fn {
+
+using asio::decay;
+using asio::declval;
+using asio::enable_if;
+using asio::is_applicable_property;
+using asio::traits::prefer_free;
+using asio::traits::prefer_member;
+using asio::traits::require_free;
+using asio::traits::require_member;
+using asio::traits::static_require;
+
+void prefer();
+void require();
+
+enum overload_type
+{
+  identity,
+  call_require_member,
+  call_require_free,
+  call_prefer_member,
+  call_prefer_free,
+  two_props,
+  n_props,
+  ill_formed
+};
+
+template <typename T, typename Properties, typename = void>
+struct call_traits
+{
+  ASIO_STATIC_CONSTEXPR(overload_type, overload = ill_formed);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
+  typedef void result_type;
+};
+
+template <typename T, typename Property>
+struct call_traits<T, void(Property),
+  typename enable_if<
+    (
+      is_applicable_property<
+        typename decay<T>::type,
+        typename decay<Property>::type
+      >::value
+      &&
+      decay<Property>::type::is_preferable
+      &&
+      static_require<T, Property>::is_valid
+    )
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(overload_type, overload = identity);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
+
+#if defined(ASIO_HAS_MOVE)
+  typedef ASIO_MOVE_ARG(T) result_type;
+#else // defined(ASIO_HAS_MOVE)
+  typedef ASIO_MOVE_ARG(typename decay<T>::type) result_type;
+#endif // defined(ASIO_HAS_MOVE)
+};
+
+template <typename T, typename Property>
+struct call_traits<T, void(Property),
+  typename enable_if<
+    (
+      is_applicable_property<
+        typename decay<T>::type,
+        typename decay<Property>::type
+      >::value
+      &&
+      decay<Property>::type::is_preferable
+      &&
+      !static_require<T, Property>::is_valid
+      &&
+      require_member<T, Property>::is_valid
+    )
+  >::type> :
+  require_member<T, Property>
+{
+  ASIO_STATIC_CONSTEXPR(overload_type, overload = call_require_member);
+};
+
+template <typename T, typename Property>
+struct call_traits<T, void(Property),
+  typename enable_if<
+    (
+      is_applicable_property<
+        typename decay<T>::type,
+        typename decay<Property>::type
+      >::value
+      &&
+      decay<Property>::type::is_preferable
+      &&
+      !static_require<T, Property>::is_valid
+      &&
+      !require_member<T, Property>::is_valid
+      &&
+      require_free<T, Property>::is_valid
+    )
+  >::type> :
+  require_free<T, Property>
+{
+  ASIO_STATIC_CONSTEXPR(overload_type, overload = call_require_free);
+};
+
+template <typename T, typename Property>
+struct call_traits<T, void(Property),
+  typename enable_if<
+    (
+      is_applicable_property<
+        typename decay<T>::type,
+        typename decay<Property>::type
+      >::value
+      &&
+      decay<Property>::type::is_preferable
+      &&
+      !static_require<T, Property>::is_valid
+      &&
+      !require_member<T, Property>::is_valid
+      &&
+      !require_free<T, Property>::is_valid
+      &&
+      prefer_member<T, Property>::is_valid
+    )
+  >::type> :
+  prefer_member<T, Property>
+{
+  ASIO_STATIC_CONSTEXPR(overload_type, overload = call_prefer_member);
+};
+
+template <typename T, typename Property>
+struct call_traits<T, void(Property),
+  typename enable_if<
+    (
+      is_applicable_property<
+        typename decay<T>::type,
+        typename decay<Property>::type
+      >::value
+      &&
+      decay<Property>::type::is_preferable
+      &&
+      !static_require<T, Property>::is_valid
+      &&
+      !require_member<T, Property>::is_valid
+      &&
+      !require_free<T, Property>::is_valid
+      &&
+      !prefer_member<T, Property>::is_valid
+      &&
+      prefer_free<T, Property>::is_valid
+    )
+  >::type> :
+  prefer_free<T, Property>
+{
+  ASIO_STATIC_CONSTEXPR(overload_type, overload = call_prefer_free);
+};
+
+template <typename T, typename Property>
+struct call_traits<T, void(Property),
+  typename enable_if<
+    (
+      is_applicable_property<
+        typename decay<T>::type,
+        typename decay<Property>::type
+      >::value
+      &&
+      decay<Property>::type::is_preferable
+      &&
+      !static_require<T, Property>::is_valid
+      &&
+      !require_member<T, Property>::is_valid
+      &&
+      !require_free<T, Property>::is_valid
+      &&
+      !prefer_member<T, Property>::is_valid
+      &&
+      !prefer_free<T, Property>::is_valid
+    )
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(overload_type, overload = identity);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
+
+#if defined(ASIO_HAS_MOVE)
+  typedef ASIO_MOVE_ARG(T) result_type;
+#else // defined(ASIO_HAS_MOVE)
+  typedef ASIO_MOVE_ARG(typename decay<T>::type) result_type;
+#endif // defined(ASIO_HAS_MOVE)
+};
+
+template <typename T, typename P0, typename P1>
+struct call_traits<T, void(P0, P1),
+  typename enable_if<
+    call_traits<T, void(P0)>::overload != ill_formed
+    &&
+    call_traits<
+      typename call_traits<T, void(P0)>::result_type,
+      void(P1)
+    >::overload != ill_formed
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(overload_type, overload = two_props);
+
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept =
+    (
+      call_traits<T, void(P0)>::is_noexcept
+      &&
+      call_traits<
+        typename call_traits<T, void(P0)>::result_type,
+        void(P1)
+      >::is_noexcept
+    ));
+
+  typedef typename decay<
+    typename call_traits<
+      typename call_traits<T, void(P0)>::result_type,
+      void(P1)
+    >::result_type
+  >::type result_type;
+};
+
+template <typename T, typename P0, typename P1, typename ASIO_ELLIPSIS PN>
+struct call_traits<T, void(P0, P1, PN ASIO_ELLIPSIS),
+  typename enable_if<
+    call_traits<T, void(P0)>::overload != ill_formed
+    &&
+    call_traits<
+      typename call_traits<T, void(P0)>::result_type,
+      void(P1, PN ASIO_ELLIPSIS)
+    >::overload != ill_formed
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(overload_type, overload = n_props);
+
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept =
+    (
+      call_traits<T, void(P0)>::is_noexcept
+      &&
+      call_traits<
+        typename call_traits<T, void(P0)>::result_type,
+        void(P1, PN ASIO_ELLIPSIS)
+      >::is_noexcept
+    ));
+
+  typedef typename decay<
+    typename call_traits<
+      typename call_traits<T, void(P0)>::result_type,
+      void(P1, PN ASIO_ELLIPSIS)
+    >::result_type
+  >::type result_type;
+};
+
+struct impl
+{
+  template <typename T, typename Property>
+  ASIO_NODISCARD ASIO_CONSTEXPR typename enable_if<
+    call_traits<T, void(Property)>::overload == identity,
+    typename call_traits<T, void(Property)>::result_type
+  >::type
+  operator()(
+      ASIO_MOVE_ARG(T) t,
+      ASIO_MOVE_ARG(Property)) const
+    ASIO_NOEXCEPT_IF((
+      call_traits<T, void(Property)>::is_noexcept))
+  {
+    return ASIO_MOVE_CAST(T)(t);
+  }
+
+  template <typename T, typename Property>
+  ASIO_NODISCARD ASIO_CONSTEXPR typename enable_if<
+    call_traits<T, void(Property)>::overload == call_require_member,
+    typename call_traits<T, void(Property)>::result_type
+  >::type
+  operator()(
+      ASIO_MOVE_ARG(T) t,
+      ASIO_MOVE_ARG(Property) p) const
+    ASIO_NOEXCEPT_IF((
+      call_traits<T, void(Property)>::is_noexcept))
+  {
+    return ASIO_MOVE_CAST(T)(t).require(
+        ASIO_MOVE_CAST(Property)(p));
+  }
+
+  template <typename T, typename Property>
+  ASIO_NODISCARD ASIO_CONSTEXPR typename enable_if<
+    call_traits<T, void(Property)>::overload == call_require_free,
+    typename call_traits<T, void(Property)>::result_type
+  >::type
+  operator()(
+      ASIO_MOVE_ARG(T) t,
+      ASIO_MOVE_ARG(Property) p) const
+    ASIO_NOEXCEPT_IF((
+      call_traits<T, void(Property)>::is_noexcept))
+  {
+    return require(
+        ASIO_MOVE_CAST(T)(t),
+        ASIO_MOVE_CAST(Property)(p));
+  }
+
+  template <typename T, typename Property>
+  ASIO_NODISCARD ASIO_CONSTEXPR typename enable_if<
+    call_traits<T, void(Property)>::overload == call_prefer_member,
+    typename call_traits<T, void(Property)>::result_type
+  >::type
+  operator()(
+      ASIO_MOVE_ARG(T) t,
+      ASIO_MOVE_ARG(Property) p) const
+    ASIO_NOEXCEPT_IF((
+      call_traits<T, void(Property)>::is_noexcept))
+  {
+    return ASIO_MOVE_CAST(T)(t).prefer(
+        ASIO_MOVE_CAST(Property)(p));
+  }
+
+  template <typename T, typename Property>
+  ASIO_NODISCARD ASIO_CONSTEXPR typename enable_if<
+    call_traits<T, void(Property)>::overload == call_prefer_free,
+    typename call_traits<T, void(Property)>::result_type
+  >::type
+  operator()(
+      ASIO_MOVE_ARG(T) t,
+      ASIO_MOVE_ARG(Property) p) const
+    ASIO_NOEXCEPT_IF((
+      call_traits<T, void(Property)>::is_noexcept))
+  {
+    return prefer(
+        ASIO_MOVE_CAST(T)(t),
+        ASIO_MOVE_CAST(Property)(p));
+  }
+
+  template <typename T, typename P0, typename P1>
+  ASIO_NODISCARD ASIO_CONSTEXPR typename enable_if<
+    call_traits<T, void(P0, P1)>::overload == two_props,
+    typename call_traits<T, void(P0, P1)>::result_type
+  >::type
+  operator()(
+      ASIO_MOVE_ARG(T) t,
+      ASIO_MOVE_ARG(P0) p0,
+      ASIO_MOVE_ARG(P1) p1) const
+    ASIO_NOEXCEPT_IF((
+      call_traits<T, void(P0, P1)>::is_noexcept))
+  {
+    return (*this)(
+        (*this)(
+          ASIO_MOVE_CAST(T)(t),
+          ASIO_MOVE_CAST(P0)(p0)),
+        ASIO_MOVE_CAST(P1)(p1));
+  }
+
+  template <typename T, typename P0, typename P1,
+    typename ASIO_ELLIPSIS PN>
+  ASIO_NODISCARD ASIO_CONSTEXPR typename enable_if<
+    call_traits<T, void(P0, P1, PN ASIO_ELLIPSIS)>::overload == n_props,
+    typename call_traits<T, void(P0, P1, PN ASIO_ELLIPSIS)>::result_type
+  >::type
+  operator()(
+      ASIO_MOVE_ARG(T) t,
+      ASIO_MOVE_ARG(P0) p0,
+      ASIO_MOVE_ARG(P1) p1,
+      ASIO_MOVE_ARG(PN) ASIO_ELLIPSIS pn) const
+    ASIO_NOEXCEPT_IF((
+      call_traits<T, void(P0, P1, PN ASIO_ELLIPSIS)>::is_noexcept))
+  {
+    return (*this)(
+        (*this)(
+          ASIO_MOVE_CAST(T)(t),
+          ASIO_MOVE_CAST(P0)(p0)),
+        ASIO_MOVE_CAST(P1)(p1),
+        ASIO_MOVE_CAST(PN)(pn) ASIO_ELLIPSIS);
+  }
+};
+
+template <typename T = impl>
+struct static_instance
+{
+  static const T instance;
+};
+
+template <typename T>
+const T static_instance<T>::instance = {};
+
+} // namespace asio_prefer_fn
+namespace asio {
+namespace {
+
+static ASIO_CONSTEXPR const asio_prefer_fn::impl&
+  prefer = asio_prefer_fn::static_instance<>::instance;
+
+} // namespace
+
+#if defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+template <typename T, typename... Properties>
+struct can_prefer :
+  integral_constant<bool,
+    asio_prefer_fn::call_traits<T, void(Properties...)>::overload
+      != asio_prefer_fn::ill_formed>
+{
+};
+
+#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+template <typename T, typename P0 = void,
+    typename P1 = void, typename P2 = void>
+struct can_prefer :
+  integral_constant<bool,
+    asio_prefer_fn::call_traits<T, void(P0, P1, P2)>::overload
+      != asio_prefer_fn::ill_formed>
+{
+};
+
+template <typename T, typename P0, typename P1>
+struct can_prefer<T, P0, P1> :
+  integral_constant<bool,
+    asio_prefer_fn::call_traits<T, void(P0, P1)>::overload
+      != asio_prefer_fn::ill_formed>
+{
+};
+
+template <typename T, typename P0>
+struct can_prefer<T, P0> :
+  integral_constant<bool,
+    asio_prefer_fn::call_traits<T, void(P0)>::overload
+      != asio_prefer_fn::ill_formed>
+{
+};
+
+template <typename T>
+struct can_prefer<T> :
+  false_type
+{
+};
+
+#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+#if defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+template <typename T, typename ASIO_ELLIPSIS Properties>
+constexpr bool can_prefer_v
+  = can_prefer<T, Properties ASIO_ELLIPSIS>::value;
+
+#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+#if defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+template <typename T, typename... Properties>
+struct is_nothrow_prefer :
+  integral_constant<bool,
+    asio_prefer_fn::call_traits<T, void(Properties...)>::is_noexcept>
+{
+};
+
+#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+template <typename T, typename P0 = void,
+    typename P1 = void, typename P2 = void>
+struct is_nothrow_prefer :
+  integral_constant<bool,
+    asio_prefer_fn::call_traits<T, void(P0, P1, P2)>::is_noexcept>
+{
+};
+
+template <typename T, typename P0, typename P1>
+struct is_nothrow_prefer<T, P0, P1> :
+  integral_constant<bool,
+    asio_prefer_fn::call_traits<T, void(P0, P1)>::is_noexcept>
+{
+};
+
+template <typename T, typename P0>
+struct is_nothrow_prefer<T, P0> :
+  integral_constant<bool,
+    asio_prefer_fn::call_traits<T, void(P0)>::is_noexcept>
+{
+};
+
+template <typename T>
+struct is_nothrow_prefer<T> :
+  false_type
+{
+};
+
+#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+#if defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+template <typename T, typename ASIO_ELLIPSIS Properties>
+constexpr bool is_nothrow_prefer_v
+  = is_nothrow_prefer<T, Properties ASIO_ELLIPSIS>::value;
+
+#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+#if defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+template <typename T, typename... Properties>
+struct prefer_result
+{
+  typedef typename asio_prefer_fn::call_traits<
+      T, void(Properties...)>::result_type type;
+};
+
+#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+template <typename T, typename P0 = void,
+    typename P1 = void, typename P2 = void>
+struct prefer_result
+{
+  typedef typename asio_prefer_fn::call_traits<
+      T, void(P0, P1, P2)>::result_type type;
+};
+
+template <typename T, typename P0, typename P1>
+struct prefer_result<T, P0, P1>
+{
+  typedef typename asio_prefer_fn::call_traits<
+      T, void(P0, P1)>::result_type type;
+};
+
+template <typename T, typename P0>
+struct prefer_result<T, P0>
+{
+  typedef typename asio_prefer_fn::call_traits<
+      T, void(P0)>::result_type type;
+};
+
+template <typename T>
+struct prefer_result<T>
+{
+};
+
+#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+} // namespace asio
+
+#endif // defined(GENERATING_DOCUMENTATION)
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_PREFER_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/query.hpp b/link/modules/asio-standalone/asio/include/asio/query.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/query.hpp
@@ -0,0 +1,296 @@
+//
+// query.hpp
+// ~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_QUERY_HPP
+#define ASIO_QUERY_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/type_traits.hpp"
+#include "asio/is_applicable_property.hpp"
+#include "asio/traits/query_member.hpp"
+#include "asio/traits/query_free.hpp"
+#include "asio/traits/static_query.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+#if defined(GENERATING_DOCUMENTATION)
+
+namespace asio {
+
+/// A customisation point that queries the value of a property.
+/**
+ * The name <tt>query</tt> denotes a customization point object. The
+ * expression <tt>asio::query(E, P)</tt> for some
+ * subexpressions <tt>E</tt> and <tt>P</tt> (with types <tt>T =
+ * decay_t<decltype(E)></tt> and <tt>Prop = decay_t<decltype(P)></tt>) is
+ * expression-equivalent to:
+ *
+ * @li If <tt>is_applicable_property_v<T, Prop></tt> is not a well-formed
+ *   constant expression with value <tt>true</tt>, <tt>asio::query(E,
+ *   P)</tt> is ill-formed.
+ *
+ * @li Otherwise, <tt>Prop::template static_query_v<T></tt> if the expression
+ *   <tt>Prop::template static_query_v<T></tt> is a well-formed constant
+ *   expression.
+ *
+ * @li Otherwise, <tt>(E).query(P)</tt> if the expression
+ *   <tt>(E).query(P)</tt> is well-formed.
+ *
+ * @li Otherwise, <tt>query(E, P)</tt> if the expression
+ *   <tt>query(E, P)</tt> is a valid expression with overload
+ *   resolution performed in a context that does not include the declaration
+ *   of the <tt>query</tt> customization point object.
+ *
+ * @li Otherwise, <tt>asio::query(E, P)</tt> is ill-formed.
+ */
+inline constexpr unspecified query = unspecified;
+
+/// A type trait that determines whether a @c query expression is well-formed.
+/**
+ * Class template @c can_query is a trait that is derived from
+ * @c true_type if the expression <tt>asio::query(std::declval<T>(),
+ * std::declval<Property>())</tt> is well formed; otherwise @c false_type.
+ */
+template <typename T, typename Property>
+struct can_query :
+  integral_constant<bool, automatically_determined>
+{
+};
+
+/// A type trait that determines whether a @c query expression will
+/// not throw.
+/**
+ * Class template @c is_nothrow_query is a trait that is derived from
+ * @c true_type if the expression <tt>asio::query(std::declval<T>(),
+ * std::declval<Property>())</tt> is @c noexcept; otherwise @c false_type.
+ */
+template <typename T, typename Property>
+struct is_nothrow_query :
+  integral_constant<bool, automatically_determined>
+{
+};
+
+/// A type trait that determines the result type of a @c query expression.
+/**
+ * Class template @c query_result is a trait that determines the result
+ * type of the expression <tt>asio::query(std::declval<T>(),
+ * std::declval<Property>())</tt>.
+ */
+template <typename T, typename Property>
+struct query_result
+{
+  /// The result of the @c query expression.
+  typedef automatically_determined type;
+};
+
+} // namespace asio
+
+#else // defined(GENERATING_DOCUMENTATION)
+
+namespace asio_query_fn {
+
+using asio::decay;
+using asio::declval;
+using asio::enable_if;
+using asio::is_applicable_property;
+using asio::traits::query_free;
+using asio::traits::query_member;
+using asio::traits::static_query;
+
+void query();
+
+enum overload_type
+{
+  static_value,
+  call_member,
+  call_free,
+  ill_formed
+};
+
+template <typename T, typename Properties, typename = void>
+struct call_traits
+{
+  ASIO_STATIC_CONSTEXPR(overload_type, overload = ill_formed);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
+  typedef void result_type;
+};
+
+template <typename T, typename Property>
+struct call_traits<T, void(Property),
+  typename enable_if<
+    (
+      is_applicable_property<
+        typename decay<T>::type,
+        typename decay<Property>::type
+      >::value
+      &&
+      static_query<T, Property>::is_valid
+    )
+  >::type> :
+  static_query<T, Property>
+{
+  ASIO_STATIC_CONSTEXPR(overload_type, overload = static_value);
+};
+
+template <typename T, typename Property>
+struct call_traits<T, void(Property),
+  typename enable_if<
+    (
+      is_applicable_property<
+        typename decay<T>::type,
+        typename decay<Property>::type
+      >::value
+      &&
+      !static_query<T, Property>::is_valid
+      &&
+      query_member<T, Property>::is_valid
+    )
+  >::type> :
+  query_member<T, Property>
+{
+  ASIO_STATIC_CONSTEXPR(overload_type, overload = call_member);
+};
+
+template <typename T, typename Property>
+struct call_traits<T, void(Property),
+  typename enable_if<
+    (
+      is_applicable_property<
+        typename decay<T>::type,
+        typename decay<Property>::type
+      >::value
+      &&
+      !static_query<T, Property>::is_valid
+      &&
+      !query_member<T, Property>::is_valid
+      &&
+      query_free<T, Property>::is_valid
+    )
+  >::type> :
+  query_free<T, Property>
+{
+  ASIO_STATIC_CONSTEXPR(overload_type, overload = call_free);
+};
+
+struct impl
+{
+  template <typename T, typename Property>
+  ASIO_NODISCARD ASIO_CONSTEXPR typename enable_if<
+    call_traits<T, void(Property)>::overload == static_value,
+    typename call_traits<T, void(Property)>::result_type
+  >::type
+  operator()(
+      ASIO_MOVE_ARG(T),
+      ASIO_MOVE_ARG(Property)) const
+    ASIO_NOEXCEPT_IF((
+      call_traits<T, void(Property)>::is_noexcept))
+  {
+    return static_query<
+      typename decay<T>::type,
+      typename decay<Property>::type
+    >::value();
+  }
+
+  template <typename T, typename Property>
+  ASIO_NODISCARD ASIO_CONSTEXPR typename enable_if<
+    call_traits<T, void(Property)>::overload == call_member,
+    typename call_traits<T, void(Property)>::result_type
+  >::type
+  operator()(
+      ASIO_MOVE_ARG(T) t,
+      ASIO_MOVE_ARG(Property) p) const
+    ASIO_NOEXCEPT_IF((
+      call_traits<T, void(Property)>::is_noexcept))
+  {
+    return ASIO_MOVE_CAST(T)(t).query(ASIO_MOVE_CAST(Property)(p));
+  }
+
+  template <typename T, typename Property>
+  ASIO_NODISCARD ASIO_CONSTEXPR typename enable_if<
+    call_traits<T, void(Property)>::overload == call_free,
+    typename call_traits<T, void(Property)>::result_type
+  >::type
+  operator()(
+      ASIO_MOVE_ARG(T) t,
+      ASIO_MOVE_ARG(Property) p) const
+    ASIO_NOEXCEPT_IF((
+      call_traits<T, void(Property)>::is_noexcept))
+  {
+    return query(ASIO_MOVE_CAST(T)(t), ASIO_MOVE_CAST(Property)(p));
+  }
+};
+
+template <typename T = impl>
+struct static_instance
+{
+  static const T instance;
+};
+
+template <typename T>
+const T static_instance<T>::instance = {};
+
+} // namespace asio_query_fn
+namespace asio {
+namespace {
+
+static ASIO_CONSTEXPR const asio_query_fn::impl&
+  query = asio_query_fn::static_instance<>::instance;
+
+} // namespace
+
+template <typename T, typename Property>
+struct can_query :
+  integral_constant<bool,
+    asio_query_fn::call_traits<T, void(Property)>::overload !=
+      asio_query_fn::ill_formed>
+{
+};
+
+#if defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+template <typename T, typename Property>
+constexpr bool can_query_v
+  = can_query<T, Property>::value;
+
+#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+template <typename T, typename Property>
+struct is_nothrow_query :
+  integral_constant<bool,
+    asio_query_fn::call_traits<T, void(Property)>::is_noexcept>
+{
+};
+
+#if defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+template <typename T, typename Property>
+constexpr bool is_nothrow_query_v
+  = is_nothrow_query<T, Property>::value;
+
+#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+template <typename T, typename Property>
+struct query_result
+{
+  typedef typename asio_query_fn::call_traits<
+      T, void(Property)>::result_type type;
+};
+
+} // namespace asio
+
+#endif // defined(GENERATING_DOCUMENTATION)
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_QUERY_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/read.hpp b/link/modules/asio-standalone/asio/include/asio/read.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/read.hpp
@@ -0,0 +1,1288 @@
+//
+// read.hpp
+// ~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_READ_HPP
+#define ASIO_READ_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <cstddef>
+#include "asio/async_result.hpp"
+#include "asio/buffer.hpp"
+#include "asio/error.hpp"
+
+#if !defined(ASIO_NO_EXTENSIONS)
+# include "asio/basic_streambuf_fwd.hpp"
+#endif // !defined(ASIO_NO_EXTENSIONS)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+/**
+ * @defgroup read asio::read
+ *
+ * @brief The @c read function is a composed operation that reads a certain
+ * amount of data from a stream before returning.
+ */
+/*@{*/
+
+/// Attempt to read a certain amount of data from a stream before returning.
+/**
+ * This function is used to read a certain number of bytes of data from a
+ * stream. The call will block until one of the following conditions is true:
+ *
+ * @li The supplied buffers are full. That is, the bytes transferred is equal to
+ * the sum of the buffer sizes.
+ *
+ * @li An error occurred.
+ *
+ * This operation is implemented in terms of zero or more calls to the stream's
+ * read_some function.
+ *
+ * @param s The stream from which the data is to be read. The type must support
+ * the SyncReadStream concept.
+ *
+ * @param buffers One or more buffers into which the data will be read. The sum
+ * of the buffer sizes indicates the maximum number of bytes to read from the
+ * stream.
+ *
+ * @returns The number of bytes transferred.
+ *
+ * @throws asio::system_error Thrown on failure.
+ *
+ * @par Example
+ * To read into a single data buffer use the @ref buffer function as follows:
+ * @code asio::read(s, asio::buffer(data, size)); @endcode
+ * See the @ref buffer documentation for information on reading into multiple
+ * buffers in one go, and how to use it with arrays, boost::array or
+ * std::vector.
+ *
+ * @note This overload is equivalent to calling:
+ * @code asio::read(
+ *     s, buffers,
+ *     asio::transfer_all()); @endcode
+ */
+template <typename SyncReadStream, typename MutableBufferSequence>
+std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers,
+    typename enable_if<
+      is_mutable_buffer_sequence<MutableBufferSequence>::value
+    >::type* = 0);
+
+/// Attempt to read a certain amount of data from a stream before returning.
+/**
+ * This function is used to read a certain number of bytes of data from a
+ * stream. The call will block until one of the following conditions is true:
+ *
+ * @li The supplied buffers are full. That is, the bytes transferred is equal to
+ * the sum of the buffer sizes.
+ *
+ * @li An error occurred.
+ *
+ * This operation is implemented in terms of zero or more calls to the stream's
+ * read_some function.
+ *
+ * @param s The stream from which the data is to be read. The type must support
+ * the SyncReadStream concept.
+ *
+ * @param buffers One or more buffers into which the data will be read. The sum
+ * of the buffer sizes indicates the maximum number of bytes to read from the
+ * stream.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @returns The number of bytes transferred.
+ *
+ * @par Example
+ * To read into a single data buffer use the @ref buffer function as follows:
+ * @code asio::read(s, asio::buffer(data, size), ec); @endcode
+ * See the @ref buffer documentation for information on reading into multiple
+ * buffers in one go, and how to use it with arrays, boost::array or
+ * std::vector.
+ *
+ * @note This overload is equivalent to calling:
+ * @code asio::read(
+ *     s, buffers,
+ *     asio::transfer_all(), ec); @endcode
+ */
+template <typename SyncReadStream, typename MutableBufferSequence>
+std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers,
+    asio::error_code& ec,
+    typename enable_if<
+      is_mutable_buffer_sequence<MutableBufferSequence>::value
+    >::type* = 0);
+
+/// Attempt to read a certain amount of data from a stream before returning.
+/**
+ * This function is used to read a certain number of bytes of data from a
+ * stream. The call will block until one of the following conditions is true:
+ *
+ * @li The supplied buffers are full. That is, the bytes transferred is equal to
+ * the sum of the buffer sizes.
+ *
+ * @li The completion_condition function object returns 0.
+ *
+ * This operation is implemented in terms of zero or more calls to the stream's
+ * read_some function.
+ *
+ * @param s The stream from which the data is to be read. The type must support
+ * the SyncReadStream concept.
+ *
+ * @param buffers One or more buffers into which the data will be read. The sum
+ * of the buffer sizes indicates the maximum number of bytes to read from the
+ * stream.
+ *
+ * @param completion_condition The function object to be called to determine
+ * whether the read operation is complete. The signature of the function object
+ * must be:
+ * @code std::size_t completion_condition(
+ *   // Result of latest read_some operation.
+ *   const asio::error_code& error,
+ *
+ *   // Number of bytes transferred so far.
+ *   std::size_t bytes_transferred
+ * ); @endcode
+ * A return value of 0 indicates that the read operation is complete. A non-zero
+ * return value indicates the maximum number of bytes to be read on the next
+ * call to the stream's read_some function.
+ *
+ * @returns The number of bytes transferred.
+ *
+ * @throws asio::system_error Thrown on failure.
+ *
+ * @par Example
+ * To read into a single data buffer use the @ref buffer function as follows:
+ * @code asio::read(s, asio::buffer(data, size),
+ *     asio::transfer_at_least(32)); @endcode
+ * See the @ref buffer documentation for information on reading into multiple
+ * buffers in one go, and how to use it with arrays, boost::array or
+ * std::vector.
+ */
+template <typename SyncReadStream, typename MutableBufferSequence,
+  typename CompletionCondition>
+std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers,
+    CompletionCondition completion_condition,
+    typename enable_if<
+      is_mutable_buffer_sequence<MutableBufferSequence>::value
+    >::type* = 0);
+
+/// Attempt to read a certain amount of data from a stream before returning.
+/**
+ * This function is used to read a certain number of bytes of data from a
+ * stream. The call will block until one of the following conditions is true:
+ *
+ * @li The supplied buffers are full. That is, the bytes transferred is equal to
+ * the sum of the buffer sizes.
+ *
+ * @li The completion_condition function object returns 0.
+ *
+ * This operation is implemented in terms of zero or more calls to the stream's
+ * read_some function.
+ *
+ * @param s The stream from which the data is to be read. The type must support
+ * the SyncReadStream concept.
+ *
+ * @param buffers One or more buffers into which the data will be read. The sum
+ * of the buffer sizes indicates the maximum number of bytes to read from the
+ * stream.
+ *
+ * @param completion_condition The function object to be called to determine
+ * whether the read operation is complete. The signature of the function object
+ * must be:
+ * @code std::size_t completion_condition(
+ *   // Result of latest read_some operation.
+ *   const asio::error_code& error,
+ *
+ *   // Number of bytes transferred so far.
+ *   std::size_t bytes_transferred
+ * ); @endcode
+ * A return value of 0 indicates that the read operation is complete. A non-zero
+ * return value indicates the maximum number of bytes to be read on the next
+ * call to the stream's read_some function.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @returns The number of bytes read. If an error occurs, returns the total
+ * number of bytes successfully transferred prior to the error.
+ */
+template <typename SyncReadStream, typename MutableBufferSequence,
+    typename CompletionCondition>
+std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers,
+    CompletionCondition completion_condition, asio::error_code& ec,
+    typename enable_if<
+      is_mutable_buffer_sequence<MutableBufferSequence>::value
+    >::type* = 0);
+
+#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1)
+
+/// Attempt to read a certain amount of data from a stream before returning.
+/**
+ * This function is used to read a certain number of bytes of data from a
+ * stream. The call will block until one of the following conditions is true:
+ *
+ * @li The specified dynamic buffer sequence is full (that is, it has reached
+ * maximum size).
+ *
+ * @li An error occurred.
+ *
+ * This operation is implemented in terms of zero or more calls to the stream's
+ * read_some function.
+ *
+ * @param s The stream from which the data is to be read. The type must support
+ * the SyncReadStream concept.
+ *
+ * @param buffers The dynamic buffer sequence into which the data will be read.
+ *
+ * @returns The number of bytes transferred.
+ *
+ * @throws asio::system_error Thrown on failure.
+ *
+ * @note This overload is equivalent to calling:
+ * @code asio::read(
+ *     s, buffers,
+ *     asio::transfer_all()); @endcode
+ */
+template <typename SyncReadStream, typename DynamicBuffer_v1>
+std::size_t read(SyncReadStream& s,
+    ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,
+    typename enable_if<
+      is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value
+        && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value
+    >::type* = 0);
+
+/// Attempt to read a certain amount of data from a stream before returning.
+/**
+ * This function is used to read a certain number of bytes of data from a
+ * stream. The call will block until one of the following conditions is true:
+ *
+ * @li The supplied buffer is full (that is, it has reached maximum size).
+ *
+ * @li An error occurred.
+ *
+ * This operation is implemented in terms of zero or more calls to the stream's
+ * read_some function.
+ *
+ * @param s The stream from which the data is to be read. The type must support
+ * the SyncReadStream concept.
+ *
+ * @param buffers The dynamic buffer sequence into which the data will be read.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @returns The number of bytes transferred.
+ *
+ * @note This overload is equivalent to calling:
+ * @code asio::read(
+ *     s, buffers,
+ *     asio::transfer_all(), ec); @endcode
+ */
+template <typename SyncReadStream, typename DynamicBuffer_v1>
+std::size_t read(SyncReadStream& s,
+    ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,
+    asio::error_code& ec,
+    typename enable_if<
+      is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value
+        && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value
+    >::type* = 0);
+
+/// Attempt to read a certain amount of data from a stream before returning.
+/**
+ * This function is used to read a certain number of bytes of data from a
+ * stream. The call will block until one of the following conditions is true:
+ *
+ * @li The specified dynamic buffer sequence is full (that is, it has reached
+ * maximum size).
+ *
+ * @li The completion_condition function object returns 0.
+ *
+ * This operation is implemented in terms of zero or more calls to the stream's
+ * read_some function.
+ *
+ * @param s The stream from which the data is to be read. The type must support
+ * the SyncReadStream concept.
+ *
+ * @param buffers The dynamic buffer sequence into which the data will be read.
+ *
+ * @param completion_condition The function object to be called to determine
+ * whether the read operation is complete. The signature of the function object
+ * must be:
+ * @code std::size_t completion_condition(
+ *   // Result of latest read_some operation.
+ *   const asio::error_code& error,
+ *
+ *   // Number of bytes transferred so far.
+ *   std::size_t bytes_transferred
+ * ); @endcode
+ * A return value of 0 indicates that the read operation is complete. A non-zero
+ * return value indicates the maximum number of bytes to be read on the next
+ * call to the stream's read_some function.
+ *
+ * @returns The number of bytes transferred.
+ *
+ * @throws asio::system_error Thrown on failure.
+ */
+template <typename SyncReadStream, typename DynamicBuffer_v1,
+    typename CompletionCondition>
+std::size_t read(SyncReadStream& s,
+    ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,
+    CompletionCondition completion_condition,
+    typename enable_if<
+      is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value
+        && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value
+    >::type* = 0);
+
+/// Attempt to read a certain amount of data from a stream before returning.
+/**
+ * This function is used to read a certain number of bytes of data from a
+ * stream. The call will block until one of the following conditions is true:
+ *
+ * @li The specified dynamic buffer sequence is full (that is, it has reached
+ * maximum size).
+ *
+ * @li The completion_condition function object returns 0.
+ *
+ * This operation is implemented in terms of zero or more calls to the stream's
+ * read_some function.
+ *
+ * @param s The stream from which the data is to be read. The type must support
+ * the SyncReadStream concept.
+ *
+ * @param buffers The dynamic buffer sequence into which the data will be read.
+ *
+ * @param completion_condition The function object to be called to determine
+ * whether the read operation is complete. The signature of the function object
+ * must be:
+ * @code std::size_t completion_condition(
+ *   // Result of latest read_some operation.
+ *   const asio::error_code& error,
+ *
+ *   // Number of bytes transferred so far.
+ *   std::size_t bytes_transferred
+ * ); @endcode
+ * A return value of 0 indicates that the read operation is complete. A non-zero
+ * return value indicates the maximum number of bytes to be read on the next
+ * call to the stream's read_some function.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @returns The number of bytes read. If an error occurs, returns the total
+ * number of bytes successfully transferred prior to the error.
+ */
+template <typename SyncReadStream, typename DynamicBuffer_v1,
+    typename CompletionCondition>
+std::size_t read(SyncReadStream& s,
+    ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,
+    CompletionCondition completion_condition, asio::error_code& ec,
+    typename enable_if<
+      is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value
+        && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value
+    >::type* = 0);
+
+#if !defined(ASIO_NO_EXTENSIONS)
+#if !defined(ASIO_NO_IOSTREAM)
+
+/// Attempt to read a certain amount of data from a stream before returning.
+/**
+ * This function is used to read a certain number of bytes of data from a
+ * stream. The call will block until one of the following conditions is true:
+ *
+ * @li The supplied buffer is full (that is, it has reached maximum size).
+ *
+ * @li An error occurred.
+ *
+ * This operation is implemented in terms of zero or more calls to the stream's
+ * read_some function.
+ *
+ * @param s The stream from which the data is to be read. The type must support
+ * the SyncReadStream concept.
+ *
+ * @param b The basic_streambuf object into which the data will be read.
+ *
+ * @returns The number of bytes transferred.
+ *
+ * @throws asio::system_error Thrown on failure.
+ *
+ * @note This overload is equivalent to calling:
+ * @code asio::read(
+ *     s, b,
+ *     asio::transfer_all()); @endcode
+ */
+template <typename SyncReadStream, typename Allocator>
+std::size_t read(SyncReadStream& s, basic_streambuf<Allocator>& b);
+
+/// Attempt to read a certain amount of data from a stream before returning.
+/**
+ * This function is used to read a certain number of bytes of data from a
+ * stream. The call will block until one of the following conditions is true:
+ *
+ * @li The supplied buffer is full (that is, it has reached maximum size).
+ *
+ * @li An error occurred.
+ *
+ * This operation is implemented in terms of zero or more calls to the stream's
+ * read_some function.
+ *
+ * @param s The stream from which the data is to be read. The type must support
+ * the SyncReadStream concept.
+ *
+ * @param b The basic_streambuf object into which the data will be read.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @returns The number of bytes transferred.
+ *
+ * @note This overload is equivalent to calling:
+ * @code asio::read(
+ *     s, b,
+ *     asio::transfer_all(), ec); @endcode
+ */
+template <typename SyncReadStream, typename Allocator>
+std::size_t read(SyncReadStream& s, basic_streambuf<Allocator>& b,
+    asio::error_code& ec);
+
+/// Attempt to read a certain amount of data from a stream before returning.
+/**
+ * This function is used to read a certain number of bytes of data from a
+ * stream. The call will block until one of the following conditions is true:
+ *
+ * @li The supplied buffer is full (that is, it has reached maximum size).
+ *
+ * @li The completion_condition function object returns 0.
+ *
+ * This operation is implemented in terms of zero or more calls to the stream's
+ * read_some function.
+ *
+ * @param s The stream from which the data is to be read. The type must support
+ * the SyncReadStream concept.
+ *
+ * @param b The basic_streambuf object into which the data will be read.
+ *
+ * @param completion_condition The function object to be called to determine
+ * whether the read operation is complete. The signature of the function object
+ * must be:
+ * @code std::size_t completion_condition(
+ *   // Result of latest read_some operation.
+ *   const asio::error_code& error,
+ *
+ *   // Number of bytes transferred so far.
+ *   std::size_t bytes_transferred
+ * ); @endcode
+ * A return value of 0 indicates that the read operation is complete. A non-zero
+ * return value indicates the maximum number of bytes to be read on the next
+ * call to the stream's read_some function.
+ *
+ * @returns The number of bytes transferred.
+ *
+ * @throws asio::system_error Thrown on failure.
+ */
+template <typename SyncReadStream, typename Allocator,
+    typename CompletionCondition>
+std::size_t read(SyncReadStream& s, basic_streambuf<Allocator>& b,
+    CompletionCondition completion_condition);
+
+/// Attempt to read a certain amount of data from a stream before returning.
+/**
+ * This function is used to read a certain number of bytes of data from a
+ * stream. The call will block until one of the following conditions is true:
+ *
+ * @li The supplied buffer is full (that is, it has reached maximum size).
+ *
+ * @li The completion_condition function object returns 0.
+ *
+ * This operation is implemented in terms of zero or more calls to the stream's
+ * read_some function.
+ *
+ * @param s The stream from which the data is to be read. The type must support
+ * the SyncReadStream concept.
+ *
+ * @param b The basic_streambuf object into which the data will be read.
+ *
+ * @param completion_condition The function object to be called to determine
+ * whether the read operation is complete. The signature of the function object
+ * must be:
+ * @code std::size_t completion_condition(
+ *   // Result of latest read_some operation.
+ *   const asio::error_code& error,
+ *
+ *   // Number of bytes transferred so far.
+ *   std::size_t bytes_transferred
+ * ); @endcode
+ * A return value of 0 indicates that the read operation is complete. A non-zero
+ * return value indicates the maximum number of bytes to be read on the next
+ * call to the stream's read_some function.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @returns The number of bytes read. If an error occurs, returns the total
+ * number of bytes successfully transferred prior to the error.
+ */
+template <typename SyncReadStream, typename Allocator,
+    typename CompletionCondition>
+std::size_t read(SyncReadStream& s, basic_streambuf<Allocator>& b,
+    CompletionCondition completion_condition, asio::error_code& ec);
+
+#endif // !defined(ASIO_NO_IOSTREAM)
+#endif // !defined(ASIO_NO_EXTENSIONS)
+#endif // !defined(ASIO_NO_DYNAMIC_BUFFER_V1)
+
+/// Attempt to read a certain amount of data from a stream before returning.
+/**
+ * This function is used to read a certain number of bytes of data from a
+ * stream. The call will block until one of the following conditions is true:
+ *
+ * @li The specified dynamic buffer sequence is full (that is, it has reached
+ * maximum size).
+ *
+ * @li An error occurred.
+ *
+ * This operation is implemented in terms of zero or more calls to the stream's
+ * read_some function.
+ *
+ * @param s The stream from which the data is to be read. The type must support
+ * the SyncReadStream concept.
+ *
+ * @param buffers The dynamic buffer sequence into which the data will be read.
+ *
+ * @returns The number of bytes transferred.
+ *
+ * @throws asio::system_error Thrown on failure.
+ *
+ * @note This overload is equivalent to calling:
+ * @code asio::read(
+ *     s, buffers,
+ *     asio::transfer_all()); @endcode
+ */
+template <typename SyncReadStream, typename DynamicBuffer_v2>
+std::size_t read(SyncReadStream& s, DynamicBuffer_v2 buffers,
+    typename enable_if<
+      is_dynamic_buffer_v2<DynamicBuffer_v2>::value
+    >::type* = 0);
+
+/// Attempt to read a certain amount of data from a stream before returning.
+/**
+ * This function is used to read a certain number of bytes of data from a
+ * stream. The call will block until one of the following conditions is true:
+ *
+ * @li The supplied buffer is full (that is, it has reached maximum size).
+ *
+ * @li An error occurred.
+ *
+ * This operation is implemented in terms of zero or more calls to the stream's
+ * read_some function.
+ *
+ * @param s The stream from which the data is to be read. The type must support
+ * the SyncReadStream concept.
+ *
+ * @param buffers The dynamic buffer sequence into which the data will be read.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @returns The number of bytes transferred.
+ *
+ * @note This overload is equivalent to calling:
+ * @code asio::read(
+ *     s, buffers,
+ *     asio::transfer_all(), ec); @endcode
+ */
+template <typename SyncReadStream, typename DynamicBuffer_v2>
+std::size_t read(SyncReadStream& s, DynamicBuffer_v2 buffers,
+    asio::error_code& ec,
+    typename enable_if<
+      is_dynamic_buffer_v2<DynamicBuffer_v2>::value
+    >::type* = 0);
+
+/// Attempt to read a certain amount of data from a stream before returning.
+/**
+ * This function is used to read a certain number of bytes of data from a
+ * stream. The call will block until one of the following conditions is true:
+ *
+ * @li The specified dynamic buffer sequence is full (that is, it has reached
+ * maximum size).
+ *
+ * @li The completion_condition function object returns 0.
+ *
+ * This operation is implemented in terms of zero or more calls to the stream's
+ * read_some function.
+ *
+ * @param s The stream from which the data is to be read. The type must support
+ * the SyncReadStream concept.
+ *
+ * @param buffers The dynamic buffer sequence into which the data will be read.
+ *
+ * @param completion_condition The function object to be called to determine
+ * whether the read operation is complete. The signature of the function object
+ * must be:
+ * @code std::size_t completion_condition(
+ *   // Result of latest read_some operation.
+ *   const asio::error_code& error,
+ *
+ *   // Number of bytes transferred so far.
+ *   std::size_t bytes_transferred
+ * ); @endcode
+ * A return value of 0 indicates that the read operation is complete. A non-zero
+ * return value indicates the maximum number of bytes to be read on the next
+ * call to the stream's read_some function.
+ *
+ * @returns The number of bytes transferred.
+ *
+ * @throws asio::system_error Thrown on failure.
+ */
+template <typename SyncReadStream, typename DynamicBuffer_v2,
+    typename CompletionCondition>
+std::size_t read(SyncReadStream& s, DynamicBuffer_v2 buffers,
+    CompletionCondition completion_condition,
+    typename enable_if<
+      is_dynamic_buffer_v2<DynamicBuffer_v2>::value
+    >::type* = 0);
+
+/// Attempt to read a certain amount of data from a stream before returning.
+/**
+ * This function is used to read a certain number of bytes of data from a
+ * stream. The call will block until one of the following conditions is true:
+ *
+ * @li The specified dynamic buffer sequence is full (that is, it has reached
+ * maximum size).
+ *
+ * @li The completion_condition function object returns 0.
+ *
+ * This operation is implemented in terms of zero or more calls to the stream's
+ * read_some function.
+ *
+ * @param s The stream from which the data is to be read. The type must support
+ * the SyncReadStream concept.
+ *
+ * @param buffers The dynamic buffer sequence into which the data will be read.
+ *
+ * @param completion_condition The function object to be called to determine
+ * whether the read operation is complete. The signature of the function object
+ * must be:
+ * @code std::size_t completion_condition(
+ *   // Result of latest read_some operation.
+ *   const asio::error_code& error,
+ *
+ *   // Number of bytes transferred so far.
+ *   std::size_t bytes_transferred
+ * ); @endcode
+ * A return value of 0 indicates that the read operation is complete. A non-zero
+ * return value indicates the maximum number of bytes to be read on the next
+ * call to the stream's read_some function.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @returns The number of bytes read. If an error occurs, returns the total
+ * number of bytes successfully transferred prior to the error.
+ */
+template <typename SyncReadStream, typename DynamicBuffer_v2,
+    typename CompletionCondition>
+std::size_t read(SyncReadStream& s, DynamicBuffer_v2 buffers,
+    CompletionCondition completion_condition, asio::error_code& ec,
+    typename enable_if<
+      is_dynamic_buffer_v2<DynamicBuffer_v2>::value
+    >::type* = 0);
+
+/*@}*/
+/**
+ * @defgroup async_read asio::async_read
+ *
+ * @brief The @c async_read function is a composed asynchronous operation that
+ * reads a certain amount of data from a stream before completion.
+ */
+/*@{*/
+
+/// Start an asynchronous operation to read a certain amount of data from a
+/// stream.
+/**
+ * This function is used to asynchronously read a certain number of bytes of
+ * data from a stream. The function call always returns immediately. The
+ * asynchronous operation will continue until one of the following conditions is
+ * true:
+ *
+ * @li The supplied buffers are full. That is, the bytes transferred is equal to
+ * the sum of the buffer sizes.
+ *
+ * @li An error occurred.
+ *
+ * This operation is implemented in terms of zero or more calls to the stream's
+ * async_read_some function, and is known as a <em>composed operation</em>. The
+ * program must ensure that the stream performs no other read operations (such
+ * as async_read, the stream's async_read_some function, or any other composed
+ * operations that perform reads) until this operation completes.
+ *
+ * @param s The stream from which the data is to be read. The type must support
+ * the AsyncReadStream concept.
+ *
+ * @param buffers One or more buffers into which the data will be read. The sum
+ * of the buffer sizes indicates the maximum number of bytes to read from the
+ * stream. Although the buffers object may be copied as necessary, ownership of
+ * the underlying memory blocks is retained by the caller, which must guarantee
+ * that they remain valid until the handler is called.
+ *
+ * @param handler The handler to be called when the read operation completes.
+ * Copies will be made of the handler as required. The function signature of the
+ * handler must be:
+ * @code void handler(
+ *   const asio::error_code& error, // Result of operation.
+ *
+ *   std::size_t bytes_transferred           // Number of bytes copied into the
+ *                                           // buffers. If an error occurred,
+ *                                           // this will be the  number of
+ *                                           // bytes successfully transferred
+ *                                           // prior to the error.
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. On
+ * immediate completion, invocation of the handler will be performed in a
+ * manner equivalent to using asio::post().
+ *
+ * @par Example
+ * To read into a single data buffer use the @ref buffer function as follows:
+ * @code
+ * asio::async_read(s, asio::buffer(data, size), handler);
+ * @endcode
+ * See the @ref buffer documentation for information on reading into multiple
+ * buffers in one go, and how to use it with arrays, boost::array or
+ * std::vector.
+ *
+ * @note This overload is equivalent to calling:
+ * @code asio::async_read(
+ *     s, buffers,
+ *     asio::transfer_all(),
+ *     handler); @endcode
+ */
+template <typename AsyncReadStream, typename MutableBufferSequence,
+    ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+      std::size_t)) ReadHandler
+        ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(
+          typename AsyncReadStream::executor_type)>
+ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,
+    void (asio::error_code, std::size_t))
+async_read(AsyncReadStream& s, const MutableBufferSequence& buffers,
+    ASIO_MOVE_ARG(ReadHandler) handler
+      ASIO_DEFAULT_COMPLETION_TOKEN(
+        typename AsyncReadStream::executor_type),
+    typename enable_if<
+      is_mutable_buffer_sequence<MutableBufferSequence>::value
+    >::type* = 0);
+
+/// Start an asynchronous operation to read a certain amount of data from a
+/// stream.
+/**
+ * This function is used to asynchronously read a certain number of bytes of
+ * data from a stream. The function call always returns immediately. The
+ * asynchronous operation will continue until one of the following conditions is
+ * true:
+ *
+ * @li The supplied buffers are full. That is, the bytes transferred is equal to
+ * the sum of the buffer sizes.
+ *
+ * @li The completion_condition function object returns 0.
+ *
+ * @param s The stream from which the data is to be read. The type must support
+ * the AsyncReadStream concept.
+ *
+ * @param buffers One or more buffers into which the data will be read. The sum
+ * of the buffer sizes indicates the maximum number of bytes to read from the
+ * stream. Although the buffers object may be copied as necessary, ownership of
+ * the underlying memory blocks is retained by the caller, which must guarantee
+ * that they remain valid until the handler is called.
+ *
+ * @param completion_condition The function object to be called to determine
+ * whether the read operation is complete. The signature of the function object
+ * must be:
+ * @code std::size_t completion_condition(
+ *   // Result of latest async_read_some operation.
+ *   const asio::error_code& error,
+ *
+ *   // Number of bytes transferred so far.
+ *   std::size_t bytes_transferred
+ * ); @endcode
+ * A return value of 0 indicates that the read operation is complete. A non-zero
+ * return value indicates the maximum number of bytes to be read on the next
+ * call to the stream's async_read_some function.
+ *
+ * @param handler The handler to be called when the read operation completes.
+ * Copies will be made of the handler as required. The function signature of the
+ * handler must be:
+ * @code void handler(
+ *   const asio::error_code& error, // Result of operation.
+ *
+ *   std::size_t bytes_transferred           // Number of bytes copied into the
+ *                                           // buffers. If an error occurred,
+ *                                           // this will be the  number of
+ *                                           // bytes successfully transferred
+ *                                           // prior to the error.
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. On
+ * immediate completion, invocation of the handler will be performed in a
+ * manner equivalent to using asio::post().
+ *
+ * @par Example
+ * To read into a single data buffer use the @ref buffer function as follows:
+ * @code asio::async_read(s,
+ *     asio::buffer(data, size),
+ *     asio::transfer_at_least(32),
+ *     handler); @endcode
+ * See the @ref buffer documentation for information on reading into multiple
+ * buffers in one go, and how to use it with arrays, boost::array or
+ * std::vector.
+ */
+template <typename AsyncReadStream,
+    typename MutableBufferSequence, typename CompletionCondition,
+    ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+      std::size_t)) ReadHandler
+        ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(
+          typename AsyncReadStream::executor_type)>
+ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,
+    void (asio::error_code, std::size_t))
+async_read(AsyncReadStream& s, const MutableBufferSequence& buffers,
+    CompletionCondition completion_condition,
+    ASIO_MOVE_ARG(ReadHandler) handler
+      ASIO_DEFAULT_COMPLETION_TOKEN(
+        typename AsyncReadStream::executor_type),
+    typename enable_if<
+      is_mutable_buffer_sequence<MutableBufferSequence>::value
+    >::type* = 0);
+
+#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1)
+
+/// Start an asynchronous operation to read a certain amount of data from a
+/// stream.
+/**
+ * This function is used to asynchronously read a certain number of bytes of
+ * data from a stream. The function call always returns immediately. The
+ * asynchronous operation will continue until one of the following conditions is
+ * true:
+ *
+ * @li The specified dynamic buffer sequence is full (that is, it has reached
+ * maximum size).
+ *
+ * @li An error occurred.
+ *
+ * This operation is implemented in terms of zero or more calls to the stream's
+ * async_read_some function, and is known as a <em>composed operation</em>. The
+ * program must ensure that the stream performs no other read operations (such
+ * as async_read, the stream's async_read_some function, or any other composed
+ * operations that perform reads) until this operation completes.
+ *
+ * @param s The stream from which the data is to be read. The type must support
+ * the AsyncReadStream concept.
+ *
+ * @param buffers The dynamic buffer sequence into which the data will be read.
+ * Although the buffers object may be copied as necessary, ownership of the
+ * underlying memory blocks is retained by the caller, which must guarantee
+ * that they remain valid until the handler is called.
+ *
+ * @param handler The handler to be called when the read operation completes.
+ * Copies will be made of the handler as required. The function signature of the
+ * handler must be:
+ * @code void handler(
+ *   const asio::error_code& error, // Result of operation.
+ *
+ *   std::size_t bytes_transferred           // Number of bytes copied into the
+ *                                           // buffers. If an error occurred,
+ *                                           // this will be the  number of
+ *                                           // bytes successfully transferred
+ *                                           // prior to the error.
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. On
+ * immediate completion, invocation of the handler will be performed in a
+ * manner equivalent to using asio::post().
+ *
+ * @note This overload is equivalent to calling:
+ * @code asio::async_read(
+ *     s, buffers,
+ *     asio::transfer_all(),
+ *     handler); @endcode
+ */
+template <typename AsyncReadStream, typename DynamicBuffer_v1,
+    ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+      std::size_t)) ReadHandler
+        ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(
+          typename AsyncReadStream::executor_type)>
+ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,
+    void (asio::error_code, std::size_t))
+async_read(AsyncReadStream& s,
+    ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,
+    ASIO_MOVE_ARG(ReadHandler) handler
+      ASIO_DEFAULT_COMPLETION_TOKEN(
+        typename AsyncReadStream::executor_type),
+    typename enable_if<
+      is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value
+        && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value
+    >::type* = 0);
+
+/// Start an asynchronous operation to read a certain amount of data from a
+/// stream.
+/**
+ * This function is used to asynchronously read a certain number of bytes of
+ * data from a stream. The function call always returns immediately. The
+ * asynchronous operation will continue until one of the following conditions is
+ * true:
+ *
+ * @li The specified dynamic buffer sequence is full (that is, it has reached
+ * maximum size).
+ *
+ * @li The completion_condition function object returns 0.
+ *
+ * This operation is implemented in terms of zero or more calls to the stream's
+ * async_read_some function, and is known as a <em>composed operation</em>. The
+ * program must ensure that the stream performs no other read operations (such
+ * as async_read, the stream's async_read_some function, or any other composed
+ * operations that perform reads) until this operation completes.
+ *
+ * @param s The stream from which the data is to be read. The type must support
+ * the AsyncReadStream concept.
+ *
+ * @param buffers The dynamic buffer sequence into which the data will be read.
+ * Although the buffers object may be copied as necessary, ownership of the
+ * underlying memory blocks is retained by the caller, which must guarantee
+ * that they remain valid until the handler is called.
+ *
+ * @param completion_condition The function object to be called to determine
+ * whether the read operation is complete. The signature of the function object
+ * must be:
+ * @code std::size_t completion_condition(
+ *   // Result of latest async_read_some operation.
+ *   const asio::error_code& error,
+ *
+ *   // Number of bytes transferred so far.
+ *   std::size_t bytes_transferred
+ * ); @endcode
+ * A return value of 0 indicates that the read operation is complete. A non-zero
+ * return value indicates the maximum number of bytes to be read on the next
+ * call to the stream's async_read_some function.
+ *
+ * @param handler The handler to be called when the read operation completes.
+ * Copies will be made of the handler as required. The function signature of the
+ * handler must be:
+ * @code void handler(
+ *   const asio::error_code& error, // Result of operation.
+ *
+ *   std::size_t bytes_transferred           // Number of bytes copied into the
+ *                                           // buffers. If an error occurred,
+ *                                           // this will be the  number of
+ *                                           // bytes successfully transferred
+ *                                           // prior to the error.
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. On
+ * immediate completion, invocation of the handler will be performed in a
+ * manner equivalent to using asio::post().
+ */
+template <typename AsyncReadStream,
+    typename DynamicBuffer_v1, typename CompletionCondition,
+    ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+      std::size_t)) ReadHandler
+        ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(
+          typename AsyncReadStream::executor_type)>
+ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,
+    void (asio::error_code, std::size_t))
+async_read(AsyncReadStream& s,
+    ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,
+    CompletionCondition completion_condition,
+    ASIO_MOVE_ARG(ReadHandler) handler
+      ASIO_DEFAULT_COMPLETION_TOKEN(
+        typename AsyncReadStream::executor_type),
+    typename enable_if<
+      is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value
+        && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value
+    >::type* = 0);
+
+#if !defined(ASIO_NO_EXTENSIONS)
+#if !defined(ASIO_NO_IOSTREAM)
+
+/// Start an asynchronous operation to read a certain amount of data from a
+/// stream.
+/**
+ * This function is used to asynchronously read a certain number of bytes of
+ * data from a stream. The function call always returns immediately. The
+ * asynchronous operation will continue until one of the following conditions is
+ * true:
+ *
+ * @li The supplied buffer is full (that is, it has reached maximum size).
+ *
+ * @li An error occurred.
+ *
+ * This operation is implemented in terms of zero or more calls to the stream's
+ * async_read_some function, and is known as a <em>composed operation</em>. The
+ * program must ensure that the stream performs no other read operations (such
+ * as async_read, the stream's async_read_some function, or any other composed
+ * operations that perform reads) until this operation completes.
+ *
+ * @param s The stream from which the data is to be read. The type must support
+ * the AsyncReadStream concept.
+ *
+ * @param b A basic_streambuf object into which the data will be read. Ownership
+ * of the streambuf is retained by the caller, which must guarantee that it
+ * remains valid until the handler is called.
+ *
+ * @param handler The handler to be called when the read operation completes.
+ * Copies will be made of the handler as required. The function signature of the
+ * handler must be:
+ * @code void handler(
+ *   const asio::error_code& error, // Result of operation.
+ *
+ *   std::size_t bytes_transferred           // Number of bytes copied into the
+ *                                           // buffers. If an error occurred,
+ *                                           // this will be the  number of
+ *                                           // bytes successfully transferred
+ *                                           // prior to the error.
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. On
+ * immediate completion, invocation of the handler will be performed in a
+ * manner equivalent to using asio::post().
+ *
+ * @note This overload is equivalent to calling:
+ * @code asio::async_read(
+ *     s, b,
+ *     asio::transfer_all(),
+ *     handler); @endcode
+ */
+template <typename AsyncReadStream, typename Allocator,
+    ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+      std::size_t)) ReadHandler
+        ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(
+          typename AsyncReadStream::executor_type)>
+ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,
+    void (asio::error_code, std::size_t))
+async_read(AsyncReadStream& s, basic_streambuf<Allocator>& b,
+    ASIO_MOVE_ARG(ReadHandler) handler
+      ASIO_DEFAULT_COMPLETION_TOKEN(
+        typename AsyncReadStream::executor_type));
+
+/// Start an asynchronous operation to read a certain amount of data from a
+/// stream.
+/**
+ * This function is used to asynchronously read a certain number of bytes of
+ * data from a stream. The function call always returns immediately. The
+ * asynchronous operation will continue until one of the following conditions is
+ * true:
+ *
+ * @li The supplied buffer is full (that is, it has reached maximum size).
+ *
+ * @li The completion_condition function object returns 0.
+ *
+ * This operation is implemented in terms of zero or more calls to the stream's
+ * async_read_some function, and is known as a <em>composed operation</em>. The
+ * program must ensure that the stream performs no other read operations (such
+ * as async_read, the stream's async_read_some function, or any other composed
+ * operations that perform reads) until this operation completes.
+ *
+ * @param s The stream from which the data is to be read. The type must support
+ * the AsyncReadStream concept.
+ *
+ * @param b A basic_streambuf object into which the data will be read. Ownership
+ * of the streambuf is retained by the caller, which must guarantee that it
+ * remains valid until the handler is called.
+ *
+ * @param completion_condition The function object to be called to determine
+ * whether the read operation is complete. The signature of the function object
+ * must be:
+ * @code std::size_t completion_condition(
+ *   // Result of latest async_read_some operation.
+ *   const asio::error_code& error,
+ *
+ *   // Number of bytes transferred so far.
+ *   std::size_t bytes_transferred
+ * ); @endcode
+ * A return value of 0 indicates that the read operation is complete. A non-zero
+ * return value indicates the maximum number of bytes to be read on the next
+ * call to the stream's async_read_some function.
+ *
+ * @param handler The handler to be called when the read operation completes.
+ * Copies will be made of the handler as required. The function signature of the
+ * handler must be:
+ * @code void handler(
+ *   const asio::error_code& error, // Result of operation.
+ *
+ *   std::size_t bytes_transferred           // Number of bytes copied into the
+ *                                           // buffers. If an error occurred,
+ *                                           // this will be the  number of
+ *                                           // bytes successfully transferred
+ *                                           // prior to the error.
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. On
+ * immediate completion, invocation of the handler will be performed in a
+ * manner equivalent to using asio::post().
+ */
+template <typename AsyncReadStream,
+    typename Allocator, typename CompletionCondition,
+    ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+      std::size_t)) ReadHandler
+        ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(
+          typename AsyncReadStream::executor_type)>
+ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,
+    void (asio::error_code, std::size_t))
+async_read(AsyncReadStream& s, basic_streambuf<Allocator>& b,
+    CompletionCondition completion_condition,
+    ASIO_MOVE_ARG(ReadHandler) handler
+      ASIO_DEFAULT_COMPLETION_TOKEN(
+        typename AsyncReadStream::executor_type));
+
+#endif // !defined(ASIO_NO_IOSTREAM)
+#endif // !defined(ASIO_NO_EXTENSIONS)
+#endif // !defined(ASIO_NO_DYNAMIC_BUFFER_V1)
+
+/// Start an asynchronous operation to read a certain amount of data from a
+/// stream.
+/**
+ * This function is used to asynchronously read a certain number of bytes of
+ * data from a stream. The function call always returns immediately. The
+ * asynchronous operation will continue until one of the following conditions is
+ * true:
+ *
+ * @li The specified dynamic buffer sequence is full (that is, it has reached
+ * maximum size).
+ *
+ * @li An error occurred.
+ *
+ * This operation is implemented in terms of zero or more calls to the stream's
+ * async_read_some function, and is known as a <em>composed operation</em>. The
+ * program must ensure that the stream performs no other read operations (such
+ * as async_read, the stream's async_read_some function, or any other composed
+ * operations that perform reads) until this operation completes.
+ *
+ * @param s The stream from which the data is to be read. The type must support
+ * the AsyncReadStream concept.
+ *
+ * @param buffers The dynamic buffer sequence into which the data will be read.
+ * Although the buffers object may be copied as necessary, ownership of the
+ * underlying memory blocks is retained by the caller, which must guarantee
+ * that they remain valid until the handler is called.
+ *
+ * @param handler The handler to be called when the read operation completes.
+ * Copies will be made of the handler as required. The function signature of the
+ * handler must be:
+ * @code void handler(
+ *   const asio::error_code& error, // Result of operation.
+ *
+ *   std::size_t bytes_transferred           // Number of bytes copied into the
+ *                                           // buffers. If an error occurred,
+ *                                           // this will be the  number of
+ *                                           // bytes successfully transferred
+ *                                           // prior to the error.
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. On
+ * immediate completion, invocation of the handler will be performed in a
+ * manner equivalent to using asio::post().
+ *
+ * @note This overload is equivalent to calling:
+ * @code asio::async_read(
+ *     s, buffers,
+ *     asio::transfer_all(),
+ *     handler); @endcode
+ */
+template <typename AsyncReadStream, typename DynamicBuffer_v2,
+    ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+      std::size_t)) ReadHandler
+        ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(
+          typename AsyncReadStream::executor_type)>
+ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,
+    void (asio::error_code, std::size_t))
+async_read(AsyncReadStream& s, DynamicBuffer_v2 buffers,
+    ASIO_MOVE_ARG(ReadHandler) handler
+      ASIO_DEFAULT_COMPLETION_TOKEN(
+        typename AsyncReadStream::executor_type),
+    typename enable_if<
+      is_dynamic_buffer_v2<DynamicBuffer_v2>::value
+    >::type* = 0);
+
+/// Start an asynchronous operation to read a certain amount of data from a
+/// stream.
+/**
+ * This function is used to asynchronously read a certain number of bytes of
+ * data from a stream. The function call always returns immediately. The
+ * asynchronous operation will continue until one of the following conditions is
+ * true:
+ *
+ * @li The specified dynamic buffer sequence is full (that is, it has reached
+ * maximum size).
+ *
+ * @li The completion_condition function object returns 0.
+ *
+ * This operation is implemented in terms of zero or more calls to the stream's
+ * async_read_some function, and is known as a <em>composed operation</em>. The
+ * program must ensure that the stream performs no other read operations (such
+ * as async_read, the stream's async_read_some function, or any other composed
+ * operations that perform reads) until this operation completes.
+ *
+ * @param s The stream from which the data is to be read. The type must support
+ * the AsyncReadStream concept.
+ *
+ * @param buffers The dynamic buffer sequence into which the data will be read.
+ * Although the buffers object may be copied as necessary, ownership of the
+ * underlying memory blocks is retained by the caller, which must guarantee
+ * that they remain valid until the handler is called.
+ *
+ * @param completion_condition The function object to be called to determine
+ * whether the read operation is complete. The signature of the function object
+ * must be:
+ * @code std::size_t completion_condition(
+ *   // Result of latest async_read_some operation.
+ *   const asio::error_code& error,
+ *
+ *   // Number of bytes transferred so far.
+ *   std::size_t bytes_transferred
+ * ); @endcode
+ * A return value of 0 indicates that the read operation is complete. A non-zero
+ * return value indicates the maximum number of bytes to be read on the next
+ * call to the stream's async_read_some function.
+ *
+ * @param handler The handler to be called when the read operation completes.
+ * Copies will be made of the handler as required. The function signature of the
+ * handler must be:
+ * @code void handler(
+ *   const asio::error_code& error, // Result of operation.
+ *
+ *   std::size_t bytes_transferred           // Number of bytes copied into the
+ *                                           // buffers. If an error occurred,
+ *                                           // this will be the  number of
+ *                                           // bytes successfully transferred
+ *                                           // prior to the error.
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. On
+ * immediate completion, invocation of the handler will be performed in a
+ * manner equivalent to using asio::post().
+ */
+template <typename AsyncReadStream,
+    typename DynamicBuffer_v2, typename CompletionCondition,
+    ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+      std::size_t)) ReadHandler
+        ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(
+          typename AsyncReadStream::executor_type)>
+ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,
+    void (asio::error_code, std::size_t))
+async_read(AsyncReadStream& s, DynamicBuffer_v2 buffers,
+    CompletionCondition completion_condition,
+    ASIO_MOVE_ARG(ReadHandler) handler
+      ASIO_DEFAULT_COMPLETION_TOKEN(
+        typename AsyncReadStream::executor_type),
+    typename enable_if<
+      is_dynamic_buffer_v2<DynamicBuffer_v2>::value
+    >::type* = 0);
+
+/*@}*/
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/impl/read.hpp"
+
+#endif // ASIO_READ_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/read_at.hpp b/link/modules/asio-standalone/asio/include/asio/read_at.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/read_at.hpp
@@ -0,0 +1,694 @@
+//
+// read_at.hpp
+// ~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_READ_AT_HPP
+#define ASIO_READ_AT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <cstddef>
+#include "asio/async_result.hpp"
+#include "asio/detail/cstdint.hpp"
+#include "asio/error.hpp"
+
+#if !defined(ASIO_NO_EXTENSIONS)
+# include "asio/basic_streambuf_fwd.hpp"
+#endif // !defined(ASIO_NO_EXTENSIONS)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+/**
+ * @defgroup read_at asio::read_at
+ *
+ * @brief The @c read_at function is a composed operation that reads a certain
+ * amount of data at the specified offset before returning.
+ */
+/*@{*/
+
+/// Attempt to read a certain amount of data at the specified offset before
+/// returning.
+/**
+ * This function is used to read a certain number of bytes of data from a
+ * random access device at the specified offset. The call will block until one
+ * of the following conditions is true:
+ *
+ * @li The supplied buffers are full. That is, the bytes transferred is equal to
+ * the sum of the buffer sizes.
+ *
+ * @li An error occurred.
+ *
+ * This operation is implemented in terms of zero or more calls to the device's
+ * read_some_at function.
+ *
+ * @param d The device from which the data is to be read. The type must support
+ * the SyncRandomAccessReadDevice concept.
+ *
+ * @param offset The offset at which the data will be read.
+ *
+ * @param buffers One or more buffers into which the data will be read. The sum
+ * of the buffer sizes indicates the maximum number of bytes to read from the
+ * device.
+ *
+ * @returns The number of bytes transferred.
+ *
+ * @throws asio::system_error Thrown on failure.
+ *
+ * @par Example
+ * To read into a single data buffer use the @ref buffer function as follows:
+ * @code asio::read_at(d, 42, asio::buffer(data, size)); @endcode
+ * See the @ref buffer documentation for information on reading into multiple
+ * buffers in one go, and how to use it with arrays, boost::array or
+ * std::vector.
+ *
+ * @note This overload is equivalent to calling:
+ * @code asio::read_at(
+ *     d, 42, buffers,
+ *     asio::transfer_all()); @endcode
+ */
+template <typename SyncRandomAccessReadDevice, typename MutableBufferSequence>
+std::size_t read_at(SyncRandomAccessReadDevice& d,
+    uint64_t offset, const MutableBufferSequence& buffers);
+
+/// Attempt to read a certain amount of data at the specified offset before
+/// returning.
+/**
+ * This function is used to read a certain number of bytes of data from a
+ * random access device at the specified offset. The call will block until one
+ * of the following conditions is true:
+ *
+ * @li The supplied buffers are full. That is, the bytes transferred is equal to
+ * the sum of the buffer sizes.
+ *
+ * @li An error occurred.
+ *
+ * This operation is implemented in terms of zero or more calls to the device's
+ * read_some_at function.
+ *
+ * @param d The device from which the data is to be read. The type must support
+ * the SyncRandomAccessReadDevice concept.
+ *
+ * @param offset The offset at which the data will be read.
+ *
+ * @param buffers One or more buffers into which the data will be read. The sum
+ * of the buffer sizes indicates the maximum number of bytes to read from the
+ * device.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @returns The number of bytes transferred.
+ *
+ * @par Example
+ * To read into a single data buffer use the @ref buffer function as follows:
+ * @code asio::read_at(d, 42,
+ *     asio::buffer(data, size), ec); @endcode
+ * See the @ref buffer documentation for information on reading into multiple
+ * buffers in one go, and how to use it with arrays, boost::array or
+ * std::vector.
+ *
+ * @note This overload is equivalent to calling:
+ * @code asio::read_at(
+ *     d, 42, buffers,
+ *     asio::transfer_all(), ec); @endcode
+ */
+template <typename SyncRandomAccessReadDevice, typename MutableBufferSequence>
+std::size_t read_at(SyncRandomAccessReadDevice& d,
+    uint64_t offset, const MutableBufferSequence& buffers,
+    asio::error_code& ec);
+
+/// Attempt to read a certain amount of data at the specified offset before
+/// returning.
+/**
+ * This function is used to read a certain number of bytes of data from a
+ * random access device at the specified offset. The call will block until one
+ * of the following conditions is true:
+ *
+ * @li The supplied buffers are full. That is, the bytes transferred is equal to
+ * the sum of the buffer sizes.
+ *
+ * @li The completion_condition function object returns 0.
+ *
+ * This operation is implemented in terms of zero or more calls to the device's
+ * read_some_at function.
+ *
+ * @param d The device from which the data is to be read. The type must support
+ * the SyncRandomAccessReadDevice concept.
+ *
+ * @param offset The offset at which the data will be read.
+ *
+ * @param buffers One or more buffers into which the data will be read. The sum
+ * of the buffer sizes indicates the maximum number of bytes to read from the
+ * device.
+ *
+ * @param completion_condition The function object to be called to determine
+ * whether the read operation is complete. The signature of the function object
+ * must be:
+ * @code std::size_t completion_condition(
+ *   // Result of latest read_some_at operation.
+ *   const asio::error_code& error,
+ *
+ *   // Number of bytes transferred so far.
+ *   std::size_t bytes_transferred
+ * ); @endcode
+ * A return value of 0 indicates that the read operation is complete. A non-zero
+ * return value indicates the maximum number of bytes to be read on the next
+ * call to the device's read_some_at function.
+ *
+ * @returns The number of bytes transferred.
+ *
+ * @throws asio::system_error Thrown on failure.
+ *
+ * @par Example
+ * To read into a single data buffer use the @ref buffer function as follows:
+ * @code asio::read_at(d, 42, asio::buffer(data, size),
+ *     asio::transfer_at_least(32)); @endcode
+ * See the @ref buffer documentation for information on reading into multiple
+ * buffers in one go, and how to use it with arrays, boost::array or
+ * std::vector.
+ */
+template <typename SyncRandomAccessReadDevice, typename MutableBufferSequence,
+    typename CompletionCondition>
+std::size_t read_at(SyncRandomAccessReadDevice& d,
+    uint64_t offset, const MutableBufferSequence& buffers,
+    CompletionCondition completion_condition);
+
+/// Attempt to read a certain amount of data at the specified offset before
+/// returning.
+/**
+ * This function is used to read a certain number of bytes of data from a
+ * random access device at the specified offset. The call will block until one
+ * of the following conditions is true:
+ *
+ * @li The supplied buffers are full. That is, the bytes transferred is equal to
+ * the sum of the buffer sizes.
+ *
+ * @li The completion_condition function object returns 0.
+ *
+ * This operation is implemented in terms of zero or more calls to the device's
+ * read_some_at function.
+ *
+ * @param d The device from which the data is to be read. The type must support
+ * the SyncRandomAccessReadDevice concept.
+ *
+ * @param offset The offset at which the data will be read.
+ *
+ * @param buffers One or more buffers into which the data will be read. The sum
+ * of the buffer sizes indicates the maximum number of bytes to read from the
+ * device.
+ *
+ * @param completion_condition The function object to be called to determine
+ * whether the read operation is complete. The signature of the function object
+ * must be:
+ * @code std::size_t completion_condition(
+ *   // Result of latest read_some_at operation.
+ *   const asio::error_code& error,
+ *
+ *   // Number of bytes transferred so far.
+ *   std::size_t bytes_transferred
+ * ); @endcode
+ * A return value of 0 indicates that the read operation is complete. A non-zero
+ * return value indicates the maximum number of bytes to be read on the next
+ * call to the device's read_some_at function.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @returns The number of bytes read. If an error occurs, returns the total
+ * number of bytes successfully transferred prior to the error.
+ */
+template <typename SyncRandomAccessReadDevice, typename MutableBufferSequence,
+    typename CompletionCondition>
+std::size_t read_at(SyncRandomAccessReadDevice& d,
+    uint64_t offset, const MutableBufferSequence& buffers,
+    CompletionCondition completion_condition, asio::error_code& ec);
+
+#if !defined(ASIO_NO_EXTENSIONS)
+#if !defined(ASIO_NO_IOSTREAM)
+
+/// Attempt to read a certain amount of data at the specified offset before
+/// returning.
+/**
+ * This function is used to read a certain number of bytes of data from a
+ * random access device at the specified offset. The call will block until one
+ * of the following conditions is true:
+ *
+ * @li An error occurred.
+ *
+ * This operation is implemented in terms of zero or more calls to the device's
+ * read_some_at function.
+ *
+ * @param d The device from which the data is to be read. The type must support
+ * the SyncRandomAccessReadDevice concept.
+ *
+ * @param offset The offset at which the data will be read.
+ *
+ * @param b The basic_streambuf object into which the data will be read.
+ *
+ * @returns The number of bytes transferred.
+ *
+ * @throws asio::system_error Thrown on failure.
+ *
+ * @note This overload is equivalent to calling:
+ * @code asio::read_at(
+ *     d, 42, b,
+ *     asio::transfer_all()); @endcode
+ */
+template <typename SyncRandomAccessReadDevice, typename Allocator>
+std::size_t read_at(SyncRandomAccessReadDevice& d,
+    uint64_t offset, basic_streambuf<Allocator>& b);
+
+/// Attempt to read a certain amount of data at the specified offset before
+/// returning.
+/**
+ * This function is used to read a certain number of bytes of data from a
+ * random access device at the specified offset. The call will block until one
+ * of the following conditions is true:
+ *
+ * @li An error occurred.
+ *
+ * This operation is implemented in terms of zero or more calls to the device's
+ * read_some_at function.
+ *
+ * @param d The device from which the data is to be read. The type must support
+ * the SyncRandomAccessReadDevice concept.
+ *
+ * @param offset The offset at which the data will be read.
+ *
+ * @param b The basic_streambuf object into which the data will be read.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @returns The number of bytes transferred.
+ *
+ * @note This overload is equivalent to calling:
+ * @code asio::read_at(
+ *     d, 42, b,
+ *     asio::transfer_all(), ec); @endcode
+ */
+template <typename SyncRandomAccessReadDevice, typename Allocator>
+std::size_t read_at(SyncRandomAccessReadDevice& d,
+    uint64_t offset, basic_streambuf<Allocator>& b,
+    asio::error_code& ec);
+
+/// Attempt to read a certain amount of data at the specified offset before
+/// returning.
+/**
+ * This function is used to read a certain number of bytes of data from a
+ * random access device at the specified offset. The call will block until one
+ * of the following conditions is true:
+ *
+ * @li The completion_condition function object returns 0.
+ *
+ * This operation is implemented in terms of zero or more calls to the device's
+ * read_some_at function.
+ *
+ * @param d The device from which the data is to be read. The type must support
+ * the SyncRandomAccessReadDevice concept.
+ *
+ * @param offset The offset at which the data will be read.
+ *
+ * @param b The basic_streambuf object into which the data will be read.
+ *
+ * @param completion_condition The function object to be called to determine
+ * whether the read operation is complete. The signature of the function object
+ * must be:
+ * @code std::size_t completion_condition(
+ *   // Result of latest read_some_at operation.
+ *   const asio::error_code& error,
+ *
+ *   // Number of bytes transferred so far.
+ *   std::size_t bytes_transferred
+ * ); @endcode
+ * A return value of 0 indicates that the read operation is complete. A non-zero
+ * return value indicates the maximum number of bytes to be read on the next
+ * call to the device's read_some_at function.
+ *
+ * @returns The number of bytes transferred.
+ *
+ * @throws asio::system_error Thrown on failure.
+ */
+template <typename SyncRandomAccessReadDevice, typename Allocator,
+    typename CompletionCondition>
+std::size_t read_at(SyncRandomAccessReadDevice& d,
+    uint64_t offset, basic_streambuf<Allocator>& b,
+    CompletionCondition completion_condition);
+
+/// Attempt to read a certain amount of data at the specified offset before
+/// returning.
+/**
+ * This function is used to read a certain number of bytes of data from a
+ * random access device at the specified offset. The call will block until one
+ * of the following conditions is true:
+ *
+ * @li The completion_condition function object returns 0.
+ *
+ * This operation is implemented in terms of zero or more calls to the device's
+ * read_some_at function.
+ *
+ * @param d The device from which the data is to be read. The type must support
+ * the SyncRandomAccessReadDevice concept.
+ *
+ * @param offset The offset at which the data will be read.
+ *
+ * @param b The basic_streambuf object into which the data will be read.
+ *
+ * @param completion_condition The function object to be called to determine
+ * whether the read operation is complete. The signature of the function object
+ * must be:
+ * @code std::size_t completion_condition(
+ *   // Result of latest read_some_at operation.
+ *   const asio::error_code& error,
+ *
+ *   // Number of bytes transferred so far.
+ *   std::size_t bytes_transferred
+ * ); @endcode
+ * A return value of 0 indicates that the read operation is complete. A non-zero
+ * return value indicates the maximum number of bytes to be read on the next
+ * call to the device's read_some_at function.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @returns The number of bytes read. If an error occurs, returns the total
+ * number of bytes successfully transferred prior to the error.
+ */
+template <typename SyncRandomAccessReadDevice, typename Allocator,
+    typename CompletionCondition>
+std::size_t read_at(SyncRandomAccessReadDevice& d,
+    uint64_t offset, basic_streambuf<Allocator>& b,
+    CompletionCondition completion_condition, asio::error_code& ec);
+
+#endif // !defined(ASIO_NO_IOSTREAM)
+#endif // !defined(ASIO_NO_EXTENSIONS)
+
+/*@}*/
+/**
+ * @defgroup async_read_at asio::async_read_at
+ *
+ * @brief The @c async_read_at function is a composed asynchronous operation
+ * that reads a certain amount of data at the specified offset.
+ */
+/*@{*/
+
+/// Start an asynchronous operation to read a certain amount of data at the
+/// specified offset.
+/**
+ * This function is used to asynchronously read a certain number of bytes of
+ * data from a random access device at the specified offset. The function call
+ * always returns immediately. The asynchronous operation will continue until
+ * one of the following conditions is true:
+ *
+ * @li The supplied buffers are full. That is, the bytes transferred is equal to
+ * the sum of the buffer sizes.
+ *
+ * @li An error occurred.
+ *
+ * This operation is implemented in terms of zero or more calls to the device's
+ * async_read_some_at function.
+ *
+ * @param d The device from which the data is to be read. The type must support
+ * the AsyncRandomAccessReadDevice concept.
+ *
+ * @param offset The offset at which the data will be read.
+ *
+ * @param buffers One or more buffers into which the data will be read. The sum
+ * of the buffer sizes indicates the maximum number of bytes to read from the
+ * device. Although the buffers object may be copied as necessary, ownership of
+ * the underlying memory blocks is retained by the caller, which must guarantee
+ * that they remain valid until the handler is called.
+ *
+ * @param handler The handler to be called when the read operation completes.
+ * Copies will be made of the handler as required. The function signature of the
+ * handler must be:
+ * @code void handler(
+ *   // Result of operation.
+ *   const asio::error_code& error,
+ *
+ *   // Number of bytes copied into the buffers. If an error
+ *   // occurred, this will be the number of bytes successfully
+ *   // transferred prior to the error.
+ *   std::size_t bytes_transferred
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. On
+ * immediate completion, invocation of the handler will be performed in a
+ * manner equivalent to using asio::post().
+ *
+ * @par Example
+ * To read into a single data buffer use the @ref buffer function as follows:
+ * @code
+ * asio::async_read_at(d, 42, asio::buffer(data, size), handler);
+ * @endcode
+ * See the @ref buffer documentation for information on reading into multiple
+ * buffers in one go, and how to use it with arrays, boost::array or
+ * std::vector.
+ *
+ * @note This overload is equivalent to calling:
+ * @code asio::async_read_at(
+ *     d, 42, buffers,
+ *     asio::transfer_all(),
+ *     handler); @endcode
+ */
+template <typename AsyncRandomAccessReadDevice, typename MutableBufferSequence,
+    ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+      std::size_t)) ReadHandler
+        ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(
+          typename AsyncRandomAccessReadDevice::executor_type)>
+ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,
+    void (asio::error_code, std::size_t))
+async_read_at(AsyncRandomAccessReadDevice& d, uint64_t offset,
+    const MutableBufferSequence& buffers,
+    ASIO_MOVE_ARG(ReadHandler) handler
+      ASIO_DEFAULT_COMPLETION_TOKEN(
+        typename AsyncRandomAccessReadDevice::executor_type));
+
+/// Start an asynchronous operation to read a certain amount of data at the
+/// specified offset.
+/**
+ * This function is used to asynchronously read a certain number of bytes of
+ * data from a random access device at the specified offset. The function call
+ * always returns immediately. The asynchronous operation will continue until
+ * one of the following conditions is true:
+ *
+ * @li The supplied buffers are full. That is, the bytes transferred is equal to
+ * the sum of the buffer sizes.
+ *
+ * @li The completion_condition function object returns 0.
+ *
+ * @param d The device from which the data is to be read. The type must support
+ * the AsyncRandomAccessReadDevice concept.
+ *
+ * @param offset The offset at which the data will be read.
+ *
+ * @param buffers One or more buffers into which the data will be read. The sum
+ * of the buffer sizes indicates the maximum number of bytes to read from the
+ * device. Although the buffers object may be copied as necessary, ownership of
+ * the underlying memory blocks is retained by the caller, which must guarantee
+ * that they remain valid until the handler is called.
+ *
+ * @param completion_condition The function object to be called to determine
+ * whether the read operation is complete. The signature of the function object
+ * must be:
+ * @code std::size_t completion_condition(
+ *   // Result of latest async_read_some_at operation.
+ *   const asio::error_code& error,
+ *
+ *   // Number of bytes transferred so far.
+ *   std::size_t bytes_transferred
+ * ); @endcode
+ * A return value of 0 indicates that the read operation is complete. A non-zero
+ * return value indicates the maximum number of bytes to be read on the next
+ * call to the device's async_read_some_at function.
+ *
+ * @param handler The handler to be called when the read operation completes.
+ * Copies will be made of the handler as required. The function signature of the
+ * handler must be:
+ * @code void handler(
+ *   // Result of operation.
+ *   const asio::error_code& error,
+ *
+ *   // Number of bytes copied into the buffers. If an error
+ *   // occurred, this will be the number of bytes successfully
+ *   // transferred prior to the error.
+ *   std::size_t bytes_transferred
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. On
+ * immediate completion, invocation of the handler will be performed in a
+ * manner equivalent to using asio::post().
+ *
+ * @par Example
+ * To read into a single data buffer use the @ref buffer function as follows:
+ * @code asio::async_read_at(d, 42,
+ *     asio::buffer(data, size),
+ *     asio::transfer_at_least(32),
+ *     handler); @endcode
+ * See the @ref buffer documentation for information on reading into multiple
+ * buffers in one go, and how to use it with arrays, boost::array or
+ * std::vector.
+ */
+template <typename AsyncRandomAccessReadDevice,
+    typename MutableBufferSequence, typename CompletionCondition,
+    ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+      std::size_t)) ReadHandler
+        ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(
+          typename AsyncRandomAccessReadDevice::executor_type)>
+ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,
+    void (asio::error_code, std::size_t))
+async_read_at(AsyncRandomAccessReadDevice& d,
+    uint64_t offset, const MutableBufferSequence& buffers,
+    CompletionCondition completion_condition,
+    ASIO_MOVE_ARG(ReadHandler) handler
+      ASIO_DEFAULT_COMPLETION_TOKEN(
+        typename AsyncRandomAccessReadDevice::executor_type));
+
+#if !defined(ASIO_NO_EXTENSIONS)
+#if !defined(ASIO_NO_IOSTREAM)
+
+/// Start an asynchronous operation to read a certain amount of data at the
+/// specified offset.
+/**
+ * This function is used to asynchronously read a certain number of bytes of
+ * data from a random access device at the specified offset. The function call
+ * always returns immediately. The asynchronous operation will continue until
+ * one of the following conditions is true:
+ *
+ * @li An error occurred.
+ *
+ * This operation is implemented in terms of zero or more calls to the device's
+ * async_read_some_at function.
+ *
+ * @param d The device from which the data is to be read. The type must support
+ * the AsyncRandomAccessReadDevice concept.
+ *
+ * @param offset The offset at which the data will be read.
+ *
+ * @param b A basic_streambuf object into which the data will be read. Ownership
+ * of the streambuf is retained by the caller, which must guarantee that it
+ * remains valid until the handler is called.
+ *
+ * @param handler The handler to be called when the read operation completes.
+ * Copies will be made of the handler as required. The function signature of the
+ * handler must be:
+ * @code void handler(
+ *   // Result of operation.
+ *   const asio::error_code& error,
+ *
+ *   // Number of bytes copied into the buffers. If an error
+ *   // occurred, this will be the number of bytes successfully
+ *   // transferred prior to the error.
+ *   std::size_t bytes_transferred
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. On
+ * immediate completion, invocation of the handler will be performed in a
+ * manner equivalent to using asio::post().
+ *
+ * @note This overload is equivalent to calling:
+ * @code asio::async_read_at(
+ *     d, 42, b,
+ *     asio::transfer_all(),
+ *     handler); @endcode
+ */
+template <typename AsyncRandomAccessReadDevice, typename Allocator,
+    ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+      std::size_t)) ReadHandler
+        ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(
+          typename AsyncRandomAccessReadDevice::executor_type)>
+ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,
+    void (asio::error_code, std::size_t))
+async_read_at(AsyncRandomAccessReadDevice& d,
+    uint64_t offset, basic_streambuf<Allocator>& b,
+    ASIO_MOVE_ARG(ReadHandler) handler
+      ASIO_DEFAULT_COMPLETION_TOKEN(
+        typename AsyncRandomAccessReadDevice::executor_type));
+
+/// Start an asynchronous operation to read a certain amount of data at the
+/// specified offset.
+/**
+ * This function is used to asynchronously read a certain number of bytes of
+ * data from a random access device at the specified offset. The function call
+ * always returns immediately. The asynchronous operation will continue until
+ * one of the following conditions is true:
+ *
+ * @li The completion_condition function object returns 0.
+ *
+ * This operation is implemented in terms of zero or more calls to the device's
+ * async_read_some_at function.
+ *
+ * @param d The device from which the data is to be read. The type must support
+ * the AsyncRandomAccessReadDevice concept.
+ *
+ * @param offset The offset at which the data will be read.
+ *
+ * @param b A basic_streambuf object into which the data will be read. Ownership
+ * of the streambuf is retained by the caller, which must guarantee that it
+ * remains valid until the handler is called.
+ *
+ * @param completion_condition The function object to be called to determine
+ * whether the read operation is complete. The signature of the function object
+ * must be:
+ * @code std::size_t completion_condition(
+ *   // Result of latest async_read_some_at operation.
+ *   const asio::error_code& error,
+ *
+ *   // Number of bytes transferred so far.
+ *   std::size_t bytes_transferred
+ * ); @endcode
+ * A return value of 0 indicates that the read operation is complete. A non-zero
+ * return value indicates the maximum number of bytes to be read on the next
+ * call to the device's async_read_some_at function.
+ *
+ * @param handler The handler to be called when the read operation completes.
+ * Copies will be made of the handler as required. The function signature of the
+ * handler must be:
+ * @code void handler(
+ *   // Result of operation.
+ *   const asio::error_code& error,
+ *
+ *   // Number of bytes copied into the buffers. If an error
+ *   // occurred, this will be the number of bytes successfully
+ *   // transferred prior to the error.
+ *   std::size_t bytes_transferred
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. On
+ * immediate completion, invocation of the handler will be performed in a
+ * manner equivalent to using asio::post().
+ */
+template <typename AsyncRandomAccessReadDevice,
+    typename Allocator, typename CompletionCondition,
+    ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+      std::size_t)) ReadHandler
+        ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(
+          typename AsyncRandomAccessReadDevice::executor_type)>
+ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,
+    void (asio::error_code, std::size_t))
+async_read_at(AsyncRandomAccessReadDevice& d,
+    uint64_t offset, basic_streambuf<Allocator>& b,
+    CompletionCondition completion_condition,
+    ASIO_MOVE_ARG(ReadHandler) handler
+      ASIO_DEFAULT_COMPLETION_TOKEN(
+        typename AsyncRandomAccessReadDevice::executor_type));
+
+#endif // !defined(ASIO_NO_IOSTREAM)
+#endif // !defined(ASIO_NO_EXTENSIONS)
+
+/*@}*/
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/impl/read_at.hpp"
+
+#endif // ASIO_READ_AT_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/read_until.hpp b/link/modules/asio-standalone/asio/include/asio/read_until.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/read_until.hpp
@@ -0,0 +1,2863 @@
+//
+// read_until.hpp
+// ~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_READ_UNTIL_HPP
+#define ASIO_READ_UNTIL_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <cstddef>
+#include <string>
+#include "asio/async_result.hpp"
+#include "asio/buffer.hpp"
+#include "asio/detail/regex_fwd.hpp"
+#include "asio/detail/string_view.hpp"
+#include "asio/detail/type_traits.hpp"
+#include "asio/error.hpp"
+
+#if !defined(ASIO_NO_EXTENSIONS)
+# include "asio/basic_streambuf_fwd.hpp"
+#endif // !defined(ASIO_NO_EXTENSIONS)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+namespace detail
+{
+  char (&has_result_type_helper(...))[2];
+
+  template <typename T>
+  char has_result_type_helper(T*, typename T::result_type* = 0);
+
+  template <typename T>
+  struct has_result_type
+  {
+    enum { value = (sizeof((has_result_type_helper)((T*)(0))) == 1) };
+  };
+} // namespace detail
+
+/// Type trait used to determine whether a type can be used as a match condition
+/// function with read_until and async_read_until.
+template <typename T>
+struct is_match_condition
+{
+#if defined(GENERATING_DOCUMENTATION)
+  /// The value member is true if the type may be used as a match condition.
+  static const bool value;
+#else
+  enum
+  {
+    value = asio::is_function<
+        typename asio::remove_pointer<T>::type>::value
+      || detail::has_result_type<T>::value
+  };
+#endif
+};
+
+/**
+ * @defgroup read_until asio::read_until
+ *
+ * @brief The @c read_until function is a composed operation that reads data
+ * into a dynamic buffer sequence, or into a streambuf, until it contains a
+ * delimiter, matches a regular expression, or a function object indicates a
+ * match.
+ */
+/*@{*/
+
+#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1)
+
+/// Read data into a dynamic buffer sequence until it contains a specified
+/// delimiter.
+/**
+ * This function is used to read data into the specified dynamic buffer
+ * sequence until the dynamic buffer sequence's get area contains the specified
+ * delimiter. The call will block until one of the following conditions is
+ * true:
+ *
+ * @li The get area of the dynamic buffer sequence contains the specified
+ * delimiter.
+ *
+ * @li An error occurred.
+ *
+ * This operation is implemented in terms of zero or more calls to the stream's
+ * read_some function. If the dynamic buffer sequence's get area already
+ * contains the delimiter, the function returns immediately.
+ *
+ * @param s The stream from which the data is to be read. The type must support
+ * the SyncReadStream concept.
+ *
+ * @param buffers The dynamic buffer sequence into which the data will be read.
+ *
+ * @param delim The delimiter character.
+ *
+ * @returns The number of bytes in the dynamic buffer sequence's get area up to
+ * and including the delimiter.
+ *
+ * @throws asio::system_error Thrown on failure.
+ *
+ * @note After a successful read_until operation, the dynamic buffer sequence
+ * may contain additional data beyond the delimiter. An application will
+ * typically leave that data in the dynamic buffer sequence for a subsequent
+ * read_until operation to examine.
+ *
+ * @par Example
+ * To read data into a @c std::string until a newline is encountered:
+ * @code std::string data;
+ * std::size_t n = asio::read_until(s,
+ *     asio::dynamic_buffer(data), '\n');
+ * std::string line = data.substr(0, n);
+ * data.erase(0, n); @endcode
+ * After the @c read_until operation completes successfully, the string @c data
+ * contains the delimiter:
+ * @code { 'a', 'b', ..., 'c', '\n', 'd', 'e', ... } @endcode
+ * The call to @c substr then extracts the data up to and including the
+ * delimiter, so that the string @c line contains:
+ * @code { 'a', 'b', ..., 'c', '\n' } @endcode
+ * After the call to @c erase, the remaining data is left in the buffer @c b as
+ * follows:
+ * @code { 'd', 'e', ... } @endcode
+ * This data may be the start of a new line, to be extracted by a subsequent
+ * @c read_until operation.
+ */
+template <typename SyncReadStream, typename DynamicBuffer_v1>
+std::size_t read_until(SyncReadStream& s,
+    ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, char delim,
+    typename enable_if<
+      is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value
+        && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value
+    >::type* = 0);
+
+/// Read data into a dynamic buffer sequence until it contains a specified
+/// delimiter.
+/**
+ * This function is used to read data into the specified dynamic buffer
+ * sequence until the dynamic buffer sequence's get area contains the specified
+ * delimiter. The call will block until one of the following conditions is
+ * true:
+ *
+ * @li The get area of the dynamic buffer sequence contains the specified
+ * delimiter.
+ *
+ * @li An error occurred.
+ *
+ * This operation is implemented in terms of zero or more calls to the stream's
+ * read_some function. If the dynamic buffer sequence's get area already
+ * contains the delimiter, the function returns immediately.
+ *
+ * @param s The stream from which the data is to be read. The type must support
+ * the SyncReadStream concept.
+ *
+ * @param buffers The dynamic buffer sequence into which the data will be read.
+ *
+ * @param delim The delimiter character.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @returns The number of bytes in the dynamic buffer sequence's get area up to
+ * and including the delimiter. Returns 0 if an error occurred.
+ *
+ * @note After a successful read_until operation, the dynamic buffer sequence
+ * may contain additional data beyond the delimiter. An application will
+ * typically leave that data in the dynamic buffer sequence for a subsequent
+ * read_until operation to examine.
+ */
+template <typename SyncReadStream, typename DynamicBuffer_v1>
+std::size_t read_until(SyncReadStream& s,
+    ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,
+    char delim, asio::error_code& ec,
+    typename enable_if<
+      is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value
+        && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value
+    >::type* = 0);
+
+/// Read data into a dynamic buffer sequence until it contains a specified
+/// delimiter.
+/**
+ * This function is used to read data into the specified dynamic buffer
+ * sequence until the dynamic buffer sequence's get area contains the specified
+ * delimiter. The call will block until one of the following conditions is
+ * true:
+ *
+ * @li The get area of the dynamic buffer sequence contains the specified
+ * delimiter.
+ *
+ * @li An error occurred.
+ *
+ * This operation is implemented in terms of zero or more calls to the stream's
+ * read_some function. If the dynamic buffer sequence's get area already
+ * contains the delimiter, the function returns immediately.
+ *
+ * @param s The stream from which the data is to be read. The type must support
+ * the SyncReadStream concept.
+ *
+ * @param buffers The dynamic buffer sequence into which the data will be read.
+ *
+ * @param delim The delimiter string.
+ *
+ * @returns The number of bytes in the dynamic buffer sequence's get area up to
+ * and including the delimiter.
+ *
+ * @note After a successful read_until operation, the dynamic buffer sequence
+ * may contain additional data beyond the delimiter. An application will
+ * typically leave that data in the dynamic buffer sequence for a subsequent
+ * read_until operation to examine.
+ *
+ * @par Example
+ * To read data into a @c std::string until a CR-LF sequence is encountered:
+ * @code std::string data;
+ * std::size_t n = asio::read_until(s,
+ *     asio::dynamic_buffer(data), "\r\n");
+ * std::string line = data.substr(0, n);
+ * data.erase(0, n); @endcode
+ * After the @c read_until operation completes successfully, the string @c data
+ * contains the delimiter:
+ * @code { 'a', 'b', ..., 'c', '\r', '\n', 'd', 'e', ... } @endcode
+ * The call to @c substr then extracts the data up to and including the
+ * delimiter, so that the string @c line contains:
+ * @code { 'a', 'b', ..., 'c', '\r', '\n' } @endcode
+ * After the call to @c erase, the remaining data is left in the buffer @c b as
+ * follows:
+ * @code { 'd', 'e', ... } @endcode
+ * This data may be the start of a new line, to be extracted by a subsequent
+ * @c read_until operation.
+ */
+template <typename SyncReadStream, typename DynamicBuffer_v1>
+std::size_t read_until(SyncReadStream& s,
+    ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,
+    ASIO_STRING_VIEW_PARAM delim,
+    typename enable_if<
+      is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value
+        && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value
+    >::type* = 0);
+
+/// Read data into a dynamic buffer sequence until it contains a specified
+/// delimiter.
+/**
+ * This function is used to read data into the specified dynamic buffer
+ * sequence until the dynamic buffer sequence's get area contains the specified
+ * delimiter. The call will block until one of the following conditions is
+ * true:
+ *
+ * @li The get area of the dynamic buffer sequence contains the specified
+ * delimiter.
+ *
+ * @li An error occurred.
+ *
+ * This operation is implemented in terms of zero or more calls to the stream's
+ * read_some function. If the dynamic buffer sequence's get area already
+ * contains the delimiter, the function returns immediately.
+ *
+ * @param s The stream from which the data is to be read. The type must support
+ * the SyncReadStream concept.
+ *
+ * @param buffers The dynamic buffer sequence into which the data will be read.
+ *
+ * @param delim The delimiter string.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @returns The number of bytes in the dynamic buffer sequence's get area up to
+ * and including the delimiter. Returns 0 if an error occurred.
+ *
+ * @note After a successful read_until operation, the dynamic buffer sequence
+ * may contain additional data beyond the delimiter. An application will
+ * typically leave that data in the dynamic buffer sequence for a subsequent
+ * read_until operation to examine.
+ */
+template <typename SyncReadStream, typename DynamicBuffer_v1>
+std::size_t read_until(SyncReadStream& s,
+    ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,
+    ASIO_STRING_VIEW_PARAM delim,
+    asio::error_code& ec,
+    typename enable_if<
+      is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value
+        && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value
+    >::type* = 0);
+
+#if !defined(ASIO_NO_EXTENSIONS)
+#if defined(ASIO_HAS_BOOST_REGEX) \
+  || defined(GENERATING_DOCUMENTATION)
+
+/// Read data into a dynamic buffer sequence until some part of the data it
+/// contains matches a regular expression.
+/**
+ * This function is used to read data into the specified dynamic buffer
+ * sequence until the dynamic buffer sequence's get area contains some data
+ * that matches a regular expression. The call will block until one of the
+ * following conditions is true:
+ *
+ * @li A substring of the dynamic buffer sequence's get area matches the
+ * regular expression.
+ *
+ * @li An error occurred.
+ *
+ * This operation is implemented in terms of zero or more calls to the stream's
+ * read_some function. If the dynamic buffer sequence's get area already
+ * contains data that matches the regular expression, the function returns
+ * immediately.
+ *
+ * @param s The stream from which the data is to be read. The type must support
+ * the SyncReadStream concept.
+ *
+ * @param buffers A dynamic buffer sequence into which the data will be read.
+ *
+ * @param expr The regular expression.
+ *
+ * @returns The number of bytes in the dynamic buffer sequence's get area up to
+ * and including the substring that matches the regular expression.
+ *
+ * @throws asio::system_error Thrown on failure.
+ *
+ * @note After a successful read_until operation, the dynamic buffer sequence
+ * may contain additional data beyond that which matched the regular
+ * expression. An application will typically leave that data in the dynamic
+ * buffer sequence for a subsequent read_until operation to examine.
+ *
+ * @par Example
+ * To read data into a @c std::string until a CR-LF sequence is encountered:
+ * @code std::string data;
+ * std::size_t n = asio::read_until(s,
+ *     asio::dynamic_buffer(data), boost::regex("\r\n"));
+ * std::string line = data.substr(0, n);
+ * data.erase(0, n); @endcode
+ * After the @c read_until operation completes successfully, the string @c data
+ * contains the delimiter:
+ * @code { 'a', 'b', ..., 'c', '\r', '\n', 'd', 'e', ... } @endcode
+ * The call to @c substr then extracts the data up to and including the
+ * delimiter, so that the string @c line contains:
+ * @code { 'a', 'b', ..., 'c', '\r', '\n' } @endcode
+ * After the call to @c erase, the remaining data is left in the buffer @c b as
+ * follows:
+ * @code { 'd', 'e', ... } @endcode
+ * This data may be the start of a new line, to be extracted by a subsequent
+ * @c read_until operation.
+ */
+template <typename SyncReadStream, typename DynamicBuffer_v1>
+std::size_t read_until(SyncReadStream& s,
+    ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,
+    const boost::regex& expr,
+    typename enable_if<
+      is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value
+        && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value
+    >::type* = 0);
+
+/// Read data into a dynamic buffer sequence until some part of the data it
+/// contains matches a regular expression.
+/**
+ * This function is used to read data into the specified dynamic buffer
+ * sequence until the dynamic buffer sequence's get area contains some data
+ * that matches a regular expression. The call will block until one of the
+ * following conditions is true:
+ *
+ * @li A substring of the dynamic buffer sequence's get area matches the
+ * regular expression.
+ *
+ * @li An error occurred.
+ *
+ * This operation is implemented in terms of zero or more calls to the stream's
+ * read_some function. If the dynamic buffer sequence's get area already
+ * contains data that matches the regular expression, the function returns
+ * immediately.
+ *
+ * @param s The stream from which the data is to be read. The type must support
+ * the SyncReadStream concept.
+ *
+ * @param buffers A dynamic buffer sequence into which the data will be read.
+ *
+ * @param expr The regular expression.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @returns The number of bytes in the dynamic buffer sequence's get area up to
+ * and including the substring that matches the regular expression. Returns 0
+ * if an error occurred.
+ *
+ * @note After a successful read_until operation, the dynamic buffer sequence
+ * may contain additional data beyond that which matched the regular
+ * expression. An application will typically leave that data in the dynamic
+ * buffer sequence for a subsequent read_until operation to examine.
+ */
+template <typename SyncReadStream, typename DynamicBuffer_v1>
+std::size_t read_until(SyncReadStream& s,
+    ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,
+    const boost::regex& expr, asio::error_code& ec,
+    typename enable_if<
+      is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value
+        && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value
+    >::type* = 0);
+
+#endif // defined(ASIO_HAS_BOOST_REGEX)
+       // || defined(GENERATING_DOCUMENTATION)
+
+/// Read data into a dynamic buffer sequence until a function object indicates a
+/// match.
+
+/**
+ * This function is used to read data into the specified dynamic buffer
+ * sequence until a user-defined match condition function object, when applied
+ * to the data contained in the dynamic buffer sequence, indicates a successful
+ * match. The call will block until one of the following conditions is true:
+ *
+ * @li The match condition function object returns a std::pair where the second
+ * element evaluates to true.
+ *
+ * @li An error occurred.
+ *
+ * This operation is implemented in terms of zero or more calls to the stream's
+ * read_some function. If the match condition function object already indicates
+ * a match, the function returns immediately.
+ *
+ * @param s The stream from which the data is to be read. The type must support
+ * the SyncReadStream concept.
+ *
+ * @param buffers A dynamic buffer sequence into which the data will be read.
+ *
+ * @param match_condition The function object to be called to determine whether
+ * a match exists. The signature of the function object must be:
+ * @code pair<iterator, bool> match_condition(iterator begin, iterator end);
+ * @endcode
+ * where @c iterator represents the type:
+ * @code buffers_iterator<typename DynamicBuffer_v1::const_buffers_type>
+ * @endcode
+ * The iterator parameters @c begin and @c end define the range of bytes to be
+ * scanned to determine whether there is a match. The @c first member of the
+ * return value is an iterator marking one-past-the-end of the bytes that have
+ * been consumed by the match function. This iterator is used to calculate the
+ * @c begin parameter for any subsequent invocation of the match condition. The
+ * @c second member of the return value is true if a match has been found, false
+ * otherwise.
+ *
+ * @returns The number of bytes in the dynamic_buffer's get area that
+ * have been fully consumed by the match function.
+ *
+ * @throws asio::system_error Thrown on failure.
+ *
+ * @note After a successful read_until operation, the dynamic buffer sequence
+ * may contain additional data beyond that which matched the function object.
+ * An application will typically leave that data in the dynamic buffer sequence
+ * for a subsequent read_until operation to examine.
+
+ * @note The default implementation of the @c is_match_condition type trait
+ * evaluates to true for function pointers and function objects with a
+ * @c result_type typedef. It must be specialised for other user-defined
+ * function objects.
+ *
+ * @par Examples
+ * To read data into a dynamic buffer sequence until whitespace is encountered:
+ * @code typedef asio::buffers_iterator<
+ *     asio::const_buffers_1> iterator;
+ *
+ * std::pair<iterator, bool>
+ * match_whitespace(iterator begin, iterator end)
+ * {
+ *   iterator i = begin;
+ *   while (i != end)
+ *     if (std::isspace(*i++))
+ *       return std::make_pair(i, true);
+ *   return std::make_pair(i, false);
+ * }
+ * ...
+ * std::string data;
+ * asio::read_until(s, data, match_whitespace);
+ * @endcode
+ *
+ * To read data into a @c std::string until a matching character is found:
+ * @code class match_char
+ * {
+ * public:
+ *   explicit match_char(char c) : c_(c) {}
+ *
+ *   template <typename Iterator>
+ *   std::pair<Iterator, bool> operator()(
+ *       Iterator begin, Iterator end) const
+ *   {
+ *     Iterator i = begin;
+ *     while (i != end)
+ *       if (c_ == *i++)
+ *         return std::make_pair(i, true);
+ *     return std::make_pair(i, false);
+ *   }
+ *
+ * private:
+ *   char c_;
+ * };
+ *
+ * namespace asio {
+ *   template <> struct is_match_condition<match_char>
+ *     : public boost::true_type {};
+ * } // namespace asio
+ * ...
+ * std::string data;
+ * asio::read_until(s, data, match_char('a'));
+ * @endcode
+ */
+template <typename SyncReadStream,
+    typename DynamicBuffer_v1, typename MatchCondition>
+std::size_t read_until(SyncReadStream& s,
+    ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,
+    MatchCondition match_condition,
+    typename enable_if<
+      is_match_condition<MatchCondition>::value
+        && is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value
+        && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value
+    >::type* = 0);
+
+/// Read data into a dynamic buffer sequence until a function object indicates a
+/// match.
+/**
+ * This function is used to read data into the specified dynamic buffer
+ * sequence until a user-defined match condition function object, when applied
+ * to the data contained in the dynamic buffer sequence, indicates a successful
+ * match. The call will block until one of the following conditions is true:
+ *
+ * @li The match condition function object returns a std::pair where the second
+ * element evaluates to true.
+ *
+ * @li An error occurred.
+ *
+ * This operation is implemented in terms of zero or more calls to the stream's
+ * read_some function. If the match condition function object already indicates
+ * a match, the function returns immediately.
+ *
+ * @param s The stream from which the data is to be read. The type must support
+ * the SyncReadStream concept.
+ *
+ * @param buffers A dynamic buffer sequence into which the data will be read.
+ *
+ * @param match_condition The function object to be called to determine whether
+ * a match exists. The signature of the function object must be:
+ * @code pair<iterator, bool> match_condition(iterator begin, iterator end);
+ * @endcode
+ * where @c iterator represents the type:
+ * @code buffers_iterator<DynamicBuffer_v1::const_buffers_type>
+ * @endcode
+ * The iterator parameters @c begin and @c end define the range of bytes to be
+ * scanned to determine whether there is a match. The @c first member of the
+ * return value is an iterator marking one-past-the-end of the bytes that have
+ * been consumed by the match function. This iterator is used to calculate the
+ * @c begin parameter for any subsequent invocation of the match condition. The
+ * @c second member of the return value is true if a match has been found, false
+ * otherwise.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @returns The number of bytes in the dynamic buffer sequence's get area that
+ * have been fully consumed by the match function. Returns 0 if an error
+ * occurred.
+ *
+ * @note After a successful read_until operation, the dynamic buffer sequence
+ * may contain additional data beyond that which matched the function object.
+ * An application will typically leave that data in the dynamic buffer sequence
+ * for a subsequent read_until operation to examine.
+ *
+ * @note The default implementation of the @c is_match_condition type trait
+ * evaluates to true for function pointers and function objects with a
+ * @c result_type typedef. It must be specialised for other user-defined
+ * function objects.
+ */
+template <typename SyncReadStream,
+    typename DynamicBuffer_v1, typename MatchCondition>
+std::size_t read_until(SyncReadStream& s,
+    ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,
+    MatchCondition match_condition, asio::error_code& ec,
+    typename enable_if<
+      is_match_condition<MatchCondition>::value
+        && is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value
+        && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value
+    >::type* = 0);
+
+#if !defined(ASIO_NO_IOSTREAM)
+
+/// Read data into a streambuf until it contains a specified delimiter.
+/**
+ * This function is used to read data into the specified streambuf until the
+ * streambuf's get area contains the specified delimiter. The call will block
+ * until one of the following conditions is true:
+ *
+ * @li The get area of the streambuf contains the specified delimiter.
+ *
+ * @li An error occurred.
+ *
+ * This operation is implemented in terms of zero or more calls to the stream's
+ * read_some function. If the streambuf's get area already contains the
+ * delimiter, the function returns immediately.
+ *
+ * @param s The stream from which the data is to be read. The type must support
+ * the SyncReadStream concept.
+ *
+ * @param b A streambuf object into which the data will be read.
+ *
+ * @param delim The delimiter character.
+ *
+ * @returns The number of bytes in the streambuf's get area up to and including
+ * the delimiter.
+ *
+ * @throws asio::system_error Thrown on failure.
+ *
+ * @note After a successful read_until operation, the streambuf may contain
+ * additional data beyond the delimiter. An application will typically leave
+ * that data in the streambuf for a subsequent read_until operation to examine.
+ *
+ * @par Example
+ * To read data into a streambuf until a newline is encountered:
+ * @code asio::streambuf b;
+ * asio::read_until(s, b, '\n');
+ * std::istream is(&b);
+ * std::string line;
+ * std::getline(is, line); @endcode
+ * After the @c read_until operation completes successfully, the buffer @c b
+ * contains the delimiter:
+ * @code { 'a', 'b', ..., 'c', '\n', 'd', 'e', ... } @endcode
+ * The call to @c std::getline then extracts the data up to and including the
+ * newline (which is discarded), so that the string @c line contains:
+ * @code { 'a', 'b', ..., 'c' } @endcode
+ * The remaining data is left in the buffer @c b as follows:
+ * @code { 'd', 'e', ... } @endcode
+ * This data may be the start of a new line, to be extracted by a subsequent
+ * @c read_until operation.
+ */
+template <typename SyncReadStream, typename Allocator>
+std::size_t read_until(SyncReadStream& s,
+    asio::basic_streambuf<Allocator>& b, char delim);
+
+/// Read data into a streambuf until it contains a specified delimiter.
+/**
+ * This function is used to read data into the specified streambuf until the
+ * streambuf's get area contains the specified delimiter. The call will block
+ * until one of the following conditions is true:
+ *
+ * @li The get area of the streambuf contains the specified delimiter.
+ *
+ * @li An error occurred.
+ *
+ * This operation is implemented in terms of zero or more calls to the stream's
+ * read_some function. If the streambuf's get area already contains the
+ * delimiter, the function returns immediately.
+ *
+ * @param s The stream from which the data is to be read. The type must support
+ * the SyncReadStream concept.
+ *
+ * @param b A streambuf object into which the data will be read.
+ *
+ * @param delim The delimiter character.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @returns The number of bytes in the streambuf's get area up to and including
+ * the delimiter. Returns 0 if an error occurred.
+ *
+ * @note After a successful read_until operation, the streambuf may contain
+ * additional data beyond the delimiter. An application will typically leave
+ * that data in the streambuf for a subsequent read_until operation to examine.
+ */
+template <typename SyncReadStream, typename Allocator>
+std::size_t read_until(SyncReadStream& s,
+    asio::basic_streambuf<Allocator>& b, char delim,
+    asio::error_code& ec);
+
+/// Read data into a streambuf until it contains a specified delimiter.
+/**
+ * This function is used to read data into the specified streambuf until the
+ * streambuf's get area contains the specified delimiter. The call will block
+ * until one of the following conditions is true:
+ *
+ * @li The get area of the streambuf contains the specified delimiter.
+ *
+ * @li An error occurred.
+ *
+ * This operation is implemented in terms of zero or more calls to the stream's
+ * read_some function. If the streambuf's get area already contains the
+ * delimiter, the function returns immediately.
+ *
+ * @param s The stream from which the data is to be read. The type must support
+ * the SyncReadStream concept.
+ *
+ * @param b A streambuf object into which the data will be read.
+ *
+ * @param delim The delimiter string.
+ *
+ * @returns The number of bytes in the streambuf's get area up to and including
+ * the delimiter.
+ *
+ * @throws asio::system_error Thrown on failure.
+ *
+ * @note After a successful read_until operation, the streambuf may contain
+ * additional data beyond the delimiter. An application will typically leave
+ * that data in the streambuf for a subsequent read_until operation to examine.
+ *
+ * @par Example
+ * To read data into a streambuf until a newline is encountered:
+ * @code asio::streambuf b;
+ * asio::read_until(s, b, "\r\n");
+ * std::istream is(&b);
+ * std::string line;
+ * std::getline(is, line); @endcode
+ * After the @c read_until operation completes successfully, the buffer @c b
+ * contains the delimiter:
+ * @code { 'a', 'b', ..., 'c', '\r', '\n', 'd', 'e', ... } @endcode
+ * The call to @c std::getline then extracts the data up to and including the
+ * newline (which is discarded), so that the string @c line contains:
+ * @code { 'a', 'b', ..., 'c', '\r' } @endcode
+ * The remaining data is left in the buffer @c b as follows:
+ * @code { 'd', 'e', ... } @endcode
+ * This data may be the start of a new line, to be extracted by a subsequent
+ * @c read_until operation.
+ */
+template <typename SyncReadStream, typename Allocator>
+std::size_t read_until(SyncReadStream& s,
+    asio::basic_streambuf<Allocator>& b,
+    ASIO_STRING_VIEW_PARAM delim);
+
+/// Read data into a streambuf until it contains a specified delimiter.
+/**
+ * This function is used to read data into the specified streambuf until the
+ * streambuf's get area contains the specified delimiter. The call will block
+ * until one of the following conditions is true:
+ *
+ * @li The get area of the streambuf contains the specified delimiter.
+ *
+ * @li An error occurred.
+ *
+ * This operation is implemented in terms of zero or more calls to the stream's
+ * read_some function. If the streambuf's get area already contains the
+ * delimiter, the function returns immediately.
+ *
+ * @param s The stream from which the data is to be read. The type must support
+ * the SyncReadStream concept.
+ *
+ * @param b A streambuf object into which the data will be read.
+ *
+ * @param delim The delimiter string.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @returns The number of bytes in the streambuf's get area up to and including
+ * the delimiter. Returns 0 if an error occurred.
+ *
+ * @note After a successful read_until operation, the streambuf may contain
+ * additional data beyond the delimiter. An application will typically leave
+ * that data in the streambuf for a subsequent read_until operation to examine.
+ */
+template <typename SyncReadStream, typename Allocator>
+std::size_t read_until(SyncReadStream& s,
+    asio::basic_streambuf<Allocator>& b,
+    ASIO_STRING_VIEW_PARAM delim, asio::error_code& ec);
+
+#if defined(ASIO_HAS_BOOST_REGEX) \
+  || defined(GENERATING_DOCUMENTATION)
+
+/// Read data into a streambuf until some part of the data it contains matches
+/// a regular expression.
+/**
+ * This function is used to read data into the specified streambuf until the
+ * streambuf's get area contains some data that matches a regular expression.
+ * The call will block until one of the following conditions is true:
+ *
+ * @li A substring of the streambuf's get area matches the regular expression.
+ *
+ * @li An error occurred.
+ *
+ * This operation is implemented in terms of zero or more calls to the stream's
+ * read_some function. If the streambuf's get area already contains data that
+ * matches the regular expression, the function returns immediately.
+ *
+ * @param s The stream from which the data is to be read. The type must support
+ * the SyncReadStream concept.
+ *
+ * @param b A streambuf object into which the data will be read.
+ *
+ * @param expr The regular expression.
+ *
+ * @returns The number of bytes in the streambuf's get area up to and including
+ * the substring that matches the regular expression.
+ *
+ * @throws asio::system_error Thrown on failure.
+ *
+ * @note After a successful read_until operation, the streambuf may contain
+ * additional data beyond that which matched the regular expression. An
+ * application will typically leave that data in the streambuf for a subsequent
+ * read_until operation to examine.
+ *
+ * @par Example
+ * To read data into a streambuf until a CR-LF sequence is encountered:
+ * @code asio::streambuf b;
+ * asio::read_until(s, b, boost::regex("\r\n"));
+ * std::istream is(&b);
+ * std::string line;
+ * std::getline(is, line); @endcode
+ * After the @c read_until operation completes successfully, the buffer @c b
+ * contains the data which matched the regular expression:
+ * @code { 'a', 'b', ..., 'c', '\r', '\n', 'd', 'e', ... } @endcode
+ * The call to @c std::getline then extracts the data up to and including the
+ * newline (which is discarded), so that the string @c line contains:
+ * @code { 'a', 'b', ..., 'c', '\r' } @endcode
+ * The remaining data is left in the buffer @c b as follows:
+ * @code { 'd', 'e', ... } @endcode
+ * This data may be the start of a new line, to be extracted by a subsequent
+ * @c read_until operation.
+ */
+template <typename SyncReadStream, typename Allocator>
+std::size_t read_until(SyncReadStream& s,
+    asio::basic_streambuf<Allocator>& b, const boost::regex& expr);
+
+/// Read data into a streambuf until some part of the data it contains matches
+/// a regular expression.
+/**
+ * This function is used to read data into the specified streambuf until the
+ * streambuf's get area contains some data that matches a regular expression.
+ * The call will block until one of the following conditions is true:
+ *
+ * @li A substring of the streambuf's get area matches the regular expression.
+ *
+ * @li An error occurred.
+ *
+ * This operation is implemented in terms of zero or more calls to the stream's
+ * read_some function. If the streambuf's get area already contains data that
+ * matches the regular expression, the function returns immediately.
+ *
+ * @param s The stream from which the data is to be read. The type must support
+ * the SyncReadStream concept.
+ *
+ * @param b A streambuf object into which the data will be read.
+ *
+ * @param expr The regular expression.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @returns The number of bytes in the streambuf's get area up to and including
+ * the substring that matches the regular expression. Returns 0 if an error
+ * occurred.
+ *
+ * @note After a successful read_until operation, the streambuf may contain
+ * additional data beyond that which matched the regular expression. An
+ * application will typically leave that data in the streambuf for a subsequent
+ * read_until operation to examine.
+ */
+template <typename SyncReadStream, typename Allocator>
+std::size_t read_until(SyncReadStream& s,
+    asio::basic_streambuf<Allocator>& b, const boost::regex& expr,
+    asio::error_code& ec);
+
+#endif // defined(ASIO_HAS_BOOST_REGEX)
+       // || defined(GENERATING_DOCUMENTATION)
+
+/// Read data into a streambuf until a function object indicates a match.
+/**
+ * This function is used to read data into the specified streambuf until a
+ * user-defined match condition function object, when applied to the data
+ * contained in the streambuf, indicates a successful match. The call will
+ * block until one of the following conditions is true:
+ *
+ * @li The match condition function object returns a std::pair where the second
+ * element evaluates to true.
+ *
+ * @li An error occurred.
+ *
+ * This operation is implemented in terms of zero or more calls to the stream's
+ * read_some function. If the match condition function object already indicates
+ * a match, the function returns immediately.
+ *
+ * @param s The stream from which the data is to be read. The type must support
+ * the SyncReadStream concept.
+ *
+ * @param b A streambuf object into which the data will be read.
+ *
+ * @param match_condition The function object to be called to determine whether
+ * a match exists. The signature of the function object must be:
+ * @code pair<iterator, bool> match_condition(iterator begin, iterator end);
+ * @endcode
+ * where @c iterator represents the type:
+ * @code buffers_iterator<basic_streambuf<Allocator>::const_buffers_type>
+ * @endcode
+ * The iterator parameters @c begin and @c end define the range of bytes to be
+ * scanned to determine whether there is a match. The @c first member of the
+ * return value is an iterator marking one-past-the-end of the bytes that have
+ * been consumed by the match function. This iterator is used to calculate the
+ * @c begin parameter for any subsequent invocation of the match condition. The
+ * @c second member of the return value is true if a match has been found, false
+ * otherwise.
+ *
+ * @returns The number of bytes in the streambuf's get area that have been fully
+ * consumed by the match function.
+ *
+ * @throws asio::system_error Thrown on failure.
+ *
+ * @note After a successful read_until operation, the streambuf may contain
+ * additional data beyond that which matched the function object. An application
+ * will typically leave that data in the streambuf for a subsequent read_until
+ * operation to examine.
+ *
+ * @note The default implementation of the @c is_match_condition type trait
+ * evaluates to true for function pointers and function objects with a
+ * @c result_type typedef. It must be specialised for other user-defined
+ * function objects.
+ *
+ * @par Examples
+ * To read data into a streambuf until whitespace is encountered:
+ * @code typedef asio::buffers_iterator<
+ *     asio::streambuf::const_buffers_type> iterator;
+ *
+ * std::pair<iterator, bool>
+ * match_whitespace(iterator begin, iterator end)
+ * {
+ *   iterator i = begin;
+ *   while (i != end)
+ *     if (std::isspace(*i++))
+ *       return std::make_pair(i, true);
+ *   return std::make_pair(i, false);
+ * }
+ * ...
+ * asio::streambuf b;
+ * asio::read_until(s, b, match_whitespace);
+ * @endcode
+ *
+ * To read data into a streambuf until a matching character is found:
+ * @code class match_char
+ * {
+ * public:
+ *   explicit match_char(char c) : c_(c) {}
+ *
+ *   template <typename Iterator>
+ *   std::pair<Iterator, bool> operator()(
+ *       Iterator begin, Iterator end) const
+ *   {
+ *     Iterator i = begin;
+ *     while (i != end)
+ *       if (c_ == *i++)
+ *         return std::make_pair(i, true);
+ *     return std::make_pair(i, false);
+ *   }
+ *
+ * private:
+ *   char c_;
+ * };
+ *
+ * namespace asio {
+ *   template <> struct is_match_condition<match_char>
+ *     : public boost::true_type {};
+ * } // namespace asio
+ * ...
+ * asio::streambuf b;
+ * asio::read_until(s, b, match_char('a'));
+ * @endcode
+ */
+template <typename SyncReadStream, typename Allocator, typename MatchCondition>
+std::size_t read_until(SyncReadStream& s,
+    asio::basic_streambuf<Allocator>& b, MatchCondition match_condition,
+    typename enable_if<is_match_condition<MatchCondition>::value>::type* = 0);
+
+/// Read data into a streambuf until a function object indicates a match.
+/**
+ * This function is used to read data into the specified streambuf until a
+ * user-defined match condition function object, when applied to the data
+ * contained in the streambuf, indicates a successful match. The call will
+ * block until one of the following conditions is true:
+ *
+ * @li The match condition function object returns a std::pair where the second
+ * element evaluates to true.
+ *
+ * @li An error occurred.
+ *
+ * This operation is implemented in terms of zero or more calls to the stream's
+ * read_some function. If the match condition function object already indicates
+ * a match, the function returns immediately.
+ *
+ * @param s The stream from which the data is to be read. The type must support
+ * the SyncReadStream concept.
+ *
+ * @param b A streambuf object into which the data will be read.
+ *
+ * @param match_condition The function object to be called to determine whether
+ * a match exists. The signature of the function object must be:
+ * @code pair<iterator, bool> match_condition(iterator begin, iterator end);
+ * @endcode
+ * where @c iterator represents the type:
+ * @code buffers_iterator<basic_streambuf<Allocator>::const_buffers_type>
+ * @endcode
+ * The iterator parameters @c begin and @c end define the range of bytes to be
+ * scanned to determine whether there is a match. The @c first member of the
+ * return value is an iterator marking one-past-the-end of the bytes that have
+ * been consumed by the match function. This iterator is used to calculate the
+ * @c begin parameter for any subsequent invocation of the match condition. The
+ * @c second member of the return value is true if a match has been found, false
+ * otherwise.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @returns The number of bytes in the streambuf's get area that have been fully
+ * consumed by the match function. Returns 0 if an error occurred.
+ *
+ * @note After a successful read_until operation, the streambuf may contain
+ * additional data beyond that which matched the function object. An application
+ * will typically leave that data in the streambuf for a subsequent read_until
+ * operation to examine.
+ *
+ * @note The default implementation of the @c is_match_condition type trait
+ * evaluates to true for function pointers and function objects with a
+ * @c result_type typedef. It must be specialised for other user-defined
+ * function objects.
+ */
+template <typename SyncReadStream, typename Allocator, typename MatchCondition>
+std::size_t read_until(SyncReadStream& s,
+    asio::basic_streambuf<Allocator>& b,
+    MatchCondition match_condition, asio::error_code& ec,
+    typename enable_if<is_match_condition<MatchCondition>::value>::type* = 0);
+
+#endif // !defined(ASIO_NO_IOSTREAM)
+#endif // !defined(ASIO_NO_EXTENSIONS)
+#endif // !defined(ASIO_NO_DYNAMIC_BUFFER_V1)
+
+/// Read data into a dynamic buffer sequence until it contains a specified
+/// delimiter.
+/**
+ * This function is used to read data into the specified dynamic buffer
+ * sequence until the dynamic buffer sequence's get area contains the specified
+ * delimiter. The call will block until one of the following conditions is
+ * true:
+ *
+ * @li The get area of the dynamic buffer sequence contains the specified
+ * delimiter.
+ *
+ * @li An error occurred.
+ *
+ * This operation is implemented in terms of zero or more calls to the stream's
+ * read_some function. If the dynamic buffer sequence's get area already
+ * contains the delimiter, the function returns immediately.
+ *
+ * @param s The stream from which the data is to be read. The type must support
+ * the SyncReadStream concept.
+ *
+ * @param buffers The dynamic buffer sequence into which the data will be read.
+ *
+ * @param delim The delimiter character.
+ *
+ * @returns The number of bytes in the dynamic buffer sequence's get area up to
+ * and including the delimiter.
+ *
+ * @throws asio::system_error Thrown on failure.
+ *
+ * @note After a successful read_until operation, the dynamic buffer sequence
+ * may contain additional data beyond the delimiter. An application will
+ * typically leave that data in the dynamic buffer sequence for a subsequent
+ * read_until operation to examine.
+ *
+ * @par Example
+ * To read data into a @c std::string until a newline is encountered:
+ * @code std::string data;
+ * std::size_t n = asio::read_until(s,
+ *     asio::dynamic_buffer(data), '\n');
+ * std::string line = data.substr(0, n);
+ * data.erase(0, n); @endcode
+ * After the @c read_until operation completes successfully, the string @c data
+ * contains the delimiter:
+ * @code { 'a', 'b', ..., 'c', '\n', 'd', 'e', ... } @endcode
+ * The call to @c substr then extracts the data up to and including the
+ * delimiter, so that the string @c line contains:
+ * @code { 'a', 'b', ..., 'c', '\n' } @endcode
+ * After the call to @c erase, the remaining data is left in the buffer @c b as
+ * follows:
+ * @code { 'd', 'e', ... } @endcode
+ * This data may be the start of a new line, to be extracted by a subsequent
+ * @c read_until operation.
+ */
+template <typename SyncReadStream, typename DynamicBuffer_v2>
+std::size_t read_until(SyncReadStream& s, DynamicBuffer_v2 buffers, char delim,
+    typename enable_if<
+      is_dynamic_buffer_v2<DynamicBuffer_v2>::value
+    >::type* = 0);
+
+/// Read data into a dynamic buffer sequence until it contains a specified
+/// delimiter.
+/**
+ * This function is used to read data into the specified dynamic buffer
+ * sequence until the dynamic buffer sequence's get area contains the specified
+ * delimiter. The call will block until one of the following conditions is
+ * true:
+ *
+ * @li The get area of the dynamic buffer sequence contains the specified
+ * delimiter.
+ *
+ * @li An error occurred.
+ *
+ * This operation is implemented in terms of zero or more calls to the stream's
+ * read_some function. If the dynamic buffer sequence's get area already
+ * contains the delimiter, the function returns immediately.
+ *
+ * @param s The stream from which the data is to be read. The type must support
+ * the SyncReadStream concept.
+ *
+ * @param buffers The dynamic buffer sequence into which the data will be read.
+ *
+ * @param delim The delimiter character.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @returns The number of bytes in the dynamic buffer sequence's get area up to
+ * and including the delimiter. Returns 0 if an error occurred.
+ *
+ * @note After a successful read_until operation, the dynamic buffer sequence
+ * may contain additional data beyond the delimiter. An application will
+ * typically leave that data in the dynamic buffer sequence for a subsequent
+ * read_until operation to examine.
+ */
+template <typename SyncReadStream, typename DynamicBuffer_v2>
+std::size_t read_until(SyncReadStream& s, DynamicBuffer_v2 buffers,
+    char delim, asio::error_code& ec,
+    typename enable_if<
+      is_dynamic_buffer_v2<DynamicBuffer_v2>::value
+    >::type* = 0);
+
+/// Read data into a dynamic buffer sequence until it contains a specified
+/// delimiter.
+/**
+ * This function is used to read data into the specified dynamic buffer
+ * sequence until the dynamic buffer sequence's get area contains the specified
+ * delimiter. The call will block until one of the following conditions is
+ * true:
+ *
+ * @li The get area of the dynamic buffer sequence contains the specified
+ * delimiter.
+ *
+ * @li An error occurred.
+ *
+ * This operation is implemented in terms of zero or more calls to the stream's
+ * read_some function. If the dynamic buffer sequence's get area already
+ * contains the delimiter, the function returns immediately.
+ *
+ * @param s The stream from which the data is to be read. The type must support
+ * the SyncReadStream concept.
+ *
+ * @param buffers The dynamic buffer sequence into which the data will be read.
+ *
+ * @param delim The delimiter string.
+ *
+ * @returns The number of bytes in the dynamic buffer sequence's get area up to
+ * and including the delimiter.
+ *
+ * @note After a successful read_until operation, the dynamic buffer sequence
+ * may contain additional data beyond the delimiter. An application will
+ * typically leave that data in the dynamic buffer sequence for a subsequent
+ * read_until operation to examine.
+ *
+ * @par Example
+ * To read data into a @c std::string until a CR-LF sequence is encountered:
+ * @code std::string data;
+ * std::size_t n = asio::read_until(s,
+ *     asio::dynamic_buffer(data), "\r\n");
+ * std::string line = data.substr(0, n);
+ * data.erase(0, n); @endcode
+ * After the @c read_until operation completes successfully, the string @c data
+ * contains the delimiter:
+ * @code { 'a', 'b', ..., 'c', '\r', '\n', 'd', 'e', ... } @endcode
+ * The call to @c substr then extracts the data up to and including the
+ * delimiter, so that the string @c line contains:
+ * @code { 'a', 'b', ..., 'c', '\r', '\n' } @endcode
+ * After the call to @c erase, the remaining data is left in the buffer @c b as
+ * follows:
+ * @code { 'd', 'e', ... } @endcode
+ * This data may be the start of a new line, to be extracted by a subsequent
+ * @c read_until operation.
+ */
+template <typename SyncReadStream, typename DynamicBuffer_v2>
+std::size_t read_until(SyncReadStream& s, DynamicBuffer_v2 buffers,
+    ASIO_STRING_VIEW_PARAM delim,
+    typename enable_if<
+      is_dynamic_buffer_v2<DynamicBuffer_v2>::value
+    >::type* = 0);
+
+/// Read data into a dynamic buffer sequence until it contains a specified
+/// delimiter.
+/**
+ * This function is used to read data into the specified dynamic buffer
+ * sequence until the dynamic buffer sequence's get area contains the specified
+ * delimiter. The call will block until one of the following conditions is
+ * true:
+ *
+ * @li The get area of the dynamic buffer sequence contains the specified
+ * delimiter.
+ *
+ * @li An error occurred.
+ *
+ * This operation is implemented in terms of zero or more calls to the stream's
+ * read_some function. If the dynamic buffer sequence's get area already
+ * contains the delimiter, the function returns immediately.
+ *
+ * @param s The stream from which the data is to be read. The type must support
+ * the SyncReadStream concept.
+ *
+ * @param buffers The dynamic buffer sequence into which the data will be read.
+ *
+ * @param delim The delimiter string.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @returns The number of bytes in the dynamic buffer sequence's get area up to
+ * and including the delimiter. Returns 0 if an error occurred.
+ *
+ * @note After a successful read_until operation, the dynamic buffer sequence
+ * may contain additional data beyond the delimiter. An application will
+ * typically leave that data in the dynamic buffer sequence for a subsequent
+ * read_until operation to examine.
+ */
+template <typename SyncReadStream, typename DynamicBuffer_v2>
+std::size_t read_until(SyncReadStream& s, DynamicBuffer_v2 buffers,
+    ASIO_STRING_VIEW_PARAM delim, asio::error_code& ec,
+    typename enable_if<
+      is_dynamic_buffer_v2<DynamicBuffer_v2>::value
+    >::type* = 0);
+
+#if !defined(ASIO_NO_EXTENSIONS)
+#if defined(ASIO_HAS_BOOST_REGEX) \
+  || defined(GENERATING_DOCUMENTATION)
+
+/// Read data into a dynamic buffer sequence until some part of the data it
+/// contains matches a regular expression.
+/**
+ * This function is used to read data into the specified dynamic buffer
+ * sequence until the dynamic buffer sequence's get area contains some data
+ * that matches a regular expression. The call will block until one of the
+ * following conditions is true:
+ *
+ * @li A substring of the dynamic buffer sequence's get area matches the
+ * regular expression.
+ *
+ * @li An error occurred.
+ *
+ * This operation is implemented in terms of zero or more calls to the stream's
+ * read_some function. If the dynamic buffer sequence's get area already
+ * contains data that matches the regular expression, the function returns
+ * immediately.
+ *
+ * @param s The stream from which the data is to be read. The type must support
+ * the SyncReadStream concept.
+ *
+ * @param buffers A dynamic buffer sequence into which the data will be read.
+ *
+ * @param expr The regular expression.
+ *
+ * @returns The number of bytes in the dynamic buffer sequence's get area up to
+ * and including the substring that matches the regular expression.
+ *
+ * @throws asio::system_error Thrown on failure.
+ *
+ * @note After a successful read_until operation, the dynamic buffer sequence
+ * may contain additional data beyond that which matched the regular
+ * expression. An application will typically leave that data in the dynamic
+ * buffer sequence for a subsequent read_until operation to examine.
+ *
+ * @par Example
+ * To read data into a @c std::string until a CR-LF sequence is encountered:
+ * @code std::string data;
+ * std::size_t n = asio::read_until(s,
+ *     asio::dynamic_buffer(data), boost::regex("\r\n"));
+ * std::string line = data.substr(0, n);
+ * data.erase(0, n); @endcode
+ * After the @c read_until operation completes successfully, the string @c data
+ * contains the delimiter:
+ * @code { 'a', 'b', ..., 'c', '\r', '\n', 'd', 'e', ... } @endcode
+ * The call to @c substr then extracts the data up to and including the
+ * delimiter, so that the string @c line contains:
+ * @code { 'a', 'b', ..., 'c', '\r', '\n' } @endcode
+ * After the call to @c erase, the remaining data is left in the buffer @c b as
+ * follows:
+ * @code { 'd', 'e', ... } @endcode
+ * This data may be the start of a new line, to be extracted by a subsequent
+ * @c read_until operation.
+ */
+template <typename SyncReadStream, typename DynamicBuffer_v2>
+std::size_t read_until(SyncReadStream& s, DynamicBuffer_v2 buffers,
+    const boost::regex& expr,
+    typename enable_if<
+      is_dynamic_buffer_v2<DynamicBuffer_v2>::value
+    >::type* = 0);
+
+/// Read data into a dynamic buffer sequence until some part of the data it
+/// contains matches a regular expression.
+/**
+ * This function is used to read data into the specified dynamic buffer
+ * sequence until the dynamic buffer sequence's get area contains some data
+ * that matches a regular expression. The call will block until one of the
+ * following conditions is true:
+ *
+ * @li A substring of the dynamic buffer sequence's get area matches the
+ * regular expression.
+ *
+ * @li An error occurred.
+ *
+ * This operation is implemented in terms of zero or more calls to the stream's
+ * read_some function. If the dynamic buffer sequence's get area already
+ * contains data that matches the regular expression, the function returns
+ * immediately.
+ *
+ * @param s The stream from which the data is to be read. The type must support
+ * the SyncReadStream concept.
+ *
+ * @param buffers A dynamic buffer sequence into which the data will be read.
+ *
+ * @param expr The regular expression.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @returns The number of bytes in the dynamic buffer sequence's get area up to
+ * and including the substring that matches the regular expression. Returns 0
+ * if an error occurred.
+ *
+ * @note After a successful read_until operation, the dynamic buffer sequence
+ * may contain additional data beyond that which matched the regular
+ * expression. An application will typically leave that data in the dynamic
+ * buffer sequence for a subsequent read_until operation to examine.
+ */
+template <typename SyncReadStream, typename DynamicBuffer_v2>
+std::size_t read_until(SyncReadStream& s, DynamicBuffer_v2 buffers,
+    const boost::regex& expr, asio::error_code& ec,
+    typename enable_if<
+        is_dynamic_buffer_v2<DynamicBuffer_v2>::value
+    >::type* = 0);
+
+#endif // defined(ASIO_HAS_BOOST_REGEX)
+       // || defined(GENERATING_DOCUMENTATION)
+
+/// Read data into a dynamic buffer sequence until a function object indicates a
+/// match.
+
+/**
+ * This function is used to read data into the specified dynamic buffer
+ * sequence until a user-defined match condition function object, when applied
+ * to the data contained in the dynamic buffer sequence, indicates a successful
+ * match. The call will block until one of the following conditions is true:
+ *
+ * @li The match condition function object returns a std::pair where the second
+ * element evaluates to true.
+ *
+ * @li An error occurred.
+ *
+ * This operation is implemented in terms of zero or more calls to the stream's
+ * read_some function. If the match condition function object already indicates
+ * a match, the function returns immediately.
+ *
+ * @param s The stream from which the data is to be read. The type must support
+ * the SyncReadStream concept.
+ *
+ * @param buffers A dynamic buffer sequence into which the data will be read.
+ *
+ * @param match_condition The function object to be called to determine whether
+ * a match exists. The signature of the function object must be:
+ * @code pair<iterator, bool> match_condition(iterator begin, iterator end);
+ * @endcode
+ * where @c iterator represents the type:
+ * @code buffers_iterator<typename DynamicBuffer_v2::const_buffers_type>
+ * @endcode
+ * The iterator parameters @c begin and @c end define the range of bytes to be
+ * scanned to determine whether there is a match. The @c first member of the
+ * return value is an iterator marking one-past-the-end of the bytes that have
+ * been consumed by the match function. This iterator is used to calculate the
+ * @c begin parameter for any subsequent invocation of the match condition. The
+ * @c second member of the return value is true if a match has been found, false
+ * otherwise.
+ *
+ * @returns The number of bytes in the dynamic_buffer's get area that
+ * have been fully consumed by the match function.
+ *
+ * @throws asio::system_error Thrown on failure.
+ *
+ * @note After a successful read_until operation, the dynamic buffer sequence
+ * may contain additional data beyond that which matched the function object.
+ * An application will typically leave that data in the dynamic buffer sequence
+ * for a subsequent read_until operation to examine.
+
+ * @note The default implementation of the @c is_match_condition type trait
+ * evaluates to true for function pointers and function objects with a
+ * @c result_type typedef. It must be specialised for other user-defined
+ * function objects.
+ *
+ * @par Examples
+ * To read data into a dynamic buffer sequence until whitespace is encountered:
+ * @code typedef asio::buffers_iterator<
+ *     asio::const_buffers_1> iterator;
+ *
+ * std::pair<iterator, bool>
+ * match_whitespace(iterator begin, iterator end)
+ * {
+ *   iterator i = begin;
+ *   while (i != end)
+ *     if (std::isspace(*i++))
+ *       return std::make_pair(i, true);
+ *   return std::make_pair(i, false);
+ * }
+ * ...
+ * std::string data;
+ * asio::read_until(s, data, match_whitespace);
+ * @endcode
+ *
+ * To read data into a @c std::string until a matching character is found:
+ * @code class match_char
+ * {
+ * public:
+ *   explicit match_char(char c) : c_(c) {}
+ *
+ *   template <typename Iterator>
+ *   std::pair<Iterator, bool> operator()(
+ *       Iterator begin, Iterator end) const
+ *   {
+ *     Iterator i = begin;
+ *     while (i != end)
+ *       if (c_ == *i++)
+ *         return std::make_pair(i, true);
+ *     return std::make_pair(i, false);
+ *   }
+ *
+ * private:
+ *   char c_;
+ * };
+ *
+ * namespace asio {
+ *   template <> struct is_match_condition<match_char>
+ *     : public boost::true_type {};
+ * } // namespace asio
+ * ...
+ * std::string data;
+ * asio::read_until(s, data, match_char('a'));
+ * @endcode
+ */
+template <typename SyncReadStream,
+    typename DynamicBuffer_v2, typename MatchCondition>
+std::size_t read_until(SyncReadStream& s, DynamicBuffer_v2 buffers,
+    MatchCondition match_condition,
+    typename enable_if<
+      is_match_condition<MatchCondition>::value
+        && is_dynamic_buffer_v2<DynamicBuffer_v2>::value
+    >::type* = 0);
+
+/// Read data into a dynamic buffer sequence until a function object indicates a
+/// match.
+/**
+ * This function is used to read data into the specified dynamic buffer
+ * sequence until a user-defined match condition function object, when applied
+ * to the data contained in the dynamic buffer sequence, indicates a successful
+ * match. The call will block until one of the following conditions is true:
+ *
+ * @li The match condition function object returns a std::pair where the second
+ * element evaluates to true.
+ *
+ * @li An error occurred.
+ *
+ * This operation is implemented in terms of zero or more calls to the stream's
+ * read_some function. If the match condition function object already indicates
+ * a match, the function returns immediately.
+ *
+ * @param s The stream from which the data is to be read. The type must support
+ * the SyncReadStream concept.
+ *
+ * @param buffers A dynamic buffer sequence into which the data will be read.
+ *
+ * @param match_condition The function object to be called to determine whether
+ * a match exists. The signature of the function object must be:
+ * @code pair<iterator, bool> match_condition(iterator begin, iterator end);
+ * @endcode
+ * where @c iterator represents the type:
+ * @code buffers_iterator<DynamicBuffer_v2::const_buffers_type>
+ * @endcode
+ * The iterator parameters @c begin and @c end define the range of bytes to be
+ * scanned to determine whether there is a match. The @c first member of the
+ * return value is an iterator marking one-past-the-end of the bytes that have
+ * been consumed by the match function. This iterator is used to calculate the
+ * @c begin parameter for any subsequent invocation of the match condition. The
+ * @c second member of the return value is true if a match has been found, false
+ * otherwise.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @returns The number of bytes in the dynamic buffer sequence's get area that
+ * have been fully consumed by the match function. Returns 0 if an error
+ * occurred.
+ *
+ * @note After a successful read_until operation, the dynamic buffer sequence
+ * may contain additional data beyond that which matched the function object.
+ * An application will typically leave that data in the dynamic buffer sequence
+ * for a subsequent read_until operation to examine.
+ *
+ * @note The default implementation of the @c is_match_condition type trait
+ * evaluates to true for function pointers and function objects with a
+ * @c result_type typedef. It must be specialised for other user-defined
+ * function objects.
+ */
+template <typename SyncReadStream,
+    typename DynamicBuffer_v2, typename MatchCondition>
+std::size_t read_until(SyncReadStream& s, DynamicBuffer_v2 buffers,
+    MatchCondition match_condition, asio::error_code& ec,
+    typename enable_if<
+      is_match_condition<MatchCondition>::value
+        && is_dynamic_buffer_v2<DynamicBuffer_v2>::value
+    >::type* = 0);
+
+#endif // !defined(ASIO_NO_EXTENSIONS)
+
+/*@}*/
+/**
+ * @defgroup async_read_until asio::async_read_until
+ *
+ * @brief The @c async_read_until function is a composed asynchronous operation
+ * that reads data into a dynamic buffer sequence, or into a streambuf, until
+ * it contains a delimiter, matches a regular expression, or a function object
+ * indicates a match.
+ */
+/*@{*/
+
+#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1)
+
+/// Start an asynchronous operation to read data into a dynamic buffer sequence
+/// until it contains a specified delimiter.
+/**
+ * This function is used to asynchronously read data into the specified dynamic
+ * buffer sequence until the dynamic buffer sequence's get area contains the
+ * specified delimiter. The function call always returns immediately. The
+ * asynchronous operation will continue until one of the following conditions
+ * is true:
+ *
+ * @li The get area of the dynamic buffer sequence contains the specified
+ * delimiter.
+ *
+ * @li An error occurred.
+ *
+ * This operation is implemented in terms of zero or more calls to the stream's
+ * async_read_some function, and is known as a <em>composed operation</em>. If
+ * the dynamic buffer sequence's get area already contains the delimiter, this
+ * asynchronous operation completes immediately. The program must ensure that
+ * the stream performs no other read operations (such as async_read,
+ * async_read_until, the stream's async_read_some function, or any other
+ * composed operations that perform reads) until this operation completes.
+ *
+ * @param s The stream from which the data is to be read. The type must support
+ * the AsyncReadStream concept.
+ *
+ * @param buffers The dynamic buffer sequence into which the data will be read.
+ * Although the buffers object may be copied as necessary, ownership of the
+ * underlying memory blocks is retained by the caller, which must guarantee
+ * that they remain valid until the handler is called.
+ *
+ * @param delim The delimiter character.
+ *
+ * @param handler The handler to be called when the read operation completes.
+ * Copies will be made of the handler as required. The function signature of the
+ * handler must be:
+ * @code void handler(
+ *   // Result of operation.
+ *   const asio::error_code& error,
+ *
+ *   // The number of bytes in the dynamic buffer sequence's
+ *   // get area up to and including the delimiter.
+ *   // 0 if an error occurred.
+ *   std::size_t bytes_transferred
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. On
+ * immediate completion, invocation of the handler will be performed in a
+ * manner equivalent to using asio::post().
+ *
+ * @note After a successful async_read_until operation, the dynamic buffer
+ * sequence may contain additional data beyond the delimiter. An application
+ * will typically leave that data in the dynamic buffer sequence for a
+ * subsequent async_read_until operation to examine.
+ *
+ * @par Example
+ * To asynchronously read data into a @c std::string until a newline is
+ * encountered:
+ * @code std::string data;
+ * ...
+ * void handler(const asio::error_code& e, std::size_t size)
+ * {
+ *   if (!e)
+ *   {
+ *     std::string line = data.substr(0, n);
+ *     data.erase(0, n);
+ *     ...
+ *   }
+ * }
+ * ...
+ * asio::async_read_until(s, data, '\n', handler); @endcode
+ * After the @c async_read_until operation completes successfully, the buffer
+ * @c data contains the delimiter:
+ * @code { 'a', 'b', ..., 'c', '\n', 'd', 'e', ... } @endcode
+ * The call to @c substr then extracts the data up to and including the
+ * delimiter, so that the string @c line contains:
+ * @code { 'a', 'b', ..., 'c', '\n' } @endcode
+ * After the call to @c erase, the remaining data is left in the buffer @c data
+ * as follows:
+ * @code { 'd', 'e', ... } @endcode
+ * This data may be the start of a new line, to be extracted by a subsequent
+ * @c async_read_until operation.
+ */
+template <typename AsyncReadStream, typename DynamicBuffer_v1,
+    ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+      std::size_t)) ReadHandler
+        ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(
+          typename AsyncReadStream::executor_type)>
+ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,
+    void (asio::error_code, std::size_t))
+async_read_until(AsyncReadStream& s,
+    ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, char delim,
+    ASIO_MOVE_ARG(ReadHandler) handler
+      ASIO_DEFAULT_COMPLETION_TOKEN(
+        typename AsyncReadStream::executor_type),
+    typename enable_if<
+      is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value
+        && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value
+    >::type* = 0);
+
+/// Start an asynchronous operation to read data into a dynamic buffer sequence
+/// until it contains a specified delimiter.
+/**
+ * This function is used to asynchronously read data into the specified dynamic
+ * buffer sequence until the dynamic buffer sequence's get area contains the
+ * specified delimiter. The function call always returns immediately. The
+ * asynchronous operation will continue until one of the following conditions
+ * is true:
+ *
+ * @li The get area of the dynamic buffer sequence contains the specified
+ * delimiter.
+ *
+ * @li An error occurred.
+ *
+ * This operation is implemented in terms of zero or more calls to the stream's
+ * async_read_some function, and is known as a <em>composed operation</em>. If
+ * the dynamic buffer sequence's get area already contains the delimiter, this
+ * asynchronous operation completes immediately. The program must ensure that
+ * the stream performs no other read operations (such as async_read,
+ * async_read_until, the stream's async_read_some function, or any other
+ * composed operations that perform reads) until this operation completes.
+ *
+ * @param s The stream from which the data is to be read. The type must support
+ * the AsyncReadStream concept.
+ *
+ * @param buffers The dynamic buffer sequence into which the data will be read.
+ * Although the buffers object may be copied as necessary, ownership of the
+ * underlying memory blocks is retained by the caller, which must guarantee
+ * that they remain valid until the handler is called.
+ *
+ * @param delim The delimiter string.
+ *
+ * @param handler The handler to be called when the read operation completes.
+ * Copies will be made of the handler as required. The function signature of the
+ * handler must be:
+ * @code void handler(
+ *   // Result of operation.
+ *   const asio::error_code& error,
+ *
+ *   // The number of bytes in the dynamic buffer sequence's
+ *   // get area up to and including the delimiter.
+ *   // 0 if an error occurred.
+ *   std::size_t bytes_transferred
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. On
+ * immediate completion, invocation of the handler will be performed in a
+ * manner equivalent to using asio::post().
+ *
+ * @note After a successful async_read_until operation, the dynamic buffer
+ * sequence may contain additional data beyond the delimiter. An application
+ * will typically leave that data in the dynamic buffer sequence for a
+ * subsequent async_read_until operation to examine.
+ *
+ * @par Example
+ * To asynchronously read data into a @c std::string until a CR-LF sequence is
+ * encountered:
+ * @code std::string data;
+ * ...
+ * void handler(const asio::error_code& e, std::size_t size)
+ * {
+ *   if (!e)
+ *   {
+ *     std::string line = data.substr(0, n);
+ *     data.erase(0, n);
+ *     ...
+ *   }
+ * }
+ * ...
+ * asio::async_read_until(s, data, "\r\n", handler); @endcode
+ * After the @c async_read_until operation completes successfully, the string
+ * @c data contains the delimiter:
+ * @code { 'a', 'b', ..., 'c', '\r', '\n', 'd', 'e', ... } @endcode
+ * The call to @c substr then extracts the data up to and including the
+ * delimiter, so that the string @c line contains:
+ * @code { 'a', 'b', ..., 'c', '\r', '\n' } @endcode
+ * After the call to @c erase, the remaining data is left in the string @c data
+ * as follows:
+ * @code { 'd', 'e', ... } @endcode
+ * This data may be the start of a new line, to be extracted by a subsequent
+ * @c async_read_until operation.
+ */
+template <typename AsyncReadStream, typename DynamicBuffer_v1,
+    ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+      std::size_t)) ReadHandler
+        ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(
+          typename AsyncReadStream::executor_type)>
+ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,
+    void (asio::error_code, std::size_t))
+async_read_until(AsyncReadStream& s,
+    ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,
+    ASIO_STRING_VIEW_PARAM delim,
+    ASIO_MOVE_ARG(ReadHandler) handler
+      ASIO_DEFAULT_COMPLETION_TOKEN(
+        typename AsyncReadStream::executor_type),
+    typename enable_if<
+      is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value
+        && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value
+    >::type* = 0);
+
+#if !defined(ASIO_NO_EXTENSIONS)
+#if defined(ASIO_HAS_BOOST_REGEX) \
+  || defined(GENERATING_DOCUMENTATION)
+
+/// Start an asynchronous operation to read data into a dynamic buffer sequence
+/// until some part of its data matches a regular expression.
+/**
+ * This function is used to asynchronously read data into the specified dynamic
+ * buffer sequence until the dynamic buffer sequence's get area contains some
+ * data that matches a regular expression. The function call always returns
+ * immediately. The asynchronous operation will continue until one of the
+ * following conditions is true:
+ *
+ * @li A substring of the dynamic buffer sequence's get area matches the regular
+ * expression.
+ *
+ * @li An error occurred.
+ *
+ * This operation is implemented in terms of zero or more calls to the stream's
+ * async_read_some function, and is known as a <em>composed operation</em>. If
+ * the dynamic buffer sequence's get area already contains data that matches
+ * the regular expression, this asynchronous operation completes immediately.
+ * The program must ensure that the stream performs no other read operations
+ * (such as async_read, async_read_until, the stream's async_read_some
+ * function, or any other composed operations that perform reads) until this
+ * operation completes.
+ *
+ * @param s The stream from which the data is to be read. The type must support
+ * the AsyncReadStream concept.
+ *
+ * @param buffers The dynamic buffer sequence into which the data will be read.
+ * Although the buffers object may be copied as necessary, ownership of the
+ * underlying memory blocks is retained by the caller, which must guarantee
+ * that they remain valid until the handler is called.
+ *
+ * @param expr The regular expression.
+ *
+ * @param handler The handler to be called when the read operation completes.
+ * Copies will be made of the handler as required. The function signature of the
+ * handler must be:
+ * @code void handler(
+ *   // Result of operation.
+ *   const asio::error_code& error,
+ *
+ *   // The number of bytes in the dynamic buffer
+ *   // sequence's get area up to and including the
+ *   // substring that matches the regular expression.
+ *   // 0 if an error occurred.
+ *   std::size_t bytes_transferred
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. On
+ * immediate completion, invocation of the handler will be performed in a
+ * manner equivalent to using asio::post().
+ *
+ * @note After a successful async_read_until operation, the dynamic buffer
+ * sequence may contain additional data beyond that which matched the regular
+ * expression. An application will typically leave that data in the dynamic
+ * buffer sequence for a subsequent async_read_until operation to examine.
+ *
+ * @par Example
+ * To asynchronously read data into a @c std::string until a CR-LF sequence is
+ * encountered:
+ * @code std::string data;
+ * ...
+ * void handler(const asio::error_code& e, std::size_t size)
+ * {
+ *   if (!e)
+ *   {
+ *     std::string line = data.substr(0, n);
+ *     data.erase(0, n);
+ *     ...
+ *   }
+ * }
+ * ...
+ * asio::async_read_until(s, data,
+ *     boost::regex("\r\n"), handler); @endcode
+ * After the @c async_read_until operation completes successfully, the string
+ * @c data contains the data which matched the regular expression:
+ * @code { 'a', 'b', ..., 'c', '\r', '\n', 'd', 'e', ... } @endcode
+ * The call to @c substr then extracts the data up to and including the match,
+ * so that the string @c line contains:
+ * @code { 'a', 'b', ..., 'c', '\r', '\n' } @endcode
+ * After the call to @c erase, the remaining data is left in the string @c data
+ * as follows:
+ * @code { 'd', 'e', ... } @endcode
+ * This data may be the start of a new line, to be extracted by a subsequent
+ * @c async_read_until operation.
+ */
+template <typename AsyncReadStream, typename DynamicBuffer_v1,
+    ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+      std::size_t)) ReadHandler
+        ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(
+          typename AsyncReadStream::executor_type)>
+ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,
+    void (asio::error_code, std::size_t))
+async_read_until(AsyncReadStream& s,
+    ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,
+    const boost::regex& expr,
+    ASIO_MOVE_ARG(ReadHandler) handler
+      ASIO_DEFAULT_COMPLETION_TOKEN(
+        typename AsyncReadStream::executor_type),
+    typename enable_if<
+      is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value
+        && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value
+    >::type* = 0);
+
+#endif // defined(ASIO_HAS_BOOST_REGEX)
+       // || defined(GENERATING_DOCUMENTATION)
+
+/// Start an asynchronous operation to read data into a dynamic buffer sequence
+/// until a function object indicates a match.
+/**
+ * This function is used to asynchronously read data into the specified dynamic
+ * buffer sequence until a user-defined match condition function object, when
+ * applied to the data contained in the dynamic buffer sequence, indicates a
+ * successful match. The function call always returns immediately. The
+ * asynchronous operation will continue until one of the following conditions
+ * is true:
+ *
+ * @li The match condition function object returns a std::pair where the second
+ * element evaluates to true.
+ *
+ * @li An error occurred.
+ *
+ * This operation is implemented in terms of zero or more calls to the stream's
+ * async_read_some function, and is known as a <em>composed operation</em>. If
+ * the match condition function object already indicates a match, this
+ * asynchronous operation completes immediately. The program must ensure that
+ * the stream performs no other read operations (such as async_read,
+ * async_read_until, the stream's async_read_some function, or any other
+ * composed operations that perform reads) until this operation completes.
+ *
+ * @param s The stream from which the data is to be read. The type must support
+ * the AsyncReadStream concept.
+ *
+ * @param buffers The dynamic buffer sequence into which the data will be read.
+ * Although the buffers object may be copied as necessary, ownership of the
+ * underlying memory blocks is retained by the caller, which must guarantee
+ * that they remain valid until the handler is called.
+ *
+ * @param match_condition The function object to be called to determine whether
+ * a match exists. The signature of the function object must be:
+ * @code pair<iterator, bool> match_condition(iterator begin, iterator end);
+ * @endcode
+ * where @c iterator represents the type:
+ * @code buffers_iterator<typename DynamicBuffer_v1::const_buffers_type>
+ * @endcode
+ * The iterator parameters @c begin and @c end define the range of bytes to be
+ * scanned to determine whether there is a match. The @c first member of the
+ * return value is an iterator marking one-past-the-end of the bytes that have
+ * been consumed by the match function. This iterator is used to calculate the
+ * @c begin parameter for any subsequent invocation of the match condition. The
+ * @c second member of the return value is true if a match has been found, false
+ * otherwise.
+ *
+ * @param handler The handler to be called when the read operation completes.
+ * Copies will be made of the handler as required. The function signature of the
+ * handler must be:
+ * @code void handler(
+ *   // Result of operation.
+ *   const asio::error_code& error,
+ *
+ *   // The number of bytes in the dynamic buffer sequence's
+ *   // get area that have been fully consumed by the match
+ *   // function. O if an error occurred.
+ *   std::size_t bytes_transferred
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. On
+ * immediate completion, invocation of the handler will be performed in a
+ * manner equivalent to using asio::post().
+ *
+ * @note After a successful async_read_until operation, the dynamic buffer
+ * sequence may contain additional data beyond that which matched the function
+ * object. An application will typically leave that data in the dynamic buffer
+ * sequence for a subsequent async_read_until operation to examine.
+ *
+ * @note The default implementation of the @c is_match_condition type trait
+ * evaluates to true for function pointers and function objects with a
+ * @c result_type typedef. It must be specialised for other user-defined
+ * function objects.
+ *
+ * @par Examples
+ * To asynchronously read data into a @c std::string until whitespace is
+ * encountered:
+ * @code typedef asio::buffers_iterator<
+ *     asio::const_buffers_1> iterator;
+ *
+ * std::pair<iterator, bool>
+ * match_whitespace(iterator begin, iterator end)
+ * {
+ *   iterator i = begin;
+ *   while (i != end)
+ *     if (std::isspace(*i++))
+ *       return std::make_pair(i, true);
+ *   return std::make_pair(i, false);
+ * }
+ * ...
+ * void handler(const asio::error_code& e, std::size_t size);
+ * ...
+ * std::string data;
+ * asio::async_read_until(s, data, match_whitespace, handler);
+ * @endcode
+ *
+ * To asynchronously read data into a @c std::string until a matching character
+ * is found:
+ * @code class match_char
+ * {
+ * public:
+ *   explicit match_char(char c) : c_(c) {}
+ *
+ *   template <typename Iterator>
+ *   std::pair<Iterator, bool> operator()(
+ *       Iterator begin, Iterator end) const
+ *   {
+ *     Iterator i = begin;
+ *     while (i != end)
+ *       if (c_ == *i++)
+ *         return std::make_pair(i, true);
+ *     return std::make_pair(i, false);
+ *   }
+ *
+ * private:
+ *   char c_;
+ * };
+ *
+ * namespace asio {
+ *   template <> struct is_match_condition<match_char>
+ *     : public boost::true_type {};
+ * } // namespace asio
+ * ...
+ * void handler(const asio::error_code& e, std::size_t size);
+ * ...
+ * std::string data;
+ * asio::async_read_until(s, data, match_char('a'), handler);
+ * @endcode
+ */
+template <typename AsyncReadStream,
+    typename DynamicBuffer_v1, typename MatchCondition,
+    ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+      std::size_t)) ReadHandler
+        ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(
+          typename AsyncReadStream::executor_type)>
+ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,
+    void (asio::error_code, std::size_t))
+async_read_until(AsyncReadStream& s,
+    ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,
+    MatchCondition match_condition,
+    ASIO_MOVE_ARG(ReadHandler) handler
+      ASIO_DEFAULT_COMPLETION_TOKEN(
+        typename AsyncReadStream::executor_type),
+    typename enable_if<
+      is_match_condition<MatchCondition>::value
+        && is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value
+        && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value
+    >::type* = 0);
+
+#if !defined(ASIO_NO_IOSTREAM)
+
+/// Start an asynchronous operation to read data into a streambuf until it
+/// contains a specified delimiter.
+/**
+ * This function is used to asynchronously read data into the specified
+ * streambuf until the streambuf's get area contains the specified delimiter.
+ * The function call always returns immediately. The asynchronous operation
+ * will continue until one of the following conditions is true:
+ *
+ * @li The get area of the streambuf contains the specified delimiter.
+ *
+ * @li An error occurred.
+ *
+ * This operation is implemented in terms of zero or more calls to the stream's
+ * async_read_some function, and is known as a <em>composed operation</em>. If
+ * the streambuf's get area already contains the delimiter, this asynchronous
+ * operation completes immediately. The program must ensure that the stream
+ * performs no other read operations (such as async_read, async_read_until, the
+ * stream's async_read_some function, or any other composed operations that
+ * perform reads) until this operation completes.
+ *
+ * @param s The stream from which the data is to be read. The type must support
+ * the AsyncReadStream concept.
+ *
+ * @param b A streambuf object into which the data will be read. Ownership of
+ * the streambuf is retained by the caller, which must guarantee that it remains
+ * valid until the handler is called.
+ *
+ * @param delim The delimiter character.
+ *
+ * @param handler The handler to be called when the read operation completes.
+ * Copies will be made of the handler as required. The function signature of the
+ * handler must be:
+ * @code void handler(
+ *   // Result of operation.
+ *   const asio::error_code& error,
+ *
+ *   // The number of bytes in the streambuf's get
+ *   // area up to and including the delimiter.
+ *   // 0 if an error occurred.
+ *   std::size_t bytes_transferred
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. On
+ * immediate completion, invocation of the handler will be performed in a
+ * manner equivalent to using asio::post().
+ *
+ * @note After a successful async_read_until operation, the streambuf may
+ * contain additional data beyond the delimiter. An application will typically
+ * leave that data in the streambuf for a subsequent async_read_until operation
+ * to examine.
+ *
+ * @par Example
+ * To asynchronously read data into a streambuf until a newline is encountered:
+ * @code asio::streambuf b;
+ * ...
+ * void handler(const asio::error_code& e, std::size_t size)
+ * {
+ *   if (!e)
+ *   {
+ *     std::istream is(&b);
+ *     std::string line;
+ *     std::getline(is, line);
+ *     ...
+ *   }
+ * }
+ * ...
+ * asio::async_read_until(s, b, '\n', handler); @endcode
+ * After the @c async_read_until operation completes successfully, the buffer
+ * @c b contains the delimiter:
+ * @code { 'a', 'b', ..., 'c', '\n', 'd', 'e', ... } @endcode
+ * The call to @c std::getline then extracts the data up to and including the
+ * newline (which is discarded), so that the string @c line contains:
+ * @code { 'a', 'b', ..., 'c' } @endcode
+ * The remaining data is left in the buffer @c b as follows:
+ * @code { 'd', 'e', ... } @endcode
+ * This data may be the start of a new line, to be extracted by a subsequent
+ * @c async_read_until operation.
+ */
+template <typename AsyncReadStream, typename Allocator,
+    ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+      std::size_t)) ReadHandler
+        ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(
+          typename AsyncReadStream::executor_type)>
+ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,
+    void (asio::error_code, std::size_t))
+async_read_until(AsyncReadStream& s,
+    asio::basic_streambuf<Allocator>& b, char delim,
+    ASIO_MOVE_ARG(ReadHandler) handler
+      ASIO_DEFAULT_COMPLETION_TOKEN(
+        typename AsyncReadStream::executor_type));
+
+/// Start an asynchronous operation to read data into a streambuf until it
+/// contains a specified delimiter.
+/**
+ * This function is used to asynchronously read data into the specified
+ * streambuf until the streambuf's get area contains the specified delimiter.
+ * The function call always returns immediately. The asynchronous operation
+ * will continue until one of the following conditions is true:
+ *
+ * @li The get area of the streambuf contains the specified delimiter.
+ *
+ * @li An error occurred.
+ *
+ * This operation is implemented in terms of zero or more calls to the stream's
+ * async_read_some function, and is known as a <em>composed operation</em>. If
+ * the streambuf's get area already contains the delimiter, this asynchronous
+ * operation completes immediately. The program must ensure that the stream
+ * performs no other read operations (such as async_read, async_read_until, the
+ * stream's async_read_some function, or any other composed operations that
+ * perform reads) until this operation completes.
+ *
+ * @param s The stream from which the data is to be read. The type must support
+ * the AsyncReadStream concept.
+ *
+ * @param b A streambuf object into which the data will be read. Ownership of
+ * the streambuf is retained by the caller, which must guarantee that it remains
+ * valid until the handler is called.
+ *
+ * @param delim The delimiter string.
+ *
+ * @param handler The handler to be called when the read operation completes.
+ * Copies will be made of the handler as required. The function signature of the
+ * handler must be:
+ * @code void handler(
+ *   // Result of operation.
+ *   const asio::error_code& error,
+ *
+ *   // The number of bytes in the streambuf's get
+ *   // area up to and including the delimiter.
+ *   // 0 if an error occurred.
+ *   std::size_t bytes_transferred
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. On
+ * immediate completion, invocation of the handler will be performed in a
+ * manner equivalent to using asio::post().
+ *
+ * @note After a successful async_read_until operation, the streambuf may
+ * contain additional data beyond the delimiter. An application will typically
+ * leave that data in the streambuf for a subsequent async_read_until operation
+ * to examine.
+ *
+ * @par Example
+ * To asynchronously read data into a streambuf until a newline is encountered:
+ * @code asio::streambuf b;
+ * ...
+ * void handler(const asio::error_code& e, std::size_t size)
+ * {
+ *   if (!e)
+ *   {
+ *     std::istream is(&b);
+ *     std::string line;
+ *     std::getline(is, line);
+ *     ...
+ *   }
+ * }
+ * ...
+ * asio::async_read_until(s, b, "\r\n", handler); @endcode
+ * After the @c async_read_until operation completes successfully, the buffer
+ * @c b contains the delimiter:
+ * @code { 'a', 'b', ..., 'c', '\r', '\n', 'd', 'e', ... } @endcode
+ * The call to @c std::getline then extracts the data up to and including the
+ * newline (which is discarded), so that the string @c line contains:
+ * @code { 'a', 'b', ..., 'c', '\r' } @endcode
+ * The remaining data is left in the buffer @c b as follows:
+ * @code { 'd', 'e', ... } @endcode
+ * This data may be the start of a new line, to be extracted by a subsequent
+ * @c async_read_until operation.
+ */
+template <typename AsyncReadStream, typename Allocator,
+    ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+      std::size_t)) ReadHandler
+        ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(
+          typename AsyncReadStream::executor_type)>
+ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,
+    void (asio::error_code, std::size_t))
+async_read_until(AsyncReadStream& s,
+    asio::basic_streambuf<Allocator>& b,
+    ASIO_STRING_VIEW_PARAM delim,
+    ASIO_MOVE_ARG(ReadHandler) handler
+      ASIO_DEFAULT_COMPLETION_TOKEN(
+        typename AsyncReadStream::executor_type));
+
+#if defined(ASIO_HAS_BOOST_REGEX) \
+  || defined(GENERATING_DOCUMENTATION)
+
+/// Start an asynchronous operation to read data into a streambuf until some
+/// part of its data matches a regular expression.
+/**
+ * This function is used to asynchronously read data into the specified
+ * streambuf until the streambuf's get area contains some data that matches a
+ * regular expression. The function call always returns immediately. The
+ * asynchronous operation will continue until one of the following conditions
+ * is true:
+ *
+ * @li A substring of the streambuf's get area matches the regular expression.
+ *
+ * @li An error occurred.
+ *
+ * This operation is implemented in terms of zero or more calls to the stream's
+ * async_read_some function, and is known as a <em>composed operation</em>. If
+ * the streambuf's get area already contains data that matches the regular
+ * expression, this asynchronous operation completes immediately. The program
+ * must ensure that the stream performs no other read operations (such as
+ * async_read, async_read_until, the stream's async_read_some function, or any
+ * other composed operations that perform reads) until this operation
+ * completes.
+ *
+ * @param s The stream from which the data is to be read. The type must support
+ * the AsyncReadStream concept.
+ *
+ * @param b A streambuf object into which the data will be read. Ownership of
+ * the streambuf is retained by the caller, which must guarantee that it remains
+ * valid until the handler is called.
+ *
+ * @param expr The regular expression.
+ *
+ * @param handler The handler to be called when the read operation completes.
+ * Copies will be made of the handler as required. The function signature of the
+ * handler must be:
+ * @code void handler(
+ *   // Result of operation.
+ *   const asio::error_code& error,
+ *
+ *   // The number of bytes in the streambuf's get
+ *   // area up to and including the substring
+ *   // that matches the regular. expression.
+ *   // 0 if an error occurred.
+ *   std::size_t bytes_transferred
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. On
+ * immediate completion, invocation of the handler will be performed in a
+ * manner equivalent to using asio::post().
+ *
+ * @note After a successful async_read_until operation, the streambuf may
+ * contain additional data beyond that which matched the regular expression. An
+ * application will typically leave that data in the streambuf for a subsequent
+ * async_read_until operation to examine.
+ *
+ * @par Example
+ * To asynchronously read data into a streambuf until a CR-LF sequence is
+ * encountered:
+ * @code asio::streambuf b;
+ * ...
+ * void handler(const asio::error_code& e, std::size_t size)
+ * {
+ *   if (!e)
+ *   {
+ *     std::istream is(&b);
+ *     std::string line;
+ *     std::getline(is, line);
+ *     ...
+ *   }
+ * }
+ * ...
+ * asio::async_read_until(s, b, boost::regex("\r\n"), handler); @endcode
+ * After the @c async_read_until operation completes successfully, the buffer
+ * @c b contains the data which matched the regular expression:
+ * @code { 'a', 'b', ..., 'c', '\r', '\n', 'd', 'e', ... } @endcode
+ * The call to @c std::getline then extracts the data up to and including the
+ * newline (which is discarded), so that the string @c line contains:
+ * @code { 'a', 'b', ..., 'c', '\r' } @endcode
+ * The remaining data is left in the buffer @c b as follows:
+ * @code { 'd', 'e', ... } @endcode
+ * This data may be the start of a new line, to be extracted by a subsequent
+ * @c async_read_until operation.
+ */
+template <typename AsyncReadStream, typename Allocator,
+    ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+      std::size_t)) ReadHandler
+        ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(
+          typename AsyncReadStream::executor_type)>
+ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,
+    void (asio::error_code, std::size_t))
+async_read_until(AsyncReadStream& s,
+    asio::basic_streambuf<Allocator>& b, const boost::regex& expr,
+    ASIO_MOVE_ARG(ReadHandler) handler
+      ASIO_DEFAULT_COMPLETION_TOKEN(
+        typename AsyncReadStream::executor_type));
+
+#endif // defined(ASIO_HAS_BOOST_REGEX)
+       // || defined(GENERATING_DOCUMENTATION)
+
+/// Start an asynchronous operation to read data into a streambuf until a
+/// function object indicates a match.
+/**
+ * This function is used to asynchronously read data into the specified
+ * streambuf until a user-defined match condition function object, when applied
+ * to the data contained in the streambuf, indicates a successful match. The
+ * function call always returns immediately. The asynchronous operation will
+ * continue until one of the following conditions is true:
+ *
+ * @li The match condition function object returns a std::pair where the second
+ * element evaluates to true.
+ *
+ * @li An error occurred.
+ *
+ * This operation is implemented in terms of zero or more calls to the stream's
+ * async_read_some function, and is known as a <em>composed operation</em>. If
+ * the match condition function object already indicates a match, this
+ * asynchronous operation completes immediately. The program must ensure that
+ * the stream performs no other read operations (such as async_read,
+ * async_read_until, the stream's async_read_some function, or any other
+ * composed operations that perform reads) until this operation completes.
+ *
+ * @param s The stream from which the data is to be read. The type must support
+ * the AsyncReadStream concept.
+ *
+ * @param b A streambuf object into which the data will be read.
+ *
+ * @param match_condition The function object to be called to determine whether
+ * a match exists. The signature of the function object must be:
+ * @code pair<iterator, bool> match_condition(iterator begin, iterator end);
+ * @endcode
+ * where @c iterator represents the type:
+ * @code buffers_iterator<basic_streambuf<Allocator>::const_buffers_type>
+ * @endcode
+ * The iterator parameters @c begin and @c end define the range of bytes to be
+ * scanned to determine whether there is a match. The @c first member of the
+ * return value is an iterator marking one-past-the-end of the bytes that have
+ * been consumed by the match function. This iterator is used to calculate the
+ * @c begin parameter for any subsequent invocation of the match condition. The
+ * @c second member of the return value is true if a match has been found, false
+ * otherwise.
+ *
+ * @param handler The handler to be called when the read operation completes.
+ * Copies will be made of the handler as required. The function signature of the
+ * handler must be:
+ * @code void handler(
+ *   // Result of operation.
+ *   const asio::error_code& error,
+ *
+ *   // The number of bytes in the streambuf's get
+ *   // area that have been fully consumed by the
+ *   // match function. O if an error occurred.
+ *   std::size_t bytes_transferred
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. On
+ * immediate completion, invocation of the handler will be performed in a
+ * manner equivalent to using asio::post().
+ *
+ * @note After a successful async_read_until operation, the streambuf may
+ * contain additional data beyond that which matched the function object. An
+ * application will typically leave that data in the streambuf for a subsequent
+ * async_read_until operation to examine.
+ *
+ * @note The default implementation of the @c is_match_condition type trait
+ * evaluates to true for function pointers and function objects with a
+ * @c result_type typedef. It must be specialised for other user-defined
+ * function objects.
+ *
+ * @par Examples
+ * To asynchronously read data into a streambuf until whitespace is encountered:
+ * @code typedef asio::buffers_iterator<
+ *     asio::streambuf::const_buffers_type> iterator;
+ *
+ * std::pair<iterator, bool>
+ * match_whitespace(iterator begin, iterator end)
+ * {
+ *   iterator i = begin;
+ *   while (i != end)
+ *     if (std::isspace(*i++))
+ *       return std::make_pair(i, true);
+ *   return std::make_pair(i, false);
+ * }
+ * ...
+ * void handler(const asio::error_code& e, std::size_t size);
+ * ...
+ * asio::streambuf b;
+ * asio::async_read_until(s, b, match_whitespace, handler);
+ * @endcode
+ *
+ * To asynchronously read data into a streambuf until a matching character is
+ * found:
+ * @code class match_char
+ * {
+ * public:
+ *   explicit match_char(char c) : c_(c) {}
+ *
+ *   template <typename Iterator>
+ *   std::pair<Iterator, bool> operator()(
+ *       Iterator begin, Iterator end) const
+ *   {
+ *     Iterator i = begin;
+ *     while (i != end)
+ *       if (c_ == *i++)
+ *         return std::make_pair(i, true);
+ *     return std::make_pair(i, false);
+ *   }
+ *
+ * private:
+ *   char c_;
+ * };
+ *
+ * namespace asio {
+ *   template <> struct is_match_condition<match_char>
+ *     : public boost::true_type {};
+ * } // namespace asio
+ * ...
+ * void handler(const asio::error_code& e, std::size_t size);
+ * ...
+ * asio::streambuf b;
+ * asio::async_read_until(s, b, match_char('a'), handler);
+ * @endcode
+ */
+template <typename AsyncReadStream, typename Allocator, typename MatchCondition,
+    ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+      std::size_t)) ReadHandler
+        ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(
+          typename AsyncReadStream::executor_type)>
+ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,
+    void (asio::error_code, std::size_t))
+async_read_until(AsyncReadStream& s,
+    asio::basic_streambuf<Allocator>& b,
+    MatchCondition match_condition,
+    ASIO_MOVE_ARG(ReadHandler) handler
+      ASIO_DEFAULT_COMPLETION_TOKEN(
+        typename AsyncReadStream::executor_type),
+    typename enable_if<is_match_condition<MatchCondition>::value>::type* = 0);
+
+#endif // !defined(ASIO_NO_IOSTREAM)
+#endif // !defined(ASIO_NO_EXTENSIONS)
+#endif // !defined(ASIO_NO_DYNAMIC_BUFFER_V1)
+
+/// Start an asynchronous operation to read data into a dynamic buffer sequence
+/// until it contains a specified delimiter.
+/**
+ * This function is used to asynchronously read data into the specified dynamic
+ * buffer sequence until the dynamic buffer sequence's get area contains the
+ * specified delimiter. The function call always returns immediately. The
+ * asynchronous operation will continue until one of the following conditions
+ * is true:
+ *
+ * @li The get area of the dynamic buffer sequence contains the specified
+ * delimiter.
+ *
+ * @li An error occurred.
+ *
+ * This operation is implemented in terms of zero or more calls to the stream's
+ * async_read_some function, and is known as a <em>composed operation</em>. If
+ * the dynamic buffer sequence's get area already contains the delimiter, this
+ * asynchronous operation completes immediately. The program must ensure that
+ * the stream performs no other read operations (such as async_read,
+ * async_read_until, the stream's async_read_some function, or any other
+ * composed operations that perform reads) until this operation completes.
+ *
+ * @param s The stream from which the data is to be read. The type must support
+ * the AsyncReadStream concept.
+ *
+ * @param buffers The dynamic buffer sequence into which the data will be read.
+ * Although the buffers object may be copied as necessary, ownership of the
+ * underlying memory blocks is retained by the caller, which must guarantee
+ * that they remain valid until the handler is called.
+ *
+ * @param delim The delimiter character.
+ *
+ * @param handler The handler to be called when the read operation completes.
+ * Copies will be made of the handler as required. The function signature of the
+ * handler must be:
+ * @code void handler(
+ *   // Result of operation.
+ *   const asio::error_code& error,
+ *
+ *   // The number of bytes in the dynamic buffer sequence's
+ *   // get area up to and including the delimiter.
+ *   // 0 if an error occurred.
+ *   std::size_t bytes_transferred
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. On
+ * immediate completion, invocation of the handler will be performed in a
+ * manner equivalent to using asio::post().
+ *
+ * @note After a successful async_read_until operation, the dynamic buffer
+ * sequence may contain additional data beyond the delimiter. An application
+ * will typically leave that data in the dynamic buffer sequence for a
+ * subsequent async_read_until operation to examine.
+ *
+ * @par Example
+ * To asynchronously read data into a @c std::string until a newline is
+ * encountered:
+ * @code std::string data;
+ * ...
+ * void handler(const asio::error_code& e, std::size_t size)
+ * {
+ *   if (!e)
+ *   {
+ *     std::string line = data.substr(0, n);
+ *     data.erase(0, n);
+ *     ...
+ *   }
+ * }
+ * ...
+ * asio::async_read_until(s, data, '\n', handler); @endcode
+ * After the @c async_read_until operation completes successfully, the buffer
+ * @c data contains the delimiter:
+ * @code { 'a', 'b', ..., 'c', '\n', 'd', 'e', ... } @endcode
+ * The call to @c substr then extracts the data up to and including the
+ * delimiter, so that the string @c line contains:
+ * @code { 'a', 'b', ..., 'c', '\n' } @endcode
+ * After the call to @c erase, the remaining data is left in the buffer @c data
+ * as follows:
+ * @code { 'd', 'e', ... } @endcode
+ * This data may be the start of a new line, to be extracted by a subsequent
+ * @c async_read_until operation.
+ */
+template <typename AsyncReadStream, typename DynamicBuffer_v2,
+    ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+      std::size_t)) ReadHandler
+        ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(
+          typename AsyncReadStream::executor_type)>
+ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,
+    void (asio::error_code, std::size_t))
+async_read_until(AsyncReadStream& s, DynamicBuffer_v2 buffers, char delim,
+    ASIO_MOVE_ARG(ReadHandler) handler
+      ASIO_DEFAULT_COMPLETION_TOKEN(
+        typename AsyncReadStream::executor_type),
+    typename enable_if<
+      is_dynamic_buffer_v2<DynamicBuffer_v2>::value
+    >::type* = 0);
+
+/// Start an asynchronous operation to read data into a dynamic buffer sequence
+/// until it contains a specified delimiter.
+/**
+ * This function is used to asynchronously read data into the specified dynamic
+ * buffer sequence until the dynamic buffer sequence's get area contains the
+ * specified delimiter. The function call always returns immediately. The
+ * asynchronous operation will continue until one of the following conditions
+ * is true:
+ *
+ * @li The get area of the dynamic buffer sequence contains the specified
+ * delimiter.
+ *
+ * @li An error occurred.
+ *
+ * This operation is implemented in terms of zero or more calls to the stream's
+ * async_read_some function, and is known as a <em>composed operation</em>. If
+ * the dynamic buffer sequence's get area already contains the delimiter, this
+ * asynchronous operation completes immediately. The program must ensure that
+ * the stream performs no other read operations (such as async_read,
+ * async_read_until, the stream's async_read_some function, or any other
+ * composed operations that perform reads) until this operation completes.
+ *
+ * @param s The stream from which the data is to be read. The type must support
+ * the AsyncReadStream concept.
+ *
+ * @param buffers The dynamic buffer sequence into which the data will be read.
+ * Although the buffers object may be copied as necessary, ownership of the
+ * underlying memory blocks is retained by the caller, which must guarantee
+ * that they remain valid until the handler is called.
+ *
+ * @param delim The delimiter string.
+ *
+ * @param handler The handler to be called when the read operation completes.
+ * Copies will be made of the handler as required. The function signature of the
+ * handler must be:
+ * @code void handler(
+ *   // Result of operation.
+ *   const asio::error_code& error,
+ *
+ *   // The number of bytes in the dynamic buffer sequence's
+ *   // get area up to and including the delimiter.
+ *   // 0 if an error occurred.
+ *   std::size_t bytes_transferred
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. On
+ * immediate completion, invocation of the handler will be performed in a
+ * manner equivalent to using asio::post().
+ *
+ * @note After a successful async_read_until operation, the dynamic buffer
+ * sequence may contain additional data beyond the delimiter. An application
+ * will typically leave that data in the dynamic buffer sequence for a
+ * subsequent async_read_until operation to examine.
+ *
+ * @par Example
+ * To asynchronously read data into a @c std::string until a CR-LF sequence is
+ * encountered:
+ * @code std::string data;
+ * ...
+ * void handler(const asio::error_code& e, std::size_t size)
+ * {
+ *   if (!e)
+ *   {
+ *     std::string line = data.substr(0, n);
+ *     data.erase(0, n);
+ *     ...
+ *   }
+ * }
+ * ...
+ * asio::async_read_until(s, data, "\r\n", handler); @endcode
+ * After the @c async_read_until operation completes successfully, the string
+ * @c data contains the delimiter:
+ * @code { 'a', 'b', ..., 'c', '\r', '\n', 'd', 'e', ... } @endcode
+ * The call to @c substr then extracts the data up to and including the
+ * delimiter, so that the string @c line contains:
+ * @code { 'a', 'b', ..., 'c', '\r', '\n' } @endcode
+ * After the call to @c erase, the remaining data is left in the string @c data
+ * as follows:
+ * @code { 'd', 'e', ... } @endcode
+ * This data may be the start of a new line, to be extracted by a subsequent
+ * @c async_read_until operation.
+ */
+template <typename AsyncReadStream, typename DynamicBuffer_v2,
+    ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+      std::size_t)) ReadHandler
+        ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(
+          typename AsyncReadStream::executor_type)>
+ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,
+    void (asio::error_code, std::size_t))
+async_read_until(AsyncReadStream& s, DynamicBuffer_v2 buffers,
+    ASIO_STRING_VIEW_PARAM delim,
+    ASIO_MOVE_ARG(ReadHandler) handler
+      ASIO_DEFAULT_COMPLETION_TOKEN(
+        typename AsyncReadStream::executor_type),
+    typename enable_if<
+      is_dynamic_buffer_v2<DynamicBuffer_v2>::value
+    >::type* = 0);
+
+#if !defined(ASIO_NO_EXTENSIONS)
+#if defined(ASIO_HAS_BOOST_REGEX) \
+  || defined(GENERATING_DOCUMENTATION)
+
+/// Start an asynchronous operation to read data into a dynamic buffer sequence
+/// until some part of its data matches a regular expression.
+/**
+ * This function is used to asynchronously read data into the specified dynamic
+ * buffer sequence until the dynamic buffer sequence's get area contains some
+ * data that matches a regular expression. The function call always returns
+ * immediately. The asynchronous operation will continue until one of the
+ * following conditions is true:
+ *
+ * @li A substring of the dynamic buffer sequence's get area matches the regular
+ * expression.
+ *
+ * @li An error occurred.
+ *
+ * This operation is implemented in terms of zero or more calls to the stream's
+ * async_read_some function, and is known as a <em>composed operation</em>. If
+ * the dynamic buffer sequence's get area already contains data that matches
+ * the regular expression, this asynchronous operation completes immediately.
+ * The program must ensure that the stream performs no other read operations
+ * (such as async_read, async_read_until, the stream's async_read_some
+ * function, or any other composed operations that perform reads) until this
+ * operation completes.
+ *
+ * @param s The stream from which the data is to be read. The type must support
+ * the AsyncReadStream concept.
+ *
+ * @param buffers The dynamic buffer sequence into which the data will be read.
+ * Although the buffers object may be copied as necessary, ownership of the
+ * underlying memory blocks is retained by the caller, which must guarantee
+ * that they remain valid until the handler is called.
+ *
+ * @param expr The regular expression.
+ *
+ * @param handler The handler to be called when the read operation completes.
+ * Copies will be made of the handler as required. The function signature of the
+ * handler must be:
+ * @code void handler(
+ *   // Result of operation.
+ *   const asio::error_code& error,
+ *
+ *   // The number of bytes in the dynamic buffer
+ *   // sequence's get area up to and including the
+ *   // substring that matches the regular expression.
+ *   // 0 if an error occurred.
+ *   std::size_t bytes_transferred
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. On
+ * immediate completion, invocation of the handler will be performed in a
+ * manner equivalent to using asio::post().
+ *
+ * @note After a successful async_read_until operation, the dynamic buffer
+ * sequence may contain additional data beyond that which matched the regular
+ * expression. An application will typically leave that data in the dynamic
+ * buffer sequence for a subsequent async_read_until operation to examine.
+ *
+ * @par Example
+ * To asynchronously read data into a @c std::string until a CR-LF sequence is
+ * encountered:
+ * @code std::string data;
+ * ...
+ * void handler(const asio::error_code& e, std::size_t size)
+ * {
+ *   if (!e)
+ *   {
+ *     std::string line = data.substr(0, n);
+ *     data.erase(0, n);
+ *     ...
+ *   }
+ * }
+ * ...
+ * asio::async_read_until(s, data,
+ *     boost::regex("\r\n"), handler); @endcode
+ * After the @c async_read_until operation completes successfully, the string
+ * @c data contains the data which matched the regular expression:
+ * @code { 'a', 'b', ..., 'c', '\r', '\n', 'd', 'e', ... } @endcode
+ * The call to @c substr then extracts the data up to and including the match,
+ * so that the string @c line contains:
+ * @code { 'a', 'b', ..., 'c', '\r', '\n' } @endcode
+ * After the call to @c erase, the remaining data is left in the string @c data
+ * as follows:
+ * @code { 'd', 'e', ... } @endcode
+ * This data may be the start of a new line, to be extracted by a subsequent
+ * @c async_read_until operation.
+ */
+template <typename AsyncReadStream, typename DynamicBuffer_v2,
+    ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+      std::size_t)) ReadHandler
+        ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(
+          typename AsyncReadStream::executor_type)>
+ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,
+    void (asio::error_code, std::size_t))
+async_read_until(AsyncReadStream& s, DynamicBuffer_v2 buffers,
+    const boost::regex& expr,
+    ASIO_MOVE_ARG(ReadHandler) handler
+      ASIO_DEFAULT_COMPLETION_TOKEN(
+        typename AsyncReadStream::executor_type),
+    typename enable_if<
+      is_dynamic_buffer_v2<DynamicBuffer_v2>::value
+    >::type* = 0);
+
+#endif // defined(ASIO_HAS_BOOST_REGEX)
+       // || defined(GENERATING_DOCUMENTATION)
+
+/// Start an asynchronous operation to read data into a dynamic buffer sequence
+/// until a function object indicates a match.
+/**
+ * This function is used to asynchronously read data into the specified dynamic
+ * buffer sequence until a user-defined match condition function object, when
+ * applied to the data contained in the dynamic buffer sequence, indicates a
+ * successful match. The function call always returns immediately. The
+ * asynchronous operation will continue until one of the following conditions
+ * is true:
+ *
+ * @li The match condition function object returns a std::pair where the second
+ * element evaluates to true.
+ *
+ * @li An error occurred.
+ *
+ * This operation is implemented in terms of zero or more calls to the stream's
+ * async_read_some function, and is known as a <em>composed operation</em>. If
+ * the match condition function object already indicates a match, this
+ * asynchronous operation completes immediately. The program must ensure that
+ * the stream performs no other read operations (such as async_read,
+ * async_read_until, the stream's async_read_some function, or any other
+ * composed operations that perform reads) until this operation completes.
+ *
+ * @param s The stream from which the data is to be read. The type must support
+ * the AsyncReadStream concept.
+ *
+ * @param buffers The dynamic buffer sequence into which the data will be read.
+ * Although the buffers object may be copied as necessary, ownership of the
+ * underlying memory blocks is retained by the caller, which must guarantee
+ * that they remain valid until the handler is called.
+ *
+ * @param match_condition The function object to be called to determine whether
+ * a match exists. The signature of the function object must be:
+ * @code pair<iterator, bool> match_condition(iterator begin, iterator end);
+ * @endcode
+ * where @c iterator represents the type:
+ * @code buffers_iterator<typename DynamicBuffer_v2::const_buffers_type>
+ * @endcode
+ * The iterator parameters @c begin and @c end define the range of bytes to be
+ * scanned to determine whether there is a match. The @c first member of the
+ * return value is an iterator marking one-past-the-end of the bytes that have
+ * been consumed by the match function. This iterator is used to calculate the
+ * @c begin parameter for any subsequent invocation of the match condition. The
+ * @c second member of the return value is true if a match has been found, false
+ * otherwise.
+ *
+ * @param handler The handler to be called when the read operation completes.
+ * Copies will be made of the handler as required. The function signature of the
+ * handler must be:
+ * @code void handler(
+ *   // Result of operation.
+ *   const asio::error_code& error,
+ *
+ *   // The number of bytes in the dynamic buffer sequence's
+ *   // get area that have been fully consumed by the match
+ *   // function. O if an error occurred.
+ *   std::size_t bytes_transferred
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. On
+ * immediate completion, invocation of the handler will be performed in a
+ * manner equivalent to using asio::post().
+ *
+ * @note After a successful async_read_until operation, the dynamic buffer
+ * sequence may contain additional data beyond that which matched the function
+ * object. An application will typically leave that data in the dynamic buffer
+ * sequence for a subsequent async_read_until operation to examine.
+ *
+ * @note The default implementation of the @c is_match_condition type trait
+ * evaluates to true for function pointers and function objects with a
+ * @c result_type typedef. It must be specialised for other user-defined
+ * function objects.
+ *
+ * @par Examples
+ * To asynchronously read data into a @c std::string until whitespace is
+ * encountered:
+ * @code typedef asio::buffers_iterator<
+ *     asio::const_buffers_1> iterator;
+ *
+ * std::pair<iterator, bool>
+ * match_whitespace(iterator begin, iterator end)
+ * {
+ *   iterator i = begin;
+ *   while (i != end)
+ *     if (std::isspace(*i++))
+ *       return std::make_pair(i, true);
+ *   return std::make_pair(i, false);
+ * }
+ * ...
+ * void handler(const asio::error_code& e, std::size_t size);
+ * ...
+ * std::string data;
+ * asio::async_read_until(s, data, match_whitespace, handler);
+ * @endcode
+ *
+ * To asynchronously read data into a @c std::string until a matching character
+ * is found:
+ * @code class match_char
+ * {
+ * public:
+ *   explicit match_char(char c) : c_(c) {}
+ *
+ *   template <typename Iterator>
+ *   std::pair<Iterator, bool> operator()(
+ *       Iterator begin, Iterator end) const
+ *   {
+ *     Iterator i = begin;
+ *     while (i != end)
+ *       if (c_ == *i++)
+ *         return std::make_pair(i, true);
+ *     return std::make_pair(i, false);
+ *   }
+ *
+ * private:
+ *   char c_;
+ * };
+ *
+ * namespace asio {
+ *   template <> struct is_match_condition<match_char>
+ *     : public boost::true_type {};
+ * } // namespace asio
+ * ...
+ * void handler(const asio::error_code& e, std::size_t size);
+ * ...
+ * std::string data;
+ * asio::async_read_until(s, data, match_char('a'), handler);
+ * @endcode
+ */
+template <typename AsyncReadStream,
+    typename DynamicBuffer_v2, typename MatchCondition,
+    ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+      std::size_t)) ReadHandler
+        ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(
+          typename AsyncReadStream::executor_type)>
+ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,
+    void (asio::error_code, std::size_t))
+async_read_until(AsyncReadStream& s, DynamicBuffer_v2 buffers,
+    MatchCondition match_condition,
+    ASIO_MOVE_ARG(ReadHandler) handler
+      ASIO_DEFAULT_COMPLETION_TOKEN(
+        typename AsyncReadStream::executor_type),
+    typename enable_if<
+      is_match_condition<MatchCondition>::value
+        && is_dynamic_buffer_v2<DynamicBuffer_v2>::value
+    >::type* = 0);
+
+#endif // !defined(ASIO_NO_EXTENSIONS)
+
+/*@}*/
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/impl/read_until.hpp"
+
+#endif // ASIO_READ_UNTIL_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/redirect_error.hpp b/link/modules/asio-standalone/asio/include/asio/redirect_error.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/redirect_error.hpp
@@ -0,0 +1,66 @@
+//
+// redirect_error.hpp
+// ~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_REDIRECT_ERROR_HPP
+#define ASIO_REDIRECT_ERROR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/type_traits.hpp"
+#include "asio/error_code.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+/// Completion token type used to specify that an error produced by an
+/// asynchronous operation is captured to an error_code variable.
+/**
+ * The redirect_error_t class is used to indicate that any error_code produced
+ * by an asynchronous operation is captured to a specified variable.
+ */
+template <typename CompletionToken>
+class redirect_error_t
+{
+public:
+  /// Constructor. 
+  template <typename T>
+  redirect_error_t(ASIO_MOVE_ARG(T) completion_token,
+      asio::error_code& ec)
+    : token_(ASIO_MOVE_CAST(T)(completion_token)),
+      ec_(ec)
+  {
+  }
+
+//private:
+  CompletionToken token_;
+  asio::error_code& ec_;
+};
+
+/// Create a completion token to capture error_code values to a variable.
+template <typename CompletionToken>
+inline redirect_error_t<typename decay<CompletionToken>::type> redirect_error(
+    ASIO_MOVE_ARG(CompletionToken) completion_token,
+    asio::error_code& ec)
+{
+  return redirect_error_t<typename decay<CompletionToken>::type>(
+      ASIO_MOVE_CAST(CompletionToken)(completion_token), ec);
+}
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/impl/redirect_error.hpp"
+
+#endif // ASIO_REDIRECT_ERROR_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/require.hpp b/link/modules/asio-standalone/asio/include/asio/require.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/require.hpp
@@ -0,0 +1,524 @@
+//
+// require.hpp
+// ~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_REQUIRE_HPP
+#define ASIO_REQUIRE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/type_traits.hpp"
+#include "asio/is_applicable_property.hpp"
+#include "asio/traits/require_member.hpp"
+#include "asio/traits/require_free.hpp"
+#include "asio/traits/static_require.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+#if defined(GENERATING_DOCUMENTATION)
+
+namespace asio {
+
+/// A customisation point that applies a concept-preserving property to an
+/// object.
+/**
+ * The name <tt>require</tt> denotes a customisation point object. The
+ * expression <tt>asio::require(E, P0, Pn...)</tt> for some
+ * subexpressions <tt>E</tt> and <tt>P0</tt>, and where <tt>Pn...</tt>
+ * represents <tt>N</tt> subexpressions (where <tt>N</tt> is 0 or more, and with
+ * types <tt>T = decay_t<decltype(E)></tt> and <tt>Prop0 =
+ * decay_t<decltype(P0)></tt>) is expression-equivalent to:
+ *
+ * @li If <tt>is_applicable_property_v<T, Prop0> && Prop0::is_requirable</tt> is
+ *   not a well-formed constant expression with value <tt>true</tt>,
+ *   <tt>asio::require(E, P0, Pn...)</tt> is ill-formed.
+ *
+ * @li Otherwise, <tt>E</tt> if <tt>N == 0</tt> and the expression
+ *   <tt>Prop0::template static_query_v<T> == Prop0::value()</tt> is a
+ *   well-formed constant expression with value <tt>true</tt>.
+ *
+ * @li Otherwise, <tt>(E).require(P0)</tt> if <tt>N == 0</tt> and the expression
+ *   <tt>(E).require(P0)</tt> is a valid expression.
+ *
+ * @li Otherwise, <tt>require(E, P0)</tt> if <tt>N == 0</tt> and the expression
+ *   <tt>require(E, P0)</tt> is a valid expression with overload resolution
+ *   performed in a context that does not include the declaration of the
+ *   <tt>require</tt> customization point object.
+ *
+ * @li Otherwise,
+ *   <tt>asio::require(asio::require(E, P0), Pn...)</tt>
+ *   if <tt>N > 0</tt> and the expression
+ *   <tt>asio::require(asio::require(E, P0), Pn...)</tt>
+ *   is a valid expression.
+ *
+ * @li Otherwise, <tt>asio::require(E, P0, Pn...)</tt> is ill-formed.
+ */
+inline constexpr unspecified require = unspecified;
+
+/// A type trait that determines whether a @c require expression is well-formed.
+/**
+ * Class template @c can_require is a trait that is derived from
+ * @c true_type if the expression <tt>asio::require(std::declval<T>(),
+ * std::declval<Properties>()...)</tt> is well formed; otherwise @c false_type.
+ */
+template <typename T, typename... Properties>
+struct can_require :
+  integral_constant<bool, automatically_determined>
+{
+};
+
+/// A type trait that determines whether a @c require expression will not throw.
+/**
+ * Class template @c is_nothrow_require is a trait that is derived from
+ * @c true_type if the expression <tt>asio::require(std::declval<T>(),
+ * std::declval<Properties>()...)</tt> is @c noexcept; otherwise @c false_type.
+ */
+template <typename T, typename... Properties>
+struct is_nothrow_require :
+  integral_constant<bool, automatically_determined>
+{
+};
+
+/// A type trait that determines the result type of a @c require expression.
+/**
+ * Class template @c require_result is a trait that determines the result
+ * type of the expression <tt>asio::require(std::declval<T>(),
+ * std::declval<Properties>()...)</tt>.
+ */
+template <typename T, typename... Properties>
+struct require_result
+{
+  /// The result of the @c require expression.
+  typedef automatically_determined type;
+};
+
+} // namespace asio
+
+#else // defined(GENERATING_DOCUMENTATION)
+
+namespace asio_require_fn {
+
+using asio::decay;
+using asio::declval;
+using asio::enable_if;
+using asio::is_applicable_property;
+using asio::traits::require_free;
+using asio::traits::require_member;
+using asio::traits::static_require;
+
+void require();
+
+enum overload_type
+{
+  identity,
+  call_member,
+  call_free,
+  two_props,
+  n_props,
+  ill_formed
+};
+
+template <typename T, typename Properties, typename = void>
+struct call_traits
+{
+  ASIO_STATIC_CONSTEXPR(overload_type, overload = ill_formed);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
+  typedef void result_type;
+};
+
+template <typename T, typename Property>
+struct call_traits<T, void(Property),
+  typename enable_if<
+    (
+      is_applicable_property<
+        typename decay<T>::type,
+        typename decay<Property>::type
+      >::value
+      &&
+      decay<Property>::type::is_requirable
+      &&
+      static_require<T, Property>::is_valid
+    )
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(overload_type, overload = identity);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
+
+#if defined(ASIO_HAS_MOVE)
+  typedef ASIO_MOVE_ARG(T) result_type;
+#else // defined(ASIO_HAS_MOVE)
+  typedef ASIO_MOVE_ARG(typename decay<T>::type) result_type;
+#endif // defined(ASIO_HAS_MOVE)
+};
+
+template <typename T, typename Property>
+struct call_traits<T, void(Property),
+  typename enable_if<
+    (
+      is_applicable_property<
+        typename decay<T>::type,
+        typename decay<Property>::type
+      >::value
+      &&
+      decay<Property>::type::is_requirable
+      &&
+      !static_require<T, Property>::is_valid
+      &&
+      require_member<T, Property>::is_valid
+    )
+  >::type> :
+  require_member<T, Property>
+{
+  ASIO_STATIC_CONSTEXPR(overload_type, overload = call_member);
+};
+
+template <typename T, typename Property>
+struct call_traits<T, void(Property),
+  typename enable_if<
+    (
+      is_applicable_property<
+        typename decay<T>::type,
+        typename decay<Property>::type
+      >::value
+      &&
+      decay<Property>::type::is_requirable
+      &&
+      !static_require<T, Property>::is_valid
+      &&
+      !require_member<T, Property>::is_valid
+      &&
+      require_free<T, Property>::is_valid
+    )
+  >::type> :
+  require_free<T, Property>
+{
+  ASIO_STATIC_CONSTEXPR(overload_type, overload = call_free);
+};
+
+template <typename T, typename P0, typename P1>
+struct call_traits<T, void(P0, P1),
+  typename enable_if<
+    call_traits<T, void(P0)>::overload != ill_formed
+    &&
+    call_traits<
+      typename call_traits<T, void(P0)>::result_type,
+      void(P1)
+    >::overload != ill_formed
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(overload_type, overload = two_props);
+
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept =
+    (
+      call_traits<T, void(P0)>::is_noexcept
+      &&
+      call_traits<
+        typename call_traits<T, void(P0)>::result_type,
+        void(P1)
+      >::is_noexcept
+    ));
+
+  typedef typename decay<
+    typename call_traits<
+      typename call_traits<T, void(P0)>::result_type,
+      void(P1)
+    >::result_type
+  >::type result_type;
+};
+
+template <typename T, typename P0, typename P1, typename ASIO_ELLIPSIS PN>
+struct call_traits<T, void(P0, P1, PN ASIO_ELLIPSIS),
+  typename enable_if<
+    call_traits<T, void(P0)>::overload != ill_formed
+    &&
+    call_traits<
+      typename call_traits<T, void(P0)>::result_type,
+      void(P1, PN ASIO_ELLIPSIS)
+    >::overload != ill_formed
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(overload_type, overload = n_props);
+
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept =
+    (
+      call_traits<T, void(P0)>::is_noexcept
+      &&
+      call_traits<
+        typename call_traits<T, void(P0)>::result_type,
+        void(P1, PN ASIO_ELLIPSIS)
+      >::is_noexcept
+    ));
+
+  typedef typename decay<
+    typename call_traits<
+      typename call_traits<T, void(P0)>::result_type,
+      void(P1, PN ASIO_ELLIPSIS)
+    >::result_type
+  >::type result_type;
+};
+
+struct impl
+{
+  template <typename T, typename Property>
+  ASIO_NODISCARD ASIO_CONSTEXPR typename enable_if<
+    call_traits<T, void(Property)>::overload == identity,
+    typename call_traits<T, void(Property)>::result_type
+  >::type
+  operator()(
+      ASIO_MOVE_ARG(T) t,
+      ASIO_MOVE_ARG(Property)) const
+    ASIO_NOEXCEPT_IF((
+      call_traits<T, void(Property)>::is_noexcept))
+  {
+    return ASIO_MOVE_CAST(T)(t);
+  }
+
+  template <typename T, typename Property>
+  ASIO_NODISCARD ASIO_CONSTEXPR typename enable_if<
+    call_traits<T, void(Property)>::overload == call_member,
+    typename call_traits<T, void(Property)>::result_type
+  >::type
+  operator()(
+      ASIO_MOVE_ARG(T) t,
+      ASIO_MOVE_ARG(Property) p) const
+    ASIO_NOEXCEPT_IF((
+      call_traits<T, void(Property)>::is_noexcept))
+  {
+    return ASIO_MOVE_CAST(T)(t).require(
+        ASIO_MOVE_CAST(Property)(p));
+  }
+
+  template <typename T, typename Property>
+  ASIO_NODISCARD ASIO_CONSTEXPR typename enable_if<
+    call_traits<T, void(Property)>::overload == call_free,
+    typename call_traits<T, void(Property)>::result_type
+  >::type
+  operator()(
+      ASIO_MOVE_ARG(T) t,
+      ASIO_MOVE_ARG(Property) p) const
+    ASIO_NOEXCEPT_IF((
+      call_traits<T, void(Property)>::is_noexcept))
+  {
+    return require(
+        ASIO_MOVE_CAST(T)(t),
+        ASIO_MOVE_CAST(Property)(p));
+  }
+
+  template <typename T, typename P0, typename P1>
+  ASIO_NODISCARD ASIO_CONSTEXPR typename enable_if<
+    call_traits<T, void(P0, P1)>::overload == two_props,
+    typename call_traits<T, void(P0, P1)>::result_type
+  >::type
+  operator()(
+      ASIO_MOVE_ARG(T) t,
+      ASIO_MOVE_ARG(P0) p0,
+      ASIO_MOVE_ARG(P1) p1) const
+    ASIO_NOEXCEPT_IF((
+      call_traits<T, void(P0, P1)>::is_noexcept))
+  {
+    return (*this)(
+        (*this)(
+          ASIO_MOVE_CAST(T)(t),
+          ASIO_MOVE_CAST(P0)(p0)),
+        ASIO_MOVE_CAST(P1)(p1));
+  }
+
+  template <typename T, typename P0, typename P1,
+    typename ASIO_ELLIPSIS PN>
+  ASIO_NODISCARD ASIO_CONSTEXPR typename enable_if<
+    call_traits<T, void(P0, P1, PN ASIO_ELLIPSIS)>::overload == n_props,
+    typename call_traits<T, void(P0, P1, PN ASIO_ELLIPSIS)>::result_type
+  >::type
+  operator()(
+      ASIO_MOVE_ARG(T) t,
+      ASIO_MOVE_ARG(P0) p0,
+      ASIO_MOVE_ARG(P1) p1,
+      ASIO_MOVE_ARG(PN) ASIO_ELLIPSIS pn) const
+    ASIO_NOEXCEPT_IF((
+      call_traits<T, void(P0, P1, PN ASIO_ELLIPSIS)>::is_noexcept))
+  {
+    return (*this)(
+        (*this)(
+          ASIO_MOVE_CAST(T)(t),
+          ASIO_MOVE_CAST(P0)(p0)),
+        ASIO_MOVE_CAST(P1)(p1),
+        ASIO_MOVE_CAST(PN)(pn) ASIO_ELLIPSIS);
+  }
+};
+
+template <typename T = impl>
+struct static_instance
+{
+  static const T instance;
+};
+
+template <typename T>
+const T static_instance<T>::instance = {};
+
+} // namespace asio_require_fn
+namespace asio {
+namespace {
+
+static ASIO_CONSTEXPR const asio_require_fn::impl&
+  require = asio_require_fn::static_instance<>::instance;
+
+} // namespace
+
+#if defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+template <typename T, typename... Properties>
+struct can_require :
+  integral_constant<bool,
+    asio_require_fn::call_traits<T, void(Properties...)>::overload
+      != asio_require_fn::ill_formed>
+{
+};
+
+#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+template <typename T, typename P0 = void,
+    typename P1 = void, typename P2 = void>
+struct can_require :
+  integral_constant<bool,
+    asio_require_fn::call_traits<T, void(P0, P1, P2)>::overload
+      != asio_require_fn::ill_formed>
+{
+};
+
+template <typename T, typename P0, typename P1>
+struct can_require<T, P0, P1> :
+  integral_constant<bool,
+    asio_require_fn::call_traits<T, void(P0, P1)>::overload
+      != asio_require_fn::ill_formed>
+{
+};
+
+template <typename T, typename P0>
+struct can_require<T, P0> :
+  integral_constant<bool,
+    asio_require_fn::call_traits<T, void(P0)>::overload
+      != asio_require_fn::ill_formed>
+{
+};
+
+template <typename T>
+struct can_require<T> :
+  false_type
+{
+};
+
+#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+#if defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+template <typename T, typename ASIO_ELLIPSIS Properties>
+constexpr bool can_require_v
+  = can_require<T, Properties ASIO_ELLIPSIS>::value;
+
+#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+#if defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+template <typename T, typename... Properties>
+struct is_nothrow_require :
+  integral_constant<bool,
+    asio_require_fn::call_traits<T, void(Properties...)>::is_noexcept>
+{
+};
+
+#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+template <typename T, typename P0 = void,
+    typename P1 = void, typename P2 = void>
+struct is_nothrow_require :
+  integral_constant<bool,
+    asio_require_fn::call_traits<T, void(P0, P1, P2)>::is_noexcept>
+{
+};
+
+template <typename T, typename P0, typename P1>
+struct is_nothrow_require<T, P0, P1> :
+  integral_constant<bool,
+    asio_require_fn::call_traits<T, void(P0, P1)>::is_noexcept>
+{
+};
+
+template <typename T, typename P0>
+struct is_nothrow_require<T, P0> :
+  integral_constant<bool,
+    asio_require_fn::call_traits<T, void(P0)>::is_noexcept>
+{
+};
+
+template <typename T>
+struct is_nothrow_require<T> :
+  false_type
+{
+};
+
+#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+#if defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+template <typename T, typename ASIO_ELLIPSIS Properties>
+constexpr bool is_nothrow_require_v
+  = is_nothrow_require<T, Properties ASIO_ELLIPSIS>::value;
+
+#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+#if defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+template <typename T, typename... Properties>
+struct require_result
+{
+  typedef typename asio_require_fn::call_traits<
+      T, void(Properties...)>::result_type type;
+};
+
+#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+template <typename T, typename P0 = void,
+    typename P1 = void, typename P2 = void>
+struct require_result
+{
+  typedef typename asio_require_fn::call_traits<
+      T, void(P0, P1, P2)>::result_type type;
+};
+
+template <typename T, typename P0, typename P1>
+struct require_result<T, P0, P1>
+{
+  typedef typename asio_require_fn::call_traits<
+      T, void(P0, P1)>::result_type type;
+};
+
+template <typename T, typename P0>
+struct require_result<T, P0>
+{
+  typedef typename asio_require_fn::call_traits<
+      T, void(P0)>::result_type type;
+};
+
+template <typename T>
+struct require_result<T>
+{
+};
+
+#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+} // namespace asio
+
+#endif // defined(GENERATING_DOCUMENTATION)
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_REQUIRE_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/require_concept.hpp b/link/modules/asio-standalone/asio/include/asio/require_concept.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/require_concept.hpp
@@ -0,0 +1,310 @@
+//
+// require_concept.hpp
+// ~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_REQUIRE_CONCEPT_HPP
+#define ASIO_REQUIRE_CONCEPT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/type_traits.hpp"
+#include "asio/is_applicable_property.hpp"
+#include "asio/traits/require_concept_member.hpp"
+#include "asio/traits/require_concept_free.hpp"
+#include "asio/traits/static_require_concept.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+#if defined(GENERATING_DOCUMENTATION)
+
+namespace asio {
+
+/// A customisation point that applies a concept-enforcing property to an
+/// object.
+/**
+ * The name <tt>require_concept</tt> denotes a customization point object. The
+ * expression <tt>asio::require_concept(E, P)</tt> for some
+ * subexpressions <tt>E</tt> and <tt>P</tt> (with types <tt>T =
+ * decay_t<decltype(E)></tt> and <tt>Prop = decay_t<decltype(P)></tt>) is
+ * expression-equivalent to:
+ *
+ * @li If <tt>is_applicable_property_v<T, Prop> &&
+ *   Prop::is_requirable_concept</tt> is not a well-formed constant expression
+ *   with value <tt>true</tt>, <tt>asio::require_concept(E, P)</tt> is
+ *   ill-formed.
+ *
+ * @li Otherwise, <tt>E</tt> if the expression <tt>Prop::template
+ *   static_query_v<T> == Prop::value()</tt> is a well-formed constant
+ *   expression with value <tt>true</tt>.
+ *
+ * @li Otherwise, <tt>(E).require_concept(P)</tt> if the expression
+ *   <tt>(E).require_concept(P)</tt> is well-formed.
+ *
+ * @li Otherwise, <tt>require_concept(E, P)</tt> if the expression
+ *   <tt>require_concept(E, P)</tt> is a valid expression with overload
+ *   resolution performed in a context that does not include the declaration
+ *   of the <tt>require_concept</tt> customization point object.
+ *
+ * @li Otherwise, <tt>asio::require_concept(E, P)</tt> is ill-formed.
+ */
+inline constexpr unspecified require_concept = unspecified;
+
+/// A type trait that determines whether a @c require_concept expression is
+/// well-formed.
+/**
+ * Class template @c can_require_concept is a trait that is derived from
+ * @c true_type if the expression
+ * <tt>asio::require_concept(std::declval<T>(),
+ * std::declval<Property>())</tt> is well formed; otherwise @c false_type.
+ */
+template <typename T, typename Property>
+struct can_require_concept :
+  integral_constant<bool, automatically_determined>
+{
+};
+
+/// A type trait that determines whether a @c require_concept expression will
+/// not throw.
+/**
+ * Class template @c is_nothrow_require_concept is a trait that is derived from
+ * @c true_type if the expression
+ * <tt>asio::require_concept(std::declval<T>(),
+ * std::declval<Property>())</tt> is @c noexcept; otherwise @c false_type.
+ */
+template <typename T, typename Property>
+struct is_nothrow_require_concept :
+  integral_constant<bool, automatically_determined>
+{
+};
+
+/// A type trait that determines the result type of a @c require_concept
+/// expression.
+/**
+ * Class template @c require_concept_result is a trait that determines the
+ * result type of the expression
+ * <tt>asio::require_concept(std::declval<T>(),
+ * std::declval<Property>())</tt>.
+ */
+template <typename T, typename Property>
+struct require_concept_result
+{
+  /// The result of the @c require_concept expression.
+  typedef automatically_determined type;
+};
+
+} // namespace asio
+
+#else // defined(GENERATING_DOCUMENTATION)
+
+namespace asio_require_concept_fn {
+
+using asio::decay;
+using asio::declval;
+using asio::enable_if;
+using asio::is_applicable_property;
+using asio::traits::require_concept_free;
+using asio::traits::require_concept_member;
+using asio::traits::static_require_concept;
+
+void require_concept();
+
+enum overload_type
+{
+  identity,
+  call_member,
+  call_free,
+  ill_formed
+};
+
+template <typename T, typename Properties, typename = void>
+struct call_traits
+{
+  ASIO_STATIC_CONSTEXPR(overload_type, overload = ill_formed);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
+  typedef void result_type;
+};
+
+template <typename T, typename Property>
+struct call_traits<T, void(Property),
+  typename enable_if<
+    (
+      is_applicable_property<
+        typename decay<T>::type,
+        typename decay<Property>::type
+      >::value
+      &&
+      decay<Property>::type::is_requirable_concept
+      &&
+      static_require_concept<T, Property>::is_valid
+    )
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(overload_type, overload = identity);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
+  typedef ASIO_MOVE_ARG(T) result_type;
+};
+
+template <typename T, typename Property>
+struct call_traits<T, void(Property),
+  typename enable_if<
+    (
+      is_applicable_property<
+        typename decay<T>::type,
+        typename decay<Property>::type
+      >::value
+      &&
+      decay<Property>::type::is_requirable_concept
+      &&
+      !static_require_concept<T, Property>::is_valid
+      &&
+      require_concept_member<T, Property>::is_valid
+    )
+  >::type> :
+  require_concept_member<T, Property>
+{
+  ASIO_STATIC_CONSTEXPR(overload_type, overload = call_member);
+};
+
+template <typename T, typename Property>
+struct call_traits<T, void(Property),
+  typename enable_if<
+    (
+      is_applicable_property<
+        typename decay<T>::type,
+        typename decay<Property>::type
+      >::value
+      &&
+      decay<Property>::type::is_requirable_concept
+      &&
+      !static_require_concept<T, Property>::is_valid
+      &&
+      !require_concept_member<T, Property>::is_valid
+      &&
+      require_concept_free<T, Property>::is_valid
+    )
+  >::type> :
+  require_concept_free<T, Property>
+{
+  ASIO_STATIC_CONSTEXPR(overload_type, overload = call_free);
+};
+
+struct impl
+{
+  template <typename T, typename Property>
+  ASIO_NODISCARD ASIO_CONSTEXPR typename enable_if<
+    call_traits<T, void(Property)>::overload == identity,
+    typename call_traits<T, void(Property)>::result_type
+  >::type
+  operator()(
+      ASIO_MOVE_ARG(T) t,
+      ASIO_MOVE_ARG(Property)) const
+    ASIO_NOEXCEPT_IF((
+      call_traits<T, void(Property)>::is_noexcept))
+  {
+    return ASIO_MOVE_CAST(T)(t);
+  }
+
+  template <typename T, typename Property>
+  ASIO_NODISCARD ASIO_CONSTEXPR typename enable_if<
+    call_traits<T, void(Property)>::overload == call_member,
+    typename call_traits<T, void(Property)>::result_type
+  >::type
+  operator()(
+      ASIO_MOVE_ARG(T) t,
+      ASIO_MOVE_ARG(Property) p) const
+    ASIO_NOEXCEPT_IF((
+      call_traits<T, void(Property)>::is_noexcept))
+  {
+    return ASIO_MOVE_CAST(T)(t).require_concept(
+        ASIO_MOVE_CAST(Property)(p));
+  }
+
+  template <typename T, typename Property>
+  ASIO_NODISCARD ASIO_CONSTEXPR typename enable_if<
+    call_traits<T, void(Property)>::overload == call_free,
+    typename call_traits<T, void(Property)>::result_type
+  >::type
+  operator()(
+      ASIO_MOVE_ARG(T) t,
+      ASIO_MOVE_ARG(Property) p) const
+    ASIO_NOEXCEPT_IF((
+      call_traits<T, void(Property)>::is_noexcept))
+  {
+    return require_concept(
+        ASIO_MOVE_CAST(T)(t),
+        ASIO_MOVE_CAST(Property)(p));
+  }
+};
+
+template <typename T = impl>
+struct static_instance
+{
+  static const T instance;
+};
+
+template <typename T>
+const T static_instance<T>::instance = {};
+
+} // namespace asio_require_concept_fn
+namespace asio {
+namespace {
+
+static ASIO_CONSTEXPR const asio_require_concept_fn::impl&
+  require_concept = asio_require_concept_fn::static_instance<>::instance;
+
+} // namespace
+
+template <typename T, typename Property>
+struct can_require_concept :
+  integral_constant<bool,
+    asio_require_concept_fn::call_traits<T, void(Property)>::overload !=
+      asio_require_concept_fn::ill_formed>
+{
+};
+
+#if defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+template <typename T, typename Property>
+constexpr bool can_require_concept_v
+  = can_require_concept<T, Property>::value;
+
+#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+template <typename T, typename Property>
+struct is_nothrow_require_concept :
+  integral_constant<bool,
+    asio_require_concept_fn::call_traits<T, void(Property)>::is_noexcept>
+{
+};
+
+#if defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+template <typename T, typename Property>
+constexpr bool is_nothrow_require_concept_v
+  = is_nothrow_require_concept<T, Property>::value;
+
+#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)
+
+template <typename T, typename Property>
+struct require_concept_result
+{
+  typedef typename asio_require_concept_fn::call_traits<
+      T, void(Property)>::result_type type;
+};
+
+} // namespace asio
+
+#endif // defined(GENERATING_DOCUMENTATION)
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_REQUIRE_CONCEPT_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/serial_port.hpp b/link/modules/asio-standalone/asio/include/asio/serial_port.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/serial_port.hpp
@@ -0,0 +1,36 @@
+//
+// serial_port.hpp
+// ~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.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 ASIO_SERIAL_PORT_HPP
+#define ASIO_SERIAL_PORT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_SERIAL_PORT) \
+  || defined(GENERATING_DOCUMENTATION)
+
+#include "asio/basic_serial_port.hpp"
+
+namespace asio {
+
+/// Typedef for the typical usage of a serial port.
+typedef basic_serial_port<> serial_port;
+
+} // namespace asio
+
+#endif // defined(ASIO_HAS_SERIAL_PORT)
+       //   || defined(GENERATING_DOCUMENTATION)
+
+#endif // ASIO_SERIAL_PORT_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/serial_port_base.hpp b/link/modules/asio-standalone/asio/include/asio/serial_port_base.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/serial_port_base.hpp
@@ -0,0 +1,167 @@
+//
+// serial_port_base.hpp
+// ~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.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 ASIO_SERIAL_PORT_BASE_HPP
+#define ASIO_SERIAL_PORT_BASE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_SERIAL_PORT) \
+  || defined(GENERATING_DOCUMENTATION)
+
+#if !defined(ASIO_WINDOWS) && !defined(__CYGWIN__)
+# include <termios.h>
+#endif // !defined(ASIO_WINDOWS) && !defined(__CYGWIN__)
+
+#include "asio/detail/socket_types.hpp"
+#include "asio/error_code.hpp"
+
+#if defined(GENERATING_DOCUMENTATION)
+# define ASIO_OPTION_STORAGE implementation_defined
+#elif defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+# define ASIO_OPTION_STORAGE DCB
+#else
+# define ASIO_OPTION_STORAGE termios
+#endif
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+/// The serial_port_base class is used as a base for the basic_serial_port class
+/// template so that we have a common place to define the serial port options.
+class serial_port_base
+{
+public:
+  /// Serial port option to permit changing the baud rate.
+  /**
+   * Implements changing the baud rate for a given serial port.
+   */
+  class baud_rate
+  {
+  public:
+    explicit baud_rate(unsigned int rate = 0);
+    unsigned int value() const;
+    ASIO_DECL ASIO_SYNC_OP_VOID store(
+        ASIO_OPTION_STORAGE& storage,
+        asio::error_code& ec) const;
+    ASIO_DECL ASIO_SYNC_OP_VOID load(
+        const ASIO_OPTION_STORAGE& storage,
+        asio::error_code& ec);
+  private:
+    unsigned int value_;
+  };
+
+  /// Serial port option to permit changing the flow control.
+  /**
+   * Implements changing the flow control for a given serial port.
+   */
+  class flow_control
+  {
+  public:
+    enum type { none, software, hardware };
+    ASIO_DECL explicit flow_control(type t = none);
+    type value() const;
+    ASIO_DECL ASIO_SYNC_OP_VOID store(
+        ASIO_OPTION_STORAGE& storage,
+        asio::error_code& ec) const;
+    ASIO_DECL ASIO_SYNC_OP_VOID load(
+        const ASIO_OPTION_STORAGE& storage,
+        asio::error_code& ec);
+  private:
+    type value_;
+  };
+
+  /// Serial port option to permit changing the parity.
+  /**
+   * Implements changing the parity for a given serial port.
+   */
+  class parity
+  {
+  public:
+    enum type { none, odd, even };
+    ASIO_DECL explicit parity(type t = none);
+    type value() const;
+    ASIO_DECL ASIO_SYNC_OP_VOID store(
+        ASIO_OPTION_STORAGE& storage,
+        asio::error_code& ec) const;
+    ASIO_DECL ASIO_SYNC_OP_VOID load(
+        const ASIO_OPTION_STORAGE& storage,
+        asio::error_code& ec);
+  private:
+    type value_;
+  };
+
+  /// Serial port option to permit changing the number of stop bits.
+  /**
+   * Implements changing the number of stop bits for a given serial port.
+   */
+  class stop_bits
+  {
+  public:
+    enum type { one, onepointfive, two };
+    ASIO_DECL explicit stop_bits(type t = one);
+    type value() const;
+    ASIO_DECL ASIO_SYNC_OP_VOID store(
+        ASIO_OPTION_STORAGE& storage,
+        asio::error_code& ec) const;
+    ASIO_DECL ASIO_SYNC_OP_VOID load(
+        const ASIO_OPTION_STORAGE& storage,
+        asio::error_code& ec);
+  private:
+    type value_;
+  };
+
+  /// Serial port option to permit changing the character size.
+  /**
+   * Implements changing the character size for a given serial port.
+   */
+  class character_size
+  {
+  public:
+    ASIO_DECL explicit character_size(unsigned int t = 8);
+    unsigned int value() const;
+    ASIO_DECL ASIO_SYNC_OP_VOID store(
+        ASIO_OPTION_STORAGE& storage,
+        asio::error_code& ec) const;
+    ASIO_DECL ASIO_SYNC_OP_VOID load(
+        const ASIO_OPTION_STORAGE& storage,
+        asio::error_code& ec);
+  private:
+    unsigned int value_;
+  };
+
+protected:
+  /// Protected destructor to prevent deletion through this type.
+  ~serial_port_base()
+  {
+  }
+};
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#undef ASIO_OPTION_STORAGE
+
+#include "asio/impl/serial_port_base.hpp"
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/impl/serial_port_base.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // defined(ASIO_HAS_SERIAL_PORT)
+       //   || defined(GENERATING_DOCUMENTATION)
+
+#endif // ASIO_SERIAL_PORT_BASE_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/signal_set.hpp b/link/modules/asio-standalone/asio/include/asio/signal_set.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/signal_set.hpp
@@ -0,0 +1,28 @@
+//
+// signal_set.hpp
+// ~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_SIGNAL_SET_HPP
+#define ASIO_SIGNAL_SET_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/basic_signal_set.hpp"
+
+namespace asio {
+
+/// Typedef for the typical usage of a signal set.
+typedef basic_signal_set<> signal_set;
+
+} // namespace asio
+
+#endif // ASIO_SIGNAL_SET_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/socket_base.hpp b/link/modules/asio-standalone/asio/include/asio/socket_base.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/socket_base.hpp
@@ -0,0 +1,559 @@
+//
+// socket_base.hpp
+// ~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_SOCKET_BASE_HPP
+#define ASIO_SOCKET_BASE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/io_control.hpp"
+#include "asio/detail/socket_option.hpp"
+#include "asio/detail/socket_types.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+/// The socket_base class is used as a base for the basic_stream_socket and
+/// basic_datagram_socket class templates so that we have a common place to
+/// define the shutdown_type and enum.
+class socket_base
+{
+public:
+  /// Different ways a socket may be shutdown.
+  enum shutdown_type
+  {
+#if defined(GENERATING_DOCUMENTATION)
+    /// Shutdown the receive side of the socket.
+    shutdown_receive = implementation_defined,
+
+    /// Shutdown the send side of the socket.
+    shutdown_send = implementation_defined,
+
+    /// Shutdown both send and receive on the socket.
+    shutdown_both = implementation_defined
+#else
+    shutdown_receive = ASIO_OS_DEF(SHUT_RD),
+    shutdown_send = ASIO_OS_DEF(SHUT_WR),
+    shutdown_both = ASIO_OS_DEF(SHUT_RDWR)
+#endif
+  };
+
+  /// Bitmask type for flags that can be passed to send and receive operations.
+  typedef int message_flags;
+
+#if defined(GENERATING_DOCUMENTATION)
+  /// Peek at incoming data without removing it from the input queue.
+  static const int message_peek = implementation_defined;
+
+  /// Process out-of-band data.
+  static const int message_out_of_band = implementation_defined;
+
+  /// Specify that the data should not be subject to routing.
+  static const int message_do_not_route = implementation_defined;
+
+  /// Specifies that the data marks the end of a record.
+  static const int message_end_of_record = implementation_defined;
+#else
+  ASIO_STATIC_CONSTANT(int,
+      message_peek = ASIO_OS_DEF(MSG_PEEK));
+  ASIO_STATIC_CONSTANT(int,
+      message_out_of_band = ASIO_OS_DEF(MSG_OOB));
+  ASIO_STATIC_CONSTANT(int,
+      message_do_not_route = ASIO_OS_DEF(MSG_DONTROUTE));
+  ASIO_STATIC_CONSTANT(int,
+      message_end_of_record = ASIO_OS_DEF(MSG_EOR));
+#endif
+
+  /// Wait types.
+  /**
+   * For use with basic_socket::wait() and basic_socket::async_wait().
+   */
+  enum wait_type
+  {
+    /// Wait for a socket to become ready to read.
+    wait_read,
+
+    /// Wait for a socket to become ready to write.
+    wait_write,
+
+    /// Wait for a socket to have error conditions pending.
+    wait_error
+  };
+
+  /// Socket option to permit sending of broadcast messages.
+  /**
+   * Implements the SOL_SOCKET/SO_BROADCAST socket option.
+   *
+   * @par Examples
+   * Setting the option:
+   * @code
+   * asio::ip::udp::socket socket(my_context);
+   * ...
+   * asio::socket_base::broadcast option(true);
+   * socket.set_option(option);
+   * @endcode
+   *
+   * @par
+   * Getting the current option value:
+   * @code
+   * asio::ip::udp::socket socket(my_context);
+   * ...
+   * asio::socket_base::broadcast option;
+   * socket.get_option(option);
+   * bool is_set = option.value();
+   * @endcode
+   *
+   * @par Concepts:
+   * Socket_Option, Boolean_Socket_Option.
+   */
+#if defined(GENERATING_DOCUMENTATION)
+  typedef implementation_defined broadcast;
+#else
+  typedef asio::detail::socket_option::boolean<
+    ASIO_OS_DEF(SOL_SOCKET), ASIO_OS_DEF(SO_BROADCAST)>
+      broadcast;
+#endif
+
+  /// Socket option to enable socket-level debugging.
+  /**
+   * Implements the SOL_SOCKET/SO_DEBUG socket option.
+   *
+   * @par Examples
+   * Setting the option:
+   * @code
+   * asio::ip::tcp::socket socket(my_context);
+   * ...
+   * asio::socket_base::debug option(true);
+   * socket.set_option(option);
+   * @endcode
+   *
+   * @par
+   * Getting the current option value:
+   * @code
+   * asio::ip::tcp::socket socket(my_context);
+   * ...
+   * asio::socket_base::debug option;
+   * socket.get_option(option);
+   * bool is_set = option.value();
+   * @endcode
+   *
+   * @par Concepts:
+   * Socket_Option, Boolean_Socket_Option.
+   */
+#if defined(GENERATING_DOCUMENTATION)
+  typedef implementation_defined debug;
+#else
+  typedef asio::detail::socket_option::boolean<
+    ASIO_OS_DEF(SOL_SOCKET), ASIO_OS_DEF(SO_DEBUG)> debug;
+#endif
+
+  /// Socket option to prevent routing, use local interfaces only.
+  /**
+   * Implements the SOL_SOCKET/SO_DONTROUTE socket option.
+   *
+   * @par Examples
+   * Setting the option:
+   * @code
+   * asio::ip::udp::socket socket(my_context);
+   * ...
+   * asio::socket_base::do_not_route option(true);
+   * socket.set_option(option);
+   * @endcode
+   *
+   * @par
+   * Getting the current option value:
+   * @code
+   * asio::ip::udp::socket socket(my_context);
+   * ...
+   * asio::socket_base::do_not_route option;
+   * socket.get_option(option);
+   * bool is_set = option.value();
+   * @endcode
+   *
+   * @par Concepts:
+   * Socket_Option, Boolean_Socket_Option.
+   */
+#if defined(GENERATING_DOCUMENTATION)
+  typedef implementation_defined do_not_route;
+#else
+  typedef asio::detail::socket_option::boolean<
+    ASIO_OS_DEF(SOL_SOCKET), ASIO_OS_DEF(SO_DONTROUTE)>
+      do_not_route;
+#endif
+
+  /// Socket option to send keep-alives.
+  /**
+   * Implements the SOL_SOCKET/SO_KEEPALIVE socket option.
+   *
+   * @par Examples
+   * Setting the option:
+   * @code
+   * asio::ip::tcp::socket socket(my_context);
+   * ...
+   * asio::socket_base::keep_alive option(true);
+   * socket.set_option(option);
+   * @endcode
+   *
+   * @par
+   * Getting the current option value:
+   * @code
+   * asio::ip::tcp::socket socket(my_context);
+   * ...
+   * asio::socket_base::keep_alive option;
+   * socket.get_option(option);
+   * bool is_set = option.value();
+   * @endcode
+   *
+   * @par Concepts:
+   * Socket_Option, Boolean_Socket_Option.
+   */
+#if defined(GENERATING_DOCUMENTATION)
+  typedef implementation_defined keep_alive;
+#else
+  typedef asio::detail::socket_option::boolean<
+    ASIO_OS_DEF(SOL_SOCKET), ASIO_OS_DEF(SO_KEEPALIVE)> keep_alive;
+#endif
+
+  /// Socket option for the send buffer size of a socket.
+  /**
+   * Implements the SOL_SOCKET/SO_SNDBUF socket option.
+   *
+   * @par Examples
+   * Setting the option:
+   * @code
+   * asio::ip::tcp::socket socket(my_context);
+   * ...
+   * asio::socket_base::send_buffer_size option(8192);
+   * socket.set_option(option);
+   * @endcode
+   *
+   * @par
+   * Getting the current option value:
+   * @code
+   * asio::ip::tcp::socket socket(my_context);
+   * ...
+   * asio::socket_base::send_buffer_size option;
+   * socket.get_option(option);
+   * int size = option.value();
+   * @endcode
+   *
+   * @par Concepts:
+   * Socket_Option, Integer_Socket_Option.
+   */
+#if defined(GENERATING_DOCUMENTATION)
+  typedef implementation_defined send_buffer_size;
+#else
+  typedef asio::detail::socket_option::integer<
+    ASIO_OS_DEF(SOL_SOCKET), ASIO_OS_DEF(SO_SNDBUF)>
+      send_buffer_size;
+#endif
+
+  /// Socket option for the send low watermark.
+  /**
+   * Implements the SOL_SOCKET/SO_SNDLOWAT socket option.
+   *
+   * @par Examples
+   * Setting the option:
+   * @code
+   * asio::ip::tcp::socket socket(my_context);
+   * ...
+   * asio::socket_base::send_low_watermark option(1024);
+   * socket.set_option(option);
+   * @endcode
+   *
+   * @par
+   * Getting the current option value:
+   * @code
+   * asio::ip::tcp::socket socket(my_context);
+   * ...
+   * asio::socket_base::send_low_watermark option;
+   * socket.get_option(option);
+   * int size = option.value();
+   * @endcode
+   *
+   * @par Concepts:
+   * Socket_Option, Integer_Socket_Option.
+   */
+#if defined(GENERATING_DOCUMENTATION)
+  typedef implementation_defined send_low_watermark;
+#else
+  typedef asio::detail::socket_option::integer<
+    ASIO_OS_DEF(SOL_SOCKET), ASIO_OS_DEF(SO_SNDLOWAT)>
+      send_low_watermark;
+#endif
+
+  /// Socket option for the receive buffer size of a socket.
+  /**
+   * Implements the SOL_SOCKET/SO_RCVBUF socket option.
+   *
+   * @par Examples
+   * Setting the option:
+   * @code
+   * asio::ip::tcp::socket socket(my_context);
+   * ...
+   * asio::socket_base::receive_buffer_size option(8192);
+   * socket.set_option(option);
+   * @endcode
+   *
+   * @par
+   * Getting the current option value:
+   * @code
+   * asio::ip::tcp::socket socket(my_context);
+   * ...
+   * asio::socket_base::receive_buffer_size option;
+   * socket.get_option(option);
+   * int size = option.value();
+   * @endcode
+   *
+   * @par Concepts:
+   * Socket_Option, Integer_Socket_Option.
+   */
+#if defined(GENERATING_DOCUMENTATION)
+  typedef implementation_defined receive_buffer_size;
+#else
+  typedef asio::detail::socket_option::integer<
+    ASIO_OS_DEF(SOL_SOCKET), ASIO_OS_DEF(SO_RCVBUF)>
+      receive_buffer_size;
+#endif
+
+  /// Socket option for the receive low watermark.
+  /**
+   * Implements the SOL_SOCKET/SO_RCVLOWAT socket option.
+   *
+   * @par Examples
+   * Setting the option:
+   * @code
+   * asio::ip::tcp::socket socket(my_context);
+   * ...
+   * asio::socket_base::receive_low_watermark option(1024);
+   * socket.set_option(option);
+   * @endcode
+   *
+   * @par
+   * Getting the current option value:
+   * @code
+   * asio::ip::tcp::socket socket(my_context);
+   * ...
+   * asio::socket_base::receive_low_watermark option;
+   * socket.get_option(option);
+   * int size = option.value();
+   * @endcode
+   *
+   * @par Concepts:
+   * Socket_Option, Integer_Socket_Option.
+   */
+#if defined(GENERATING_DOCUMENTATION)
+  typedef implementation_defined receive_low_watermark;
+#else
+  typedef asio::detail::socket_option::integer<
+    ASIO_OS_DEF(SOL_SOCKET), ASIO_OS_DEF(SO_RCVLOWAT)>
+      receive_low_watermark;
+#endif
+
+  /// Socket option to allow the socket to be bound to an address that is
+  /// already in use.
+  /**
+   * Implements the SOL_SOCKET/SO_REUSEADDR socket option.
+   *
+   * @par Examples
+   * Setting the option:
+   * @code
+   * asio::ip::tcp::acceptor acceptor(my_context);
+   * ...
+   * asio::socket_base::reuse_address option(true);
+   * acceptor.set_option(option);
+   * @endcode
+   *
+   * @par
+   * Getting the current option value:
+   * @code
+   * asio::ip::tcp::acceptor acceptor(my_context);
+   * ...
+   * asio::socket_base::reuse_address option;
+   * acceptor.get_option(option);
+   * bool is_set = option.value();
+   * @endcode
+   *
+   * @par Concepts:
+   * Socket_Option, Boolean_Socket_Option.
+   */
+#if defined(GENERATING_DOCUMENTATION)
+  typedef implementation_defined reuse_address;
+#else
+  typedef asio::detail::socket_option::boolean<
+    ASIO_OS_DEF(SOL_SOCKET), ASIO_OS_DEF(SO_REUSEADDR)>
+      reuse_address;
+#endif
+
+  /// Socket option to specify whether the socket lingers on close if unsent
+  /// data is present.
+  /**
+   * Implements the SOL_SOCKET/SO_LINGER socket option.
+   *
+   * @par Examples
+   * Setting the option:
+   * @code
+   * asio::ip::tcp::socket socket(my_context);
+   * ...
+   * asio::socket_base::linger option(true, 30);
+   * socket.set_option(option);
+   * @endcode
+   *
+   * @par
+   * Getting the current option value:
+   * @code
+   * asio::ip::tcp::socket socket(my_context);
+   * ...
+   * asio::socket_base::linger option;
+   * socket.get_option(option);
+   * bool is_set = option.enabled();
+   * unsigned short timeout = option.timeout();
+   * @endcode
+   *
+   * @par Concepts:
+   * Socket_Option, Linger_Socket_Option.
+   */
+#if defined(GENERATING_DOCUMENTATION)
+  typedef implementation_defined linger;
+#else
+  typedef asio::detail::socket_option::linger<
+    ASIO_OS_DEF(SOL_SOCKET), ASIO_OS_DEF(SO_LINGER)>
+      linger;
+#endif
+
+  /// Socket option for putting received out-of-band data inline.
+  /**
+   * Implements the SOL_SOCKET/SO_OOBINLINE socket option.
+   *
+   * @par Examples
+   * Setting the option:
+   * @code
+   * asio::ip::tcp::socket socket(my_context);
+   * ...
+   * asio::socket_base::out_of_band_inline option(true);
+   * socket.set_option(option);
+   * @endcode
+   *
+   * @par
+   * Getting the current option value:
+   * @code
+   * asio::ip::tcp::socket socket(my_context);
+   * ...
+   * asio::socket_base::out_of_band_inline option;
+   * socket.get_option(option);
+   * bool value = option.value();
+   * @endcode
+   *
+   * @par Concepts:
+   * Socket_Option, Boolean_Socket_Option.
+   */
+#if defined(GENERATING_DOCUMENTATION)
+  typedef implementation_defined out_of_band_inline;
+#else
+  typedef asio::detail::socket_option::boolean<
+    ASIO_OS_DEF(SOL_SOCKET), ASIO_OS_DEF(SO_OOBINLINE)>
+      out_of_band_inline;
+#endif
+
+  /// Socket option to report aborted connections on accept.
+  /**
+   * Implements a custom socket option that determines whether or not an accept
+   * operation is permitted to fail with asio::error::connection_aborted.
+   * By default the option is false.
+   *
+   * @par Examples
+   * Setting the option:
+   * @code
+   * asio::ip::tcp::acceptor acceptor(my_context);
+   * ...
+   * asio::socket_base::enable_connection_aborted option(true);
+   * acceptor.set_option(option);
+   * @endcode
+   *
+   * @par
+   * Getting the current option value:
+   * @code
+   * asio::ip::tcp::acceptor acceptor(my_context);
+   * ...
+   * asio::socket_base::enable_connection_aborted option;
+   * acceptor.get_option(option);
+   * bool is_set = option.value();
+   * @endcode
+   *
+   * @par Concepts:
+   * Socket_Option, Boolean_Socket_Option.
+   */
+#if defined(GENERATING_DOCUMENTATION)
+  typedef implementation_defined enable_connection_aborted;
+#else
+  typedef asio::detail::socket_option::boolean<
+    asio::detail::custom_socket_option_level,
+    asio::detail::enable_connection_aborted_option>
+    enable_connection_aborted;
+#endif
+
+  /// IO control command to get the amount of data that can be read without
+  /// blocking.
+  /**
+   * Implements the FIONREAD IO control command.
+   *
+   * @par Example
+   * @code
+   * asio::ip::tcp::socket socket(my_context);
+   * ...
+   * asio::socket_base::bytes_readable command(true);
+   * socket.io_control(command);
+   * std::size_t bytes_readable = command.get();
+   * @endcode
+   *
+   * @par Concepts:
+   * IO_Control_Command, Size_IO_Control_Command.
+   */
+#if defined(GENERATING_DOCUMENTATION)
+  typedef implementation_defined bytes_readable;
+#else
+  typedef asio::detail::io_control::bytes_readable bytes_readable;
+#endif
+
+  /// The maximum length of the queue of pending incoming connections.
+#if defined(GENERATING_DOCUMENTATION)
+  static const int max_listen_connections = implementation_defined;
+#else
+  ASIO_STATIC_CONSTANT(int, max_listen_connections
+      = ASIO_OS_DEF(SOMAXCONN));
+#endif
+
+#if !defined(ASIO_NO_DEPRECATED)
+  /// (Deprecated: Use max_listen_connections.) The maximum length of the queue
+  /// of pending incoming connections.
+#if defined(GENERATING_DOCUMENTATION)
+  static const int max_connections = implementation_defined;
+#else
+  ASIO_STATIC_CONSTANT(int, max_connections
+      = ASIO_OS_DEF(SOMAXCONN));
+#endif
+#endif // !defined(ASIO_NO_DEPRECATED)
+
+protected:
+  /// Protected destructor to prevent deletion through this type.
+  ~socket_base()
+  {
+  }
+};
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_SOCKET_BASE_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/spawn.hpp b/link/modules/asio-standalone/asio/include/asio/spawn.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/spawn.hpp
@@ -0,0 +1,344 @@
+//
+// spawn.hpp
+// ~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_SPAWN_HPP
+#define ASIO_SPAWN_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <boost/coroutine/all.hpp>
+#include "asio/any_io_executor.hpp"
+#include "asio/bind_executor.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/detail/type_traits.hpp"
+#include "asio/detail/wrapped_handler.hpp"
+#include "asio/io_context.hpp"
+#include "asio/is_executor.hpp"
+#include "asio/strand.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+/// Context object the represents the currently executing coroutine.
+/**
+ * The basic_yield_context class is used to represent the currently executing
+ * stackful coroutine. A basic_yield_context may be passed as a handler to an
+ * asynchronous operation. For example:
+ *
+ * @code template <typename Handler>
+ * void my_coroutine(basic_yield_context<Handler> yield)
+ * {
+ *   ...
+ *   std::size_t n = my_socket.async_read_some(buffer, yield);
+ *   ...
+ * } @endcode
+ *
+ * The initiating function (async_read_some in the above example) suspends the
+ * current coroutine. The coroutine is resumed when the asynchronous operation
+ * completes, and the result of the operation is returned.
+ */
+template <typename Handler>
+class basic_yield_context
+{
+public:
+  /// The coroutine callee type, used by the implementation.
+  /**
+   * When using Boost.Coroutine v1, this type is:
+   * @code typename coroutine<void()> @endcode
+   * When using Boost.Coroutine v2 (unidirectional coroutines), this type is:
+   * @code push_coroutine<void> @endcode
+   */
+#if defined(GENERATING_DOCUMENTATION)
+  typedef implementation_defined callee_type;
+#elif defined(BOOST_COROUTINES_UNIDIRECT) || defined(BOOST_COROUTINES_V2)
+  typedef boost::coroutines::push_coroutine<void> callee_type;
+#else
+  typedef boost::coroutines::coroutine<void()> callee_type;
+#endif
+  
+  /// The coroutine caller type, used by the implementation.
+  /**
+   * When using Boost.Coroutine v1, this type is:
+   * @code typename coroutine<void()>::caller_type @endcode
+   * When using Boost.Coroutine v2 (unidirectional coroutines), this type is:
+   * @code pull_coroutine<void> @endcode
+   */
+#if defined(GENERATING_DOCUMENTATION)
+  typedef implementation_defined caller_type;
+#elif defined(BOOST_COROUTINES_UNIDIRECT) || defined(BOOST_COROUTINES_V2)
+  typedef boost::coroutines::pull_coroutine<void> caller_type;
+#else
+  typedef boost::coroutines::coroutine<void()>::caller_type caller_type;
+#endif
+
+  /// Construct a yield context to represent the specified coroutine.
+  /**
+   * Most applications do not need to use this constructor. Instead, the
+   * spawn() function passes a yield context as an argument to the coroutine
+   * function.
+   */
+  basic_yield_context(
+      const detail::weak_ptr<callee_type>& coro,
+      caller_type& ca, Handler& handler)
+    : coro_(coro),
+      ca_(ca),
+      handler_(handler),
+      ec_(0)
+  {
+  }
+
+  /// Construct a yield context from another yield context type.
+  /**
+   * Requires that OtherHandler be convertible to Handler.
+   */
+  template <typename OtherHandler>
+  basic_yield_context(const basic_yield_context<OtherHandler>& other)
+    : coro_(other.coro_),
+      ca_(other.ca_),
+      handler_(other.handler_),
+      ec_(other.ec_)
+  {
+  }
+
+  /// Return a yield context that sets the specified error_code.
+  /**
+   * By default, when a yield context is used with an asynchronous operation, a
+   * non-success error_code is converted to system_error and thrown. This
+   * operator may be used to specify an error_code object that should instead be
+   * set with the asynchronous operation's result. For example:
+   *
+   * @code template <typename Handler>
+   * void my_coroutine(basic_yield_context<Handler> yield)
+   * {
+   *   ...
+   *   std::size_t n = my_socket.async_read_some(buffer, yield[ec]);
+   *   if (ec)
+   *   {
+   *     // An error occurred.
+   *   }
+   *   ...
+   * } @endcode
+   */
+  basic_yield_context operator[](asio::error_code& ec) const
+  {
+    basic_yield_context tmp(*this);
+    tmp.ec_ = &ec;
+    return tmp;
+  }
+
+#if defined(GENERATING_DOCUMENTATION)
+private:
+#endif // defined(GENERATING_DOCUMENTATION)
+  detail::weak_ptr<callee_type> coro_;
+  caller_type& ca_;
+  Handler handler_;
+  asio::error_code* ec_;
+};
+
+#if defined(GENERATING_DOCUMENTATION)
+/// Context object that represents the currently executing coroutine.
+typedef basic_yield_context<unspecified> yield_context;
+#else // defined(GENERATING_DOCUMENTATION)
+typedef basic_yield_context<
+  executor_binder<void(*)(), any_io_executor> > yield_context;
+#endif // defined(GENERATING_DOCUMENTATION)
+
+/**
+ * @defgroup spawn asio::spawn
+ *
+ * @brief Start a new stackful coroutine.
+ *
+ * The spawn() function is a high-level wrapper over the Boost.Coroutine
+ * library. This function enables programs to implement asynchronous logic in a
+ * synchronous manner, as illustrated by the following example:
+ *
+ * @code asio::spawn(my_strand, do_echo);
+ *
+ * // ...
+ *
+ * void do_echo(asio::yield_context yield)
+ * {
+ *   try
+ *   {
+ *     char data[128];
+ *     for (;;)
+ *     {
+ *       std::size_t length =
+ *         my_socket.async_read_some(
+ *           asio::buffer(data), yield);
+ *
+ *       asio::async_write(my_socket,
+ *           asio::buffer(data, length), yield);
+ *     }
+ *   }
+ *   catch (std::exception& e)
+ *   {
+ *     // ...
+ *   }
+ * } @endcode
+ */
+/*@{*/
+
+/// Start a new stackful coroutine, calling the specified handler when it
+/// completes.
+/**
+ * This function is used to launch a new coroutine.
+ *
+ * @param function The coroutine function. The function must have the signature:
+ * @code void function(basic_yield_context<Handler> yield); @endcode
+ *
+ * @param attributes Boost.Coroutine attributes used to customise the coroutine.
+ */
+template <typename Function>
+void spawn(ASIO_MOVE_ARG(Function) function,
+    const boost::coroutines::attributes& attributes
+      = boost::coroutines::attributes());
+
+/// Start a new stackful coroutine, calling the specified handler when it
+/// completes.
+/**
+ * This function is used to launch a new coroutine.
+ *
+ * @param handler A handler to be called when the coroutine exits. More
+ * importantly, the handler provides an execution context (via the the handler
+ * invocation hook) for the coroutine. The handler must have the signature:
+ * @code void handler(); @endcode
+ *
+ * @param function The coroutine function. The function must have the signature:
+ * @code void function(basic_yield_context<Handler> yield); @endcode
+ *
+ * @param attributes Boost.Coroutine attributes used to customise the coroutine.
+ */
+template <typename Handler, typename Function>
+void spawn(ASIO_MOVE_ARG(Handler) handler,
+    ASIO_MOVE_ARG(Function) function,
+    const boost::coroutines::attributes& attributes
+      = boost::coroutines::attributes(),
+    typename enable_if<
+      !is_executor<typename decay<Handler>::type>::value &&
+      !execution::is_executor<typename decay<Handler>::type>::value &&
+      !is_convertible<Handler&, execution_context&>::value>::type* = 0);
+
+/// Start a new stackful coroutine, inheriting the execution context of another.
+/**
+ * This function is used to launch a new coroutine.
+ *
+ * @param ctx Identifies the current coroutine as a parent of the new
+ * coroutine. This specifies that the new coroutine should inherit the
+ * execution context of the parent. For example, if the parent coroutine is
+ * executing in a particular strand, then the new coroutine will execute in the
+ * same strand.
+ *
+ * @param function The coroutine function. The function must have the signature:
+ * @code void function(basic_yield_context<Handler> yield); @endcode
+ *
+ * @param attributes Boost.Coroutine attributes used to customise the coroutine.
+ */
+template <typename Handler, typename Function>
+void spawn(basic_yield_context<Handler> ctx,
+    ASIO_MOVE_ARG(Function) function,
+    const boost::coroutines::attributes& attributes
+      = boost::coroutines::attributes());
+
+/// Start a new stackful coroutine that executes on a given executor.
+/**
+ * This function is used to launch a new coroutine.
+ *
+ * @param ex Identifies the executor that will run the coroutine. The new
+ * coroutine is implicitly given its own strand within this executor.
+ *
+ * @param function The coroutine function. The function must have the signature:
+ * @code void function(yield_context yield); @endcode
+ *
+ * @param attributes Boost.Coroutine attributes used to customise the coroutine.
+ */
+template <typename Function, typename Executor>
+void spawn(const Executor& ex,
+    ASIO_MOVE_ARG(Function) function,
+    const boost::coroutines::attributes& attributes
+      = boost::coroutines::attributes(),
+    typename enable_if<
+      is_executor<Executor>::value || execution::is_executor<Executor>::value
+    >::type* = 0);
+
+/// Start a new stackful coroutine that executes on a given strand.
+/**
+ * This function is used to launch a new coroutine.
+ *
+ * @param ex Identifies the strand that will run the coroutine.
+ *
+ * @param function The coroutine function. The function must have the signature:
+ * @code void function(yield_context yield); @endcode
+ *
+ * @param attributes Boost.Coroutine attributes used to customise the coroutine.
+ */
+template <typename Function, typename Executor>
+void spawn(const strand<Executor>& ex,
+    ASIO_MOVE_ARG(Function) function,
+    const boost::coroutines::attributes& attributes
+      = boost::coroutines::attributes());
+
+#if !defined(ASIO_NO_TS_EXECUTORS)
+
+/// Start a new stackful coroutine that executes in the context of a strand.
+/**
+ * This function is used to launch a new coroutine.
+ *
+ * @param s Identifies a strand. By starting multiple coroutines on the same
+ * strand, the implementation ensures that none of those coroutines can execute
+ * simultaneously.
+ *
+ * @param function The coroutine function. The function must have the signature:
+ * @code void function(yield_context yield); @endcode
+ *
+ * @param attributes Boost.Coroutine attributes used to customise the coroutine.
+ */
+template <typename Function>
+void spawn(const asio::io_context::strand& s,
+    ASIO_MOVE_ARG(Function) function,
+    const boost::coroutines::attributes& attributes
+      = boost::coroutines::attributes());
+
+#endif // !defined(ASIO_NO_TS_EXECUTORS)
+
+/// Start a new stackful coroutine that executes on a given execution context.
+/**
+ * This function is used to launch a new coroutine.
+ *
+ * @param ctx Identifies the execution context that will run the coroutine. The
+ * new coroutine is implicitly given its own strand within this execution
+ * context.
+ *
+ * @param function The coroutine function. The function must have the signature:
+ * @code void function(yield_context yield); @endcode
+ *
+ * @param attributes Boost.Coroutine attributes used to customise the coroutine.
+ */
+template <typename Function, typename ExecutionContext>
+void spawn(ExecutionContext& ctx,
+    ASIO_MOVE_ARG(Function) function,
+    const boost::coroutines::attributes& attributes
+      = boost::coroutines::attributes(),
+    typename enable_if<is_convertible<
+      ExecutionContext&, execution_context&>::value>::type* = 0);
+
+/*@}*/
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/impl/spawn.hpp"
+
+#endif // ASIO_SPAWN_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/ssl.hpp b/link/modules/asio-standalone/asio/include/asio/ssl.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/ssl.hpp
@@ -0,0 +1,28 @@
+//
+// ssl.hpp
+// ~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_SSL_HPP
+#define ASIO_SSL_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/ssl/context.hpp"
+#include "asio/ssl/context_base.hpp"
+#include "asio/ssl/error.hpp"
+#include "asio/ssl/rfc2818_verification.hpp"
+#include "asio/ssl/host_name_verification.hpp"
+#include "asio/ssl/stream.hpp"
+#include "asio/ssl/stream_base.hpp"
+#include "asio/ssl/verify_context.hpp"
+#include "asio/ssl/verify_mode.hpp"
+
+#endif // ASIO_SSL_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/ssl/context.hpp b/link/modules/asio-standalone/asio/include/asio/ssl/context.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/ssl/context.hpp
@@ -0,0 +1,761 @@
+//
+// ssl/context.hpp
+// ~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_SSL_CONTEXT_HPP
+#define ASIO_SSL_CONTEXT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#include <string>
+#include "asio/buffer.hpp"
+#include "asio/io_context.hpp"
+#include "asio/ssl/context_base.hpp"
+#include "asio/ssl/detail/openssl_types.hpp"
+#include "asio/ssl/detail/openssl_init.hpp"
+#include "asio/ssl/detail/password_callback.hpp"
+#include "asio/ssl/detail/verify_callback.hpp"
+#include "asio/ssl/verify_mode.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace ssl {
+
+class context
+  : public context_base,
+    private noncopyable
+{
+public:
+  /// The native handle type of the SSL context.
+  typedef SSL_CTX* native_handle_type;
+
+  /// Constructor.
+  ASIO_DECL explicit context(method m);
+
+  /// Construct to take ownership of a native handle.
+  ASIO_DECL explicit context(native_handle_type native_handle);
+
+#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+  /// Move-construct a context from another.
+  /**
+   * This constructor moves an SSL context from one object to another.
+   *
+   * @param other The other context object from which the move will occur.
+   *
+   * @note Following the move, the following operations only are valid for the
+   * moved-from object:
+   * @li Destruction.
+   * @li As a target for move-assignment.
+   */
+  ASIO_DECL context(context&& other);
+
+  /// Move-assign a context from another.
+  /**
+   * This assignment operator moves an SSL context from one object to another.
+   *
+   * @param other The other context object from which the move will occur.
+   *
+   * @note Following the move, the following operations only are valid for the
+   * moved-from object:
+   * @li Destruction.
+   * @li As a target for move-assignment.
+   */
+  ASIO_DECL context& operator=(context&& other);
+#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+
+  /// Destructor.
+  ASIO_DECL ~context();
+
+  /// Get the underlying implementation in the native type.
+  /**
+   * This function may be used to obtain the underlying implementation of the
+   * context. This is intended to allow access to context functionality that is
+   * not otherwise provided.
+   */
+  ASIO_DECL native_handle_type native_handle();
+
+  /// Clear options on the context.
+  /**
+   * This function may be used to configure the SSL options used by the context.
+   *
+   * @param o A bitmask of options. The available option values are defined in
+   * the context_base class. The specified options, if currently enabled on the
+   * context, are cleared.
+   *
+   * @throws asio::system_error Thrown on failure.
+   *
+   * @note Calls @c SSL_CTX_clear_options.
+   */
+  ASIO_DECL void clear_options(options o);
+
+  /// Clear options on the context.
+  /**
+   * This function may be used to configure the SSL options used by the context.
+   *
+   * @param o A bitmask of options. The available option values are defined in
+   * the context_base class. The specified options, if currently enabled on the
+   * context, are cleared.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   *
+   * @note Calls @c SSL_CTX_clear_options.
+   */
+  ASIO_DECL ASIO_SYNC_OP_VOID clear_options(options o,
+      asio::error_code& ec);
+
+  /// Set options on the context.
+  /**
+   * This function may be used to configure the SSL options used by the context.
+   *
+   * @param o A bitmask of options. The available option values are defined in
+   * the context_base class. The options are bitwise-ored with any existing
+   * value for the options.
+   *
+   * @throws asio::system_error Thrown on failure.
+   *
+   * @note Calls @c SSL_CTX_set_options.
+   */
+  ASIO_DECL void set_options(options o);
+
+  /// Set options on the context.
+  /**
+   * This function may be used to configure the SSL options used by the context.
+   *
+   * @param o A bitmask of options. The available option values are defined in
+   * the context_base class. The options are bitwise-ored with any existing
+   * value for the options.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   *
+   * @note Calls @c SSL_CTX_set_options.
+   */
+  ASIO_DECL ASIO_SYNC_OP_VOID set_options(options o,
+      asio::error_code& ec);
+
+  /// Set the peer verification mode.
+  /**
+   * This function may be used to configure the peer verification mode used by
+   * the context.
+   *
+   * @param v A bitmask of peer verification modes. See @ref verify_mode for
+   * available values.
+   *
+   * @throws asio::system_error Thrown on failure.
+   *
+   * @note Calls @c SSL_CTX_set_verify.
+   */
+  ASIO_DECL void set_verify_mode(verify_mode v);
+
+  /// Set the peer verification mode.
+  /**
+   * This function may be used to configure the peer verification mode used by
+   * the context.
+   *
+   * @param v A bitmask of peer verification modes. See @ref verify_mode for
+   * available values.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   *
+   * @note Calls @c SSL_CTX_set_verify.
+   */
+  ASIO_DECL ASIO_SYNC_OP_VOID set_verify_mode(
+      verify_mode v, asio::error_code& ec);
+
+  /// Set the peer verification depth.
+  /**
+   * This function may be used to configure the maximum verification depth
+   * allowed by the context.
+   *
+   * @param depth Maximum depth for the certificate chain verification that
+   * shall be allowed.
+   *
+   * @throws asio::system_error Thrown on failure.
+   *
+   * @note Calls @c SSL_CTX_set_verify_depth.
+   */
+  ASIO_DECL void set_verify_depth(int depth);
+
+  /// Set the peer verification depth.
+  /**
+   * This function may be used to configure the maximum verification depth
+   * allowed by the context.
+   *
+   * @param depth Maximum depth for the certificate chain verification that
+   * shall be allowed.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   *
+   * @note Calls @c SSL_CTX_set_verify_depth.
+   */
+  ASIO_DECL ASIO_SYNC_OP_VOID set_verify_depth(
+      int depth, asio::error_code& ec);
+
+  /// Set the callback used to verify peer certificates.
+  /**
+   * This function is used to specify a callback function that will be called
+   * by the implementation when it needs to verify a peer certificate.
+   *
+   * @param callback The function object to be used for verifying a certificate.
+   * The function signature of the handler must be:
+   * @code bool verify_callback(
+   *   bool preverified, // True if the certificate passed pre-verification.
+   *   verify_context& ctx // The peer certificate and other context.
+   * ); @endcode
+   * The return value of the callback is true if the certificate has passed
+   * verification, false otherwise.
+   *
+   * @throws asio::system_error Thrown on failure.
+   *
+   * @note Calls @c SSL_CTX_set_verify.
+   */
+  template <typename VerifyCallback>
+  void set_verify_callback(VerifyCallback callback);
+
+  /// Set the callback used to verify peer certificates.
+  /**
+   * This function is used to specify a callback function that will be called
+   * by the implementation when it needs to verify a peer certificate.
+   *
+   * @param callback The function object to be used for verifying a certificate.
+   * The function signature of the handler must be:
+   * @code bool verify_callback(
+   *   bool preverified, // True if the certificate passed pre-verification.
+   *   verify_context& ctx // The peer certificate and other context.
+   * ); @endcode
+   * The return value of the callback is true if the certificate has passed
+   * verification, false otherwise.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   *
+   * @note Calls @c SSL_CTX_set_verify.
+   */
+  template <typename VerifyCallback>
+  ASIO_SYNC_OP_VOID set_verify_callback(VerifyCallback callback,
+      asio::error_code& ec);
+
+  /// Load a certification authority file for performing verification.
+  /**
+   * This function is used to load one or more trusted certification authorities
+   * from a file.
+   *
+   * @param filename The name of a file containing certification authority
+   * certificates in PEM format.
+   *
+   * @throws asio::system_error Thrown on failure.
+   *
+   * @note Calls @c SSL_CTX_load_verify_locations.
+   */
+  ASIO_DECL void load_verify_file(const std::string& filename);
+
+  /// Load a certification authority file for performing verification.
+  /**
+   * This function is used to load the certificates for one or more trusted
+   * certification authorities from a file.
+   *
+   * @param filename The name of a file containing certification authority
+   * certificates in PEM format.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   *
+   * @note Calls @c SSL_CTX_load_verify_locations.
+   */
+  ASIO_DECL ASIO_SYNC_OP_VOID load_verify_file(
+      const std::string& filename, asio::error_code& ec);
+
+  /// Add certification authority for performing verification.
+  /**
+   * This function is used to add one trusted certification authority
+   * from a memory buffer.
+   *
+   * @param ca The buffer containing the certification authority certificate.
+   * The certificate must use the PEM format.
+   *
+   * @throws asio::system_error Thrown on failure.
+   *
+   * @note Calls @c SSL_CTX_get_cert_store and @c X509_STORE_add_cert.
+   */
+  ASIO_DECL void add_certificate_authority(const const_buffer& ca);
+
+  /// Add certification authority for performing verification.
+  /**
+   * This function is used to add one trusted certification authority
+   * from a memory buffer.
+   *
+   * @param ca The buffer containing the certification authority certificate.
+   * The certificate must use the PEM format.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   *
+   * @note Calls @c SSL_CTX_get_cert_store and @c X509_STORE_add_cert.
+   */
+  ASIO_DECL ASIO_SYNC_OP_VOID add_certificate_authority(
+      const const_buffer& ca, asio::error_code& ec);
+
+  /// Configures the context to use the default directories for finding
+  /// certification authority certificates.
+  /**
+   * This function specifies that the context should use the default,
+   * system-dependent directories for locating certification authority
+   * certificates.
+   *
+   * @throws asio::system_error Thrown on failure.
+   *
+   * @note Calls @c SSL_CTX_set_default_verify_paths.
+   */
+  ASIO_DECL void set_default_verify_paths();
+
+  /// Configures the context to use the default directories for finding
+  /// certification authority certificates.
+  /**
+   * This function specifies that the context should use the default,
+   * system-dependent directories for locating certification authority
+   * certificates.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   *
+   * @note Calls @c SSL_CTX_set_default_verify_paths.
+   */
+  ASIO_DECL ASIO_SYNC_OP_VOID set_default_verify_paths(
+      asio::error_code& ec);
+
+  /// Add a directory containing certificate authority files to be used for
+  /// performing verification.
+  /**
+   * This function is used to specify the name of a directory containing
+   * certification authority certificates. Each file in the directory must
+   * contain a single certificate. The files must be named using the subject
+   * name's hash and an extension of ".0".
+   *
+   * @param path The name of a directory containing the certificates.
+   *
+   * @throws asio::system_error Thrown on failure.
+   *
+   * @note Calls @c SSL_CTX_load_verify_locations.
+   */
+  ASIO_DECL void add_verify_path(const std::string& path);
+
+  /// Add a directory containing certificate authority files to be used for
+  /// performing verification.
+  /**
+   * This function is used to specify the name of a directory containing
+   * certification authority certificates. Each file in the directory must
+   * contain a single certificate. The files must be named using the subject
+   * name's hash and an extension of ".0".
+   *
+   * @param path The name of a directory containing the certificates.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   *
+   * @note Calls @c SSL_CTX_load_verify_locations.
+   */
+  ASIO_DECL ASIO_SYNC_OP_VOID add_verify_path(
+      const std::string& path, asio::error_code& ec);
+
+  /// Use a certificate from a memory buffer.
+  /**
+   * This function is used to load a certificate into the context from a buffer.
+   *
+   * @param certificate The buffer containing the certificate.
+   *
+   * @param format The certificate format (ASN.1 or PEM).
+   *
+   * @throws asio::system_error Thrown on failure.
+   *
+   * @note Calls @c SSL_CTX_use_certificate or SSL_CTX_use_certificate_ASN1.
+   */
+  ASIO_DECL void use_certificate(
+      const const_buffer& certificate, file_format format);
+
+  /// Use a certificate from a memory buffer.
+  /**
+   * This function is used to load a certificate into the context from a buffer.
+   *
+   * @param certificate The buffer containing the certificate.
+   *
+   * @param format The certificate format (ASN.1 or PEM).
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   *
+   * @note Calls @c SSL_CTX_use_certificate or SSL_CTX_use_certificate_ASN1.
+   */
+  ASIO_DECL ASIO_SYNC_OP_VOID use_certificate(
+      const const_buffer& certificate, file_format format,
+      asio::error_code& ec);
+
+  /// Use a certificate from a file.
+  /**
+   * This function is used to load a certificate into the context from a file.
+   *
+   * @param filename The name of the file containing the certificate.
+   *
+   * @param format The file format (ASN.1 or PEM).
+   *
+   * @throws asio::system_error Thrown on failure.
+   *
+   * @note Calls @c SSL_CTX_use_certificate_file.
+   */
+  ASIO_DECL void use_certificate_file(
+      const std::string& filename, file_format format);
+
+  /// Use a certificate from a file.
+  /**
+   * This function is used to load a certificate into the context from a file.
+   *
+   * @param filename The name of the file containing the certificate.
+   *
+   * @param format The file format (ASN.1 or PEM).
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   *
+   * @note Calls @c SSL_CTX_use_certificate_file.
+   */
+  ASIO_DECL ASIO_SYNC_OP_VOID use_certificate_file(
+      const std::string& filename, file_format format,
+      asio::error_code& ec);
+
+  /// Use a certificate chain from a memory buffer.
+  /**
+   * This function is used to load a certificate chain into the context from a
+   * buffer.
+   *
+   * @param chain The buffer containing the certificate chain. The certificate
+   * chain must use the PEM format.
+   *
+   * @throws asio::system_error Thrown on failure.
+   *
+   * @note Calls @c SSL_CTX_use_certificate and SSL_CTX_add_extra_chain_cert.
+   */
+  ASIO_DECL void use_certificate_chain(const const_buffer& chain);
+
+  /// Use a certificate chain from a memory buffer.
+  /**
+   * This function is used to load a certificate chain into the context from a
+   * buffer.
+   *
+   * @param chain The buffer containing the certificate chain. The certificate
+   * chain must use the PEM format.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   *
+   * @note Calls @c SSL_CTX_use_certificate and SSL_CTX_add_extra_chain_cert.
+   */
+  ASIO_DECL ASIO_SYNC_OP_VOID use_certificate_chain(
+      const const_buffer& chain, asio::error_code& ec);
+
+  /// Use a certificate chain from a file.
+  /**
+   * This function is used to load a certificate chain into the context from a
+   * file.
+   *
+   * @param filename The name of the file containing the certificate. The file
+   * must use the PEM format.
+   *
+   * @throws asio::system_error Thrown on failure.
+   *
+   * @note Calls @c SSL_CTX_use_certificate_chain_file.
+   */
+  ASIO_DECL void use_certificate_chain_file(const std::string& filename);
+
+  /// Use a certificate chain from a file.
+  /**
+   * This function is used to load a certificate chain into the context from a
+   * file.
+   *
+   * @param filename The name of the file containing the certificate. The file
+   * must use the PEM format.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   *
+   * @note Calls @c SSL_CTX_use_certificate_chain_file.
+   */
+  ASIO_DECL ASIO_SYNC_OP_VOID use_certificate_chain_file(
+      const std::string& filename, asio::error_code& ec);
+
+  /// Use a private key from a memory buffer.
+  /**
+   * This function is used to load a private key into the context from a buffer.
+   *
+   * @param private_key The buffer containing the private key.
+   *
+   * @param format The private key format (ASN.1 or PEM).
+   *
+   * @throws asio::system_error Thrown on failure.
+   *
+   * @note Calls @c SSL_CTX_use_PrivateKey or SSL_CTX_use_PrivateKey_ASN1.
+   */
+  ASIO_DECL void use_private_key(
+      const const_buffer& private_key, file_format format);
+
+  /// Use a private key from a memory buffer.
+  /**
+   * This function is used to load a private key into the context from a buffer.
+   *
+   * @param private_key The buffer containing the private key.
+   *
+   * @param format The private key format (ASN.1 or PEM).
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   *
+   * @note Calls @c SSL_CTX_use_PrivateKey or SSL_CTX_use_PrivateKey_ASN1.
+   */
+  ASIO_DECL ASIO_SYNC_OP_VOID use_private_key(
+      const const_buffer& private_key, file_format format,
+      asio::error_code& ec);
+
+  /// Use a private key from a file.
+  /**
+   * This function is used to load a private key into the context from a file.
+   *
+   * @param filename The name of the file containing the private key.
+   *
+   * @param format The file format (ASN.1 or PEM).
+   *
+   * @throws asio::system_error Thrown on failure.
+   *
+   * @note Calls @c SSL_CTX_use_PrivateKey_file.
+   */
+  ASIO_DECL void use_private_key_file(
+      const std::string& filename, file_format format);
+
+  /// Use a private key from a file.
+  /**
+   * This function is used to load a private key into the context from a file.
+   *
+   * @param filename The name of the file containing the private key.
+   *
+   * @param format The file format (ASN.1 or PEM).
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   *
+   * @note Calls @c SSL_CTX_use_PrivateKey_file.
+   */
+  ASIO_DECL ASIO_SYNC_OP_VOID use_private_key_file(
+      const std::string& filename, file_format format,
+      asio::error_code& ec);
+
+  /// Use an RSA private key from a memory buffer.
+  /**
+   * This function is used to load an RSA private key into the context from a
+   * buffer.
+   *
+   * @param private_key The buffer containing the RSA private key.
+   *
+   * @param format The private key format (ASN.1 or PEM).
+   *
+   * @throws asio::system_error Thrown on failure.
+   *
+   * @note Calls @c SSL_CTX_use_RSAPrivateKey or SSL_CTX_use_RSAPrivateKey_ASN1.
+   */
+  ASIO_DECL void use_rsa_private_key(
+      const const_buffer& private_key, file_format format);
+
+  /// Use an RSA private key from a memory buffer.
+  /**
+   * This function is used to load an RSA private key into the context from a
+   * buffer.
+   *
+   * @param private_key The buffer containing the RSA private key.
+   *
+   * @param format The private key format (ASN.1 or PEM).
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   *
+   * @note Calls @c SSL_CTX_use_RSAPrivateKey or SSL_CTX_use_RSAPrivateKey_ASN1.
+   */
+  ASIO_DECL ASIO_SYNC_OP_VOID use_rsa_private_key(
+      const const_buffer& private_key, file_format format,
+      asio::error_code& ec);
+
+  /// Use an RSA private key from a file.
+  /**
+   * This function is used to load an RSA private key into the context from a
+   * file.
+   *
+   * @param filename The name of the file containing the RSA private key.
+   *
+   * @param format The file format (ASN.1 or PEM).
+   *
+   * @throws asio::system_error Thrown on failure.
+   *
+   * @note Calls @c SSL_CTX_use_RSAPrivateKey_file.
+   */
+  ASIO_DECL void use_rsa_private_key_file(
+      const std::string& filename, file_format format);
+
+  /// Use an RSA private key from a file.
+  /**
+   * This function is used to load an RSA private key into the context from a
+   * file.
+   *
+   * @param filename The name of the file containing the RSA private key.
+   *
+   * @param format The file format (ASN.1 or PEM).
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   *
+   * @note Calls @c SSL_CTX_use_RSAPrivateKey_file.
+   */
+  ASIO_DECL ASIO_SYNC_OP_VOID use_rsa_private_key_file(
+      const std::string& filename, file_format format,
+      asio::error_code& ec);
+
+  /// Use the specified memory buffer to obtain the temporary Diffie-Hellman
+  /// parameters.
+  /**
+   * This function is used to load Diffie-Hellman parameters into the context
+   * from a buffer.
+   *
+   * @param dh The memory buffer containing the Diffie-Hellman parameters. The
+   * buffer must use the PEM format.
+   *
+   * @throws asio::system_error Thrown on failure.
+   *
+   * @note Calls @c SSL_CTX_set_tmp_dh.
+   */
+  ASIO_DECL void use_tmp_dh(const const_buffer& dh);
+
+  /// Use the specified memory buffer to obtain the temporary Diffie-Hellman
+  /// parameters.
+  /**
+   * This function is used to load Diffie-Hellman parameters into the context
+   * from a buffer.
+   *
+   * @param dh The memory buffer containing the Diffie-Hellman parameters. The
+   * buffer must use the PEM format.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   *
+   * @note Calls @c SSL_CTX_set_tmp_dh.
+   */
+  ASIO_DECL ASIO_SYNC_OP_VOID use_tmp_dh(
+      const const_buffer& dh, asio::error_code& ec);
+
+  /// Use the specified file to obtain the temporary Diffie-Hellman parameters.
+  /**
+   * This function is used to load Diffie-Hellman parameters into the context
+   * from a file.
+   *
+   * @param filename The name of the file containing the Diffie-Hellman
+   * parameters. The file must use the PEM format.
+   *
+   * @throws asio::system_error Thrown on failure.
+   *
+   * @note Calls @c SSL_CTX_set_tmp_dh.
+   */
+  ASIO_DECL void use_tmp_dh_file(const std::string& filename);
+
+  /// Use the specified file to obtain the temporary Diffie-Hellman parameters.
+  /**
+   * This function is used to load Diffie-Hellman parameters into the context
+   * from a file.
+   *
+   * @param filename The name of the file containing the Diffie-Hellman
+   * parameters. The file must use the PEM format.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   *
+   * @note Calls @c SSL_CTX_set_tmp_dh.
+   */
+  ASIO_DECL ASIO_SYNC_OP_VOID use_tmp_dh_file(
+      const std::string& filename, asio::error_code& ec);
+
+  /// Set the password callback.
+  /**
+   * This function is used to specify a callback function to obtain password
+   * information about an encrypted key in PEM format.
+   *
+   * @param callback The function object to be used for obtaining the password.
+   * The function signature of the handler must be:
+   * @code std::string password_callback(
+   *   std::size_t max_length,  // The maximum size for a password.
+   *   password_purpose purpose // Whether password is for reading or writing.
+   * ); @endcode
+   * The return value of the callback is a string containing the password.
+   *
+   * @throws asio::system_error Thrown on failure.
+   *
+   * @note Calls @c SSL_CTX_set_default_passwd_cb.
+   */
+  template <typename PasswordCallback>
+  void set_password_callback(PasswordCallback callback);
+
+  /// Set the password callback.
+  /**
+   * This function is used to specify a callback function to obtain password
+   * information about an encrypted key in PEM format.
+   *
+   * @param callback The function object to be used for obtaining the password.
+   * The function signature of the handler must be:
+   * @code std::string password_callback(
+   *   std::size_t max_length,  // The maximum size for a password.
+   *   password_purpose purpose // Whether password is for reading or writing.
+   * ); @endcode
+   * The return value of the callback is a string containing the password.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   *
+   * @note Calls @c SSL_CTX_set_default_passwd_cb.
+   */
+  template <typename PasswordCallback>
+  ASIO_SYNC_OP_VOID set_password_callback(PasswordCallback callback,
+      asio::error_code& ec);
+
+private:
+  struct bio_cleanup;
+  struct x509_cleanup;
+  struct evp_pkey_cleanup;
+  struct rsa_cleanup;
+  struct dh_cleanup;
+
+  // Helper function used to set a peer certificate verification callback.
+  ASIO_DECL ASIO_SYNC_OP_VOID do_set_verify_callback(
+      detail::verify_callback_base* callback, asio::error_code& ec);
+
+  // Callback used when the SSL implementation wants to verify a certificate.
+  ASIO_DECL static int verify_callback_function(
+      int preverified, X509_STORE_CTX* ctx);
+
+  // Helper function used to set a password callback.
+  ASIO_DECL ASIO_SYNC_OP_VOID do_set_password_callback(
+      detail::password_callback_base* callback, asio::error_code& ec);
+
+  // Callback used when the SSL implementation wants a password.
+  ASIO_DECL static int password_callback_function(
+      char* buf, int size, int purpose, void* data);
+
+  // Helper function to set the temporary Diffie-Hellman parameters from a BIO.
+  ASIO_DECL ASIO_SYNC_OP_VOID do_use_tmp_dh(
+      BIO* bio, asio::error_code& ec);
+
+  // Helper function to make a BIO from a memory buffer.
+  ASIO_DECL BIO* make_buffer_bio(const const_buffer& b);
+
+  // The underlying native implementation.
+  native_handle_type handle_;
+
+  // Ensure openssl is initialised.
+  asio::ssl::detail::openssl_init<> init_;
+};
+
+} // namespace ssl
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/ssl/impl/context.hpp"
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/ssl/impl/context.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // ASIO_SSL_CONTEXT_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/ssl/context_base.hpp b/link/modules/asio-standalone/asio/include/asio/ssl/context_base.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/ssl/context_base.hpp
@@ -0,0 +1,209 @@
+//
+// ssl/context_base.hpp
+// ~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_SSL_CONTEXT_BASE_HPP
+#define ASIO_SSL_CONTEXT_BASE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/ssl/detail/openssl_types.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace ssl {
+
+/// The context_base class is used as a base for the basic_context class
+/// template so that we have a common place to define various enums.
+class context_base
+{
+public:
+  /// Different methods supported by a context.
+  enum method
+  {
+    /// Generic SSL version 2.
+    sslv2,
+
+    /// SSL version 2 client.
+    sslv2_client,
+
+    /// SSL version 2 server.
+    sslv2_server,
+
+    /// Generic SSL version 3.
+    sslv3,
+
+    /// SSL version 3 client.
+    sslv3_client,
+
+    /// SSL version 3 server.
+    sslv3_server,
+
+    /// Generic TLS version 1.
+    tlsv1,
+
+    /// TLS version 1 client.
+    tlsv1_client,
+
+    /// TLS version 1 server.
+    tlsv1_server,
+
+    /// Generic SSL/TLS.
+    sslv23,
+
+    /// SSL/TLS client.
+    sslv23_client,
+
+    /// SSL/TLS server.
+    sslv23_server,
+
+    /// Generic TLS version 1.1.
+    tlsv11,
+
+    /// TLS version 1.1 client.
+    tlsv11_client,
+
+    /// TLS version 1.1 server.
+    tlsv11_server,
+
+    /// Generic TLS version 1.2.
+    tlsv12,
+
+    /// TLS version 1.2 client.
+    tlsv12_client,
+
+    /// TLS version 1.2 server.
+    tlsv12_server,
+
+    /// Generic TLS version 1.3.
+    tlsv13,
+
+    /// TLS version 1.3 client.
+    tlsv13_client,
+
+    /// TLS version 1.3 server.
+    tlsv13_server,
+
+    /// Generic TLS.
+    tls,
+
+    /// TLS client.
+    tls_client,
+
+    /// TLS server.
+    tls_server
+  };
+
+  /// Bitmask type for SSL options.
+  typedef long options;
+
+#if defined(GENERATING_DOCUMENTATION)
+  /// Implement various bug workarounds.
+  static const long default_workarounds = implementation_defined;
+
+  /// Always create a new key when using tmp_dh parameters.
+  static const long single_dh_use = implementation_defined;
+
+  /// Disable SSL v2.
+  static const long no_sslv2 = implementation_defined;
+
+  /// Disable SSL v3.
+  static const long no_sslv3 = implementation_defined;
+
+  /// Disable TLS v1.
+  static const long no_tlsv1 = implementation_defined;
+
+  /// Disable TLS v1.1.
+  static const long no_tlsv1_1 = implementation_defined;
+
+  /// Disable TLS v1.2.
+  static const long no_tlsv1_2 = implementation_defined;
+
+  /// Disable TLS v1.3.
+  static const long no_tlsv1_3 = implementation_defined;
+
+  /// Disable compression. Compression is disabled by default.
+  static const long no_compression = implementation_defined;
+#else
+  ASIO_STATIC_CONSTANT(long, default_workarounds = SSL_OP_ALL);
+  ASIO_STATIC_CONSTANT(long, single_dh_use = SSL_OP_SINGLE_DH_USE);
+  ASIO_STATIC_CONSTANT(long, no_sslv2 = SSL_OP_NO_SSLv2);
+  ASIO_STATIC_CONSTANT(long, no_sslv3 = SSL_OP_NO_SSLv3);
+  ASIO_STATIC_CONSTANT(long, no_tlsv1 = SSL_OP_NO_TLSv1);
+# if defined(SSL_OP_NO_TLSv1_1)
+  ASIO_STATIC_CONSTANT(long, no_tlsv1_1 = SSL_OP_NO_TLSv1_1);
+# else // defined(SSL_OP_NO_TLSv1_1)
+  ASIO_STATIC_CONSTANT(long, no_tlsv1_1 = 0x10000000L);
+# endif // defined(SSL_OP_NO_TLSv1_1)
+# if defined(SSL_OP_NO_TLSv1_2)
+  ASIO_STATIC_CONSTANT(long, no_tlsv1_2 = SSL_OP_NO_TLSv1_2);
+# else // defined(SSL_OP_NO_TLSv1_2)
+  ASIO_STATIC_CONSTANT(long, no_tlsv1_2 = 0x08000000L);
+# endif // defined(SSL_OP_NO_TLSv1_2)
+# if defined(SSL_OP_NO_TLSv1_3)
+  ASIO_STATIC_CONSTANT(long, no_tlsv1_3 = SSL_OP_NO_TLSv1_3);
+# else // defined(SSL_OP_NO_TLSv1_3)
+  ASIO_STATIC_CONSTANT(long, no_tlsv1_3 = 0x20000000L);
+# endif // defined(SSL_OP_NO_TLSv1_3)
+# if defined(SSL_OP_NO_COMPRESSION)
+  ASIO_STATIC_CONSTANT(long, no_compression = SSL_OP_NO_COMPRESSION);
+# else // defined(SSL_OP_NO_COMPRESSION)
+  ASIO_STATIC_CONSTANT(long, no_compression = 0x20000L);
+# endif // defined(SSL_OP_NO_COMPRESSION)
+#endif
+
+  /// File format types.
+  enum file_format
+  {
+    /// ASN.1 file.
+    asn1,
+
+    /// PEM file.
+    pem
+  };
+
+#if !defined(GENERATING_DOCUMENTATION)
+  // The following types and constants are preserved for backward compatibility.
+  // New programs should use the equivalents of the same names that are defined
+  // in the asio::ssl namespace.
+  typedef int verify_mode;
+  ASIO_STATIC_CONSTANT(int, verify_none = SSL_VERIFY_NONE);
+  ASIO_STATIC_CONSTANT(int, verify_peer = SSL_VERIFY_PEER);
+  ASIO_STATIC_CONSTANT(int,
+      verify_fail_if_no_peer_cert = SSL_VERIFY_FAIL_IF_NO_PEER_CERT);
+  ASIO_STATIC_CONSTANT(int, verify_client_once = SSL_VERIFY_CLIENT_ONCE);
+#endif
+
+  /// Purpose of PEM password.
+  enum password_purpose
+  {
+    /// The password is needed for reading/decryption.
+    for_reading,
+
+    /// The password is needed for writing/encryption.
+    for_writing
+  };
+
+protected:
+  /// Protected destructor to prevent deletion through this type.
+  ~context_base()
+  {
+  }
+};
+
+} // namespace ssl
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_SSL_CONTEXT_BASE_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/ssl/detail/buffered_handshake_op.hpp b/link/modules/asio-standalone/asio/include/asio/ssl/detail/buffered_handshake_op.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/ssl/detail/buffered_handshake_op.hpp
@@ -0,0 +1,119 @@
+//
+// ssl/detail/buffered_handshake_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_SSL_DETAIL_BUFFERED_HANDSHAKE_OP_HPP
+#define ASIO_SSL_DETAIL_BUFFERED_HANDSHAKE_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#include "asio/ssl/detail/engine.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace ssl {
+namespace detail {
+
+template <typename ConstBufferSequence>
+class buffered_handshake_op
+{
+public:
+  static ASIO_CONSTEXPR const char* tracking_name()
+  {
+    return "ssl::stream<>::async_buffered_handshake";
+  }
+
+  buffered_handshake_op(stream_base::handshake_type type,
+      const ConstBufferSequence& buffers)
+    : type_(type),
+      buffers_(buffers),
+      total_buffer_size_(asio::buffer_size(buffers_))
+  {
+  }
+
+  engine::want operator()(engine& eng,
+      asio::error_code& ec,
+      std::size_t& bytes_transferred) const
+  {
+    return this->process(eng, ec, bytes_transferred,
+        asio::buffer_sequence_begin(buffers_),
+        asio::buffer_sequence_end(buffers_));
+  }
+
+  template <typename Handler>
+  void call_handler(Handler& handler,
+      const asio::error_code& ec,
+      const std::size_t& bytes_transferred) const
+  {
+    handler(ec, bytes_transferred);
+  }
+
+private:
+  template <typename Iterator>
+  engine::want process(engine& eng,
+      asio::error_code& ec,
+      std::size_t& bytes_transferred,
+      Iterator begin, Iterator end) const
+  {
+    Iterator iter = begin;
+    std::size_t accumulated_size = 0;
+
+    for (;;)
+    {
+      engine::want want = eng.handshake(type_, ec);
+      if (want != engine::want_input_and_retry
+          || bytes_transferred == total_buffer_size_)
+        return want;
+
+      // Find the next buffer piece to be fed to the engine.
+      while (iter != end)
+      {
+        const_buffer buffer(*iter);
+
+        // Skip over any buffers which have already been consumed by the engine.
+        if (bytes_transferred >= accumulated_size + buffer.size())
+        {
+          accumulated_size += buffer.size();
+          ++iter;
+          continue;
+        }
+
+        // The current buffer may have been partially consumed by the engine on
+        // a previous iteration. If so, adjust the buffer to point to the
+        // unused portion.
+        if (bytes_transferred > accumulated_size)
+          buffer = buffer + (bytes_transferred - accumulated_size);
+
+        // Pass the buffer to the engine, and update the bytes transferred to
+        // reflect the total number of bytes consumed so far.
+        bytes_transferred += buffer.size();
+        buffer = eng.put_input(buffer);
+        bytes_transferred -= buffer.size();
+        break;
+      }
+    }
+  }
+
+  stream_base::handshake_type type_;
+  ConstBufferSequence buffers_;
+  std::size_t total_buffer_size_;
+};
+
+} // namespace detail
+} // namespace ssl
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_SSL_DETAIL_BUFFERED_HANDSHAKE_OP_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/ssl/detail/engine.hpp b/link/modules/asio-standalone/asio/include/asio/ssl/detail/engine.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/ssl/detail/engine.hpp
@@ -0,0 +1,165 @@
+//
+// ssl/detail/engine.hpp
+// ~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_SSL_DETAIL_ENGINE_HPP
+#define ASIO_SSL_DETAIL_ENGINE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#include "asio/buffer.hpp"
+#include "asio/detail/static_mutex.hpp"
+#include "asio/ssl/detail/openssl_types.hpp"
+#include "asio/ssl/detail/verify_callback.hpp"
+#include "asio/ssl/stream_base.hpp"
+#include "asio/ssl/verify_mode.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace ssl {
+namespace detail {
+
+class engine
+{
+public:
+  enum want
+  {
+    // Returned by functions to indicate that the engine wants input. The input
+    // buffer should be updated to point to the data. The engine then needs to
+    // be called again to retry the operation.
+    want_input_and_retry = -2,
+
+    // Returned by functions to indicate that the engine wants to write output.
+    // The output buffer points to the data to be written. The engine then
+    // needs to be called again to retry the operation.
+    want_output_and_retry = -1,
+
+    // Returned by functions to indicate that the engine doesn't need input or
+    // output.
+    want_nothing = 0,
+
+    // Returned by functions to indicate that the engine wants to write output.
+    // The output buffer points to the data to be written. After that the
+    // operation is complete, and the engine does not need to be called again.
+    want_output = 1
+  };
+
+  // Construct a new engine for the specified context.
+  ASIO_DECL explicit engine(SSL_CTX* context);
+
+#if defined(ASIO_HAS_MOVE)
+  // Move construct from another engine.
+  ASIO_DECL engine(engine&& other) ASIO_NOEXCEPT;
+#endif // defined(ASIO_HAS_MOVE)
+
+  // Destructor.
+  ASIO_DECL ~engine();
+
+  // Get the underlying implementation in the native type.
+  ASIO_DECL SSL* native_handle();
+
+  // Set the peer verification mode.
+  ASIO_DECL asio::error_code set_verify_mode(
+      verify_mode v, asio::error_code& ec);
+
+  // Set the peer verification depth.
+  ASIO_DECL asio::error_code set_verify_depth(
+      int depth, asio::error_code& ec);
+
+  // Set a peer certificate verification callback.
+  ASIO_DECL asio::error_code set_verify_callback(
+      verify_callback_base* callback, asio::error_code& ec);
+
+  // Perform an SSL handshake using either SSL_connect (client-side) or
+  // SSL_accept (server-side).
+  ASIO_DECL want handshake(
+      stream_base::handshake_type type, asio::error_code& ec);
+
+  // Perform a graceful shutdown of the SSL session.
+  ASIO_DECL want shutdown(asio::error_code& ec);
+
+  // Write bytes to the SSL session.
+  ASIO_DECL want write(const asio::const_buffer& data,
+      asio::error_code& ec, std::size_t& bytes_transferred);
+
+  // Read bytes from the SSL session.
+  ASIO_DECL want read(const asio::mutable_buffer& data,
+      asio::error_code& ec, std::size_t& bytes_transferred);
+
+  // Get output data to be written to the transport.
+  ASIO_DECL asio::mutable_buffer get_output(
+      const asio::mutable_buffer& data);
+
+  // Put input data that was read from the transport.
+  ASIO_DECL asio::const_buffer put_input(
+      const asio::const_buffer& data);
+
+  // Map an error::eof code returned by the underlying transport according to
+  // the type and state of the SSL session. Returns a const reference to the
+  // error code object, suitable for passing to a completion handler.
+  ASIO_DECL const asio::error_code& map_error_code(
+      asio::error_code& ec) const;
+
+private:
+  // Disallow copying and assignment.
+  engine(const engine&);
+  engine& operator=(const engine&);
+
+  // Callback used when the SSL implementation wants to verify a certificate.
+  ASIO_DECL static int verify_callback_function(
+      int preverified, X509_STORE_CTX* ctx);
+
+#if (OPENSSL_VERSION_NUMBER < 0x10000000L)
+  // The SSL_accept function may not be thread safe. This mutex is used to
+  // protect all calls to the SSL_accept function.
+  ASIO_DECL static asio::detail::static_mutex& accept_mutex();
+#endif // (OPENSSL_VERSION_NUMBER < 0x10000000L)
+
+  // Perform one operation. Returns >= 0 on success or error, want_read if the
+  // operation needs more input, or want_write if it needs to write some output
+  // before the operation can complete.
+  ASIO_DECL want perform(int (engine::* op)(void*, std::size_t),
+      void* data, std::size_t length, asio::error_code& ec,
+      std::size_t* bytes_transferred);
+
+  // Adapt the SSL_accept function to the signature needed for perform().
+  ASIO_DECL int do_accept(void*, std::size_t);
+
+  // Adapt the SSL_connect function to the signature needed for perform().
+  ASIO_DECL int do_connect(void*, std::size_t);
+
+  // Adapt the SSL_shutdown function to the signature needed for perform().
+  ASIO_DECL int do_shutdown(void*, std::size_t);
+
+  // Adapt the SSL_read function to the signature needed for perform().
+  ASIO_DECL int do_read(void* data, std::size_t length);
+
+  // Adapt the SSL_write function to the signature needed for perform().
+  ASIO_DECL int do_write(void* data, std::size_t length);
+
+  SSL* ssl_;
+  BIO* ext_bio_;
+};
+
+} // namespace detail
+} // namespace ssl
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/ssl/detail/impl/engine.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // ASIO_SSL_DETAIL_ENGINE_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/ssl/detail/handshake_op.hpp b/link/modules/asio-standalone/asio/include/asio/ssl/detail/handshake_op.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/ssl/detail/handshake_op.hpp
@@ -0,0 +1,67 @@
+//
+// ssl/detail/handshake_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_SSL_DETAIL_HANDSHAKE_OP_HPP
+#define ASIO_SSL_DETAIL_HANDSHAKE_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#include "asio/ssl/detail/engine.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace ssl {
+namespace detail {
+
+class handshake_op
+{
+public:
+  static ASIO_CONSTEXPR const char* tracking_name()
+  {
+    return "ssl::stream<>::async_handshake";
+  }
+
+  handshake_op(stream_base::handshake_type type)
+    : type_(type)
+  {
+  }
+
+  engine::want operator()(engine& eng,
+      asio::error_code& ec,
+      std::size_t& bytes_transferred) const
+  {
+    bytes_transferred = 0;
+    return eng.handshake(type_, ec);
+  }
+
+  template <typename Handler>
+  void call_handler(Handler& handler,
+      const asio::error_code& ec,
+      const std::size_t&) const
+  {
+    handler(ec);
+  }
+
+private:
+  stream_base::handshake_type type_;
+};
+
+} // namespace detail
+} // namespace ssl
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_SSL_DETAIL_HANDSHAKE_OP_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/ssl/detail/impl/engine.ipp b/link/modules/asio-standalone/asio/include/asio/ssl/detail/impl/engine.ipp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/ssl/detail/impl/engine.ipp
@@ -0,0 +1,349 @@
+//
+// ssl/detail/impl/engine.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_SSL_DETAIL_IMPL_ENGINE_IPP
+#define ASIO_SSL_DETAIL_IMPL_ENGINE_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#include "asio/detail/throw_error.hpp"
+#include "asio/error.hpp"
+#include "asio/ssl/detail/engine.hpp"
+#include "asio/ssl/error.hpp"
+#include "asio/ssl/verify_context.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace ssl {
+namespace detail {
+
+engine::engine(SSL_CTX* context)
+  : ssl_(::SSL_new(context))
+{
+  if (!ssl_)
+  {
+    asio::error_code ec(
+        static_cast<int>(::ERR_get_error()),
+        asio::error::get_ssl_category());
+    asio::detail::throw_error(ec, "engine");
+  }
+
+#if (OPENSSL_VERSION_NUMBER < 0x10000000L)
+  accept_mutex().init();
+#endif // (OPENSSL_VERSION_NUMBER < 0x10000000L)
+
+  ::SSL_set_mode(ssl_, SSL_MODE_ENABLE_PARTIAL_WRITE);
+  ::SSL_set_mode(ssl_, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
+#if defined(SSL_MODE_RELEASE_BUFFERS)
+  ::SSL_set_mode(ssl_, SSL_MODE_RELEASE_BUFFERS);
+#endif // defined(SSL_MODE_RELEASE_BUFFERS)
+
+  ::BIO* int_bio = 0;
+  ::BIO_new_bio_pair(&int_bio, 0, &ext_bio_, 0);
+  ::SSL_set_bio(ssl_, int_bio, int_bio);
+}
+
+#if defined(ASIO_HAS_MOVE)
+engine::engine(engine&& other) ASIO_NOEXCEPT
+  : ssl_(other.ssl_),
+    ext_bio_(other.ext_bio_)
+{
+  other.ssl_ = 0;
+  other.ext_bio_ = 0;
+}
+#endif // defined(ASIO_HAS_MOVE)
+
+engine::~engine()
+{
+  if (ssl_ && SSL_get_app_data(ssl_))
+  {
+    delete static_cast<verify_callback_base*>(SSL_get_app_data(ssl_));
+    SSL_set_app_data(ssl_, 0);
+  }
+
+  if (ext_bio_)
+    ::BIO_free(ext_bio_);
+
+  if (ssl_)
+    ::SSL_free(ssl_);
+}
+
+SSL* engine::native_handle()
+{
+  return ssl_;
+}
+
+asio::error_code engine::set_verify_mode(
+    verify_mode v, asio::error_code& ec)
+{
+  ::SSL_set_verify(ssl_, v, ::SSL_get_verify_callback(ssl_));
+
+  ec = asio::error_code();
+  return ec;
+}
+
+asio::error_code engine::set_verify_depth(
+    int depth, asio::error_code& ec)
+{
+  ::SSL_set_verify_depth(ssl_, depth);
+
+  ec = asio::error_code();
+  return ec;
+}
+
+asio::error_code engine::set_verify_callback(
+    verify_callback_base* callback, asio::error_code& ec)
+{
+  if (SSL_get_app_data(ssl_))
+    delete static_cast<verify_callback_base*>(SSL_get_app_data(ssl_));
+
+  SSL_set_app_data(ssl_, callback);
+
+  ::SSL_set_verify(ssl_, ::SSL_get_verify_mode(ssl_),
+      &engine::verify_callback_function);
+
+  ec = asio::error_code();
+  return ec;
+}
+
+int engine::verify_callback_function(int preverified, X509_STORE_CTX* ctx)
+{
+  if (ctx)
+  {
+    if (SSL* ssl = static_cast<SSL*>(
+          ::X509_STORE_CTX_get_ex_data(
+            ctx, ::SSL_get_ex_data_X509_STORE_CTX_idx())))
+    {
+      if (SSL_get_app_data(ssl))
+      {
+        verify_callback_base* callback =
+          static_cast<verify_callback_base*>(
+              SSL_get_app_data(ssl));
+
+        verify_context verify_ctx(ctx);
+        return callback->call(preverified != 0, verify_ctx) ? 1 : 0;
+      }
+    }
+  }
+
+  return 0;
+}
+
+engine::want engine::handshake(
+    stream_base::handshake_type type, asio::error_code& ec)
+{
+  return perform((type == asio::ssl::stream_base::client)
+      ? &engine::do_connect : &engine::do_accept, 0, 0, ec, 0);
+}
+
+engine::want engine::shutdown(asio::error_code& ec)
+{
+  return perform(&engine::do_shutdown, 0, 0, ec, 0);
+}
+
+engine::want engine::write(const asio::const_buffer& data,
+    asio::error_code& ec, std::size_t& bytes_transferred)
+{
+  if (data.size() == 0)
+  {
+    ec = asio::error_code();
+    return engine::want_nothing;
+  }
+
+  return perform(&engine::do_write,
+      const_cast<void*>(data.data()),
+      data.size(), ec, &bytes_transferred);
+}
+
+engine::want engine::read(const asio::mutable_buffer& data,
+    asio::error_code& ec, std::size_t& bytes_transferred)
+{
+  if (data.size() == 0)
+  {
+    ec = asio::error_code();
+    return engine::want_nothing;
+  }
+
+  return perform(&engine::do_read, data.data(),
+      data.size(), ec, &bytes_transferred);
+}
+
+asio::mutable_buffer engine::get_output(
+    const asio::mutable_buffer& data)
+{
+  int length = ::BIO_read(ext_bio_,
+      data.data(), static_cast<int>(data.size()));
+
+  return asio::buffer(data,
+      length > 0 ? static_cast<std::size_t>(length) : 0);
+}
+
+asio::const_buffer engine::put_input(
+    const asio::const_buffer& data)
+{
+  int length = ::BIO_write(ext_bio_,
+      data.data(), static_cast<int>(data.size()));
+
+  return asio::buffer(data +
+      (length > 0 ? static_cast<std::size_t>(length) : 0));
+}
+
+const asio::error_code& engine::map_error_code(
+    asio::error_code& ec) const
+{
+  // We only want to map the error::eof code.
+  if (ec != asio::error::eof)
+    return ec;
+
+  // If there's data yet to be read, it's an error.
+  if (BIO_wpending(ext_bio_))
+  {
+    ec = asio::ssl::error::stream_truncated;
+    return ec;
+  }
+
+  // SSL v2 doesn't provide a protocol-level shutdown, so an eof on the
+  // underlying transport is passed through.
+#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
+  if (SSL_version(ssl_) == SSL2_VERSION)
+    return ec;
+#endif // (OPENSSL_VERSION_NUMBER < 0x10100000L)
+
+  // Otherwise, the peer should have negotiated a proper shutdown.
+  if ((::SSL_get_shutdown(ssl_) & SSL_RECEIVED_SHUTDOWN) == 0)
+  {
+    ec = asio::ssl::error::stream_truncated;
+  }
+
+  return ec;
+}
+
+#if (OPENSSL_VERSION_NUMBER < 0x10000000L)
+asio::detail::static_mutex& engine::accept_mutex()
+{
+  static asio::detail::static_mutex mutex = ASIO_STATIC_MUTEX_INIT;
+  return mutex;
+}
+#endif // (OPENSSL_VERSION_NUMBER < 0x10000000L)
+
+engine::want engine::perform(int (engine::* op)(void*, std::size_t),
+    void* data, std::size_t length, asio::error_code& ec,
+    std::size_t* bytes_transferred)
+{
+  std::size_t pending_output_before = ::BIO_ctrl_pending(ext_bio_);
+  ::ERR_clear_error();
+  int result = (this->*op)(data, length);
+  int ssl_error = ::SSL_get_error(ssl_, result);
+  int sys_error = static_cast<int>(::ERR_get_error());
+  std::size_t pending_output_after = ::BIO_ctrl_pending(ext_bio_);
+
+  if (ssl_error == SSL_ERROR_SSL)
+  {
+    ec = asio::error_code(sys_error,
+        asio::error::get_ssl_category());
+    return pending_output_after > pending_output_before
+      ? want_output : want_nothing;
+  }
+
+  if (ssl_error == SSL_ERROR_SYSCALL)
+  {
+    if (sys_error == 0)
+    {
+      ec = asio::ssl::error::unspecified_system_error;
+    }
+    else
+    {
+      ec = asio::error_code(sys_error,
+          asio::error::get_ssl_category());
+    }
+    return pending_output_after > pending_output_before
+      ? want_output : want_nothing;
+  }
+
+  if (result > 0 && bytes_transferred)
+    *bytes_transferred = static_cast<std::size_t>(result);
+
+  if (ssl_error == SSL_ERROR_WANT_WRITE)
+  {
+    ec = asio::error_code();
+    return want_output_and_retry;
+  }
+  else if (pending_output_after > pending_output_before)
+  {
+    ec = asio::error_code();
+    return result > 0 ? want_output : want_output_and_retry;
+  }
+  else if (ssl_error == SSL_ERROR_WANT_READ)
+  {
+    ec = asio::error_code();
+    return want_input_and_retry;
+  }
+  else if (ssl_error == SSL_ERROR_ZERO_RETURN)
+  {
+    ec = asio::error::eof;
+    return want_nothing;
+  }
+  else if (ssl_error == SSL_ERROR_NONE)
+  {
+    ec = asio::error_code();
+    return want_nothing;
+  }
+  else
+  {
+    ec = asio::ssl::error::unexpected_result;
+    return want_nothing;
+  }
+}
+
+int engine::do_accept(void*, std::size_t)
+{
+#if (OPENSSL_VERSION_NUMBER < 0x10000000L)
+  asio::detail::static_mutex::scoped_lock lock(accept_mutex());
+#endif // (OPENSSL_VERSION_NUMBER < 0x10000000L)
+  return ::SSL_accept(ssl_);
+}
+
+int engine::do_connect(void*, std::size_t)
+{
+  return ::SSL_connect(ssl_);
+}
+
+int engine::do_shutdown(void*, std::size_t)
+{
+  int result = ::SSL_shutdown(ssl_);
+  if (result == 0)
+    result = ::SSL_shutdown(ssl_);
+  return result;
+}
+
+int engine::do_read(void* data, std::size_t length)
+{
+  return ::SSL_read(ssl_, data,
+      length < INT_MAX ? static_cast<int>(length) : INT_MAX);
+}
+
+int engine::do_write(void* data, std::size_t length)
+{
+  return ::SSL_write(ssl_, data,
+      length < INT_MAX ? static_cast<int>(length) : INT_MAX);
+}
+
+} // namespace detail
+} // namespace ssl
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_SSL_DETAIL_IMPL_ENGINE_IPP
diff --git a/link/modules/asio-standalone/asio/include/asio/ssl/detail/impl/openssl_init.ipp b/link/modules/asio-standalone/asio/include/asio/ssl/detail/impl/openssl_init.ipp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/ssl/detail/impl/openssl_init.ipp
@@ -0,0 +1,165 @@
+//
+// ssl/detail/impl/openssl_init.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com
+// Copyright (c) 2005-2020 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 ASIO_SSL_DETAIL_IMPL_OPENSSL_INIT_IPP
+#define ASIO_SSL_DETAIL_IMPL_OPENSSL_INIT_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <vector>
+#include "asio/detail/assert.hpp"
+#include "asio/detail/mutex.hpp"
+#include "asio/detail/tss_ptr.hpp"
+#include "asio/ssl/detail/openssl_init.hpp"
+#include "asio/ssl/detail/openssl_types.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace ssl {
+namespace detail {
+
+class openssl_init_base::do_init
+{
+public:
+  do_init()
+  {
+#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
+    ::SSL_library_init();
+    ::SSL_load_error_strings();        
+    ::OpenSSL_add_all_algorithms();
+
+    mutexes_.resize(::CRYPTO_num_locks());
+    for (size_t i = 0; i < mutexes_.size(); ++i)
+      mutexes_[i].reset(new asio::detail::mutex);
+    ::CRYPTO_set_locking_callback(&do_init::openssl_locking_func);
+#endif // (OPENSSL_VERSION_NUMBER < 0x10100000L)
+#if (OPENSSL_VERSION_NUMBER < 0x10000000L)
+    ::CRYPTO_set_id_callback(&do_init::openssl_id_func);
+#endif // (OPENSSL_VERSION_NUMBER < 0x10000000L)
+
+#if !defined(SSL_OP_NO_COMPRESSION) \
+  && (OPENSSL_VERSION_NUMBER >= 0x00908000L)
+    null_compression_methods_ = sk_SSL_COMP_new_null();
+#endif // !defined(SSL_OP_NO_COMPRESSION)
+       // && (OPENSSL_VERSION_NUMBER >= 0x00908000L)
+  }
+
+  ~do_init()
+  {
+#if !defined(SSL_OP_NO_COMPRESSION) \
+  && (OPENSSL_VERSION_NUMBER >= 0x00908000L)
+    sk_SSL_COMP_free(null_compression_methods_);
+#endif // !defined(SSL_OP_NO_COMPRESSION)
+       // && (OPENSSL_VERSION_NUMBER >= 0x00908000L)
+
+#if (OPENSSL_VERSION_NUMBER < 0x10000000L)
+    ::CRYPTO_set_id_callback(0);
+#endif // (OPENSSL_VERSION_NUMBER < 0x10000000L)
+#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
+    ::CRYPTO_set_locking_callback(0);
+    ::ERR_free_strings();
+    ::EVP_cleanup();
+    ::CRYPTO_cleanup_all_ex_data();
+#endif // (OPENSSL_VERSION_NUMBER < 0x10100000L)
+#if (OPENSSL_VERSION_NUMBER < 0x10000000L)
+    ::ERR_remove_state(0);
+#elif (OPENSSL_VERSION_NUMBER < 0x10100000L)
+    ::ERR_remove_thread_state(NULL);
+#endif // (OPENSSL_VERSION_NUMBER < 0x10000000L)
+#if (OPENSSL_VERSION_NUMBER >= 0x10002000L) \
+    && (OPENSSL_VERSION_NUMBER < 0x10100000L) \
+    && !defined(SSL_OP_NO_COMPRESSION)
+    ::SSL_COMP_free_compression_methods();
+#endif // (OPENSSL_VERSION_NUMBER >= 0x10002000L)
+       // && (OPENSSL_VERSION_NUMBER < 0x10100000L)
+       // && !defined(SSL_OP_NO_COMPRESSION)
+#if !defined(OPENSSL_IS_BORINGSSL) && !defined(ASIO_USE_WOLFSSL)
+    ::CONF_modules_unload(1);
+#endif // !defined(OPENSSL_IS_BORINGSSL) && !defined(ASIO_USE_WOLFSSL)
+#if !defined(OPENSSL_NO_ENGINE) \
+  && (OPENSSL_VERSION_NUMBER < 0x10100000L)
+    ::ENGINE_cleanup();
+#endif // !defined(OPENSSL_NO_ENGINE)
+       // && (OPENSSL_VERSION_NUMBER < 0x10100000L)
+  }
+
+#if !defined(SSL_OP_NO_COMPRESSION) \
+  && (OPENSSL_VERSION_NUMBER >= 0x00908000L)
+  STACK_OF(SSL_COMP)* get_null_compression_methods() const
+  {
+    return null_compression_methods_;
+  }
+#endif // !defined(SSL_OP_NO_COMPRESSION)
+       // && (OPENSSL_VERSION_NUMBER >= 0x00908000L)
+
+private:
+#if (OPENSSL_VERSION_NUMBER < 0x10000000L)
+  static unsigned long openssl_id_func()
+  {
+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+    return ::GetCurrentThreadId();
+#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+    void* id = &errno;
+    ASIO_ASSERT(sizeof(unsigned long) >= sizeof(void*));
+    return reinterpret_cast<unsigned long>(id);
+#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+  }
+#endif // (OPENSSL_VERSION_NUMBER < 0x10000000L)
+
+#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
+  static void openssl_locking_func(int mode, int n, 
+    const char* /*file*/, int /*line*/)
+  {
+    if (mode & CRYPTO_LOCK)
+      instance()->mutexes_[n]->lock();
+    else
+      instance()->mutexes_[n]->unlock();
+  }
+
+  // Mutexes to be used in locking callbacks.
+  std::vector<asio::detail::shared_ptr<
+        asio::detail::mutex> > mutexes_;
+#endif // (OPENSSL_VERSION_NUMBER < 0x10100000L)
+
+#if !defined(SSL_OP_NO_COMPRESSION) \
+  && (OPENSSL_VERSION_NUMBER >= 0x00908000L)
+  STACK_OF(SSL_COMP)* null_compression_methods_;
+#endif // !defined(SSL_OP_NO_COMPRESSION)
+       // && (OPENSSL_VERSION_NUMBER >= 0x00908000L)
+};
+
+asio::detail::shared_ptr<openssl_init_base::do_init>
+openssl_init_base::instance()
+{
+  static asio::detail::shared_ptr<do_init> init(new do_init);
+  return init;
+}
+
+#if !defined(SSL_OP_NO_COMPRESSION) \
+  && (OPENSSL_VERSION_NUMBER >= 0x00908000L)
+STACK_OF(SSL_COMP)* openssl_init_base::get_null_compression_methods()
+{
+  return instance()->get_null_compression_methods();
+}
+#endif // !defined(SSL_OP_NO_COMPRESSION)
+       // && (OPENSSL_VERSION_NUMBER >= 0x00908000L)
+
+} // namespace detail
+} // namespace ssl
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_SSL_DETAIL_IMPL_OPENSSL_INIT_IPP
diff --git a/link/modules/asio-standalone/asio/include/asio/ssl/detail/io.hpp b/link/modules/asio-standalone/asio/include/asio/ssl/detail/io.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/ssl/detail/io.hpp
@@ -0,0 +1,415 @@
+//
+// ssl/detail/io.hpp
+// ~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_SSL_DETAIL_IO_HPP
+#define ASIO_SSL_DETAIL_IO_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#include "asio/detail/handler_tracking.hpp"
+#include "asio/ssl/detail/engine.hpp"
+#include "asio/ssl/detail/stream_core.hpp"
+#include "asio/write.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace ssl {
+namespace detail {
+
+template <typename Stream, typename Operation>
+std::size_t io(Stream& next_layer, stream_core& core,
+    const Operation& op, asio::error_code& ec)
+{
+  asio::error_code io_ec;
+  std::size_t bytes_transferred = 0;
+  do switch (op(core.engine_, ec, bytes_transferred))
+  {
+  case engine::want_input_and_retry:
+
+    // If the input buffer is empty then we need to read some more data from
+    // the underlying transport.
+    if (core.input_.size() == 0)
+    {
+      core.input_ = asio::buffer(core.input_buffer_,
+          next_layer.read_some(core.input_buffer_, io_ec));
+      if (!ec)
+        ec = io_ec;
+    }
+
+    // Pass the new input data to the engine.
+    core.input_ = core.engine_.put_input(core.input_);
+
+    // Try the operation again.
+    continue;
+
+  case engine::want_output_and_retry:
+
+    // Get output data from the engine and write it to the underlying
+    // transport.
+    asio::write(next_layer,
+        core.engine_.get_output(core.output_buffer_), io_ec);
+    if (!ec)
+      ec = io_ec;
+
+    // Try the operation again.
+    continue;
+
+  case engine::want_output:
+
+    // Get output data from the engine and write it to the underlying
+    // transport.
+    asio::write(next_layer,
+        core.engine_.get_output(core.output_buffer_), io_ec);
+    if (!ec)
+      ec = io_ec;
+
+    // Operation is complete. Return result to caller.
+    core.engine_.map_error_code(ec);
+    return bytes_transferred;
+
+  default:
+
+    // Operation is complete. Return result to caller.
+    core.engine_.map_error_code(ec);
+    return bytes_transferred;
+
+  } while (!ec);
+
+  // Operation failed. Return result to caller.
+  core.engine_.map_error_code(ec);
+  return 0;
+}
+
+template <typename Stream, typename Operation, typename Handler>
+class io_op
+{
+public:
+  io_op(Stream& next_layer, stream_core& core,
+      const Operation& op, Handler& handler)
+    : next_layer_(next_layer),
+      core_(core),
+      op_(op),
+      start_(0),
+      want_(engine::want_nothing),
+      bytes_transferred_(0),
+      handler_(ASIO_MOVE_CAST(Handler)(handler))
+  {
+  }
+
+#if defined(ASIO_HAS_MOVE)
+  io_op(const io_op& other)
+    : next_layer_(other.next_layer_),
+      core_(other.core_),
+      op_(other.op_),
+      start_(other.start_),
+      want_(other.want_),
+      ec_(other.ec_),
+      bytes_transferred_(other.bytes_transferred_),
+      handler_(other.handler_)
+  {
+  }
+
+  io_op(io_op&& other)
+    : next_layer_(other.next_layer_),
+      core_(other.core_),
+      op_(ASIO_MOVE_CAST(Operation)(other.op_)),
+      start_(other.start_),
+      want_(other.want_),
+      ec_(other.ec_),
+      bytes_transferred_(other.bytes_transferred_),
+      handler_(ASIO_MOVE_CAST(Handler)(other.handler_))
+  {
+  }
+#endif // defined(ASIO_HAS_MOVE)
+
+  void operator()(asio::error_code ec,
+      std::size_t bytes_transferred = ~std::size_t(0), int start = 0)
+  {
+    switch (start_ = start)
+    {
+    case 1: // Called after at least one async operation.
+      do
+      {
+        switch (want_ = op_(core_.engine_, ec_, bytes_transferred_))
+        {
+        case engine::want_input_and_retry:
+
+          // If the input buffer already has data in it we can pass it to the
+          // engine and then retry the operation immediately.
+          if (core_.input_.size() != 0)
+          {
+            core_.input_ = core_.engine_.put_input(core_.input_);
+            continue;
+          }
+
+          // The engine wants more data to be read from input. However, we
+          // cannot allow more than one read operation at a time on the
+          // underlying transport. The pending_read_ timer's expiry is set to
+          // pos_infin if a read is in progress, and neg_infin otherwise.
+          if (core_.expiry(core_.pending_read_) == core_.neg_infin())
+          {
+            // Prevent other read operations from being started.
+            core_.pending_read_.expires_at(core_.pos_infin());
+
+            ASIO_HANDLER_LOCATION((
+                  __FILE__, __LINE__, Operation::tracking_name()));
+
+            // Start reading some data from the underlying transport.
+            next_layer_.async_read_some(
+                asio::buffer(core_.input_buffer_),
+                ASIO_MOVE_CAST(io_op)(*this));
+          }
+          else
+          {
+            ASIO_HANDLER_LOCATION((
+                  __FILE__, __LINE__, Operation::tracking_name()));
+
+            // Wait until the current read operation completes.
+            core_.pending_read_.async_wait(ASIO_MOVE_CAST(io_op)(*this));
+          }
+
+          // Yield control until asynchronous operation completes. Control
+          // resumes at the "default:" label below.
+          return;
+
+        case engine::want_output_and_retry:
+        case engine::want_output:
+
+          // The engine wants some data to be written to the output. However, we
+          // cannot allow more than one write operation at a time on the
+          // underlying transport. The pending_write_ timer's expiry is set to
+          // pos_infin if a write is in progress, and neg_infin otherwise.
+          if (core_.expiry(core_.pending_write_) == core_.neg_infin())
+          {
+            // Prevent other write operations from being started.
+            core_.pending_write_.expires_at(core_.pos_infin());
+
+            ASIO_HANDLER_LOCATION((
+                  __FILE__, __LINE__, Operation::tracking_name()));
+
+            // Start writing all the data to the underlying transport.
+            asio::async_write(next_layer_,
+                core_.engine_.get_output(core_.output_buffer_),
+                ASIO_MOVE_CAST(io_op)(*this));
+          }
+          else
+          {
+            ASIO_HANDLER_LOCATION((
+                  __FILE__, __LINE__, Operation::tracking_name()));
+
+            // Wait until the current write operation completes.
+            core_.pending_write_.async_wait(ASIO_MOVE_CAST(io_op)(*this));
+          }
+
+          // Yield control until asynchronous operation completes. Control
+          // resumes at the "default:" label below.
+          return;
+
+        default:
+
+          // The SSL operation is done and we can invoke the handler, but we
+          // have to keep in mind that this function might be being called from
+          // the async operation's initiating function. In this case we're not
+          // allowed to call the handler directly. Instead, issue a zero-sized
+          // read so the handler runs "as-if" posted using io_context::post().
+          if (start)
+          {
+            ASIO_HANDLER_LOCATION((
+                  __FILE__, __LINE__, Operation::tracking_name()));
+
+            next_layer_.async_read_some(
+                asio::buffer(core_.input_buffer_, 0),
+                ASIO_MOVE_CAST(io_op)(*this));
+
+            // Yield control until asynchronous operation completes. Control
+            // resumes at the "default:" label below.
+            return;
+          }
+          else
+          {
+            // Continue on to run handler directly.
+            break;
+          }
+        }
+
+        default:
+        if (bytes_transferred == ~std::size_t(0))
+          bytes_transferred = 0; // Timer cancellation, no data transferred.
+        else if (!ec_)
+          ec_ = ec;
+
+        switch (want_)
+        {
+        case engine::want_input_and_retry:
+
+          // Add received data to the engine's input.
+          core_.input_ = asio::buffer(
+              core_.input_buffer_, bytes_transferred);
+          core_.input_ = core_.engine_.put_input(core_.input_);
+
+          // Release any waiting read operations.
+          core_.pending_read_.expires_at(core_.neg_infin());
+
+          // Try the operation again.
+          continue;
+
+        case engine::want_output_and_retry:
+
+          // Release any waiting write operations.
+          core_.pending_write_.expires_at(core_.neg_infin());
+
+          // Try the operation again.
+          continue;
+
+        case engine::want_output:
+
+          // Release any waiting write operations.
+          core_.pending_write_.expires_at(core_.neg_infin());
+
+          // Fall through to call handler.
+
+        default:
+
+          // Pass the result to the handler.
+          op_.call_handler(handler_,
+              core_.engine_.map_error_code(ec_),
+              ec_ ? 0 : bytes_transferred_);
+
+          // Our work here is done.
+          return;
+        }
+      } while (!ec_);
+
+      // Operation failed. Pass the result to the handler.
+      op_.call_handler(handler_, core_.engine_.map_error_code(ec_), 0);
+    }
+  }
+
+//private:
+  Stream& next_layer_;
+  stream_core& core_;
+  Operation op_;
+  int start_;
+  engine::want want_;
+  asio::error_code ec_;
+  std::size_t bytes_transferred_;
+  Handler handler_;
+};
+
+template <typename Stream, typename Operation, typename Handler>
+inline asio_handler_allocate_is_deprecated
+asio_handler_allocate(std::size_t size,
+    io_op<Stream, Operation, Handler>* this_handler)
+{
+#if defined(ASIO_NO_DEPRECATED)
+  asio_handler_alloc_helpers::allocate(size, this_handler->handler_);
+  return asio_handler_allocate_is_no_longer_used();
+#else // defined(ASIO_NO_DEPRECATED)
+  return asio_handler_alloc_helpers::allocate(
+      size, this_handler->handler_);
+#endif // defined(ASIO_NO_DEPRECATED)
+}
+
+template <typename Stream, typename Operation, typename Handler>
+inline asio_handler_deallocate_is_deprecated
+asio_handler_deallocate(void* pointer, std::size_t size,
+    io_op<Stream, Operation, Handler>* this_handler)
+{
+  asio_handler_alloc_helpers::deallocate(
+      pointer, size, this_handler->handler_);
+#if defined(ASIO_NO_DEPRECATED)
+  return asio_handler_deallocate_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+}
+
+template <typename Stream, typename Operation, typename Handler>
+inline bool asio_handler_is_continuation(
+    io_op<Stream, Operation, Handler>* this_handler)
+{
+  return this_handler->start_ == 0 ? true
+    : asio_handler_cont_helpers::is_continuation(this_handler->handler_);
+}
+
+template <typename Function, typename Stream,
+    typename Operation, typename Handler>
+inline asio_handler_invoke_is_deprecated
+asio_handler_invoke(Function& function,
+    io_op<Stream, Operation, Handler>* this_handler)
+{
+  asio_handler_invoke_helpers::invoke(
+      function, this_handler->handler_);
+#if defined(ASIO_NO_DEPRECATED)
+  return asio_handler_invoke_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+}
+
+template <typename Function, typename Stream,
+    typename Operation, typename Handler>
+inline asio_handler_invoke_is_deprecated
+asio_handler_invoke(const Function& function,
+    io_op<Stream, Operation, Handler>* this_handler)
+{
+  asio_handler_invoke_helpers::invoke(
+      function, this_handler->handler_);
+#if defined(ASIO_NO_DEPRECATED)
+  return asio_handler_invoke_is_no_longer_used();
+#endif // defined(ASIO_NO_DEPRECATED)
+}
+
+template <typename Stream, typename Operation, typename Handler>
+inline void async_io(Stream& next_layer, stream_core& core,
+    const Operation& op, Handler& handler)
+{
+  io_op<Stream, Operation, Handler>(
+    next_layer, core, op, handler)(
+      asio::error_code(), 0, 1);
+}
+
+} // namespace detail
+} // namespace ssl
+
+template <typename Stream, typename Operation,
+    typename Handler, typename Allocator>
+struct associated_allocator<
+    ssl::detail::io_op<Stream, Operation, Handler>, Allocator>
+{
+  typedef typename associated_allocator<Handler, Allocator>::type type;
+
+  static type get(const ssl::detail::io_op<Stream, Operation, Handler>& h,
+      const Allocator& a = Allocator()) ASIO_NOEXCEPT
+  {
+    return associated_allocator<Handler, Allocator>::get(h.handler_, a);
+  }
+};
+
+template <typename Stream, typename Operation,
+    typename Handler, typename Executor>
+struct associated_executor<
+    ssl::detail::io_op<Stream, Operation, Handler>, Executor>
+{
+  typedef typename associated_executor<Handler, Executor>::type type;
+
+  static type get(const ssl::detail::io_op<Stream, Operation, Handler>& h,
+      const Executor& ex = Executor()) ASIO_NOEXCEPT
+  {
+    return associated_executor<Handler, Executor>::get(h.handler_, ex);
+  }
+};
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_SSL_DETAIL_IO_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/ssl/detail/openssl_init.hpp b/link/modules/asio-standalone/asio/include/asio/ssl/detail/openssl_init.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/ssl/detail/openssl_init.hpp
@@ -0,0 +1,101 @@
+//
+// ssl/detail/openssl_init.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_SSL_DETAIL_OPENSSL_INIT_HPP
+#define ASIO_SSL_DETAIL_OPENSSL_INIT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <cstring>
+#include "asio/detail/memory.hpp"
+#include "asio/detail/noncopyable.hpp"
+#include "asio/ssl/detail/openssl_types.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace ssl {
+namespace detail {
+
+class openssl_init_base
+  : private noncopyable
+{
+protected:
+  // Class that performs the actual initialisation.
+  class do_init;
+
+  // Helper function to manage a do_init singleton. The static instance of the
+  // openssl_init object ensures that this function is always called before
+  // main, and therefore before any other threads can get started. The do_init
+  // instance must be static in this function to ensure that it gets
+  // initialised before any other global objects try to use it.
+  ASIO_DECL static asio::detail::shared_ptr<do_init> instance();
+
+#if !defined(SSL_OP_NO_COMPRESSION) \
+  && (OPENSSL_VERSION_NUMBER >= 0x00908000L)
+  // Get an empty stack of compression methods, to be used when disabling
+  // compression.
+  ASIO_DECL static STACK_OF(SSL_COMP)* get_null_compression_methods();
+#endif // !defined(SSL_OP_NO_COMPRESSION)
+       // && (OPENSSL_VERSION_NUMBER >= 0x00908000L)
+};
+
+template <bool Do_Init = true>
+class openssl_init : private openssl_init_base
+{
+public:
+  // Constructor.
+  openssl_init()
+    : ref_(instance())
+  {
+    using namespace std; // For memmove.
+
+    // Ensure openssl_init::instance_ is linked in.
+    openssl_init* tmp = &instance_;
+    memmove(&tmp, &tmp, sizeof(openssl_init*));
+  }
+
+  // Destructor.
+  ~openssl_init()
+  {
+  }
+
+#if !defined(SSL_OP_NO_COMPRESSION) \
+  && (OPENSSL_VERSION_NUMBER >= 0x00908000L)
+  using openssl_init_base::get_null_compression_methods;
+#endif // !defined(SSL_OP_NO_COMPRESSION)
+       // && (OPENSSL_VERSION_NUMBER >= 0x00908000L)
+
+private:
+  // Instance to force initialisation of openssl at global scope.
+  static openssl_init instance_;
+
+  // Reference to singleton do_init object to ensure that openssl does not get
+  // cleaned up until the last user has finished with it.
+  asio::detail::shared_ptr<do_init> ref_;
+};
+
+template <bool Do_Init>
+openssl_init<Do_Init> openssl_init<Do_Init>::instance_;
+
+} // namespace detail
+} // namespace ssl
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/ssl/detail/impl/openssl_init.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // ASIO_SSL_DETAIL_OPENSSL_INIT_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/ssl/detail/openssl_types.hpp b/link/modules/asio-standalone/asio/include/asio/ssl/detail/openssl_types.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/ssl/detail/openssl_types.hpp
@@ -0,0 +1,34 @@
+//
+// ssl/detail/openssl_types.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_SSL_DETAIL_OPENSSL_TYPES_HPP
+#define ASIO_SSL_DETAIL_OPENSSL_TYPES_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/socket_types.hpp"
+#if defined(ASIO_USE_WOLFSSL)
+# include <wolfssl/options.h>
+#endif // defined(ASIO_USE_WOLFSSL)
+#include <openssl/conf.h>
+#include <openssl/ssl.h>
+#if !defined(OPENSSL_NO_ENGINE)
+# include <openssl/engine.h>
+#endif // !defined(OPENSSL_NO_ENGINE)
+#include <openssl/dh.h>
+#include <openssl/err.h>
+#include <openssl/rsa.h>
+#include <openssl/x509.h>
+#include <openssl/x509v3.h>
+
+#endif // ASIO_SSL_DETAIL_OPENSSL_TYPES_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/ssl/detail/password_callback.hpp b/link/modules/asio-standalone/asio/include/asio/ssl/detail/password_callback.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/ssl/detail/password_callback.hpp
@@ -0,0 +1,66 @@
+//
+// ssl/detail/password_callback.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_SSL_DETAIL_PASSWORD_CALLBACK_HPP
+#define ASIO_SSL_DETAIL_PASSWORD_CALLBACK_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#include <cstddef>
+#include <string>
+#include "asio/ssl/context_base.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace ssl {
+namespace detail {
+
+class password_callback_base
+{
+public:
+  virtual ~password_callback_base()
+  {
+  }
+
+  virtual std::string call(std::size_t size,
+      context_base::password_purpose purpose) = 0;
+};
+
+template <typename PasswordCallback>
+class password_callback : public password_callback_base
+{
+public:
+  explicit password_callback(PasswordCallback callback)
+    : callback_(callback)
+  {
+  }
+
+  virtual std::string call(std::size_t size,
+      context_base::password_purpose purpose)
+  {
+    return callback_(size, purpose);
+  }
+
+private:
+  PasswordCallback callback_;
+};
+
+} // namespace detail
+} // namespace ssl
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_SSL_DETAIL_PASSWORD_CALLBACK_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/ssl/detail/read_op.hpp b/link/modules/asio-standalone/asio/include/asio/ssl/detail/read_op.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/ssl/detail/read_op.hpp
@@ -0,0 +1,72 @@
+//
+// ssl/detail/read_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_SSL_DETAIL_READ_OP_HPP
+#define ASIO_SSL_DETAIL_READ_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#include "asio/detail/buffer_sequence_adapter.hpp"
+#include "asio/ssl/detail/engine.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace ssl {
+namespace detail {
+
+template <typename MutableBufferSequence>
+class read_op
+{
+public:
+  static ASIO_CONSTEXPR const char* tracking_name()
+  {
+    return "ssl::stream<>::async_read_some";
+  }
+
+  read_op(const MutableBufferSequence& buffers)
+    : buffers_(buffers)
+  {
+  }
+
+  engine::want operator()(engine& eng,
+      asio::error_code& ec,
+      std::size_t& bytes_transferred) const
+  {
+    asio::mutable_buffer buffer =
+      asio::detail::buffer_sequence_adapter<asio::mutable_buffer,
+        MutableBufferSequence>::first(buffers_);
+
+    return eng.read(buffer, ec, bytes_transferred);
+  }
+
+  template <typename Handler>
+  void call_handler(Handler& handler,
+      const asio::error_code& ec,
+      const std::size_t& bytes_transferred) const
+  {
+    handler(ec, bytes_transferred);
+  }
+
+private:
+  MutableBufferSequence buffers_;
+};
+
+} // namespace detail
+} // namespace ssl
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_SSL_DETAIL_READ_OP_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/ssl/detail/shutdown_op.hpp b/link/modules/asio-standalone/asio/include/asio/ssl/detail/shutdown_op.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/ssl/detail/shutdown_op.hpp
@@ -0,0 +1,69 @@
+//
+// ssl/detail/shutdown_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_SSL_DETAIL_SHUTDOWN_OP_HPP
+#define ASIO_SSL_DETAIL_SHUTDOWN_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#include "asio/ssl/detail/engine.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace ssl {
+namespace detail {
+
+class shutdown_op
+{
+public:
+  static ASIO_CONSTEXPR const char* tracking_name()
+  {
+    return "ssl::stream<>::async_shutdown";
+  }
+
+  engine::want operator()(engine& eng,
+      asio::error_code& ec,
+      std::size_t& bytes_transferred) const
+  {
+    bytes_transferred = 0;
+    return eng.shutdown(ec);
+  }
+
+  template <typename Handler>
+  void call_handler(Handler& handler,
+      const asio::error_code& ec,
+      const std::size_t&) const
+  {
+    if (ec == asio::error::eof)
+    {
+      // The engine only generates an eof when the shutdown notification has
+      // been received from the peer. This indicates that the shutdown has
+      // completed successfully, and thus need not be passed on to the handler.
+      handler(asio::error_code());
+    }
+    else
+    {
+      handler(ec);
+    }
+  }
+};
+
+} // namespace detail
+} // namespace ssl
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_SSL_DETAIL_SHUTDOWN_OP_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/ssl/detail/stream_core.hpp b/link/modules/asio-standalone/asio/include/asio/ssl/detail/stream_core.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/ssl/detail/stream_core.hpp
@@ -0,0 +1,169 @@
+//
+// ssl/detail/stream_core.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_SSL_DETAIL_STREAM_CORE_HPP
+#define ASIO_SSL_DETAIL_STREAM_CORE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_BOOST_DATE_TIME)
+# include "asio/deadline_timer.hpp"
+#else // defined(ASIO_HAS_BOOST_DATE_TIME)
+# include "asio/steady_timer.hpp"
+#endif // defined(ASIO_HAS_BOOST_DATE_TIME)
+#include "asio/ssl/detail/engine.hpp"
+#include "asio/buffer.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace ssl {
+namespace detail {
+
+struct stream_core
+{
+  // According to the OpenSSL documentation, this is the buffer size that is
+  // sufficient to hold the largest possible TLS record.
+  enum { max_tls_record_size = 17 * 1024 };
+
+  template <typename Executor>
+  stream_core(SSL_CTX* context, const Executor& ex)
+    : engine_(context),
+      pending_read_(ex),
+      pending_write_(ex),
+      output_buffer_space_(max_tls_record_size),
+      output_buffer_(asio::buffer(output_buffer_space_)),
+      input_buffer_space_(max_tls_record_size),
+      input_buffer_(asio::buffer(input_buffer_space_))
+  {
+    pending_read_.expires_at(neg_infin());
+    pending_write_.expires_at(neg_infin());
+  }
+
+#if defined(ASIO_HAS_MOVE)
+  stream_core(stream_core&& other)
+    : engine_(ASIO_MOVE_CAST(engine)(other.engine_)),
+#if defined(ASIO_HAS_BOOST_DATE_TIME)
+      pending_read_(
+         ASIO_MOVE_CAST(asio::deadline_timer)(
+           other.pending_read_)),
+      pending_write_(
+         ASIO_MOVE_CAST(asio::deadline_timer)(
+           other.pending_write_)),
+#else // defined(ASIO_HAS_BOOST_DATE_TIME)
+      pending_read_(
+         ASIO_MOVE_CAST(asio::steady_timer)(
+           other.pending_read_)),
+      pending_write_(
+         ASIO_MOVE_CAST(asio::steady_timer)(
+           other.pending_write_)),
+#endif // defined(ASIO_HAS_BOOST_DATE_TIME)
+      output_buffer_space_(
+          ASIO_MOVE_CAST(std::vector<unsigned char>)(
+            other.output_buffer_space_)),
+      output_buffer_(other.output_buffer_),
+      input_buffer_space_(
+          ASIO_MOVE_CAST(std::vector<unsigned char>)(
+            other.input_buffer_space_)),
+      input_buffer_(other.input_buffer_),
+      input_(other.input_)
+  {
+    other.output_buffer_ = asio::mutable_buffer(0, 0);
+    other.input_buffer_ = asio::mutable_buffer(0, 0);
+    other.input_ = asio::const_buffer(0, 0);
+  }
+#endif // defined(ASIO_HAS_MOVE)
+
+  ~stream_core()
+  {
+  }
+
+  // The SSL engine.
+  engine engine_;
+
+#if defined(ASIO_HAS_BOOST_DATE_TIME)
+  // Timer used for storing queued read operations.
+  asio::deadline_timer pending_read_;
+
+  // Timer used for storing queued write operations.
+  asio::deadline_timer pending_write_;
+
+  // Helper function for obtaining a time value that always fires.
+  static asio::deadline_timer::time_type neg_infin()
+  {
+    return boost::posix_time::neg_infin;
+  }
+
+  // Helper function for obtaining a time value that never fires.
+  static asio::deadline_timer::time_type pos_infin()
+  {
+    return boost::posix_time::pos_infin;
+  }
+
+  // Helper function to get a timer's expiry time.
+  static asio::deadline_timer::time_type expiry(
+      const asio::deadline_timer& timer)
+  {
+    return timer.expires_at();
+  }
+#else // defined(ASIO_HAS_BOOST_DATE_TIME)
+  // Timer used for storing queued read operations.
+  asio::steady_timer pending_read_;
+
+  // Timer used for storing queued write operations.
+  asio::steady_timer pending_write_;
+
+  // Helper function for obtaining a time value that always fires.
+  static asio::steady_timer::time_point neg_infin()
+  {
+    return (asio::steady_timer::time_point::min)();
+  }
+
+  // Helper function for obtaining a time value that never fires.
+  static asio::steady_timer::time_point pos_infin()
+  {
+    return (asio::steady_timer::time_point::max)();
+  }
+
+  // Helper function to get a timer's expiry time.
+  static asio::steady_timer::time_point expiry(
+      const asio::steady_timer& timer)
+  {
+    return timer.expiry();
+  }
+#endif // defined(ASIO_HAS_BOOST_DATE_TIME)
+
+  // Buffer space used to prepare output intended for the transport.
+  std::vector<unsigned char> output_buffer_space_;
+
+  // A buffer that may be used to prepare output intended for the transport.
+  asio::mutable_buffer output_buffer_;
+
+  // Buffer space used to read input intended for the engine.
+  std::vector<unsigned char> input_buffer_space_;
+
+  // A buffer that may be used to read input intended for the engine.
+  asio::mutable_buffer input_buffer_;
+
+  // The buffer pointing to the engine's unconsumed input.
+  asio::const_buffer input_;
+};
+
+} // namespace detail
+} // namespace ssl
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_SSL_DETAIL_STREAM_CORE_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/ssl/detail/verify_callback.hpp b/link/modules/asio-standalone/asio/include/asio/ssl/detail/verify_callback.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/ssl/detail/verify_callback.hpp
@@ -0,0 +1,62 @@
+//
+// ssl/detail/verify_callback.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_SSL_DETAIL_VERIFY_CALLBACK_HPP
+#define ASIO_SSL_DETAIL_VERIFY_CALLBACK_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#include "asio/ssl/verify_context.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace ssl {
+namespace detail {
+
+class verify_callback_base
+{
+public:
+  virtual ~verify_callback_base()
+  {
+  }
+
+  virtual bool call(bool preverified, verify_context& ctx) = 0;
+};
+
+template <typename VerifyCallback>
+class verify_callback : public verify_callback_base
+{
+public:
+  explicit verify_callback(VerifyCallback callback)
+    : callback_(callback)
+  {
+  }
+
+  virtual bool call(bool preverified, verify_context& ctx)
+  {
+    return callback_(preverified, ctx);
+  }
+
+private:
+  VerifyCallback callback_;
+};
+
+} // namespace detail
+} // namespace ssl
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_SSL_DETAIL_VERIFY_CALLBACK_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/ssl/detail/write_op.hpp b/link/modules/asio-standalone/asio/include/asio/ssl/detail/write_op.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/ssl/detail/write_op.hpp
@@ -0,0 +1,76 @@
+//
+// ssl/detail/write_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_SSL_DETAIL_WRITE_OP_HPP
+#define ASIO_SSL_DETAIL_WRITE_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#include "asio/detail/buffer_sequence_adapter.hpp"
+#include "asio/ssl/detail/engine.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace ssl {
+namespace detail {
+
+template <typename ConstBufferSequence>
+class write_op
+{
+public:
+  static ASIO_CONSTEXPR const char* tracking_name()
+  {
+    return "ssl::stream<>::async_write_some";
+  }
+
+  write_op(const ConstBufferSequence& buffers)
+    : buffers_(buffers)
+  {
+  }
+
+  engine::want operator()(engine& eng,
+      asio::error_code& ec,
+      std::size_t& bytes_transferred) const
+  {
+    unsigned char storage[
+      asio::detail::buffer_sequence_adapter<asio::const_buffer,
+        ConstBufferSequence>::linearisation_storage_size];
+
+    asio::const_buffer buffer =
+      asio::detail::buffer_sequence_adapter<asio::const_buffer,
+        ConstBufferSequence>::linearise(buffers_, asio::buffer(storage));
+
+    return eng.write(buffer, ec, bytes_transferred);
+  }
+
+  template <typename Handler>
+  void call_handler(Handler& handler,
+      const asio::error_code& ec,
+      const std::size_t& bytes_transferred) const
+  {
+    handler(ec, bytes_transferred);
+  }
+
+private:
+  ConstBufferSequence buffers_;
+};
+
+} // namespace detail
+} // namespace ssl
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_SSL_DETAIL_WRITE_OP_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/ssl/error.hpp b/link/modules/asio-standalone/asio/include/asio/ssl/error.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/ssl/error.hpp
@@ -0,0 +1,125 @@
+//
+// ssl/error.hpp
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_SSL_ERROR_HPP
+#define ASIO_SSL_ERROR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/error_code.hpp"
+#include "asio/ssl/detail/openssl_types.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace error {
+
+enum ssl_errors
+{
+  // Error numbers are those produced by openssl.
+};
+
+extern ASIO_DECL
+const asio::error_category& get_ssl_category();
+
+static const asio::error_category&
+  ssl_category ASIO_UNUSED_VARIABLE
+  = asio::error::get_ssl_category();
+
+} // namespace error
+namespace ssl {
+namespace error {
+
+enum stream_errors
+{
+#if defined(GENERATING_DOCUMENTATION)
+  /// The underlying stream closed before the ssl stream gracefully shut down.
+  stream_truncated,
+
+  /// The underlying SSL library returned a system error without providing
+  /// further information.
+  unspecified_system_error,
+
+  /// The underlying SSL library generated an unexpected result from a function
+  /// call.
+  unexpected_result
+#else // defined(GENERATING_DOCUMENTATION)
+# if (OPENSSL_VERSION_NUMBER < 0x10100000L) \
+    && !defined(OPENSSL_IS_BORINGSSL) \
+    && !defined(ASIO_USE_WOLFSSL)
+  stream_truncated = ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SHORT_READ),
+# else
+  stream_truncated = 1,
+# endif
+  unspecified_system_error = 2,
+  unexpected_result = 3
+#endif // defined(GENERATING_DOCUMENTATION)
+};
+
+extern ASIO_DECL
+const asio::error_category& get_stream_category();
+
+static const asio::error_category&
+  stream_category ASIO_UNUSED_VARIABLE
+  = asio::ssl::error::get_stream_category();
+
+} // namespace error
+} // namespace ssl
+} // namespace asio
+
+#if defined(ASIO_HAS_STD_SYSTEM_ERROR)
+namespace std {
+
+template<> struct is_error_code_enum<asio::error::ssl_errors>
+{
+  static const bool value = true;
+};
+
+template<> struct is_error_code_enum<asio::ssl::error::stream_errors>
+{
+  static const bool value = true;
+};
+
+} // namespace std
+#endif // defined(ASIO_HAS_STD_SYSTEM_ERROR)
+
+namespace asio {
+namespace error {
+
+inline asio::error_code make_error_code(ssl_errors e)
+{
+  return asio::error_code(
+      static_cast<int>(e), get_ssl_category());
+}
+
+} // namespace error
+namespace ssl {
+namespace error {
+
+inline asio::error_code make_error_code(stream_errors e)
+{
+  return asio::error_code(
+      static_cast<int>(e), get_stream_category());
+}
+
+} // namespace error
+} // namespace ssl
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/ssl/impl/error.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // ASIO_SSL_ERROR_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/ssl/host_name_verification.hpp b/link/modules/asio-standalone/asio/include/asio/ssl/host_name_verification.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/ssl/host_name_verification.hpp
@@ -0,0 +1,90 @@
+//
+// ssl/host_name_verification.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_SSL_HOST_NAME_VERIFICATION_HPP
+#define ASIO_SSL_HOST_NAME_VERIFICATION_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#include <string>
+#include "asio/ssl/detail/openssl_types.hpp"
+#include "asio/ssl/verify_context.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace ssl {
+
+/// Verifies a certificate against a host_name according to the rules described
+/// in RFC 6125.
+/**
+ * @par Example
+ * The following example shows how to synchronously open a secure connection to
+ * a given host name:
+ * @code
+ * using asio::ip::tcp;
+ * namespace ssl = asio::ssl;
+ * typedef ssl::stream<tcp::socket> ssl_socket;
+ *
+ * // Create a context that uses the default paths for finding CA certificates.
+ * ssl::context ctx(ssl::context::sslv23);
+ * ctx.set_default_verify_paths();
+ *
+ * // Open a socket and connect it to the remote host.
+ * asio::io_context io_context;
+ * ssl_socket sock(io_context, ctx);
+ * tcp::resolver resolver(io_context);
+ * tcp::resolver::query query("host.name", "https");
+ * asio::connect(sock.lowest_layer(), resolver.resolve(query));
+ * sock.lowest_layer().set_option(tcp::no_delay(true));
+ *
+ * // Perform SSL handshake and verify the remote host's certificate.
+ * sock.set_verify_mode(ssl::verify_peer);
+ * sock.set_verify_callback(ssl::host_name_verification("host.name"));
+ * sock.handshake(ssl_socket::client);
+ *
+ * // ... read and write as normal ...
+ * @endcode
+ */
+class host_name_verification
+{
+public:
+  /// The type of the function object's result.
+  typedef bool result_type;
+
+  /// Constructor.
+  explicit host_name_verification(const std::string& host)
+    : host_(host)
+  {
+  }
+
+  /// Perform certificate verification.
+  ASIO_DECL bool operator()(bool preverified, verify_context& ctx) const;
+
+private:
+  // Helper function to check a host name against an IPv4 address
+  // The host name to be checked.
+  std::string host_;
+};
+
+} // namespace ssl
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/ssl/impl/host_name_verification.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // ASIO_SSL_HOST_NAME_VERIFICATION_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/ssl/impl/context.hpp b/link/modules/asio-standalone/asio/include/asio/ssl/impl/context.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/ssl/impl/context.hpp
@@ -0,0 +1,67 @@
+//
+// ssl/impl/context.hpp
+// ~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com
+// Copyright (c) 2005-2020 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 ASIO_SSL_IMPL_CONTEXT_HPP
+#define ASIO_SSL_IMPL_CONTEXT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#include "asio/detail/throw_error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace ssl {
+
+template <typename VerifyCallback>
+void context::set_verify_callback(VerifyCallback callback)
+{
+  asio::error_code ec;
+  this->set_verify_callback(callback, ec);
+  asio::detail::throw_error(ec, "set_verify_callback");
+}
+
+template <typename VerifyCallback>
+ASIO_SYNC_OP_VOID context::set_verify_callback(
+    VerifyCallback callback, asio::error_code& ec)
+{
+  do_set_verify_callback(
+      new detail::verify_callback<VerifyCallback>(callback), ec);
+  ASIO_SYNC_OP_VOID_RETURN(ec);
+}
+
+template <typename PasswordCallback>
+void context::set_password_callback(PasswordCallback callback)
+{
+  asio::error_code ec;
+  this->set_password_callback(callback, ec);
+  asio::detail::throw_error(ec, "set_password_callback");
+}
+
+template <typename PasswordCallback>
+ASIO_SYNC_OP_VOID context::set_password_callback(
+    PasswordCallback callback, asio::error_code& ec)
+{
+  do_set_password_callback(
+      new detail::password_callback<PasswordCallback>(callback), ec);
+  ASIO_SYNC_OP_VOID_RETURN(ec);
+}
+
+} // namespace ssl
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_SSL_IMPL_CONTEXT_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/ssl/impl/context.ipp b/link/modules/asio-standalone/asio/include/asio/ssl/impl/context.ipp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/ssl/impl/context.ipp
@@ -0,0 +1,1238 @@
+//
+// ssl/impl/context.ipp
+// ~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com
+// Copyright (c) 2005-2020 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 ASIO_SSL_IMPL_CONTEXT_IPP
+#define ASIO_SSL_IMPL_CONTEXT_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#include <cstring>
+#include "asio/detail/throw_error.hpp"
+#include "asio/error.hpp"
+#include "asio/ssl/context.hpp"
+#include "asio/ssl/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace ssl {
+
+struct context::bio_cleanup
+{
+  BIO* p;
+  ~bio_cleanup() { if (p) ::BIO_free(p); }
+};
+
+struct context::x509_cleanup
+{
+  X509* p;
+  ~x509_cleanup() { if (p) ::X509_free(p); }
+};
+
+struct context::evp_pkey_cleanup
+{
+  EVP_PKEY* p;
+  ~evp_pkey_cleanup() { if (p) ::EVP_PKEY_free(p); }
+};
+
+struct context::rsa_cleanup
+{
+  RSA* p;
+  ~rsa_cleanup() { if (p) ::RSA_free(p); }
+};
+
+struct context::dh_cleanup
+{
+  DH* p;
+  ~dh_cleanup() { if (p) ::DH_free(p); }
+};
+
+context::context(context::method m)
+  : handle_(0)
+{
+  ::ERR_clear_error();
+
+  switch (m)
+  {
+    // SSL v2.
+#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) || defined(OPENSSL_NO_SSL2)
+  case context::sslv2:
+  case context::sslv2_client:
+  case context::sslv2_server:
+    asio::detail::throw_error(
+        asio::error::invalid_argument, "context");
+    break;
+#else // (OPENSSL_VERSION_NUMBER >= 0x10100000L) || defined(OPENSSL_NO_SSL2)
+  case context::sslv2:
+    handle_ = ::SSL_CTX_new(::SSLv2_method());
+    break;
+  case context::sslv2_client:
+    handle_ = ::SSL_CTX_new(::SSLv2_client_method());
+    break;
+  case context::sslv2_server:
+    handle_ = ::SSL_CTX_new(::SSLv2_server_method());
+    break;
+#endif // (OPENSSL_VERSION_NUMBER >= 0x10100000L) || defined(OPENSSL_NO_SSL2)
+
+    // SSL v3.
+#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && !defined(LIBRESSL_VERSION_NUMBER)
+  case context::sslv3:
+    handle_ = ::SSL_CTX_new(::TLS_method());
+    if (handle_)
+    {
+      SSL_CTX_set_min_proto_version(handle_, SSL3_VERSION);
+      SSL_CTX_set_max_proto_version(handle_, SSL3_VERSION);
+    }
+    break;
+  case context::sslv3_client:
+    handle_ = ::SSL_CTX_new(::TLS_client_method());
+    if (handle_)
+    {
+      SSL_CTX_set_min_proto_version(handle_, SSL3_VERSION);
+      SSL_CTX_set_max_proto_version(handle_, SSL3_VERSION);
+    }
+    break;
+  case context::sslv3_server:
+    handle_ = ::SSL_CTX_new(::TLS_server_method());
+    if (handle_)
+    {
+      SSL_CTX_set_min_proto_version(handle_, SSL3_VERSION);
+      SSL_CTX_set_max_proto_version(handle_, SSL3_VERSION);
+    }
+    break;
+#elif defined(OPENSSL_NO_SSL3)
+  case context::sslv3:
+  case context::sslv3_client:
+  case context::sslv3_server:
+    asio::detail::throw_error(
+        asio::error::invalid_argument, "context");
+    break;
+#else // defined(OPENSSL_NO_SSL3)
+  case context::sslv3:
+    handle_ = ::SSL_CTX_new(::SSLv3_method());
+    break;
+  case context::sslv3_client:
+    handle_ = ::SSL_CTX_new(::SSLv3_client_method());
+    break;
+  case context::sslv3_server:
+    handle_ = ::SSL_CTX_new(::SSLv3_server_method());
+    break;
+#endif // defined(OPENSSL_NO_SSL3)
+
+    // TLS v1.0.
+#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && !defined(LIBRESSL_VERSION_NUMBER)
+  case context::tlsv1:
+    handle_ = ::SSL_CTX_new(::TLS_method());
+    if (handle_)
+    {
+      SSL_CTX_set_min_proto_version(handle_, TLS1_VERSION);
+      SSL_CTX_set_max_proto_version(handle_, TLS1_VERSION);
+    }
+    break;
+  case context::tlsv1_client:
+    handle_ = ::SSL_CTX_new(::TLS_client_method());
+    if (handle_)
+    {
+      SSL_CTX_set_min_proto_version(handle_, TLS1_VERSION);
+      SSL_CTX_set_max_proto_version(handle_, TLS1_VERSION);
+    }
+    break;
+  case context::tlsv1_server:
+    handle_ = ::SSL_CTX_new(::TLS_server_method());
+    if (handle_)
+    {
+      SSL_CTX_set_min_proto_version(handle_, TLS1_VERSION);
+      SSL_CTX_set_max_proto_version(handle_, TLS1_VERSION);
+    }
+    break;
+#elif defined(SSL_TXT_TLSV1)
+  case context::tlsv1:
+    handle_ = ::SSL_CTX_new(::TLSv1_method());
+    break;
+  case context::tlsv1_client:
+    handle_ = ::SSL_CTX_new(::TLSv1_client_method());
+    break;
+  case context::tlsv1_server:
+    handle_ = ::SSL_CTX_new(::TLSv1_server_method());
+    break;
+#else // defined(SSL_TXT_TLSV1)
+  case context::tlsv1:
+  case context::tlsv1_client:
+  case context::tlsv1_server:
+    asio::detail::throw_error(
+        asio::error::invalid_argument, "context");
+    break;
+#endif // defined(SSL_TXT_TLSV1)
+
+    // TLS v1.1.
+#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && !defined(LIBRESSL_VERSION_NUMBER)
+  case context::tlsv11:
+    handle_ = ::SSL_CTX_new(::TLS_method());
+    if (handle_)
+    {
+      SSL_CTX_set_min_proto_version(handle_, TLS1_1_VERSION);
+      SSL_CTX_set_max_proto_version(handle_, TLS1_1_VERSION);
+    }
+    break;
+  case context::tlsv11_client:
+    handle_ = ::SSL_CTX_new(::TLS_client_method());
+    if (handle_)
+    {
+      SSL_CTX_set_min_proto_version(handle_, TLS1_1_VERSION);
+      SSL_CTX_set_max_proto_version(handle_, TLS1_1_VERSION);
+    }
+    break;
+  case context::tlsv11_server:
+    handle_ = ::SSL_CTX_new(::TLS_server_method());
+    if (handle_)
+    {
+      SSL_CTX_set_min_proto_version(handle_, TLS1_1_VERSION);
+      SSL_CTX_set_max_proto_version(handle_, TLS1_1_VERSION);
+    }
+    break;
+#elif defined(SSL_TXT_TLSV1_1)
+  case context::tlsv11:
+    handle_ = ::SSL_CTX_new(::TLSv1_1_method());
+    break;
+  case context::tlsv11_client:
+    handle_ = ::SSL_CTX_new(::TLSv1_1_client_method());
+    break;
+  case context::tlsv11_server:
+    handle_ = ::SSL_CTX_new(::TLSv1_1_server_method());
+    break;
+#else // defined(SSL_TXT_TLSV1_1)
+  case context::tlsv11:
+  case context::tlsv11_client:
+  case context::tlsv11_server:
+    asio::detail::throw_error(
+        asio::error::invalid_argument, "context");
+    break;
+#endif // defined(SSL_TXT_TLSV1_1)
+
+    // TLS v1.2.
+#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && !defined(LIBRESSL_VERSION_NUMBER)
+  case context::tlsv12:
+    handle_ = ::SSL_CTX_new(::TLS_method());
+    if (handle_)
+    {
+      SSL_CTX_set_min_proto_version(handle_, TLS1_2_VERSION);
+      SSL_CTX_set_max_proto_version(handle_, TLS1_2_VERSION);
+    }
+    break;
+  case context::tlsv12_client:
+    handle_ = ::SSL_CTX_new(::TLS_client_method());
+    if (handle_)
+    {
+      SSL_CTX_set_min_proto_version(handle_, TLS1_2_VERSION);
+      SSL_CTX_set_max_proto_version(handle_, TLS1_2_VERSION);
+    }
+    break;
+  case context::tlsv12_server:
+    handle_ = ::SSL_CTX_new(::TLS_server_method());
+    if (handle_)
+    {
+      SSL_CTX_set_min_proto_version(handle_, TLS1_2_VERSION);
+      SSL_CTX_set_max_proto_version(handle_, TLS1_2_VERSION);
+    }
+    break;
+#elif defined(SSL_TXT_TLSV1_2)
+  case context::tlsv12:
+    handle_ = ::SSL_CTX_new(::TLSv1_2_method());
+    break;
+  case context::tlsv12_client:
+    handle_ = ::SSL_CTX_new(::TLSv1_2_client_method());
+    break;
+  case context::tlsv12_server:
+    handle_ = ::SSL_CTX_new(::TLSv1_2_server_method());
+    break;
+#else // defined(SSL_TXT_TLSV1_2)
+  case context::tlsv12:
+  case context::tlsv12_client:
+  case context::tlsv12_server:
+    asio::detail::throw_error(
+        asio::error::invalid_argument, "context");
+    break;
+#endif // defined(SSL_TXT_TLSV1_2)
+
+    // TLS v1.3.
+#if (OPENSSL_VERSION_NUMBER >= 0x10101000L) \
+    && !defined(LIBRESSL_VERSION_NUMBER)
+  case context::tlsv13:
+    handle_ = ::SSL_CTX_new(::TLS_method());
+    if (handle_)
+    {
+      SSL_CTX_set_min_proto_version(handle_, TLS1_3_VERSION);
+      SSL_CTX_set_max_proto_version(handle_, TLS1_3_VERSION);
+    }
+    break;
+  case context::tlsv13_client:
+    handle_ = ::SSL_CTX_new(::TLS_client_method());
+    if (handle_)
+    {
+      SSL_CTX_set_min_proto_version(handle_, TLS1_3_VERSION);
+      SSL_CTX_set_max_proto_version(handle_, TLS1_3_VERSION);
+    }
+    break;
+  case context::tlsv13_server:
+    handle_ = ::SSL_CTX_new(::TLS_server_method());
+    if (handle_)
+    {
+      SSL_CTX_set_min_proto_version(handle_, TLS1_3_VERSION);
+      SSL_CTX_set_max_proto_version(handle_, TLS1_3_VERSION);
+    }
+    break;
+#else // (OPENSSL_VERSION_NUMBER >= 0x10101000L)
+      //   && !defined(LIBRESSL_VERSION_NUMBER)
+  case context::tlsv13:
+  case context::tlsv13_client:
+  case context::tlsv13_server:
+    asio::detail::throw_error(
+        asio::error::invalid_argument, "context");
+    break;
+#endif // (OPENSSL_VERSION_NUMBER >= 0x10101000L)
+       //   && !defined(LIBRESSL_VERSION_NUMBER)
+
+    // Any supported SSL/TLS version.
+  case context::sslv23:
+    handle_ = ::SSL_CTX_new(::SSLv23_method());
+    break;
+  case context::sslv23_client:
+    handle_ = ::SSL_CTX_new(::SSLv23_client_method());
+    break;
+  case context::sslv23_server:
+    handle_ = ::SSL_CTX_new(::SSLv23_server_method());
+    break;
+
+    // Any supported TLS version.
+#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && !defined(LIBRESSL_VERSION_NUMBER)
+  case context::tls:
+    handle_ = ::SSL_CTX_new(::TLS_method());
+    if (handle_)
+      SSL_CTX_set_min_proto_version(handle_, TLS1_VERSION);
+    break;
+  case context::tls_client:
+    handle_ = ::SSL_CTX_new(::TLS_client_method());
+    if (handle_)
+      SSL_CTX_set_min_proto_version(handle_, TLS1_VERSION);
+    break;
+  case context::tls_server:
+    handle_ = ::SSL_CTX_new(::TLS_server_method());
+    if (handle_)
+      SSL_CTX_set_min_proto_version(handle_, TLS1_VERSION);
+    break;
+#else // (OPENSSL_VERSION_NUMBER >= 0x10100000L)
+  case context::tls:
+    handle_ = ::SSL_CTX_new(::SSLv23_method());
+    if (handle_)
+      SSL_CTX_set_options(handle_, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);
+    break;
+  case context::tls_client:
+    handle_ = ::SSL_CTX_new(::SSLv23_client_method());
+    if (handle_)
+      SSL_CTX_set_options(handle_, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);
+    break;
+  case context::tls_server:
+    handle_ = ::SSL_CTX_new(::SSLv23_server_method());
+    if (handle_)
+      SSL_CTX_set_options(handle_, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);
+    break;
+#endif // (OPENSSL_VERSION_NUMBER >= 0x10100000L)
+
+  default:
+    handle_ = ::SSL_CTX_new(0);
+    break;
+  }
+
+  if (handle_ == 0)
+  {
+    asio::error_code ec(
+        static_cast<int>(::ERR_get_error()),
+        asio::error::get_ssl_category());
+    asio::detail::throw_error(ec, "context");
+  }
+
+  set_options(no_compression);
+}
+
+context::context(context::native_handle_type native_handle)
+  : handle_(native_handle)
+{
+  if (!handle_)
+  {
+    asio::detail::throw_error(
+        asio::error::invalid_argument, "context");
+  }
+}
+
+#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+context::context(context&& other)
+{
+  handle_ = other.handle_;
+  other.handle_ = 0;
+}
+
+context& context::operator=(context&& other)
+{
+  context tmp(ASIO_MOVE_CAST(context)(*this));
+  handle_ = other.handle_;
+  other.handle_ = 0;
+  return *this;
+}
+#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+
+context::~context()
+{
+  if (handle_)
+  {
+#if ((OPENSSL_VERSION_NUMBER >= 0x10100000L) \
+      && !defined(LIBRESSL_VERSION_NUMBER)) \
+    || defined(ASIO_USE_WOLFSSL)
+    void* cb_userdata = ::SSL_CTX_get_default_passwd_cb_userdata(handle_);
+#else // (OPENSSL_VERSION_NUMBER >= 0x10100000L)
+    void* cb_userdata = handle_->default_passwd_callback_userdata;
+#endif // (OPENSSL_VERSION_NUMBER >= 0x10100000L)
+    if (cb_userdata)
+    {
+      detail::password_callback_base* callback =
+        static_cast<detail::password_callback_base*>(
+            cb_userdata);
+      delete callback;
+#if ((OPENSSL_VERSION_NUMBER >= 0x10100000L) \
+      && !defined(LIBRESSL_VERSION_NUMBER)) \
+    || defined(ASIO_USE_WOLFSSL)
+      ::SSL_CTX_set_default_passwd_cb_userdata(handle_, 0);
+#else // (OPENSSL_VERSION_NUMBER >= 0x10100000L)
+      handle_->default_passwd_callback_userdata = 0;
+#endif // (OPENSSL_VERSION_NUMBER >= 0x10100000L)
+    }
+
+    if (SSL_CTX_get_app_data(handle_))
+    {
+      detail::verify_callback_base* callback =
+        static_cast<detail::verify_callback_base*>(
+            SSL_CTX_get_app_data(handle_));
+      delete callback;
+      SSL_CTX_set_app_data(handle_, 0);
+    }
+
+    ::SSL_CTX_free(handle_);
+  }
+}
+
+context::native_handle_type context::native_handle()
+{
+  return handle_;
+}
+
+void context::clear_options(context::options o)
+{
+  asio::error_code ec;
+  clear_options(o, ec);
+  asio::detail::throw_error(ec, "clear_options");
+}
+
+ASIO_SYNC_OP_VOID context::clear_options(
+    context::options o, asio::error_code& ec)
+{
+#if (OPENSSL_VERSION_NUMBER >= 0x009080DFL) \
+  && (OPENSSL_VERSION_NUMBER != 0x00909000L)
+# if !defined(SSL_OP_NO_COMPRESSION)
+  if ((o & context::no_compression) != 0)
+  {
+# if (OPENSSL_VERSION_NUMBER >= 0x00908000L)
+    handle_->comp_methods = SSL_COMP_get_compression_methods();
+# endif // (OPENSSL_VERSION_NUMBER >= 0x00908000L)
+    o ^= context::no_compression;
+  }
+# endif // !defined(SSL_OP_NO_COMPRESSION)
+
+  ::SSL_CTX_clear_options(handle_, o);
+
+  ec = asio::error_code();
+#else // (OPENSSL_VERSION_NUMBER >= 0x009080DFL)
+      //   && (OPENSSL_VERSION_NUMBER != 0x00909000L)
+  (void)o;
+  ec = asio::error::operation_not_supported;
+#endif // (OPENSSL_VERSION_NUMBER >= 0x009080DFL)
+       //   && (OPENSSL_VERSION_NUMBER != 0x00909000L)
+  ASIO_SYNC_OP_VOID_RETURN(ec);
+}
+
+void context::set_options(context::options o)
+{
+  asio::error_code ec;
+  set_options(o, ec);
+  asio::detail::throw_error(ec, "set_options");
+}
+
+ASIO_SYNC_OP_VOID context::set_options(
+    context::options o, asio::error_code& ec)
+{
+#if !defined(SSL_OP_NO_COMPRESSION)
+  if ((o & context::no_compression) != 0)
+  {
+#if (OPENSSL_VERSION_NUMBER >= 0x00908000L)
+    handle_->comp_methods =
+      asio::ssl::detail::openssl_init<>::get_null_compression_methods();
+#endif // (OPENSSL_VERSION_NUMBER >= 0x00908000L)
+    o ^= context::no_compression;
+  }
+#endif // !defined(SSL_OP_NO_COMPRESSION)
+
+  ::SSL_CTX_set_options(handle_, o);
+
+  ec = asio::error_code();
+  ASIO_SYNC_OP_VOID_RETURN(ec);
+}
+
+void context::set_verify_mode(verify_mode v)
+{
+  asio::error_code ec;
+  set_verify_mode(v, ec);
+  asio::detail::throw_error(ec, "set_verify_mode");
+}
+
+ASIO_SYNC_OP_VOID context::set_verify_mode(
+    verify_mode v, asio::error_code& ec)
+{
+  ::SSL_CTX_set_verify(handle_, v, ::SSL_CTX_get_verify_callback(handle_));
+
+  ec = asio::error_code();
+  ASIO_SYNC_OP_VOID_RETURN(ec);
+}
+
+void context::set_verify_depth(int depth)
+{
+  asio::error_code ec;
+  set_verify_depth(depth, ec);
+  asio::detail::throw_error(ec, "set_verify_depth");
+}
+
+ASIO_SYNC_OP_VOID context::set_verify_depth(
+    int depth, asio::error_code& ec)
+{
+  ::SSL_CTX_set_verify_depth(handle_, depth);
+
+  ec = asio::error_code();
+  ASIO_SYNC_OP_VOID_RETURN(ec);
+}
+
+void context::load_verify_file(const std::string& filename)
+{
+  asio::error_code ec;
+  load_verify_file(filename, ec);
+  asio::detail::throw_error(ec, "load_verify_file");
+}
+
+ASIO_SYNC_OP_VOID context::load_verify_file(
+    const std::string& filename, asio::error_code& ec)
+{
+  ::ERR_clear_error();
+
+  if (::SSL_CTX_load_verify_locations(handle_, filename.c_str(), 0) != 1)
+  {
+    ec = asio::error_code(
+        static_cast<int>(::ERR_get_error()),
+        asio::error::get_ssl_category());
+    ASIO_SYNC_OP_VOID_RETURN(ec);
+  }
+
+  ec = asio::error_code();
+  ASIO_SYNC_OP_VOID_RETURN(ec);
+}
+
+void context::add_certificate_authority(const const_buffer& ca)
+{
+  asio::error_code ec;
+  add_certificate_authority(ca, ec);
+  asio::detail::throw_error(ec, "add_certificate_authority");
+}
+
+ASIO_SYNC_OP_VOID context::add_certificate_authority(
+    const const_buffer& ca, asio::error_code& ec)
+{
+  ::ERR_clear_error();
+
+  bio_cleanup bio = { make_buffer_bio(ca) };
+  if (bio.p)
+  {
+    if (X509_STORE* store = ::SSL_CTX_get_cert_store(handle_))
+    {
+      for (bool added = false;; added = true)
+      {
+        x509_cleanup cert = { ::PEM_read_bio_X509(bio.p, 0, 0, 0) };
+        if (!cert.p)
+        {
+          unsigned long err = ::ERR_get_error();
+          if (added && ERR_GET_LIB(err) == ERR_LIB_PEM
+              && ERR_GET_REASON(err) == PEM_R_NO_START_LINE)
+            break;
+
+          ec = asio::error_code(
+              static_cast<int>(err),
+              asio::error::get_ssl_category());
+          ASIO_SYNC_OP_VOID_RETURN(ec);
+        }
+
+        if (::X509_STORE_add_cert(store, cert.p) != 1)
+        {
+          ec = asio::error_code(
+              static_cast<int>(::ERR_get_error()),
+              asio::error::get_ssl_category());
+          ASIO_SYNC_OP_VOID_RETURN(ec);
+        }
+      }
+    }
+  }
+
+  ec = asio::error_code();
+  ASIO_SYNC_OP_VOID_RETURN(ec);
+}
+
+void context::set_default_verify_paths()
+{
+  asio::error_code ec;
+  set_default_verify_paths(ec);
+  asio::detail::throw_error(ec, "set_default_verify_paths");
+}
+
+ASIO_SYNC_OP_VOID context::set_default_verify_paths(
+    asio::error_code& ec)
+{
+  ::ERR_clear_error();
+
+  if (::SSL_CTX_set_default_verify_paths(handle_) != 1)
+  {
+    ec = asio::error_code(
+        static_cast<int>(::ERR_get_error()),
+        asio::error::get_ssl_category());
+    ASIO_SYNC_OP_VOID_RETURN(ec);
+  }
+
+  ec = asio::error_code();
+  ASIO_SYNC_OP_VOID_RETURN(ec);
+}
+
+void context::add_verify_path(const std::string& path)
+{
+  asio::error_code ec;
+  add_verify_path(path, ec);
+  asio::detail::throw_error(ec, "add_verify_path");
+}
+
+ASIO_SYNC_OP_VOID context::add_verify_path(
+    const std::string& path, asio::error_code& ec)
+{
+  ::ERR_clear_error();
+
+  if (::SSL_CTX_load_verify_locations(handle_, 0, path.c_str()) != 1)
+  {
+    ec = asio::error_code(
+        static_cast<int>(::ERR_get_error()),
+        asio::error::get_ssl_category());
+    ASIO_SYNC_OP_VOID_RETURN(ec);
+  }
+
+  ec = asio::error_code();
+  ASIO_SYNC_OP_VOID_RETURN(ec);
+}
+
+void context::use_certificate(
+    const const_buffer& certificate, file_format format)
+{
+  asio::error_code ec;
+  use_certificate(certificate, format, ec);
+  asio::detail::throw_error(ec, "use_certificate");
+}
+
+ASIO_SYNC_OP_VOID context::use_certificate(
+    const const_buffer& certificate, file_format format,
+    asio::error_code& ec)
+{
+  ::ERR_clear_error();
+
+  if (format == context_base::asn1)
+  {
+    if (::SSL_CTX_use_certificate_ASN1(handle_,
+          static_cast<int>(certificate.size()),
+          static_cast<const unsigned char*>(certificate.data())) == 1)
+    {
+      ec = asio::error_code();
+      ASIO_SYNC_OP_VOID_RETURN(ec);
+    }
+  }
+  else if (format == context_base::pem)
+  {
+    bio_cleanup bio = { make_buffer_bio(certificate) };
+    if (bio.p)
+    {
+      x509_cleanup cert = { ::PEM_read_bio_X509(bio.p, 0, 0, 0) };
+      if (cert.p)
+      {
+        if (::SSL_CTX_use_certificate(handle_, cert.p) == 1)
+        {
+          ec = asio::error_code();
+          ASIO_SYNC_OP_VOID_RETURN(ec);
+        }
+      }
+    }
+  }
+  else
+  {
+    ec = asio::error::invalid_argument;
+    ASIO_SYNC_OP_VOID_RETURN(ec);
+  }
+
+  ec = asio::error_code(
+      static_cast<int>(::ERR_get_error()),
+      asio::error::get_ssl_category());
+  ASIO_SYNC_OP_VOID_RETURN(ec);
+}
+
+void context::use_certificate_file(
+    const std::string& filename, file_format format)
+{
+  asio::error_code ec;
+  use_certificate_file(filename, format, ec);
+  asio::detail::throw_error(ec, "use_certificate_file");
+}
+
+ASIO_SYNC_OP_VOID context::use_certificate_file(
+    const std::string& filename, file_format format,
+    asio::error_code& ec)
+{
+  int file_type;
+  switch (format)
+  {
+  case context_base::asn1:
+    file_type = SSL_FILETYPE_ASN1;
+    break;
+  case context_base::pem:
+    file_type = SSL_FILETYPE_PEM;
+    break;
+  default:
+    {
+      ec = asio::error::invalid_argument;
+      ASIO_SYNC_OP_VOID_RETURN(ec);
+    }
+  }
+
+  ::ERR_clear_error();
+
+  if (::SSL_CTX_use_certificate_file(handle_, filename.c_str(), file_type) != 1)
+  {
+    ec = asio::error_code(
+        static_cast<int>(::ERR_get_error()),
+        asio::error::get_ssl_category());
+    ASIO_SYNC_OP_VOID_RETURN(ec);
+  }
+
+  ec = asio::error_code();
+  ASIO_SYNC_OP_VOID_RETURN(ec);
+}
+
+void context::use_certificate_chain(const const_buffer& chain)
+{
+  asio::error_code ec;
+  use_certificate_chain(chain, ec);
+  asio::detail::throw_error(ec, "use_certificate_chain");
+}
+
+ASIO_SYNC_OP_VOID context::use_certificate_chain(
+    const const_buffer& chain, asio::error_code& ec)
+{
+  ::ERR_clear_error();
+
+  bio_cleanup bio = { make_buffer_bio(chain) };
+  if (bio.p)
+  {
+#if ((OPENSSL_VERSION_NUMBER >= 0x10100000L) \
+      && !defined(LIBRESSL_VERSION_NUMBER)) \
+    || defined(ASIO_USE_WOLFSSL)
+    pem_password_cb* callback = ::SSL_CTX_get_default_passwd_cb(handle_);
+    void* cb_userdata = ::SSL_CTX_get_default_passwd_cb_userdata(handle_);
+#else // (OPENSSL_VERSION_NUMBER >= 0x10100000L)
+    pem_password_cb* callback = handle_->default_passwd_callback;
+    void* cb_userdata = handle_->default_passwd_callback_userdata;
+#endif // (OPENSSL_VERSION_NUMBER >= 0x10100000L)
+    x509_cleanup cert = {
+      ::PEM_read_bio_X509_AUX(bio.p, 0,
+          callback,
+          cb_userdata) };
+    if (!cert.p)
+    {
+      ec = asio::error_code(ERR_R_PEM_LIB,
+          asio::error::get_ssl_category());
+      ASIO_SYNC_OP_VOID_RETURN(ec);
+    }
+
+    int result = ::SSL_CTX_use_certificate(handle_, cert.p);
+    if (result == 0 || ::ERR_peek_error() != 0)
+    {
+      ec = asio::error_code(
+          static_cast<int>(::ERR_get_error()),
+          asio::error::get_ssl_category());
+      ASIO_SYNC_OP_VOID_RETURN(ec);
+    }
+
+#if ((OPENSSL_VERSION_NUMBER >= 0x10002000L) \
+      && !defined(LIBRESSL_VERSION_NUMBER)) \
+    || defined(ASIO_USE_WOLFSSL)
+    ::SSL_CTX_clear_chain_certs(handle_);
+#else
+    if (handle_->extra_certs)
+    {
+      ::sk_X509_pop_free(handle_->extra_certs, X509_free);
+      handle_->extra_certs = 0;
+    }
+#endif // (OPENSSL_VERSION_NUMBER >= 0x10002000L)
+
+    while (X509* cacert = ::PEM_read_bio_X509(bio.p, 0,
+          callback,
+          cb_userdata))
+    {
+      if (!::SSL_CTX_add_extra_chain_cert(handle_, cacert))
+      {
+        ec = asio::error_code(
+            static_cast<int>(::ERR_get_error()),
+            asio::error::get_ssl_category());
+        ASIO_SYNC_OP_VOID_RETURN(ec);
+      }
+    }
+  
+    result = ::ERR_peek_last_error();
+    if ((ERR_GET_LIB(result) == ERR_LIB_PEM)
+        && (ERR_GET_REASON(result) == PEM_R_NO_START_LINE))
+    {
+      ::ERR_clear_error();
+      ec = asio::error_code();
+      ASIO_SYNC_OP_VOID_RETURN(ec);
+    }
+  }
+
+  ec = asio::error_code(
+      static_cast<int>(::ERR_get_error()),
+      asio::error::get_ssl_category());
+  ASIO_SYNC_OP_VOID_RETURN(ec);
+}
+
+void context::use_certificate_chain_file(const std::string& filename)
+{
+  asio::error_code ec;
+  use_certificate_chain_file(filename, ec);
+  asio::detail::throw_error(ec, "use_certificate_chain_file");
+}
+
+ASIO_SYNC_OP_VOID context::use_certificate_chain_file(
+    const std::string& filename, asio::error_code& ec)
+{
+  ::ERR_clear_error();
+
+  if (::SSL_CTX_use_certificate_chain_file(handle_, filename.c_str()) != 1)
+  {
+    ec = asio::error_code(
+        static_cast<int>(::ERR_get_error()),
+        asio::error::get_ssl_category());
+    ASIO_SYNC_OP_VOID_RETURN(ec);
+  }
+
+  ec = asio::error_code();
+  ASIO_SYNC_OP_VOID_RETURN(ec);
+}
+
+void context::use_private_key(
+    const const_buffer& private_key, context::file_format format)
+{
+  asio::error_code ec;
+  use_private_key(private_key, format, ec);
+  asio::detail::throw_error(ec, "use_private_key");
+}
+
+ASIO_SYNC_OP_VOID context::use_private_key(
+    const const_buffer& private_key, context::file_format format,
+    asio::error_code& ec)
+{
+  ::ERR_clear_error();
+
+#if ((OPENSSL_VERSION_NUMBER >= 0x10100000L) \
+      && !defined(LIBRESSL_VERSION_NUMBER)) \
+    || defined(ASIO_USE_WOLFSSL)
+    pem_password_cb* callback = ::SSL_CTX_get_default_passwd_cb(handle_);
+    void* cb_userdata = ::SSL_CTX_get_default_passwd_cb_userdata(handle_);
+#else // (OPENSSL_VERSION_NUMBER >= 0x10100000L)
+    pem_password_cb* callback = handle_->default_passwd_callback;
+    void* cb_userdata = handle_->default_passwd_callback_userdata;
+#endif // (OPENSSL_VERSION_NUMBER >= 0x10100000L)
+
+  bio_cleanup bio = { make_buffer_bio(private_key) };
+  if (bio.p)
+  {
+    evp_pkey_cleanup evp_private_key = { 0 };
+    switch (format)
+    {
+    case context_base::asn1:
+      evp_private_key.p = ::d2i_PrivateKey_bio(bio.p, 0);
+      break;
+    case context_base::pem:
+      evp_private_key.p = ::PEM_read_bio_PrivateKey(
+          bio.p, 0, callback,
+          cb_userdata);
+      break;
+    default:
+      {
+        ec = asio::error::invalid_argument;
+        ASIO_SYNC_OP_VOID_RETURN(ec);
+      }
+    }
+
+    if (evp_private_key.p)
+    {
+      if (::SSL_CTX_use_PrivateKey(handle_, evp_private_key.p) == 1)
+      {
+        ec = asio::error_code();
+        ASIO_SYNC_OP_VOID_RETURN(ec);
+      }
+    }
+  }
+
+  ec = asio::error_code(
+      static_cast<int>(::ERR_get_error()),
+      asio::error::get_ssl_category());
+  ASIO_SYNC_OP_VOID_RETURN(ec);
+}
+
+void context::use_private_key_file(
+    const std::string& filename, context::file_format format)
+{
+  asio::error_code ec;
+  use_private_key_file(filename, format, ec);
+  asio::detail::throw_error(ec, "use_private_key_file");
+}
+
+void context::use_rsa_private_key(
+    const const_buffer& private_key, context::file_format format)
+{
+  asio::error_code ec;
+  use_rsa_private_key(private_key, format, ec);
+  asio::detail::throw_error(ec, "use_rsa_private_key");
+}
+
+ASIO_SYNC_OP_VOID context::use_rsa_private_key(
+    const const_buffer& private_key, context::file_format format,
+    asio::error_code& ec)
+{
+  ::ERR_clear_error();
+
+#if ((OPENSSL_VERSION_NUMBER >= 0x10100000L) \
+      && !defined(LIBRESSL_VERSION_NUMBER)) \
+    || defined(ASIO_USE_WOLFSSL)
+    pem_password_cb* callback = ::SSL_CTX_get_default_passwd_cb(handle_);
+    void* cb_userdata = ::SSL_CTX_get_default_passwd_cb_userdata(handle_);
+#else // (OPENSSL_VERSION_NUMBER >= 0x10100000L)
+    pem_password_cb* callback = handle_->default_passwd_callback;
+    void* cb_userdata = handle_->default_passwd_callback_userdata;
+#endif // (OPENSSL_VERSION_NUMBER >= 0x10100000L)
+
+  bio_cleanup bio = { make_buffer_bio(private_key) };
+  if (bio.p)
+  {
+    rsa_cleanup rsa_private_key = { 0 };
+    switch (format)
+    {
+    case context_base::asn1:
+      rsa_private_key.p = ::d2i_RSAPrivateKey_bio(bio.p, 0);
+      break;
+    case context_base::pem:
+      rsa_private_key.p = ::PEM_read_bio_RSAPrivateKey(
+          bio.p, 0, callback,
+          cb_userdata);
+      break;
+    default:
+      {
+        ec = asio::error::invalid_argument;
+        ASIO_SYNC_OP_VOID_RETURN(ec);
+      }
+    }
+
+    if (rsa_private_key.p)
+    {
+      if (::SSL_CTX_use_RSAPrivateKey(handle_, rsa_private_key.p) == 1)
+      {
+        ec = asio::error_code();
+        ASIO_SYNC_OP_VOID_RETURN(ec);
+      }
+    }
+  }
+
+  ec = asio::error_code(
+      static_cast<int>(::ERR_get_error()),
+      asio::error::get_ssl_category());
+  ASIO_SYNC_OP_VOID_RETURN(ec);
+}
+
+ASIO_SYNC_OP_VOID context::use_private_key_file(
+    const std::string& filename, context::file_format format,
+    asio::error_code& ec)
+{
+  int file_type;
+  switch (format)
+  {
+  case context_base::asn1:
+    file_type = SSL_FILETYPE_ASN1;
+    break;
+  case context_base::pem:
+    file_type = SSL_FILETYPE_PEM;
+    break;
+  default:
+    {
+      ec = asio::error::invalid_argument;
+      ASIO_SYNC_OP_VOID_RETURN(ec);
+    }
+  }
+
+  ::ERR_clear_error();
+
+  if (::SSL_CTX_use_PrivateKey_file(handle_, filename.c_str(), file_type) != 1)
+  {
+    ec = asio::error_code(
+        static_cast<int>(::ERR_get_error()),
+        asio::error::get_ssl_category());
+    ASIO_SYNC_OP_VOID_RETURN(ec);
+  }
+
+  ec = asio::error_code();
+  ASIO_SYNC_OP_VOID_RETURN(ec);
+}
+
+void context::use_rsa_private_key_file(
+    const std::string& filename, context::file_format format)
+{
+  asio::error_code ec;
+  use_rsa_private_key_file(filename, format, ec);
+  asio::detail::throw_error(ec, "use_rsa_private_key_file");
+}
+
+ASIO_SYNC_OP_VOID context::use_rsa_private_key_file(
+    const std::string& filename, context::file_format format,
+    asio::error_code& ec)
+{
+  int file_type;
+  switch (format)
+  {
+  case context_base::asn1:
+    file_type = SSL_FILETYPE_ASN1;
+    break;
+  case context_base::pem:
+    file_type = SSL_FILETYPE_PEM;
+    break;
+  default:
+    {
+      ec = asio::error::invalid_argument;
+      ASIO_SYNC_OP_VOID_RETURN(ec);
+    }
+  }
+
+  ::ERR_clear_error();
+
+  if (::SSL_CTX_use_RSAPrivateKey_file(
+        handle_, filename.c_str(), file_type) != 1)
+  {
+    ec = asio::error_code(
+        static_cast<int>(::ERR_get_error()),
+        asio::error::get_ssl_category());
+    ASIO_SYNC_OP_VOID_RETURN(ec);
+  }
+
+  ec = asio::error_code();
+  ASIO_SYNC_OP_VOID_RETURN(ec);
+}
+
+void context::use_tmp_dh(const const_buffer& dh)
+{
+  asio::error_code ec;
+  use_tmp_dh(dh, ec);
+  asio::detail::throw_error(ec, "use_tmp_dh");
+}
+
+ASIO_SYNC_OP_VOID context::use_tmp_dh(
+    const const_buffer& dh, asio::error_code& ec)
+{
+  ::ERR_clear_error();
+
+  bio_cleanup bio = { make_buffer_bio(dh) };
+  if (bio.p)
+  {
+    return do_use_tmp_dh(bio.p, ec);
+  }
+
+  ec = asio::error_code(
+      static_cast<int>(::ERR_get_error()),
+      asio::error::get_ssl_category());
+  ASIO_SYNC_OP_VOID_RETURN(ec);
+}
+
+void context::use_tmp_dh_file(const std::string& filename)
+{
+  asio::error_code ec;
+  use_tmp_dh_file(filename, ec);
+  asio::detail::throw_error(ec, "use_tmp_dh_file");
+}
+
+ASIO_SYNC_OP_VOID context::use_tmp_dh_file(
+    const std::string& filename, asio::error_code& ec)
+{
+  ::ERR_clear_error();
+
+  bio_cleanup bio = { ::BIO_new_file(filename.c_str(), "r") };
+  if (bio.p)
+  {
+    return do_use_tmp_dh(bio.p, ec);
+  }
+
+  ec = asio::error_code(
+      static_cast<int>(::ERR_get_error()),
+      asio::error::get_ssl_category());
+  ASIO_SYNC_OP_VOID_RETURN(ec);
+}
+
+ASIO_SYNC_OP_VOID context::do_use_tmp_dh(
+    BIO* bio, asio::error_code& ec)
+{
+  ::ERR_clear_error();
+
+  dh_cleanup dh = { ::PEM_read_bio_DHparams(bio, 0, 0, 0) };
+  if (dh.p)
+  {
+    if (::SSL_CTX_set_tmp_dh(handle_, dh.p) == 1)
+    {
+      ec = asio::error_code();
+      ASIO_SYNC_OP_VOID_RETURN(ec);
+    }
+  }
+
+  ec = asio::error_code(
+      static_cast<int>(::ERR_get_error()),
+      asio::error::get_ssl_category());
+  ASIO_SYNC_OP_VOID_RETURN(ec);
+}
+
+ASIO_SYNC_OP_VOID context::do_set_verify_callback(
+    detail::verify_callback_base* callback, asio::error_code& ec)
+{
+  if (SSL_CTX_get_app_data(handle_))
+  {
+    delete static_cast<detail::verify_callback_base*>(
+        SSL_CTX_get_app_data(handle_));
+  }
+
+  SSL_CTX_set_app_data(handle_, callback);
+
+  ::SSL_CTX_set_verify(handle_,
+      ::SSL_CTX_get_verify_mode(handle_),
+      &context::verify_callback_function);
+
+  ec = asio::error_code();
+  ASIO_SYNC_OP_VOID_RETURN(ec);
+}
+
+int context::verify_callback_function(int preverified, X509_STORE_CTX* ctx)
+{
+  if (ctx)
+  {
+    if (SSL* ssl = static_cast<SSL*>(
+          ::X509_STORE_CTX_get_ex_data(
+            ctx, ::SSL_get_ex_data_X509_STORE_CTX_idx())))
+    {
+      if (SSL_CTX* handle = ::SSL_get_SSL_CTX(ssl))
+      {
+        if (SSL_CTX_get_app_data(handle))
+        {
+          detail::verify_callback_base* callback =
+            static_cast<detail::verify_callback_base*>(
+                SSL_CTX_get_app_data(handle));
+
+          verify_context verify_ctx(ctx);
+          return callback->call(preverified != 0, verify_ctx) ? 1 : 0;
+        }
+      }
+    }
+  }
+
+  return 0;
+}
+
+ASIO_SYNC_OP_VOID context::do_set_password_callback(
+    detail::password_callback_base* callback, asio::error_code& ec)
+{
+#if ((OPENSSL_VERSION_NUMBER >= 0x10100000L) \
+      && !defined(LIBRESSL_VERSION_NUMBER)) \
+    || defined(ASIO_USE_WOLFSSL)
+  void* old_callback = ::SSL_CTX_get_default_passwd_cb_userdata(handle_);
+  ::SSL_CTX_set_default_passwd_cb_userdata(handle_, callback);
+#else // (OPENSSL_VERSION_NUMBER >= 0x10100000L)
+  void* old_callback = handle_->default_passwd_callback_userdata;
+  handle_->default_passwd_callback_userdata = callback;
+#endif // (OPENSSL_VERSION_NUMBER >= 0x10100000L)
+
+  if (old_callback)
+    delete static_cast<detail::password_callback_base*>(
+        old_callback);
+
+  SSL_CTX_set_default_passwd_cb(handle_, &context::password_callback_function);
+
+  ec = asio::error_code();
+  ASIO_SYNC_OP_VOID_RETURN(ec);
+}
+
+int context::password_callback_function(
+    char* buf, int size, int purpose, void* data)
+{
+  using namespace std; // For strncat and strlen.
+
+  if (data)
+  {
+    detail::password_callback_base* callback =
+      static_cast<detail::password_callback_base*>(data);
+
+    std::string passwd = callback->call(static_cast<std::size_t>(size),
+        purpose ? context_base::for_writing : context_base::for_reading);
+
+#if defined(ASIO_HAS_SECURE_RTL)
+    strcpy_s(buf, size, passwd.c_str());
+#else // defined(ASIO_HAS_SECURE_RTL)
+    *buf = '\0';
+    if (size > 0)
+      strncat(buf, passwd.c_str(), size - 1);
+#endif // defined(ASIO_HAS_SECURE_RTL)
+
+    return static_cast<int>(strlen(buf));
+  }
+
+  return 0;
+}
+
+BIO* context::make_buffer_bio(const const_buffer& b)
+{
+  return ::BIO_new_mem_buf(
+      const_cast<void*>(b.data()),
+      static_cast<int>(b.size()));
+}
+
+} // namespace ssl
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_SSL_IMPL_CONTEXT_IPP
diff --git a/link/modules/asio-standalone/asio/include/asio/ssl/impl/error.ipp b/link/modules/asio-standalone/asio/include/asio/ssl/impl/error.ipp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/ssl/impl/error.ipp
@@ -0,0 +1,102 @@
+//
+// ssl/impl/error.ipp
+// ~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_SSL_IMPL_ERROR_IPP
+#define ASIO_SSL_IMPL_ERROR_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/ssl/error.hpp"
+#include "asio/ssl/detail/openssl_init.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace error {
+namespace detail {
+
+class ssl_category : public asio::error_category
+{
+public:
+  const char* name() const ASIO_ERROR_CATEGORY_NOEXCEPT
+  {
+    return "asio.ssl";
+  }
+
+  std::string message(int value) const
+  {
+    const char* s = ::ERR_reason_error_string(value);
+    return s ? s : "asio.ssl error";
+  }
+};
+
+} // namespace detail
+
+const asio::error_category& get_ssl_category()
+{
+  static detail::ssl_category instance;
+  return instance;
+}
+
+} // namespace error
+namespace ssl {
+namespace error {
+
+#if (OPENSSL_VERSION_NUMBER < 0x10100000L) && !defined(OPENSSL_IS_BORINGSSL)
+
+const asio::error_category& get_stream_category()
+{
+  return asio::error::get_ssl_category();
+}
+
+#else
+
+namespace detail {
+
+class stream_category : public asio::error_category
+{
+public:
+  const char* name() const ASIO_ERROR_CATEGORY_NOEXCEPT
+  {
+    return "asio.ssl.stream";
+  }
+
+  std::string message(int value) const
+  {
+    switch (value)
+    {
+    case stream_truncated: return "stream truncated";
+    case unspecified_system_error: return "unspecified system error";
+    case unexpected_result: return "unexpected result";
+    default: return "asio.ssl.stream error";
+    }
+  }
+};
+
+} // namespace detail
+
+const asio::error_category& get_stream_category()
+{
+  static detail::stream_category instance;
+  return instance;
+}
+
+#endif
+
+} // namespace error
+} // namespace ssl
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_SSL_IMPL_ERROR_IPP
diff --git a/link/modules/asio-standalone/asio/include/asio/ssl/impl/host_name_verification.ipp b/link/modules/asio-standalone/asio/include/asio/ssl/impl/host_name_verification.ipp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/ssl/impl/host_name_verification.ipp
@@ -0,0 +1,73 @@
+//
+// ssl/impl/host_name_verification.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_SSL_IMPL_HOST_NAME_VERIFICATION_IPP
+#define ASIO_SSL_IMPL_HOST_NAME_VERIFICATION_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#include <cctype>
+#include <cstring>
+#include "asio/ip/address.hpp"
+#include "asio/ssl/host_name_verification.hpp"
+#include "asio/ssl/detail/openssl_types.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace ssl {
+
+bool host_name_verification::operator()(
+    bool preverified, verify_context& ctx) const
+{
+  using namespace std; // For memcmp.
+
+  // Don't bother looking at certificates that have failed pre-verification.
+  if (!preverified)
+    return false;
+
+  // We're only interested in checking the certificate at the end of the chain.
+  int depth = X509_STORE_CTX_get_error_depth(ctx.native_handle());
+  if (depth > 0)
+    return true;
+
+  // Try converting the host name to an address. If it is an address then we
+  // need to look for an IP address in the certificate rather than a host name.
+  asio::error_code ec;
+  ip::address address = ip::make_address(host_, ec);
+  const bool is_address = !ec;
+  (void)address;
+
+  X509* cert = X509_STORE_CTX_get_current_cert(ctx.native_handle());
+
+  if (is_address)
+  {
+    return X509_check_ip_asc(cert, host_.c_str(), 0) == 1;
+  }
+  else
+  {
+    char* peername = 0;
+    const int result = X509_check_host(cert,
+        host_.c_str(), host_.size(), 0, &peername);
+    OPENSSL_free(peername);
+    return result == 1;
+  }
+}
+
+} // namespace ssl
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_SSL_IMPL_HOST_NAME_VERIFICATION_IPP
diff --git a/link/modules/asio-standalone/asio/include/asio/ssl/impl/rfc2818_verification.ipp b/link/modules/asio-standalone/asio/include/asio/ssl/impl/rfc2818_verification.ipp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/ssl/impl/rfc2818_verification.ipp
@@ -0,0 +1,164 @@
+//
+// ssl/impl/rfc2818_verification.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_SSL_IMPL_RFC2818_VERIFICATION_IPP
+#define ASIO_SSL_IMPL_RFC2818_VERIFICATION_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if !defined(ASIO_NO_DEPRECATED)
+
+#include <cctype>
+#include <cstring>
+#include "asio/ip/address.hpp"
+#include "asio/ssl/rfc2818_verification.hpp"
+#include "asio/ssl/detail/openssl_types.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace ssl {
+
+bool rfc2818_verification::operator()(
+    bool preverified, verify_context& ctx) const
+{
+  using namespace std; // For memcmp.
+
+  // Don't bother looking at certificates that have failed pre-verification.
+  if (!preverified)
+    return false;
+
+  // We're only interested in checking the certificate at the end of the chain.
+  int depth = X509_STORE_CTX_get_error_depth(ctx.native_handle());
+  if (depth > 0)
+    return true;
+
+  // Try converting the host name to an address. If it is an address then we
+  // need to look for an IP address in the certificate rather than a host name.
+  asio::error_code ec;
+  ip::address address = ip::make_address(host_, ec);
+  bool is_address = !ec;
+
+  X509* cert = X509_STORE_CTX_get_current_cert(ctx.native_handle());
+
+  // Go through the alternate names in the certificate looking for matching DNS
+  // or IP address entries.
+  GENERAL_NAMES* gens = static_cast<GENERAL_NAMES*>(
+      X509_get_ext_d2i(cert, NID_subject_alt_name, 0, 0));
+  for (int i = 0; i < sk_GENERAL_NAME_num(gens); ++i)
+  {
+    GENERAL_NAME* gen = sk_GENERAL_NAME_value(gens, i);
+    if (gen->type == GEN_DNS && !is_address)
+    {
+      ASN1_IA5STRING* domain = gen->d.dNSName;
+      if (domain->type == V_ASN1_IA5STRING && domain->data && domain->length)
+      {
+        const char* pattern = reinterpret_cast<const char*>(domain->data);
+        std::size_t pattern_length = domain->length;
+        if (match_pattern(pattern, pattern_length, host_.c_str()))
+        {
+          GENERAL_NAMES_free(gens);
+          return true;
+        }
+      }
+    }
+    else if (gen->type == GEN_IPADD && is_address)
+    {
+      ASN1_OCTET_STRING* ip_address = gen->d.iPAddress;
+      if (ip_address->type == V_ASN1_OCTET_STRING && ip_address->data)
+      {
+        if (address.is_v4() && ip_address->length == 4)
+        {
+          ip::address_v4::bytes_type bytes = address.to_v4().to_bytes();
+          if (memcmp(bytes.data(), ip_address->data, 4) == 0)
+          {
+            GENERAL_NAMES_free(gens);
+            return true;
+          }
+        }
+        else if (address.is_v6() && ip_address->length == 16)
+        {
+          ip::address_v6::bytes_type bytes = address.to_v6().to_bytes();
+          if (memcmp(bytes.data(), ip_address->data, 16) == 0)
+          {
+            GENERAL_NAMES_free(gens);
+            return true;
+          }
+        }
+      }
+    }
+  }
+  GENERAL_NAMES_free(gens);
+
+  // No match in the alternate names, so try the common names. We should only
+  // use the "most specific" common name, which is the last one in the list.
+  X509_NAME* name = X509_get_subject_name(cert);
+  int i = -1;
+  ASN1_STRING* common_name = 0;
+  while ((i = X509_NAME_get_index_by_NID(name, NID_commonName, i)) >= 0)
+  {
+    X509_NAME_ENTRY* name_entry = X509_NAME_get_entry(name, i);
+    common_name = X509_NAME_ENTRY_get_data(name_entry);
+  }
+  if (common_name && common_name->data && common_name->length)
+  {
+    const char* pattern = reinterpret_cast<const char*>(common_name->data);
+    std::size_t pattern_length = common_name->length;
+    if (match_pattern(pattern, pattern_length, host_.c_str()))
+      return true;
+  }
+
+  return false;
+}
+
+bool rfc2818_verification::match_pattern(const char* pattern,
+    std::size_t pattern_length, const char* host)
+{
+  using namespace std; // For tolower.
+
+  const char* p = pattern;
+  const char* p_end = p + pattern_length;
+  const char* h = host;
+
+  while (p != p_end && *h)
+  {
+    if (*p == '*')
+    {
+      ++p;
+      while (*h && *h != '.')
+        if (match_pattern(p, p_end - p, h++))
+          return true;
+    }
+    else if (tolower(*p) == tolower(*h))
+    {
+      ++p;
+      ++h;
+    }
+    else
+    {
+      return false;
+    }
+  }
+
+  return p == p_end && !*h;
+}
+
+} // namespace ssl
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // !defined(ASIO_NO_DEPRECATED)
+
+#endif // ASIO_SSL_IMPL_RFC2818_VERIFICATION_IPP
diff --git a/link/modules/asio-standalone/asio/include/asio/ssl/impl/src.hpp b/link/modules/asio-standalone/asio/include/asio/ssl/impl/src.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/ssl/impl/src.hpp
@@ -0,0 +1,29 @@
+//
+// impl/ssl/src.hpp
+// ~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_SSL_IMPL_SRC_HPP
+#define ASIO_SSL_IMPL_SRC_HPP
+
+#define ASIO_SOURCE
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HEADER_ONLY)
+# error Do not compile Asio library source with ASIO_HEADER_ONLY defined
+#endif
+
+#include "asio/ssl/impl/context.ipp"
+#include "asio/ssl/impl/error.ipp"
+#include "asio/ssl/detail/impl/engine.ipp"
+#include "asio/ssl/detail/impl/openssl_init.ipp"
+#include "asio/ssl/impl/host_name_verification.ipp"
+#include "asio/ssl/impl/rfc2818_verification.ipp"
+
+#endif // ASIO_SSL_IMPL_SRC_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/ssl/rfc2818_verification.hpp b/link/modules/asio-standalone/asio/include/asio/ssl/rfc2818_verification.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/ssl/rfc2818_verification.hpp
@@ -0,0 +1,98 @@
+//
+// ssl/rfc2818_verification.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_SSL_RFC2818_VERIFICATION_HPP
+#define ASIO_SSL_RFC2818_VERIFICATION_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if !defined(ASIO_NO_DEPRECATED)
+
+#include <string>
+#include "asio/ssl/detail/openssl_types.hpp"
+#include "asio/ssl/verify_context.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace ssl {
+
+/// (Deprecated. Use ssl::host_name_verification.) Verifies a certificate
+/// against a hostname according to the rules described in RFC 2818.
+/**
+ * @par Example
+ * The following example shows how to synchronously open a secure connection to
+ * a given host name:
+ * @code
+ * using asio::ip::tcp;
+ * namespace ssl = asio::ssl;
+ * typedef ssl::stream<tcp::socket> ssl_socket;
+ *
+ * // Create a context that uses the default paths for finding CA certificates.
+ * ssl::context ctx(ssl::context::sslv23);
+ * ctx.set_default_verify_paths();
+ *
+ * // Open a socket and connect it to the remote host.
+ * asio::io_context io_context;
+ * ssl_socket sock(io_context, ctx);
+ * tcp::resolver resolver(io_context);
+ * tcp::resolver::query query("host.name", "https");
+ * asio::connect(sock.lowest_layer(), resolver.resolve(query));
+ * sock.lowest_layer().set_option(tcp::no_delay(true));
+ *
+ * // Perform SSL handshake and verify the remote host's certificate.
+ * sock.set_verify_mode(ssl::verify_peer);
+ * sock.set_verify_callback(ssl::rfc2818_verification("host.name"));
+ * sock.handshake(ssl_socket::client);
+ *
+ * // ... read and write as normal ...
+ * @endcode
+ */
+class rfc2818_verification
+{
+public:
+  /// The type of the function object's result.
+  typedef bool result_type;
+
+  /// Constructor.
+  explicit rfc2818_verification(const std::string& host)
+    : host_(host)
+  {
+  }
+
+  /// Perform certificate verification.
+  ASIO_DECL bool operator()(bool preverified, verify_context& ctx) const;
+
+private:
+  // Helper function to check a host name against a pattern.
+  ASIO_DECL static bool match_pattern(const char* pattern,
+      std::size_t pattern_length, const char* host);
+
+  // Helper function to check a host name against an IPv4 address
+  // The host name to be checked.
+  std::string host_;
+};
+
+} // namespace ssl
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/ssl/impl/rfc2818_verification.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // !defined(ASIO_NO_DEPRECATED)
+
+#endif // ASIO_SSL_RFC2818_VERIFICATION_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/ssl/stream.hpp b/link/modules/asio-standalone/asio/include/asio/ssl/stream.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/ssl/stream.hpp
@@ -0,0 +1,900 @@
+//
+// ssl/stream.hpp
+// ~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_SSL_STREAM_HPP
+#define ASIO_SSL_STREAM_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#include "asio/async_result.hpp"
+#include "asio/detail/buffer_sequence_adapter.hpp"
+#include "asio/detail/handler_type_requirements.hpp"
+#include "asio/detail/non_const_lvalue.hpp"
+#include "asio/detail/noncopyable.hpp"
+#include "asio/detail/type_traits.hpp"
+#include "asio/ssl/context.hpp"
+#include "asio/ssl/detail/buffered_handshake_op.hpp"
+#include "asio/ssl/detail/handshake_op.hpp"
+#include "asio/ssl/detail/io.hpp"
+#include "asio/ssl/detail/read_op.hpp"
+#include "asio/ssl/detail/shutdown_op.hpp"
+#include "asio/ssl/detail/stream_core.hpp"
+#include "asio/ssl/detail/write_op.hpp"
+#include "asio/ssl/stream_base.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace ssl {
+
+/// Provides stream-oriented functionality using SSL.
+/**
+ * The stream class template provides asynchronous and blocking stream-oriented
+ * functionality using SSL.
+ *
+ * @par Thread Safety
+ * @e Distinct @e objects: Safe.@n
+ * @e Shared @e objects: Unsafe. The application must also ensure that all
+ * asynchronous operations are performed within the same implicit or explicit
+ * strand.
+ *
+ * @par Example
+ * To use the SSL stream template with an ip::tcp::socket, you would write:
+ * @code
+ * asio::io_context my_context;
+ * asio::ssl::context ctx(asio::ssl::context::sslv23);
+ * asio::ssl::stream<asio:ip::tcp::socket> sock(my_context, ctx);
+ * @endcode
+ *
+ * @par Concepts:
+ * AsyncReadStream, AsyncWriteStream, Stream, SyncReadStream, SyncWriteStream.
+ */
+template <typename Stream>
+class stream :
+  public stream_base,
+  private noncopyable
+{
+public:
+  /// The native handle type of the SSL stream.
+  typedef SSL* native_handle_type;
+
+  /// Structure for use with deprecated impl_type.
+  struct impl_struct
+  {
+    SSL* ssl;
+  };
+
+  /// The type of the next layer.
+  typedef typename remove_reference<Stream>::type next_layer_type;
+
+  /// The type of the lowest layer.
+  typedef typename next_layer_type::lowest_layer_type lowest_layer_type;
+
+  /// The type of the executor associated with the object.
+  typedef typename lowest_layer_type::executor_type executor_type;
+
+#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+  /// Construct a stream.
+  /**
+   * This constructor creates a stream and initialises the underlying stream
+   * object.
+   *
+   * @param arg The argument to be passed to initialise the underlying stream.
+   *
+   * @param ctx The SSL context to be used for the stream.
+   */
+  template <typename Arg>
+  stream(Arg&& arg, context& ctx)
+    : next_layer_(ASIO_MOVE_CAST(Arg)(arg)),
+      core_(ctx.native_handle(), next_layer_.lowest_layer().get_executor())
+  {
+  }
+#else // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+  template <typename Arg>
+  stream(Arg& arg, context& ctx)
+    : next_layer_(arg),
+      core_(ctx.native_handle(), next_layer_.lowest_layer().get_executor())
+  {
+  }
+#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+
+#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+  /// Move-construct a stream from another.
+  /**
+   * @param other The other stream object from which the move will occur. Must
+   * have no outstanding asynchronous operations associated with it. Following
+   * the move, @c other has a valid but unspecified state where the only safe
+   * operation is destruction.
+   */
+  stream(stream&& other)
+    : next_layer_(ASIO_MOVE_CAST(Stream)(other.next_layer_)),
+      core_(ASIO_MOVE_CAST(detail::stream_core)(other.core_))
+  {
+  }
+#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+
+  /// Destructor.
+  /**
+   * @note A @c stream object must not be destroyed while there are pending
+   * asynchronous operations associated with it.
+   */
+  ~stream()
+  {
+  }
+
+  /// Get the executor associated with the object.
+  /**
+   * This function may be used to obtain the executor object that the stream
+   * uses to dispatch handlers for asynchronous operations.
+   *
+   * @return A copy of the executor that stream will use to dispatch handlers.
+   */
+  executor_type get_executor() ASIO_NOEXCEPT
+  {
+    return next_layer_.lowest_layer().get_executor();
+  }
+
+  /// Get the underlying implementation in the native type.
+  /**
+   * This function may be used to obtain the underlying implementation of the
+   * context. This is intended to allow access to context functionality that is
+   * not otherwise provided.
+   *
+   * @par Example
+   * The native_handle() function returns a pointer of type @c SSL* that is
+   * suitable for passing to functions such as @c SSL_get_verify_result and
+   * @c SSL_get_peer_certificate:
+   * @code
+   * asio::ssl::stream<asio:ip::tcp::socket> sock(my_context, ctx);
+   *
+   * // ... establish connection and perform handshake ...
+   *
+   * if (X509* cert = SSL_get_peer_certificate(sock.native_handle()))
+   * {
+   *   if (SSL_get_verify_result(sock.native_handle()) == X509_V_OK)
+   *   {
+   *     // ...
+   *   }
+   * }
+   * @endcode
+   */
+  native_handle_type native_handle()
+  {
+    return core_.engine_.native_handle();
+  }
+
+  /// Get a reference to the next layer.
+  /**
+   * This function returns a reference to the next layer in a stack of stream
+   * layers.
+   *
+   * @return A reference to the next layer in the stack of stream layers.
+   * Ownership is not transferred to the caller.
+   */
+  const next_layer_type& next_layer() const
+  {
+    return next_layer_;
+  }
+
+  /// Get a reference to the next layer.
+  /**
+   * This function returns a reference to the next layer in a stack of stream
+   * layers.
+   *
+   * @return A reference to the next layer in the stack of stream layers.
+   * Ownership is not transferred to the caller.
+   */
+  next_layer_type& next_layer()
+  {
+    return next_layer_;
+  }
+
+  /// Get a reference to the lowest layer.
+  /**
+   * This function returns a reference to the lowest layer in a stack of
+   * stream layers.
+   *
+   * @return A reference to the lowest layer in the stack of stream layers.
+   * Ownership is not transferred to the caller.
+   */
+  lowest_layer_type& lowest_layer()
+  {
+    return next_layer_.lowest_layer();
+  }
+
+  /// Get a reference to the lowest layer.
+  /**
+   * This function returns a reference to the lowest layer in a stack of
+   * stream layers.
+   *
+   * @return A reference to the lowest layer in the stack of stream layers.
+   * Ownership is not transferred to the caller.
+   */
+  const lowest_layer_type& lowest_layer() const
+  {
+    return next_layer_.lowest_layer();
+  }
+
+  /// Set the peer verification mode.
+  /**
+   * This function may be used to configure the peer verification mode used by
+   * the stream. The new mode will override the mode inherited from the context.
+   *
+   * @param v A bitmask of peer verification modes. See @ref verify_mode for
+   * available values.
+   *
+   * @throws asio::system_error Thrown on failure.
+   *
+   * @note Calls @c SSL_set_verify.
+   */
+  void set_verify_mode(verify_mode v)
+  {
+    asio::error_code ec;
+    set_verify_mode(v, ec);
+    asio::detail::throw_error(ec, "set_verify_mode");
+  }
+
+  /// Set the peer verification mode.
+  /**
+   * This function may be used to configure the peer verification mode used by
+   * the stream. The new mode will override the mode inherited from the context.
+   *
+   * @param v A bitmask of peer verification modes. See @ref verify_mode for
+   * available values.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   *
+   * @note Calls @c SSL_set_verify.
+   */
+  ASIO_SYNC_OP_VOID set_verify_mode(
+      verify_mode v, asio::error_code& ec)
+  {
+    core_.engine_.set_verify_mode(v, ec);
+    ASIO_SYNC_OP_VOID_RETURN(ec);
+  }
+
+  /// Set the peer verification depth.
+  /**
+   * This function may be used to configure the maximum verification depth
+   * allowed by the stream.
+   *
+   * @param depth Maximum depth for the certificate chain verification that
+   * shall be allowed.
+   *
+   * @throws asio::system_error Thrown on failure.
+   *
+   * @note Calls @c SSL_set_verify_depth.
+   */
+  void set_verify_depth(int depth)
+  {
+    asio::error_code ec;
+    set_verify_depth(depth, ec);
+    asio::detail::throw_error(ec, "set_verify_depth");
+  }
+
+  /// Set the peer verification depth.
+  /**
+   * This function may be used to configure the maximum verification depth
+   * allowed by the stream.
+   *
+   * @param depth Maximum depth for the certificate chain verification that
+   * shall be allowed.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   *
+   * @note Calls @c SSL_set_verify_depth.
+   */
+  ASIO_SYNC_OP_VOID set_verify_depth(
+      int depth, asio::error_code& ec)
+  {
+    core_.engine_.set_verify_depth(depth, ec);
+    ASIO_SYNC_OP_VOID_RETURN(ec);
+  }
+
+  /// Set the callback used to verify peer certificates.
+  /**
+   * This function is used to specify a callback function that will be called
+   * by the implementation when it needs to verify a peer certificate.
+   *
+   * @param callback The function object to be used for verifying a certificate.
+   * The function signature of the handler must be:
+   * @code bool verify_callback(
+   *   bool preverified, // True if the certificate passed pre-verification.
+   *   verify_context& ctx // The peer certificate and other context.
+   * ); @endcode
+   * The return value of the callback is true if the certificate has passed
+   * verification, false otherwise.
+   *
+   * @throws asio::system_error Thrown on failure.
+   *
+   * @note Calls @c SSL_set_verify.
+   */
+  template <typename VerifyCallback>
+  void set_verify_callback(VerifyCallback callback)
+  {
+    asio::error_code ec;
+    this->set_verify_callback(callback, ec);
+    asio::detail::throw_error(ec, "set_verify_callback");
+  }
+
+  /// Set the callback used to verify peer certificates.
+  /**
+   * This function is used to specify a callback function that will be called
+   * by the implementation when it needs to verify a peer certificate.
+   *
+   * @param callback The function object to be used for verifying a certificate.
+   * The function signature of the handler must be:
+   * @code bool verify_callback(
+   *   bool preverified, // True if the certificate passed pre-verification.
+   *   verify_context& ctx // The peer certificate and other context.
+   * ); @endcode
+   * The return value of the callback is true if the certificate has passed
+   * verification, false otherwise.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   *
+   * @note Calls @c SSL_set_verify.
+   */
+  template <typename VerifyCallback>
+  ASIO_SYNC_OP_VOID set_verify_callback(VerifyCallback callback,
+      asio::error_code& ec)
+  {
+    core_.engine_.set_verify_callback(
+        new detail::verify_callback<VerifyCallback>(callback), ec);
+    ASIO_SYNC_OP_VOID_RETURN(ec);
+  }
+
+  /// Perform SSL handshaking.
+  /**
+   * This function is used to perform SSL handshaking on the stream. The
+   * function call will block until handshaking is complete or an error occurs.
+   *
+   * @param type The type of handshaking to be performed, i.e. as a client or as
+   * a server.
+   *
+   * @throws asio::system_error Thrown on failure.
+   */
+  void handshake(handshake_type type)
+  {
+    asio::error_code ec;
+    handshake(type, ec);
+    asio::detail::throw_error(ec, "handshake");
+  }
+
+  /// Perform SSL handshaking.
+  /**
+   * This function is used to perform SSL handshaking on the stream. The
+   * function call will block until handshaking is complete or an error occurs.
+   *
+   * @param type The type of handshaking to be performed, i.e. as a client or as
+   * a server.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   */
+  ASIO_SYNC_OP_VOID handshake(handshake_type type,
+      asio::error_code& ec)
+  {
+    detail::io(next_layer_, core_, detail::handshake_op(type), ec);
+    ASIO_SYNC_OP_VOID_RETURN(ec);
+  }
+
+  /// Perform SSL handshaking.
+  /**
+   * This function is used to perform SSL handshaking on the stream. The
+   * function call will block until handshaking is complete or an error occurs.
+   *
+   * @param type The type of handshaking to be performed, i.e. as a client or as
+   * a server.
+   *
+   * @param buffers The buffered data to be reused for the handshake.
+   *
+   * @throws asio::system_error Thrown on failure.
+   */
+  template <typename ConstBufferSequence>
+  void handshake(handshake_type type, const ConstBufferSequence& buffers)
+  {
+    asio::error_code ec;
+    handshake(type, buffers, ec);
+    asio::detail::throw_error(ec, "handshake");
+  }
+
+  /// Perform SSL handshaking.
+  /**
+   * This function is used to perform SSL handshaking on the stream. The
+   * function call will block until handshaking is complete or an error occurs.
+   *
+   * @param type The type of handshaking to be performed, i.e. as a client or as
+   * a server.
+   *
+   * @param buffers The buffered data to be reused for the handshake.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   */
+  template <typename ConstBufferSequence>
+  ASIO_SYNC_OP_VOID handshake(handshake_type type,
+      const ConstBufferSequence& buffers, asio::error_code& ec)
+  {
+    detail::io(next_layer_, core_,
+        detail::buffered_handshake_op<ConstBufferSequence>(type, buffers), ec);
+    ASIO_SYNC_OP_VOID_RETURN(ec);
+  }
+
+  /// Start an asynchronous SSL handshake.
+  /**
+   * This function is used to asynchronously perform an SSL handshake on the
+   * stream. This function call always returns immediately.
+   *
+   * @param type The type of handshaking to be performed, i.e. as a client or as
+   * a server.
+   *
+   * @param handler The handler to be called when the handshake operation
+   * completes. Copies will be made of the handler as required. The equivalent
+   * function signature of the handler must be:
+   * @code void handler(
+   *   const asio::error_code& error // Result of operation.
+   * ); @endcode
+   */
+  template <
+      ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code))
+        HandshakeHandler
+          ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
+  ASIO_INITFN_AUTO_RESULT_TYPE(HandshakeHandler,
+      void (asio::error_code))
+  async_handshake(handshake_type type,
+      ASIO_MOVE_ARG(HandshakeHandler) handler
+        ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
+  {
+    return async_initiate<HandshakeHandler,
+      void (asio::error_code)>(
+        initiate_async_handshake(this), handler, type);
+  }
+
+  /// Start an asynchronous SSL handshake.
+  /**
+   * This function is used to asynchronously perform an SSL handshake on the
+   * stream. This function call always returns immediately.
+   *
+   * @param type The type of handshaking to be performed, i.e. as a client or as
+   * a server.
+   *
+   * @param buffers The buffered data to be reused for the handshake. Although
+   * the buffers object may be copied as necessary, ownership of the underlying
+   * buffers is retained by the caller, which must guarantee that they remain
+   * valid until the handler is called.
+   *
+   * @param handler The handler to be called when the handshake operation
+   * completes. Copies will be made of the handler as required. The equivalent
+   * function signature of the handler must be:
+   * @code void handler(
+   *   const asio::error_code& error, // Result of operation.
+   *   std::size_t bytes_transferred // Amount of buffers used in handshake.
+   * ); @endcode
+   */
+  template <typename ConstBufferSequence,
+      ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+        std::size_t)) BufferedHandshakeHandler
+          ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
+  ASIO_INITFN_AUTO_RESULT_TYPE(BufferedHandshakeHandler,
+      void (asio::error_code, std::size_t))
+  async_handshake(handshake_type type, const ConstBufferSequence& buffers,
+      ASIO_MOVE_ARG(BufferedHandshakeHandler) handler
+        ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
+  {
+    return async_initiate<BufferedHandshakeHandler,
+      void (asio::error_code, std::size_t)>(
+        initiate_async_buffered_handshake(this), handler, type, buffers);
+  }
+
+  /// Shut down SSL on the stream.
+  /**
+   * This function is used to shut down SSL on the stream. The function call
+   * will block until SSL has been shut down or an error occurs.
+   *
+   * @throws asio::system_error Thrown on failure.
+   */
+  void shutdown()
+  {
+    asio::error_code ec;
+    shutdown(ec);
+    asio::detail::throw_error(ec, "shutdown");
+  }
+
+  /// Shut down SSL on the stream.
+  /**
+   * This function is used to shut down SSL on the stream. The function call
+   * will block until SSL has been shut down or an error occurs.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   */
+  ASIO_SYNC_OP_VOID shutdown(asio::error_code& ec)
+  {
+    detail::io(next_layer_, core_, detail::shutdown_op(), ec);
+    ASIO_SYNC_OP_VOID_RETURN(ec);
+  }
+
+  /// Asynchronously shut down SSL on the stream.
+  /**
+   * This function is used to asynchronously shut down SSL on the stream. This
+   * function call always returns immediately.
+   *
+   * @param handler The handler to be called when the handshake operation
+   * completes. Copies will be made of the handler as required. The equivalent
+   * function signature of the handler must be:
+   * @code void handler(
+   *   const asio::error_code& error // Result of operation.
+   * ); @endcode
+   */
+  template <
+      ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code))
+        ShutdownHandler
+          ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
+  ASIO_INITFN_AUTO_RESULT_TYPE(ShutdownHandler,
+      void (asio::error_code))
+  async_shutdown(
+      ASIO_MOVE_ARG(ShutdownHandler) handler
+        ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
+  {
+    return async_initiate<ShutdownHandler,
+      void (asio::error_code)>(
+        initiate_async_shutdown(this), handler);
+  }
+
+  /// Write some data to the stream.
+  /**
+   * This function is used to write data on the stream. The function call will
+   * block until one or more bytes of data has been written successfully, or
+   * until an error occurs.
+   *
+   * @param buffers The data to be written.
+   *
+   * @returns The number of bytes written.
+   *
+   * @throws asio::system_error Thrown on failure.
+   *
+   * @note The write_some operation may not transmit all of the data to the
+   * peer. Consider using the @ref write function if you need to ensure that all
+   * data is written before the blocking operation completes.
+   */
+  template <typename ConstBufferSequence>
+  std::size_t write_some(const ConstBufferSequence& buffers)
+  {
+    asio::error_code ec;
+    std::size_t n = write_some(buffers, ec);
+    asio::detail::throw_error(ec, "write_some");
+    return n;
+  }
+
+  /// Write some data to the stream.
+  /**
+   * This function is used to write data on the stream. The function call will
+   * block until one or more bytes of data has been written successfully, or
+   * until an error occurs.
+   *
+   * @param buffers The data to be written to the stream.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   *
+   * @returns The number of bytes written. Returns 0 if an error occurred.
+   *
+   * @note The write_some operation may not transmit all of the data to the
+   * peer. Consider using the @ref write function if you need to ensure that all
+   * data is written before the blocking operation completes.
+   */
+  template <typename ConstBufferSequence>
+  std::size_t write_some(const ConstBufferSequence& buffers,
+      asio::error_code& ec)
+  {
+    return detail::io(next_layer_, core_,
+        detail::write_op<ConstBufferSequence>(buffers), ec);
+  }
+
+  /// Start an asynchronous write.
+  /**
+   * This function is used to asynchronously write one or more bytes of data to
+   * the stream. The function call always returns immediately.
+   *
+   * @param buffers The data to be written to the stream. Although the buffers
+   * object may be copied as necessary, ownership of the underlying buffers is
+   * retained by the caller, which must guarantee that they remain valid until
+   * the handler is called.
+   *
+   * @param handler The handler to be called when the write operation completes.
+   * Copies will be made of the handler as required. The equivalent function
+   * signature of the handler must be:
+   * @code void handler(
+   *   const asio::error_code& error, // Result of operation.
+   *   std::size_t bytes_transferred           // Number of bytes written.
+   * ); @endcode
+   *
+   * @note The async_write_some operation may not transmit all of the data to
+   * the peer. Consider using the @ref async_write function if you need to
+   * ensure that all data is written before the asynchronous operation
+   * completes.
+   */
+  template <typename ConstBufferSequence,
+      ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+        std::size_t)) WriteHandler
+          ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
+  ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,
+      void (asio::error_code, std::size_t))
+  async_write_some(const ConstBufferSequence& buffers,
+      ASIO_MOVE_ARG(WriteHandler) handler
+        ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
+  {
+    return async_initiate<WriteHandler,
+      void (asio::error_code, std::size_t)>(
+        initiate_async_write_some(this), handler, buffers);
+  }
+
+  /// Read some data from the stream.
+  /**
+   * This function is used to read data from the stream. The function call will
+   * block until one or more bytes of data has been read successfully, or until
+   * an error occurs.
+   *
+   * @param buffers The buffers into which the data will be read.
+   *
+   * @returns The number of bytes read.
+   *
+   * @throws asio::system_error Thrown on failure.
+   *
+   * @note The read_some operation may not read all of the requested number of
+   * bytes. Consider using the @ref read function if you need to ensure that the
+   * requested amount of data is read before the blocking operation completes.
+   */
+  template <typename MutableBufferSequence>
+  std::size_t read_some(const MutableBufferSequence& buffers)
+  {
+    asio::error_code ec;
+    std::size_t n = read_some(buffers, ec);
+    asio::detail::throw_error(ec, "read_some");
+    return n;
+  }
+
+  /// Read some data from the stream.
+  /**
+   * This function is used to read data from the stream. The function call will
+   * block until one or more bytes of data has been read successfully, or until
+   * an error occurs.
+   *
+   * @param buffers The buffers into which the data will be read.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   *
+   * @returns The number of bytes read. Returns 0 if an error occurred.
+   *
+   * @note The read_some operation may not read all of the requested number of
+   * bytes. Consider using the @ref read function if you need to ensure that the
+   * requested amount of data is read before the blocking operation completes.
+   */
+  template <typename MutableBufferSequence>
+  std::size_t read_some(const MutableBufferSequence& buffers,
+      asio::error_code& ec)
+  {
+    return detail::io(next_layer_, core_,
+        detail::read_op<MutableBufferSequence>(buffers), ec);
+  }
+
+  /// Start an asynchronous read.
+  /**
+   * This function is used to asynchronously read one or more bytes of data from
+   * the stream. The function call always returns immediately.
+   *
+   * @param buffers The buffers into which the data will be read. Although the
+   * buffers object may be copied as necessary, ownership of the underlying
+   * buffers is retained by the caller, which must guarantee that they remain
+   * valid until the handler is called.
+   *
+   * @param handler The handler to be called when the read operation completes.
+   * Copies will be made of the handler as required. The equivalent function
+   * signature of the handler must be:
+   * @code void handler(
+   *   const asio::error_code& error, // Result of operation.
+   *   std::size_t bytes_transferred           // Number of bytes read.
+   * ); @endcode
+   *
+   * @note The async_read_some operation may not read all of the requested
+   * number of bytes. Consider using the @ref async_read function if you need to
+   * ensure that the requested amount of data is read before the asynchronous
+   * operation completes.
+   */
+  template <typename MutableBufferSequence,
+      ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+        std::size_t)) ReadHandler
+          ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
+  ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,
+      void (asio::error_code, std::size_t))
+  async_read_some(const MutableBufferSequence& buffers,
+      ASIO_MOVE_ARG(ReadHandler) handler
+        ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
+  {
+    return async_initiate<ReadHandler,
+      void (asio::error_code, std::size_t)>(
+        initiate_async_read_some(this), handler, buffers);
+  }
+
+private:
+  class initiate_async_handshake
+  {
+  public:
+    typedef typename stream::executor_type executor_type;
+
+    explicit initiate_async_handshake(stream* self)
+      : self_(self)
+    {
+    }
+
+    executor_type get_executor() const ASIO_NOEXCEPT
+    {
+      return self_->get_executor();
+    }
+
+    template <typename HandshakeHandler>
+    void operator()(ASIO_MOVE_ARG(HandshakeHandler) handler,
+        handshake_type type) const
+    {
+      // If you get an error on the following line it means that your handler
+      // does not meet the documented type requirements for a HandshakeHandler.
+      ASIO_HANDSHAKE_HANDLER_CHECK(HandshakeHandler, handler) type_check;
+
+      asio::detail::non_const_lvalue<HandshakeHandler> handler2(handler);
+      detail::async_io(self_->next_layer_, self_->core_,
+          detail::handshake_op(type), handler2.value);
+    }
+
+  private:
+    stream* self_;
+  };
+
+  class initiate_async_buffered_handshake
+  {
+  public:
+    typedef typename stream::executor_type executor_type;
+
+    explicit initiate_async_buffered_handshake(stream* self)
+      : self_(self)
+    {
+    }
+
+    executor_type get_executor() const ASIO_NOEXCEPT
+    {
+      return self_->get_executor();
+    }
+
+    template <typename BufferedHandshakeHandler, typename ConstBufferSequence>
+    void operator()(ASIO_MOVE_ARG(BufferedHandshakeHandler) handler,
+        handshake_type type, const ConstBufferSequence& buffers) const
+    {
+      // If you get an error on the following line it means that your
+      // handler does not meet the documented type requirements for a
+      // BufferedHandshakeHandler.
+      ASIO_BUFFERED_HANDSHAKE_HANDLER_CHECK(
+          BufferedHandshakeHandler, handler) type_check;
+
+      asio::detail::non_const_lvalue<
+          BufferedHandshakeHandler> handler2(handler);
+      detail::async_io(self_->next_layer_, self_->core_,
+          detail::buffered_handshake_op<ConstBufferSequence>(type, buffers),
+          handler2.value);
+    }
+
+  private:
+    stream* self_;
+  };
+
+  class initiate_async_shutdown
+  {
+  public:
+    typedef typename stream::executor_type executor_type;
+
+    explicit initiate_async_shutdown(stream* self)
+      : self_(self)
+    {
+    }
+
+    executor_type get_executor() const ASIO_NOEXCEPT
+    {
+      return self_->get_executor();
+    }
+
+    template <typename ShutdownHandler>
+    void operator()(ASIO_MOVE_ARG(ShutdownHandler) handler) const
+    {
+      // If you get an error on the following line it means that your handler
+      // does not meet the documented type requirements for a ShutdownHandler.
+      ASIO_HANDSHAKE_HANDLER_CHECK(ShutdownHandler, handler) type_check;
+
+      asio::detail::non_const_lvalue<ShutdownHandler> handler2(handler);
+      detail::async_io(self_->next_layer_, self_->core_,
+          detail::shutdown_op(), handler2.value);
+    }
+
+  private:
+    stream* self_;
+  };
+
+  class initiate_async_write_some
+  {
+  public:
+    typedef typename stream::executor_type executor_type;
+
+    explicit initiate_async_write_some(stream* self)
+      : self_(self)
+    {
+    }
+
+    executor_type get_executor() const ASIO_NOEXCEPT
+    {
+      return self_->get_executor();
+    }
+
+    template <typename WriteHandler, typename ConstBufferSequence>
+    void operator()(ASIO_MOVE_ARG(WriteHandler) handler,
+        const ConstBufferSequence& buffers) const
+    {
+      // If you get an error on the following line it means that your handler
+      // does not meet the documented type requirements for a WriteHandler.
+      ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check;
+
+      asio::detail::non_const_lvalue<WriteHandler> handler2(handler);
+      detail::async_io(self_->next_layer_, self_->core_,
+          detail::write_op<ConstBufferSequence>(buffers), handler2.value);
+    }
+
+  private:
+    stream* self_;
+  };
+
+  class initiate_async_read_some
+  {
+  public:
+    typedef typename stream::executor_type executor_type;
+
+    explicit initiate_async_read_some(stream* self)
+      : self_(self)
+    {
+    }
+
+    executor_type get_executor() const ASIO_NOEXCEPT
+    {
+      return self_->get_executor();
+    }
+
+    template <typename ReadHandler, typename MutableBufferSequence>
+    void operator()(ASIO_MOVE_ARG(ReadHandler) handler,
+        const MutableBufferSequence& buffers) const
+    {
+      // If you get an error on the following line it means that your handler
+      // does not meet the documented type requirements for a ReadHandler.
+      ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
+
+      asio::detail::non_const_lvalue<ReadHandler> handler2(handler);
+      detail::async_io(self_->next_layer_, self_->core_,
+          detail::read_op<MutableBufferSequence>(buffers), handler2.value);
+    }
+
+  private:
+    stream* self_;
+  };
+
+  Stream next_layer_;
+  detail::stream_core core_;
+};
+
+} // namespace ssl
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_SSL_STREAM_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/ssl/stream_base.hpp b/link/modules/asio-standalone/asio/include/asio/ssl/stream_base.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/ssl/stream_base.hpp
@@ -0,0 +1,52 @@
+//
+// ssl/stream_base.hpp
+// ~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_SSL_STREAM_BASE_HPP
+#define ASIO_SSL_STREAM_BASE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace ssl {
+
+/// The stream_base class is used as a base for the asio::ssl::stream
+/// class template so that we have a common place to define various enums.
+class stream_base
+{
+public:
+  /// Different handshake types.
+  enum handshake_type
+  {
+    /// Perform handshaking as a client.
+    client,
+
+    /// Perform handshaking as a server.
+    server
+  };
+
+protected:
+  /// Protected destructor to prevent deletion through this type.
+  ~stream_base()
+  {
+  }
+};
+
+} // namespace ssl
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_SSL_STREAM_BASE_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/ssl/verify_context.hpp b/link/modules/asio-standalone/asio/include/asio/ssl/verify_context.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/ssl/verify_context.hpp
@@ -0,0 +1,67 @@
+//
+// ssl/verify_context.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_SSL_VERIFY_CONTEXT_HPP
+#define ASIO_SSL_VERIFY_CONTEXT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#include "asio/detail/noncopyable.hpp"
+#include "asio/ssl/detail/openssl_types.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace ssl {
+
+/// A simple wrapper around the X509_STORE_CTX type, used during verification of
+/// a peer certificate.
+/**
+ * @note The verify_context does not own the underlying X509_STORE_CTX object.
+ */
+class verify_context
+  : private noncopyable
+{
+public:
+  /// The native handle type of the verification context.
+  typedef X509_STORE_CTX* native_handle_type;
+
+  /// Constructor.
+  explicit verify_context(native_handle_type handle)
+    : handle_(handle)
+  {
+  }
+
+  /// Get the underlying implementation in the native type.
+  /**
+   * This function may be used to obtain the underlying implementation of the
+   * context. This is intended to allow access to context functionality that is
+   * not otherwise provided.
+   */
+  native_handle_type native_handle()
+  {
+    return handle_;
+  }
+
+private:
+  // The underlying native implementation.
+  native_handle_type handle_;
+};
+
+} // namespace ssl
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_SSL_VERIFY_CONTEXT_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/ssl/verify_mode.hpp b/link/modules/asio-standalone/asio/include/asio/ssl/verify_mode.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/ssl/verify_mode.hpp
@@ -0,0 +1,63 @@
+//
+// ssl/verify_mode.hpp
+// ~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_SSL_VERIFY_MODE_HPP
+#define ASIO_SSL_VERIFY_MODE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/ssl/detail/openssl_types.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace ssl {
+
+/// Bitmask type for peer verification.
+/**
+ * Possible values are:
+ *
+ * @li @ref verify_none
+ * @li @ref verify_peer
+ * @li @ref verify_fail_if_no_peer_cert
+ * @li @ref verify_client_once
+ */
+typedef int verify_mode;
+
+#if defined(GENERATING_DOCUMENTATION)
+/// No verification.
+const int verify_none = implementation_defined;
+
+/// Verify the peer.
+const int verify_peer = implementation_defined;
+
+/// Fail verification if the peer has no certificate. Ignored unless
+/// @ref verify_peer is set.
+const int verify_fail_if_no_peer_cert = implementation_defined;
+
+/// Do not request client certificate on renegotiation. Ignored unless
+/// @ref verify_peer is set.
+const int verify_client_once = implementation_defined;
+#else
+const int verify_none = SSL_VERIFY_NONE;
+const int verify_peer = SSL_VERIFY_PEER;
+const int verify_fail_if_no_peer_cert = SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
+const int verify_client_once = SSL_VERIFY_CLIENT_ONCE;
+#endif
+
+} // namespace ssl
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_SSL_VERIFY_MODE_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/static_thread_pool.hpp b/link/modules/asio-standalone/asio/include/asio/static_thread_pool.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/static_thread_pool.hpp
@@ -0,0 +1,31 @@
+//
+// static_thread_pool.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_STATIC_THREAD_POOL_HPP
+#define ASIO_STATIC_THREAD_POOL_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/thread_pool.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+typedef thread_pool static_thread_pool;
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_STATIC_THREAD_POOL_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/steady_timer.hpp b/link/modules/asio-standalone/asio/include/asio/steady_timer.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/steady_timer.hpp
@@ -0,0 +1,42 @@
+//
+// steady_timer.hpp
+// ~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_STEADY_TIMER_HPP
+#define ASIO_STEADY_TIMER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_CHRONO) || defined(GENERATING_DOCUMENTATION)
+
+#include "asio/basic_waitable_timer.hpp"
+#include "asio/detail/chrono.hpp"
+
+namespace asio {
+
+/// Typedef for a timer based on the steady clock.
+/**
+ * This typedef uses the C++11 @c &lt;chrono&gt; standard library facility, if
+ * available. Otherwise, it may use the Boost.Chrono library. To explicitly
+ * utilise Boost.Chrono, use the basic_waitable_timer template directly:
+ * @code
+ * typedef basic_waitable_timer<boost::chrono::steady_clock> timer;
+ * @endcode
+ */
+typedef basic_waitable_timer<chrono::steady_clock> steady_timer;
+
+} // namespace asio
+
+#endif // defined(ASIO_HAS_CHRONO) || defined(GENERATING_DOCUMENTATION)
+
+#endif // ASIO_STEADY_TIMER_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/strand.hpp b/link/modules/asio-standalone/asio/include/asio/strand.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/strand.hpp
@@ -0,0 +1,537 @@
+//
+// strand.hpp
+// ~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_STRAND_HPP
+#define ASIO_STRAND_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/strand_executor_service.hpp"
+#include "asio/detail/type_traits.hpp"
+#include "asio/execution/executor.hpp"
+#include "asio/is_executor.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+/// Provides serialised function invocation for any executor type.
+template <typename Executor>
+class strand
+{
+public:
+  /// The type of the underlying executor.
+  typedef Executor inner_executor_type;
+
+  /// Default constructor.
+  /**
+   * This constructor is only valid if the underlying executor type is default
+   * constructible.
+   */
+  strand()
+    : executor_(),
+      impl_(strand::create_implementation(executor_))
+  {
+  }
+
+  /// Construct a strand for the specified executor.
+  template <typename Executor1>
+  explicit strand(const Executor1& e,
+      typename enable_if<
+        conditional<
+          !is_same<Executor1, strand>::value,
+          is_convertible<Executor1, Executor>,
+          false_type
+        >::type::value
+      >::type* = 0)
+    : executor_(e),
+      impl_(strand::create_implementation(executor_))
+  {
+  }
+
+  /// Copy constructor.
+  strand(const strand& other) ASIO_NOEXCEPT
+    : executor_(other.executor_),
+      impl_(other.impl_)
+  {
+  }
+
+  /// Converting constructor.
+  /**
+   * This constructor is only valid if the @c OtherExecutor type is convertible
+   * to @c Executor.
+   */
+  template <class OtherExecutor>
+  strand(
+      const strand<OtherExecutor>& other) ASIO_NOEXCEPT
+    : executor_(other.executor_),
+      impl_(other.impl_)
+  {
+  }
+
+  /// Assignment operator.
+  strand& operator=(const strand& other) ASIO_NOEXCEPT
+  {
+    executor_ = other.executor_;
+    impl_ = other.impl_;
+    return *this;
+  }
+
+  /// Converting assignment operator.
+  /**
+   * This assignment operator is only valid if the @c OtherExecutor type is
+   * convertible to @c Executor.
+   */
+  template <class OtherExecutor>
+  strand& operator=(
+      const strand<OtherExecutor>& other) ASIO_NOEXCEPT
+  {
+    executor_ = other.executor_;
+    impl_ = other.impl_;
+    return *this;
+  }
+
+#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+  /// Move constructor.
+  strand(strand&& other) ASIO_NOEXCEPT
+    : executor_(ASIO_MOVE_CAST(Executor)(other.executor_)),
+      impl_(ASIO_MOVE_CAST(implementation_type)(other.impl_))
+  {
+  }
+
+  /// Converting move constructor.
+  /**
+   * This constructor is only valid if the @c OtherExecutor type is convertible
+   * to @c Executor.
+   */
+  template <class OtherExecutor>
+  strand(strand<OtherExecutor>&& other) ASIO_NOEXCEPT
+    : executor_(ASIO_MOVE_CAST(OtherExecutor)(other.executor_)),
+      impl_(ASIO_MOVE_CAST(implementation_type)(other.impl_))
+  {
+  }
+
+  /// Move assignment operator.
+  strand& operator=(strand&& other) ASIO_NOEXCEPT
+  {
+    executor_ = ASIO_MOVE_CAST(Executor)(other.executor_);
+    impl_ = ASIO_MOVE_CAST(implementation_type)(other.impl_);
+    return *this;
+  }
+
+  /// Converting move assignment operator.
+  /**
+   * This assignment operator is only valid if the @c OtherExecutor type is
+   * convertible to @c Executor.
+   */
+  template <class OtherExecutor>
+  strand& operator=(strand<OtherExecutor>&& other) ASIO_NOEXCEPT
+  {
+    executor_ = ASIO_MOVE_CAST(OtherExecutor)(other.executor_);
+    impl_ = ASIO_MOVE_CAST(implementation_type)(other.impl_);
+    return *this;
+  }
+#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+
+  /// Destructor.
+  ~strand() ASIO_NOEXCEPT
+  {
+  }
+
+  /// Obtain the underlying executor.
+  inner_executor_type get_inner_executor() const ASIO_NOEXCEPT
+  {
+    return executor_;
+  }
+
+  /// Forward a query to the underlying executor.
+  /**
+   * Do not call this function directly. It is intended for use with the
+   * execution::execute customisation point.
+   *
+   * For example:
+   * @code asio::strand<my_executor_type> ex = ...;
+   * if (asio::query(ex, asio::execution::blocking)
+   *       == asio::execution::blocking.never)
+   *   ... @endcode
+   */
+  template <typename Property>
+  typename enable_if<
+    can_query<const Executor&, Property>::value,
+    typename query_result<const Executor&, Property>::type
+  >::type query(const Property& p) const
+    ASIO_NOEXCEPT_IF((
+      is_nothrow_query<const Executor&, Property>::value))
+  {
+    return asio::query(executor_, p);
+  }
+
+  /// Forward a requirement to the underlying executor.
+  /**
+   * Do not call this function directly. It is intended for use with the
+   * asio::require customisation point.
+   *
+   * For example:
+   * @code asio::strand<my_executor_type> ex1 = ...;
+   * auto ex2 = asio::require(ex1,
+   *     asio::execution::blocking.never); @endcode
+   */
+  template <typename Property>
+  typename enable_if<
+    can_require<const Executor&, Property>::value,
+    strand<typename decay<
+      typename require_result<const Executor&, Property>::type
+    >::type>
+  >::type require(const Property& p) const
+    ASIO_NOEXCEPT_IF((
+      is_nothrow_require<const Executor&, Property>::value))
+  {
+    return strand<typename decay<
+      typename require_result<const Executor&, Property>::type
+        >::type>(asio::require(executor_, p), impl_);
+  }
+
+  /// Forward a preference to the underlying executor.
+  /**
+   * Do not call this function directly. It is intended for use with the
+   * asio::prefer customisation point.
+   *
+   * For example:
+   * @code asio::strand<my_executor_type> ex1 = ...;
+   * auto ex2 = asio::prefer(ex1,
+   *     asio::execution::blocking.never); @endcode
+   */
+  template <typename Property>
+  typename enable_if<
+    can_prefer<const Executor&, Property>::value,
+    strand<typename decay<
+      typename prefer_result<const Executor&, Property>::type
+    >::type>
+  >::type prefer(const Property& p) const
+    ASIO_NOEXCEPT_IF((
+      is_nothrow_prefer<const Executor&, Property>::value))
+  {
+    return strand<typename decay<
+      typename prefer_result<const Executor&, Property>::type
+        >::type>(asio::prefer(executor_, p), impl_);
+  }
+
+#if !defined(ASIO_NO_TS_EXECUTORS)
+  /// Obtain the underlying execution context.
+  execution_context& context() const ASIO_NOEXCEPT
+  {
+    return executor_.context();
+  }
+
+  /// Inform the strand that it has some outstanding work to do.
+  /**
+   * The strand delegates this call to its underlying executor.
+   */
+  void on_work_started() const ASIO_NOEXCEPT
+  {
+    executor_.on_work_started();
+  }
+
+  /// Inform the strand that some work is no longer outstanding.
+  /**
+   * The strand delegates this call to its underlying executor.
+   */
+  void on_work_finished() const ASIO_NOEXCEPT
+  {
+    executor_.on_work_finished();
+  }
+#endif // !defined(ASIO_NO_TS_EXECUTORS)
+
+  /// Request the strand to invoke the given function object.
+  /**
+   * Do not call this function directly. It is intended for use with the
+   * execution::execute customisation point.
+   *
+   * For example:
+   * @code asio::strand<my_executor_type> ex = ...;
+   * execution::execute(ex, my_function_object); @endcode
+   *
+   * This function is used to ask the strand to execute the given function
+   * object on its underlying executor. The function object will be executed
+   * according to the properties of the underlying executor.
+   *
+   * @param f The function object to be called. The executor will make
+   * a copy of the handler object as required. The function signature of the
+   * function object must be: @code void function(); @endcode
+   */
+  template <typename Function>
+  typename enable_if<
+    execution::can_execute<const Executor&, Function>::value
+  >::type execute(ASIO_MOVE_ARG(Function) f) const
+  {
+    detail::strand_executor_service::execute(impl_,
+        executor_, ASIO_MOVE_CAST(Function)(f));
+  }
+
+#if !defined(ASIO_NO_TS_EXECUTORS)
+  /// Request the strand to invoke the given function object.
+  /**
+   * This function is used to ask the strand to execute the given function
+   * object on its underlying executor. The function object will be executed
+   * inside this function if the strand is not otherwise busy and if the
+   * underlying executor's @c dispatch() function is also able to execute the
+   * function before returning.
+   *
+   * @param f The function object to be called. The executor will make
+   * a copy of the handler object as required. The function signature of the
+   * function object must be: @code void function(); @endcode
+   *
+   * @param a An allocator that may be used by the executor to allocate the
+   * internal storage needed for function invocation.
+   */
+  template <typename Function, typename Allocator>
+  void dispatch(ASIO_MOVE_ARG(Function) f, const Allocator& a) const
+  {
+    detail::strand_executor_service::dispatch(impl_,
+        executor_, ASIO_MOVE_CAST(Function)(f), a);
+  }
+
+  /// Request the strand to invoke the given function object.
+  /**
+   * This function is used to ask the executor to execute the given function
+   * object. The function object will never be executed inside this function.
+   * Instead, it will be scheduled by the underlying executor's defer function.
+   *
+   * @param f The function object to be called. The executor will make
+   * a copy of the handler object as required. The function signature of the
+   * function object must be: @code void function(); @endcode
+   *
+   * @param a An allocator that may be used by the executor to allocate the
+   * internal storage needed for function invocation.
+   */
+  template <typename Function, typename Allocator>
+  void post(ASIO_MOVE_ARG(Function) f, const Allocator& a) const
+  {
+    detail::strand_executor_service::post(impl_,
+        executor_, ASIO_MOVE_CAST(Function)(f), a);
+  }
+
+  /// Request the strand to invoke the given function object.
+  /**
+   * This function is used to ask the executor to execute the given function
+   * object. The function object will never be executed inside this function.
+   * Instead, it will be scheduled by the underlying executor's defer function.
+   *
+   * @param f The function object to be called. The executor will make
+   * a copy of the handler object as required. The function signature of the
+   * function object must be: @code void function(); @endcode
+   *
+   * @param a An allocator that may be used by the executor to allocate the
+   * internal storage needed for function invocation.
+   */
+  template <typename Function, typename Allocator>
+  void defer(ASIO_MOVE_ARG(Function) f, const Allocator& a) const
+  {
+    detail::strand_executor_service::defer(impl_,
+        executor_, ASIO_MOVE_CAST(Function)(f), a);
+  }
+#endif // !defined(ASIO_NO_TS_EXECUTORS)
+
+  /// Determine whether the strand is running in the current thread.
+  /**
+   * @return @c true if the current thread is executing a function that was
+   * submitted to the strand using post(), dispatch() or defer(). Otherwise
+   * returns @c false.
+   */
+  bool running_in_this_thread() const ASIO_NOEXCEPT
+  {
+    return detail::strand_executor_service::running_in_this_thread(impl_);
+  }
+
+  /// Compare two strands for equality.
+  /**
+   * Two strands are equal if they refer to the same ordered, non-concurrent
+   * state.
+   */
+  friend bool operator==(const strand& a, const strand& b) ASIO_NOEXCEPT
+  {
+    return a.impl_ == b.impl_;
+  }
+
+  /// Compare two strands for inequality.
+  /**
+   * Two strands are equal if they refer to the same ordered, non-concurrent
+   * state.
+   */
+  friend bool operator!=(const strand& a, const strand& b) ASIO_NOEXCEPT
+  {
+    return a.impl_ != b.impl_;
+  }
+
+#if defined(GENERATING_DOCUMENTATION)
+private:
+#endif // defined(GENERATING_DOCUMENTATION)
+  typedef detail::strand_executor_service::implementation_type
+    implementation_type;
+
+  template <typename InnerExecutor>
+  static implementation_type create_implementation(const InnerExecutor& ex,
+      typename enable_if<
+        can_query<InnerExecutor, execution::context_t>::value
+      >::type* = 0)
+  {
+    return use_service<detail::strand_executor_service>(
+        asio::query(ex, execution::context)).create_implementation();
+  }
+
+  template <typename InnerExecutor>
+  static implementation_type create_implementation(const InnerExecutor& ex,
+      typename enable_if<
+        !can_query<InnerExecutor, execution::context_t>::value
+      >::type* = 0)
+  {
+    return use_service<detail::strand_executor_service>(
+        ex.context()).create_implementation();
+  }
+
+  strand(const Executor& ex, const implementation_type& impl)
+    : executor_(ex),
+      impl_(impl)
+  {
+  }
+
+  Executor executor_;
+  implementation_type impl_;
+};
+
+/** @defgroup make_strand asio::make_strand
+ *
+ * @brief The asio::make_strand function creates a @ref strand object for
+ * an executor or execution context.
+ */
+/*@{*/
+
+/// Create a @ref strand object for an executor.
+template <typename Executor>
+inline strand<Executor> make_strand(const Executor& ex,
+    typename enable_if<
+      is_executor<Executor>::value || execution::is_executor<Executor>::value
+    >::type* = 0)
+{
+  return strand<Executor>(ex);
+}
+
+/// Create a @ref strand object for an execution context.
+template <typename ExecutionContext>
+inline strand<typename ExecutionContext::executor_type>
+make_strand(ExecutionContext& ctx,
+    typename enable_if<
+      is_convertible<ExecutionContext&, execution_context&>::value
+    >::type* = 0)
+{
+  return strand<typename ExecutionContext::executor_type>(ctx.get_executor());
+}
+
+/*@}*/
+
+#if !defined(GENERATING_DOCUMENTATION)
+
+namespace traits {
+
+#if !defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)
+
+template <typename Executor>
+struct equality_comparable<strand<Executor> >
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
+};
+
+#endif // !defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)
+
+#if !defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)
+
+template <typename Executor, typename Function>
+struct execute_member<strand<Executor>, Function>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
+  typedef void result_type;
+};
+
+#endif // !defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)
+
+#if !defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT)
+
+template <typename Executor, typename Property>
+struct query_member<strand<Executor>, Property,
+    typename enable_if<
+      can_query<const Executor&, Property>::value
+    >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept =
+      (is_nothrow_query<Executor, Property>::value));
+  typedef typename query_result<Executor, Property>::type result_type;
+};
+
+#endif // !defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT)
+
+#if !defined(ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT)
+
+template <typename Executor, typename Property>
+struct require_member<strand<Executor>, Property,
+    typename enable_if<
+      can_require<const Executor&, Property>::value
+    >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept =
+      (is_nothrow_require<Executor, Property>::value));
+  typedef strand<typename decay<
+    typename require_result<Executor, Property>::type
+      >::type> result_type;
+};
+
+#endif // !defined(ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT)
+
+#if !defined(ASIO_HAS_DEDUCED_PREFER_MEMBER_TRAIT)
+
+template <typename Executor, typename Property>
+struct prefer_member<strand<Executor>, Property,
+    typename enable_if<
+      can_prefer<const Executor&, Property>::value
+    >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept =
+      (is_nothrow_prefer<Executor, Property>::value));
+  typedef strand<typename decay<
+    typename prefer_result<Executor, Property>::type
+      >::type> result_type;
+};
+
+#endif // !defined(ASIO_HAS_DEDUCED_PREFER_MEMBER_TRAIT)
+
+} // namespace traits
+
+#endif // !defined(GENERATING_DOCUMENTATION)
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+// If both io_context.hpp and strand.hpp have been included, automatically
+// include the header file needed for the io_context::strand class.
+#if !defined(ASIO_NO_EXTENSIONS)
+# if defined(ASIO_IO_CONTEXT_HPP)
+#  include "asio/io_context_strand.hpp"
+# endif // defined(ASIO_IO_CONTEXT_HPP)
+#endif // !defined(ASIO_NO_EXTENSIONS)
+
+#endif // ASIO_STRAND_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/streambuf.hpp b/link/modules/asio-standalone/asio/include/asio/streambuf.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/streambuf.hpp
@@ -0,0 +1,33 @@
+//
+// streambuf.hpp
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_STREAMBUF_HPP
+#define ASIO_STREAMBUF_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if !defined(ASIO_NO_IOSTREAM)
+
+#include "asio/basic_streambuf.hpp"
+
+namespace asio {
+
+/// Typedef for the typical usage of basic_streambuf.
+typedef basic_streambuf<> streambuf;
+
+} // namespace asio
+
+#endif // !defined(ASIO_NO_IOSTREAM)
+
+#endif // ASIO_STREAMBUF_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/system_context.hpp b/link/modules/asio-standalone/asio/include/asio/system_context.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/system_context.hpp
@@ -0,0 +1,90 @@
+//
+// system_context.hpp
+// ~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_SYSTEM_CONTEXT_HPP
+#define ASIO_SYSTEM_CONTEXT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/scheduler.hpp"
+#include "asio/detail/thread_group.hpp"
+#include "asio/execution.hpp"
+#include "asio/execution_context.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+template <typename Blocking, typename Relationship, typename Allocator>
+class basic_system_executor;
+
+/// The executor context for the system executor.
+class system_context : public execution_context
+{
+public:
+  /// The executor type associated with the context.
+  typedef basic_system_executor<
+      execution::blocking_t::possibly_t,
+      execution::relationship_t::fork_t,
+      std::allocator<void>
+    > executor_type;
+
+  /// Destructor shuts down all threads in the system thread pool.
+  ASIO_DECL ~system_context();
+
+  /// Obtain an executor for the context.
+  executor_type get_executor() ASIO_NOEXCEPT;
+
+  /// Signal all threads in the system thread pool to stop.
+  ASIO_DECL void stop();
+
+  /// Determine whether the system thread pool has been stopped.
+  ASIO_DECL bool stopped() const ASIO_NOEXCEPT;
+
+  /// Join all threads in the system thread pool.
+  ASIO_DECL void join();
+
+#if defined(GENERATING_DOCUMENTATION)
+private:
+#endif // defined(GENERATING_DOCUMENTATION)
+  // Constructor creates all threads in the system thread pool.
+  ASIO_DECL system_context();
+
+private:
+  template <typename, typename, typename> friend class basic_system_executor;
+
+  struct thread_function;
+
+  // Helper function to create the underlying scheduler.
+  ASIO_DECL detail::scheduler& add_scheduler(detail::scheduler* s);
+
+  // The underlying scheduler.
+  detail::scheduler& scheduler_;
+
+  // The threads in the system thread pool.
+  detail::thread_group threads_;
+
+  // The number of threads in the pool.
+  std::size_t num_threads_;
+};
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/impl/system_context.hpp"
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/impl/system_context.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // ASIO_SYSTEM_CONTEXT_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/system_error.hpp b/link/modules/asio-standalone/asio/include/asio/system_error.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/system_error.hpp
@@ -0,0 +1,131 @@
+//
+// system_error.hpp
+// ~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_SYSTEM_ERROR_HPP
+#define ASIO_SYSTEM_ERROR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_STD_SYSTEM_ERROR)
+# include <system_error>
+#else // defined(ASIO_HAS_STD_SYSTEM_ERROR)
+# include <cerrno>
+# include <exception>
+# include <string>
+# include "asio/error_code.hpp"
+# include "asio/detail/scoped_ptr.hpp"
+#endif // defined(ASIO_HAS_STD_SYSTEM_ERROR)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+#if defined(ASIO_HAS_STD_SYSTEM_ERROR)
+
+typedef std::system_error system_error;
+
+#else // defined(ASIO_HAS_STD_SYSTEM_ERROR)
+
+/// The system_error class is used to represent system conditions that
+/// prevent the library from operating correctly.
+class system_error
+  : public std::exception
+{
+public:
+  /// Construct with an error code.
+  system_error(const error_code& ec)
+    : code_(ec),
+      context_()
+  {
+  }
+
+  /// Construct with an error code and context.
+  system_error(const error_code& ec, const std::string& context)
+    : code_(ec),
+      context_(context)
+  {
+  }
+
+  /// Copy constructor.
+  system_error(const system_error& other)
+    : std::exception(other),
+      code_(other.code_),
+      context_(other.context_),
+      what_()
+  {
+  }
+
+  /// Destructor.
+  virtual ~system_error() throw ()
+  {
+  }
+
+  /// Assignment operator.
+  system_error& operator=(const system_error& e)
+  {
+    context_ = e.context_;
+    code_ = e.code_;
+    what_.reset();
+    return *this;
+  }
+
+  /// Get a string representation of the exception.
+  virtual const char* what() const throw ()
+  {
+#if !defined(ASIO_NO_EXCEPTIONS)
+    try
+#endif // !defined(ASIO_NO_EXCEPTIONS)
+    {
+      if (!what_.get())
+      {
+        std::string tmp(context_);
+        if (tmp.length())
+          tmp += ": ";
+        tmp += code_.message();
+        what_.reset(new std::string(tmp));
+      }
+      return what_->c_str();
+    }
+#if !defined(ASIO_NO_EXCEPTIONS)
+    catch (std::exception&)
+    {
+      return "system_error";
+    }
+#endif // !defined(ASIO_NO_EXCEPTIONS)
+  }
+
+  /// Get the error code associated with the exception.
+  error_code code() const
+  {
+    return code_;
+  }
+
+private:
+  // The code associated with the error.
+  error_code code_;
+
+  // The context associated with the error.
+  std::string context_;
+
+  // The string representation of the error.
+  mutable asio::detail::scoped_ptr<std::string> what_;
+};
+
+#endif // defined(ASIO_HAS_STD_SYSTEM_ERROR)
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_SYSTEM_ERROR_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/system_executor.hpp b/link/modules/asio-standalone/asio/include/asio/system_executor.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/system_executor.hpp
@@ -0,0 +1,662 @@
+//
+// system_executor.hpp
+// ~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_SYSTEM_EXECUTOR_HPP
+#define ASIO_SYSTEM_EXECUTOR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/execution.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+class system_context;
+
+/// An executor that uses arbitrary threads.
+/**
+ * The system executor represents an execution context where functions are
+ * permitted to run on arbitrary threads. When the blocking.never property is
+ * established, the system executor will schedule the function to run on an
+ * unspecified system thread pool. When either blocking.possibly or
+ * blocking.always is established, the executor invokes the function
+ * immediately.
+ */
+template <typename Blocking, typename Relationship, typename Allocator>
+class basic_system_executor
+{
+public:
+  /// Default constructor.
+  basic_system_executor() ASIO_NOEXCEPT
+    : allocator_(Allocator())
+  {
+  }
+
+  /// Obtain an executor with the @c blocking.possibly property.
+  /**
+   * Do not call this function directly. It is intended for use with the
+   * asio::require customisation point.
+   *
+   * For example:
+   * @code asio::system_executor ex1;
+   * auto ex2 = asio::require(ex1,
+   *     asio::execution::blocking.possibly); @endcode
+   */
+  basic_system_executor<execution::blocking_t::possibly_t,
+      Relationship, Allocator>
+  require(execution::blocking_t::possibly_t) const
+  {
+    return basic_system_executor<execution::blocking_t::possibly_t,
+        Relationship, Allocator>(allocator_);
+  }
+
+  /// Obtain an executor with the @c blocking.always property.
+  /**
+   * Do not call this function directly. It is intended for use with the
+   * asio::require customisation point.
+   *
+   * For example:
+   * @code asio::system_executor ex1;
+   * auto ex2 = asio::require(ex1,
+   *     asio::execution::blocking.always); @endcode
+   */
+  basic_system_executor<execution::blocking_t::always_t,
+      Relationship, Allocator>
+  require(execution::blocking_t::always_t) const
+  {
+    return basic_system_executor<execution::blocking_t::always_t,
+        Relationship, Allocator>(allocator_);
+  }
+
+  /// Obtain an executor with the @c blocking.never property.
+  /**
+   * Do not call this function directly. It is intended for use with the
+   * asio::require customisation point.
+   *
+   * For example:
+   * @code asio::system_executor ex1;
+   * auto ex2 = asio::require(ex1,
+   *     asio::execution::blocking.never); @endcode
+   */
+  basic_system_executor<execution::blocking_t::never_t,
+      Relationship, Allocator>
+  require(execution::blocking_t::never_t) const
+  {
+    return basic_system_executor<execution::blocking_t::never_t,
+        Relationship, Allocator>(allocator_);
+  }
+
+  /// Obtain an executor with the @c relationship.continuation property.
+  /**
+   * Do not call this function directly. It is intended for use with the
+   * asio::require customisation point.
+   *
+   * For example:
+   * @code asio::system_executor ex1;
+   * auto ex2 = asio::require(ex1,
+   *     asio::execution::relationship.continuation); @endcode
+   */
+  basic_system_executor<Blocking,
+      execution::relationship_t::continuation_t, Allocator>
+  require(execution::relationship_t::continuation_t) const
+  {
+    return basic_system_executor<Blocking,
+        execution::relationship_t::continuation_t, Allocator>(allocator_);
+  }
+
+  /// Obtain an executor with the @c relationship.fork property.
+  /**
+   * Do not call this function directly. It is intended for use with the
+   * asio::require customisation point.
+   *
+   * For example:
+   * @code asio::system_executor ex1;
+   * auto ex2 = asio::require(ex1,
+   *     asio::execution::relationship.fork); @endcode
+   */
+  basic_system_executor<Blocking,
+      execution::relationship_t::fork_t, Allocator>
+  require(execution::relationship_t::fork_t) const
+  {
+    return basic_system_executor<Blocking,
+        execution::relationship_t::fork_t, Allocator>(allocator_);
+  }
+
+  /// Obtain an executor with the specified @c allocator property.
+  /**
+   * Do not call this function directly. It is intended for use with the
+   * asio::require customisation point.
+   *
+   * For example:
+   * @code asio::system_executor ex1;
+   * auto ex2 = asio::require(ex1,
+   *     asio::execution::allocator(my_allocator)); @endcode
+   */
+  template <typename OtherAllocator>
+  basic_system_executor<Blocking, Relationship, OtherAllocator>
+  require(execution::allocator_t<OtherAllocator> a) const
+  {
+    return basic_system_executor<Blocking,
+        Relationship, OtherAllocator>(a.value());
+  }
+
+  /// Obtain an executor with the default @c allocator property.
+  /**
+   * Do not call this function directly. It is intended for use with the
+   * asio::require customisation point.
+   *
+   * For example:
+   * @code asio::system_executor ex1;
+   * auto ex2 = asio::require(ex1,
+   *     asio::execution::allocator); @endcode
+   */
+  basic_system_executor<Blocking, Relationship, std::allocator<void> >
+  require(execution::allocator_t<void>) const
+  {
+    return basic_system_executor<Blocking,
+        Relationship, std::allocator<void> >();
+  }
+
+  /// Query the current value of the @c mapping property.
+  /**
+   * Do not call this function directly. It is intended for use with the
+   * asio::query customisation point.
+   *
+   * For example:
+   * @code asio::system_executor ex;
+   * if (asio::query(ex, asio::execution::mapping)
+   *       == asio::execution::mapping.thread)
+   *   ... @endcode
+   */
+  static ASIO_CONSTEXPR execution::mapping_t query(
+      execution::mapping_t) ASIO_NOEXCEPT
+  {
+    return execution::mapping.thread;
+  }
+
+  /// Query the current value of the @c context property.
+  /**
+   * Do not call this function directly. It is intended for use with the
+   * asio::query customisation point.
+   *
+   * For example:
+   * @code asio::system_executor ex;
+   * asio::system_context& pool = asio::query(
+   *     ex, asio::execution::context); @endcode
+   */
+  static system_context& query(execution::context_t) ASIO_NOEXCEPT;
+
+  /// Query the current value of the @c blocking property.
+  /**
+   * Do not call this function directly. It is intended for use with the
+   * asio::query customisation point.
+   *
+   * For example:
+   * @code asio::system_executor ex;
+   * if (asio::query(ex, asio::execution::blocking)
+   *       == asio::execution::blocking.always)
+   *   ... @endcode
+   */
+  static ASIO_CONSTEXPR execution::blocking_t query(
+      execution::blocking_t) ASIO_NOEXCEPT
+  {
+    return Blocking();
+  }
+
+  /// Query the current value of the @c relationship property.
+  /**
+   * Do not call this function directly. It is intended for use with the
+   * asio::query customisation point.
+   *
+   * For example:
+   * @code asio::system_executor ex;
+   * if (asio::query(ex, asio::execution::relationship)
+   *       == asio::execution::relationship.continuation)
+   *   ... @endcode
+   */
+  static ASIO_CONSTEXPR execution::relationship_t query(
+      execution::relationship_t) ASIO_NOEXCEPT
+  {
+    return Relationship();
+  }
+
+  /// Query the current value of the @c allocator property.
+  /**
+   * Do not call this function directly. It is intended for use with the
+   * asio::query customisation point.
+   *
+   * For example:
+   * @code asio::system_executor ex;
+   * auto alloc = asio::query(ex,
+   *     asio::execution::allocator); @endcode
+   */
+  template <typename OtherAllocator>
+  ASIO_CONSTEXPR Allocator query(
+      execution::allocator_t<OtherAllocator>) const ASIO_NOEXCEPT
+  {
+    return allocator_;
+  }
+
+  /// Query the current value of the @c allocator property.
+  /**
+   * Do not call this function directly. It is intended for use with the
+   * asio::query customisation point.
+   *
+   * For example:
+   * @code asio::system_executor ex;
+   * auto alloc = asio::query(ex,
+   *     asio::execution::allocator); @endcode
+   */
+  ASIO_CONSTEXPR Allocator query(
+      execution::allocator_t<void>) const ASIO_NOEXCEPT
+  {
+    return allocator_;
+  }
+
+  /// Query the occupancy (recommended number of work items) for the system
+  /// context.
+  /**
+   * Do not call this function directly. It is intended for use with the
+   * asio::query customisation point.
+   *
+   * For example:
+   * @code asio::system_executor ex;
+   * std::size_t occupancy = asio::query(
+   *     ex, asio::execution::occupancy); @endcode
+   */
+  std::size_t query(execution::occupancy_t) const ASIO_NOEXCEPT;
+
+  /// Compare two executors for equality.
+  /**
+   * Two executors are equal if they refer to the same underlying io_context.
+   */
+  friend bool operator==(const basic_system_executor&,
+      const basic_system_executor&) ASIO_NOEXCEPT
+  {
+    return true;
+  }
+
+  /// Compare two executors for inequality.
+  /**
+   * Two executors are equal if they refer to the same underlying io_context.
+   */
+  friend bool operator!=(const basic_system_executor&,
+      const basic_system_executor&) ASIO_NOEXCEPT
+  {
+    return false;
+  }
+
+  /// Execution function.
+  /**
+   * Do not call this function directly. It is intended for use with the
+   * execution::execute customisation point.
+   *
+   * For example:
+   * @code asio::system_executor ex;
+   * execution::execute(ex, my_function_object); @endcode
+   */
+  template <typename Function>
+  void execute(ASIO_MOVE_ARG(Function) f) const
+  {
+    this->do_execute(ASIO_MOVE_CAST(Function)(f), Blocking());
+  }
+
+#if !defined(ASIO_NO_TS_EXECUTORS)
+  /// Obtain the underlying execution context.
+  system_context& context() const ASIO_NOEXCEPT;
+
+  /// Inform the executor that it has some outstanding work to do.
+  /**
+   * For the system executor, this is a no-op.
+   */
+  void on_work_started() const ASIO_NOEXCEPT
+  {
+  }
+
+  /// Inform the executor that some work is no longer outstanding.
+  /**
+   * For the system executor, this is a no-op.
+   */
+  void on_work_finished() const ASIO_NOEXCEPT
+  {
+  }
+
+  /// Request the system executor to invoke the given function object.
+  /**
+   * This function is used to ask the executor to execute the given function
+   * object. The function object will always be executed inside this function.
+   *
+   * @param f The function object to be called. The executor will make
+   * a copy of the handler object as required. The function signature of the
+   * function object must be: @code void function(); @endcode
+   *
+   * @param a An allocator that may be used by the executor to allocate the
+   * internal storage needed for function invocation.
+   */
+  template <typename Function, typename OtherAllocator>
+  void dispatch(ASIO_MOVE_ARG(Function) f, const OtherAllocator& a) const;
+
+  /// Request the system executor to invoke the given function object.
+  /**
+   * This function is used to ask the executor to execute the given function
+   * object. The function object will never be executed inside this function.
+   * Instead, it will be scheduled to run on an unspecified system thread pool.
+   *
+   * @param f The function object to be called. The executor will make
+   * a copy of the handler object as required. The function signature of the
+   * function object must be: @code void function(); @endcode
+   *
+   * @param a An allocator that may be used by the executor to allocate the
+   * internal storage needed for function invocation.
+   */
+  template <typename Function, typename OtherAllocator>
+  void post(ASIO_MOVE_ARG(Function) f, const OtherAllocator& a) const;
+
+  /// Request the system executor to invoke the given function object.
+  /**
+   * This function is used to ask the executor to execute the given function
+   * object. The function object will never be executed inside this function.
+   * Instead, it will be scheduled to run on an unspecified system thread pool.
+   *
+   * @param f The function object to be called. The executor will make
+   * a copy of the handler object as required. The function signature of the
+   * function object must be: @code void function(); @endcode
+   *
+   * @param a An allocator that may be used by the executor to allocate the
+   * internal storage needed for function invocation.
+   */
+  template <typename Function, typename OtherAllocator>
+  void defer(ASIO_MOVE_ARG(Function) f, const OtherAllocator& a) const;
+#endif // !defined(ASIO_NO_TS_EXECUTORS)
+
+private:
+  template <typename, typename, typename> friend class basic_system_executor;
+
+  // Constructor used by require().
+  basic_system_executor(const Allocator& a)
+    : allocator_(a)
+  {
+  }
+
+  /// Execution helper implementation for the possibly blocking property.
+  template <typename Function>
+  void do_execute(ASIO_MOVE_ARG(Function) f,
+      execution::blocking_t::possibly_t) const;
+
+  /// Execution helper implementation for the always blocking property.
+  template <typename Function>
+  void do_execute(ASIO_MOVE_ARG(Function) f,
+      execution::blocking_t::always_t) const;
+
+  /// Execution helper implementation for the never blocking property.
+  template <typename Function>
+  void do_execute(ASIO_MOVE_ARG(Function) f,
+      execution::blocking_t::never_t) const;
+
+  // The allocator used for execution functions.
+  Allocator allocator_;
+};
+
+/// An executor that uses arbitrary threads.
+/**
+ * The system executor represents an execution context where functions are
+ * permitted to run on arbitrary threads. When the blocking.never property is
+ * established, the system executor will schedule the function to run on an
+ * unspecified system thread pool. When either blocking.possibly or
+ * blocking.always is established, the executor invokes the function
+ * immediately.
+ */
+typedef basic_system_executor<execution::blocking_t::possibly_t,
+    execution::relationship_t::fork_t, std::allocator<void> >
+  system_executor;
+
+#if !defined(GENERATING_DOCUMENTATION)
+
+namespace traits {
+
+#if !defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)
+
+template <typename Blocking, typename Relationship, typename Allocator>
+struct equality_comparable<
+    asio::basic_system_executor<Blocking, Relationship, Allocator>
+  >
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
+};
+
+#endif // !defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)
+
+#if !defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)
+
+template <typename Blocking, typename Relationship,
+    typename Allocator, typename Function>
+struct execute_member<
+    asio::basic_system_executor<Blocking, Relationship, Allocator>,
+    Function
+  >
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
+  typedef void result_type;
+};
+
+#endif // !defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)
+
+#if !defined(ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT)
+
+template <typename Blocking, typename Relationship, typename Allocator>
+struct require_member<
+    asio::basic_system_executor<Blocking, Relationship, Allocator>,
+    asio::execution::blocking_t::possibly_t
+  >
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
+  typedef asio::basic_system_executor<
+      asio::execution::blocking_t::possibly_t,
+      Relationship, Allocator> result_type;
+};
+
+template <typename Blocking, typename Relationship, typename Allocator>
+struct require_member<
+    asio::basic_system_executor<Blocking, Relationship, Allocator>,
+    asio::execution::blocking_t::always_t
+  >
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
+  typedef asio::basic_system_executor<
+      asio::execution::blocking_t::always_t,
+      Relationship, Allocator> result_type;
+};
+
+template <typename Blocking, typename Relationship, typename Allocator>
+struct require_member<
+    asio::basic_system_executor<Blocking, Relationship, Allocator>,
+    asio::execution::blocking_t::never_t
+  >
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
+  typedef asio::basic_system_executor<
+      asio::execution::blocking_t::never_t,
+      Relationship, Allocator> result_type;
+};
+
+template <typename Blocking, typename Relationship, typename Allocator>
+struct require_member<
+    asio::basic_system_executor<Blocking, Relationship, Allocator>,
+    asio::execution::relationship_t::fork_t
+  >
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
+  typedef asio::basic_system_executor<Blocking,
+      asio::execution::relationship_t::fork_t,
+      Allocator> result_type;
+};
+
+template <typename Blocking, typename Relationship, typename Allocator>
+struct require_member<
+    asio::basic_system_executor<Blocking, Relationship, Allocator>,
+    asio::execution::relationship_t::continuation_t
+  >
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
+  typedef asio::basic_system_executor<Blocking,
+      asio::execution::relationship_t::continuation_t,
+      Allocator> result_type;
+};
+
+template <typename Blocking, typename Relationship, typename Allocator>
+struct require_member<
+    asio::basic_system_executor<Blocking, Relationship, Allocator>,
+    asio::execution::allocator_t<void>
+  >
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
+  typedef asio::basic_system_executor<Blocking,
+      Relationship, std::allocator<void> > result_type;
+};
+
+template <typename Blocking, typename Relationship,
+    typename Allocator, typename OtherAllocator>
+struct require_member<
+    asio::basic_system_executor<Blocking, Relationship, Allocator>,
+    asio::execution::allocator_t<OtherAllocator>
+  >
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
+  typedef asio::basic_system_executor<Blocking,
+      Relationship, OtherAllocator> result_type;
+};
+
+#endif // !defined(ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT)
+
+#if !defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT)
+
+template <typename Blocking, typename Relationship,
+    typename Allocator, typename Property>
+struct query_static_constexpr_member<
+    asio::basic_system_executor<Blocking, Relationship, Allocator>,
+    Property,
+    typename asio::enable_if<
+      asio::is_convertible<
+        Property,
+        asio::execution::mapping_t
+      >::value
+    >::type
+  >
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
+  typedef asio::execution::mapping_t::thread_t result_type;
+
+  static ASIO_CONSTEXPR result_type value() ASIO_NOEXCEPT
+  {
+    return result_type();
+  }
+};
+
+#endif // !defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT)
+
+#if !defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT)
+
+template <typename Blocking, typename Relationship,
+    typename Allocator, typename Property>
+struct query_member<
+    asio::basic_system_executor<Blocking, Relationship, Allocator>,
+    Property,
+    typename asio::enable_if<
+      asio::is_convertible<
+        Property,
+        asio::execution::blocking_t
+      >::value
+    >::type
+  >
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
+  typedef asio::execution::blocking_t result_type;
+};
+
+template <typename Blocking, typename Relationship,
+    typename Allocator, typename Property>
+struct query_member<
+    asio::basic_system_executor<Blocking, Relationship, Allocator>,
+    Property,
+    typename asio::enable_if<
+      asio::is_convertible<
+        Property,
+        asio::execution::relationship_t
+      >::value
+    >::type
+  >
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
+  typedef asio::execution::relationship_t result_type;
+};
+
+template <typename Blocking, typename Relationship, typename Allocator>
+struct query_member<
+    asio::basic_system_executor<Blocking, Relationship, Allocator>,
+    asio::execution::context_t
+  >
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
+  typedef asio::system_context& result_type;
+};
+
+template <typename Blocking, typename Relationship, typename Allocator>
+struct query_member<
+    asio::basic_system_executor<Blocking, Relationship, Allocator>,
+    asio::execution::allocator_t<void>
+  >
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
+  typedef Allocator result_type;
+};
+
+template <typename Blocking, typename Relationship, typename Allocator>
+struct query_member<
+    asio::basic_system_executor<Blocking, Relationship, Allocator>,
+    asio::execution::allocator_t<Allocator>
+  >
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
+  typedef Allocator result_type;
+};
+
+#endif // !defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT)
+
+} // namespace traits
+
+#endif // !defined(GENERATING_DOCUMENTATION)
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/impl/system_executor.hpp"
+
+#endif // ASIO_SYSTEM_EXECUTOR_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/system_timer.hpp b/link/modules/asio-standalone/asio/include/asio/system_timer.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/system_timer.hpp
@@ -0,0 +1,42 @@
+//
+// system_timer.hpp
+// ~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_SYSTEM_TIMER_HPP
+#define ASIO_SYSTEM_TIMER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_CHRONO) || defined(GENERATING_DOCUMENTATION)
+
+#include "asio/basic_waitable_timer.hpp"
+#include "asio/detail/chrono.hpp"
+
+namespace asio {
+
+/// Typedef for a timer based on the system clock.
+/**
+ * This typedef uses the C++11 @c &lt;chrono&gt; standard library facility, if
+ * available. Otherwise, it may use the Boost.Chrono library. To explicitly
+ * utilise Boost.Chrono, use the basic_waitable_timer template directly:
+ * @code
+ * typedef basic_waitable_timer<boost::chrono::system_clock> timer;
+ * @endcode
+ */
+typedef basic_waitable_timer<chrono::system_clock> system_timer;
+
+} // namespace asio
+
+#endif // defined(ASIO_HAS_CHRONO) || defined(GENERATING_DOCUMENTATION)
+
+#endif // ASIO_SYSTEM_TIMER_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/this_coro.hpp b/link/modules/asio-standalone/asio/include/asio/this_coro.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/this_coro.hpp
@@ -0,0 +1,45 @@
+//
+// this_coro.hpp
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_THIS_CORO_HPP
+#define ASIO_THIS_CORO_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace this_coro {
+
+/// Awaitable type that returns the executor of the current coroutine.
+struct executor_t
+{
+  ASIO_CONSTEXPR executor_t()
+  {
+  }
+};
+
+/// Awaitable object that returns the executor of the current coroutine.
+#if defined(ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION)
+constexpr executor_t executor;
+#elif defined(ASIO_MSVC)
+__declspec(selectany) executor_t executor;
+#endif
+
+} // namespace this_coro
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_THIS_CORO_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/thread.hpp b/link/modules/asio-standalone/asio/include/asio/thread.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/thread.hpp
@@ -0,0 +1,92 @@
+//
+// thread.hpp
+// ~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_THREAD_HPP
+#define ASIO_THREAD_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/noncopyable.hpp"
+#include "asio/detail/thread.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+/// A simple abstraction for starting threads.
+/**
+ * The asio::thread class implements the smallest possible subset of the
+ * functionality of boost::thread. It is intended to be used only for starting
+ * a thread and waiting for it to exit. If more extensive threading
+ * capabilities are required, you are strongly advised to use something else.
+ *
+ * @par Thread Safety
+ * @e Distinct @e objects: Safe.@n
+ * @e Shared @e objects: Unsafe.
+ *
+ * @par Example
+ * A typical use of asio::thread would be to launch a thread to run an
+ * io_context's event processing loop:
+ *
+ * @par
+ * @code asio::io_context io_context;
+ * // ...
+ * asio::thread t(boost::bind(&asio::io_context::run, &io_context));
+ * // ...
+ * t.join(); @endcode
+ */
+class thread
+  : private noncopyable
+{
+public:
+  /// Start a new thread that executes the supplied function.
+  /**
+   * This constructor creates a new thread that will execute the given function
+   * or function object.
+   *
+   * @param f The function or function object to be run in the thread. The
+   * function signature must be: @code void f(); @endcode
+   */
+  template <typename Function>
+  explicit thread(Function f)
+    : impl_(f)
+  {
+  }
+
+  /// Destructor.
+  ~thread()
+  {
+  }
+
+  /// Wait for the thread to exit.
+  /**
+   * This function will block until the thread has exited.
+   *
+   * If this function is not called before the thread object is destroyed, the
+   * thread itself will continue to run until completion. You will, however,
+   * no longer have the ability to wait for it to exit.
+   */
+  void join()
+  {
+    impl_.join();
+  }
+
+private:
+  detail::thread impl_;
+};
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_THREAD_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/thread_pool.hpp b/link/modules/asio-standalone/asio/include/asio/thread_pool.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/thread_pool.hpp
@@ -0,0 +1,1111 @@
+//
+// thread_pool.hpp
+// ~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_THREAD_POOL_HPP
+#define ASIO_THREAD_POOL_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/atomic_count.hpp"
+#include "asio/detail/scheduler.hpp"
+#include "asio/detail/thread_group.hpp"
+#include "asio/execution.hpp"
+#include "asio/execution_context.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+  struct thread_pool_bits
+  {
+    ASIO_STATIC_CONSTEXPR(unsigned int, blocking_never = 1);
+    ASIO_STATIC_CONSTEXPR(unsigned int, blocking_always = 2);
+    ASIO_STATIC_CONSTEXPR(unsigned int, blocking_mask = 3);
+    ASIO_STATIC_CONSTEXPR(unsigned int, relationship_continuation = 4);
+    ASIO_STATIC_CONSTEXPR(unsigned int, outstanding_work_tracked = 8);
+  };
+} // namespace detail
+
+/// A simple fixed-size thread pool.
+/**
+ * The thread pool class is an execution context where functions are permitted
+ * to run on one of a fixed number of threads.
+ *
+ * @par Submitting tasks to the pool
+ *
+ * To submit functions to the thread pool, use the @ref asio::dispatch,
+ * @ref asio::post or @ref asio::defer free functions.
+ *
+ * For example:
+ *
+ * @code void my_task()
+ * {
+ *   ...
+ * }
+ *
+ * ...
+ *
+ * // Launch the pool with four threads.
+ * asio::thread_pool pool(4);
+ *
+ * // Submit a function to the pool.
+ * asio::post(pool, my_task);
+ *
+ * // Submit a lambda object to the pool.
+ * asio::post(pool,
+ *     []()
+ *     {
+ *       ...
+ *     });
+ *
+ * // Wait for all tasks in the pool to complete.
+ * pool.join(); @endcode
+ */
+class thread_pool
+  : public execution_context
+{
+public:
+  template <typename Allocator, unsigned int Bits>
+  class basic_executor_type;
+
+  template <typename Allocator, unsigned int Bits>
+  friend class basic_executor_type;
+
+  /// Executor used to submit functions to a thread pool.
+  typedef basic_executor_type<std::allocator<void>, 0> executor_type;
+
+  /// Scheduler used to schedule receivers on a thread pool.
+  typedef basic_executor_type<std::allocator<void>, 0> scheduler_type;
+
+#if !defined(ASIO_NO_TS_EXECUTORS)
+  /// Constructs a pool with an automatically determined number of threads.
+  ASIO_DECL thread_pool();
+#endif // !defined(ASIO_NO_TS_EXECUTORS)
+
+  /// Constructs a pool with a specified number of threads.
+  ASIO_DECL thread_pool(std::size_t num_threads);
+
+  /// Destructor.
+  /**
+   * Automatically stops and joins the pool, if not explicitly done beforehand.
+   */
+  ASIO_DECL ~thread_pool();
+
+  /// Obtains the executor associated with the pool.
+  executor_type get_executor() ASIO_NOEXCEPT;
+
+  /// Obtains the executor associated with the pool.
+  executor_type executor() ASIO_NOEXCEPT;
+
+  /// Obtains the scheduler associated with the pool.
+  scheduler_type scheduler() ASIO_NOEXCEPT;
+
+  /// Stops the threads.
+  /**
+   * This function stops the threads as soon as possible. As a result of calling
+   * @c stop(), pending function objects may be never be invoked.
+   */
+  ASIO_DECL void stop();
+
+  /// Attaches the current thread to the pool.
+  /**
+   * This function attaches the current thread to the pool so that it may be
+   * used for executing submitted function objects. Blocks the calling thread
+   * until the pool is stopped or joined and has no outstanding work.
+   */
+  ASIO_DECL void attach();
+
+  /// Joins the threads.
+  /**
+   * This function blocks until the threads in the pool have completed. If @c
+   * stop() is not called prior to @c join(), the @c join() call will wait
+   * until the pool has no more outstanding work.
+   */
+  ASIO_DECL void join();
+
+  /// Waits for threads to complete.
+  /**
+   * This function blocks until the threads in the pool have completed. If @c
+   * stop() is not called prior to @c wait(), the @c wait() call will wait
+   * until the pool has no more outstanding work.
+   */
+  ASIO_DECL void wait();
+
+private:
+  thread_pool(const thread_pool&) ASIO_DELETED;
+  thread_pool& operator=(const thread_pool&) ASIO_DELETED;
+
+  struct thread_function;
+
+  // Helper function to create the underlying scheduler.
+  ASIO_DECL detail::scheduler& add_scheduler(detail::scheduler* s);
+
+  // The underlying scheduler.
+  detail::scheduler& scheduler_;
+
+  // The threads in the pool.
+  detail::thread_group threads_;
+
+  // The current number of threads in the pool.
+  detail::atomic_count num_threads_;
+};
+
+/// Executor implementation type used to submit functions to a thread pool.
+template <typename Allocator, unsigned int Bits>
+class thread_pool::basic_executor_type : detail::thread_pool_bits
+{
+public:
+  /// The sender type, when this type is used as a scheduler.
+  typedef basic_executor_type sender_type;
+
+  /// The bulk execution shape type.
+  typedef std::size_t shape_type;
+
+  /// The bulk execution index type.
+  typedef std::size_t index_type;
+
+#if defined(ASIO_HAS_DEDUCED_EXECUTION_IS_TYPED_SENDER_TRAIT) \
+  && defined(ASIO_HAS_STD_EXCEPTION_PTR)
+  template <
+      template <typename...> class Tuple,
+      template <typename...> class Variant>
+  using value_types = Variant<Tuple<>>;
+
+  template <template <typename...> class Variant>
+  using error_types = Variant<std::exception_ptr>;
+
+  ASIO_STATIC_CONSTEXPR(bool, sends_done = true);
+#endif // defined(ASIO_HAS_DEDUCED_EXECUTION_IS_TYPED_SENDER_TRAIT)
+       //   && defined(ASIO_HAS_STD_EXCEPTION_PTR)
+
+  /// Copy constructor.
+  basic_executor_type(
+      const basic_executor_type& other) ASIO_NOEXCEPT
+    : pool_(other.pool_),
+      allocator_(other.allocator_),
+      bits_(other.bits_)
+  {
+    if (Bits & outstanding_work_tracked)
+      if (pool_)
+        pool_->scheduler_.work_started();
+  }
+
+#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+  /// Move constructor.
+  basic_executor_type(basic_executor_type&& other) ASIO_NOEXCEPT
+    : pool_(other.pool_),
+      allocator_(ASIO_MOVE_CAST(Allocator)(other.allocator_)),
+      bits_(other.bits_)
+  {
+    if (Bits & outstanding_work_tracked)
+      other.pool_ = 0;
+  }
+#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+
+  /// Destructor.
+  ~basic_executor_type() ASIO_NOEXCEPT
+  {
+    if (Bits & outstanding_work_tracked)
+      if (pool_)
+        pool_->scheduler_.work_finished();
+  }
+
+  /// Assignment operator.
+  basic_executor_type& operator=(
+      const basic_executor_type& other) ASIO_NOEXCEPT;
+
+#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+  /// Move assignment operator.
+  basic_executor_type& operator=(
+      basic_executor_type&& other) ASIO_NOEXCEPT;
+#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+
+  /// Obtain an executor with the @c blocking.possibly property.
+  /**
+   * Do not call this function directly. It is intended for use with the
+   * asio::require customisation point.
+   *
+   * For example:
+   * @code auto ex1 = my_thread_pool.executor();
+   * auto ex2 = asio::require(ex1,
+   *     asio::execution::blocking.possibly); @endcode
+   */
+  ASIO_CONSTEXPR basic_executor_type<Allocator,
+      ASIO_UNSPECIFIED(Bits & ~blocking_mask)>
+  require(execution::blocking_t::possibly_t) const
+  {
+    return basic_executor_type<Allocator, Bits & ~blocking_mask>(
+        pool_, allocator_, bits_ & ~blocking_mask);
+  }
+
+  /// Obtain an executor with the @c blocking.always property.
+  /**
+   * Do not call this function directly. It is intended for use with the
+   * asio::require customisation point.
+   *
+   * For example:
+   * @code auto ex1 = my_thread_pool.executor();
+   * auto ex2 = asio::require(ex1,
+   *     asio::execution::blocking.always); @endcode
+   */
+  ASIO_CONSTEXPR basic_executor_type<Allocator,
+      ASIO_UNSPECIFIED((Bits & ~blocking_mask) | blocking_always)>
+  require(execution::blocking_t::always_t) const
+  {
+    return basic_executor_type<Allocator,
+        ASIO_UNSPECIFIED((Bits & ~blocking_mask) | blocking_always)>(
+          pool_, allocator_, bits_ & ~blocking_mask);
+  }
+
+  /// Obtain an executor with the @c blocking.never property.
+  /**
+   * Do not call this function directly. It is intended for use with the
+   * asio::require customisation point.
+   *
+   * For example:
+   * @code auto ex1 = my_thread_pool.executor();
+   * auto ex2 = asio::require(ex1,
+   *     asio::execution::blocking.never); @endcode
+   */
+  ASIO_CONSTEXPR basic_executor_type<Allocator,
+      ASIO_UNSPECIFIED(Bits & ~blocking_mask)>
+  require(execution::blocking_t::never_t) const
+  {
+    return basic_executor_type<Allocator, Bits & ~blocking_mask>(
+        pool_, allocator_, (bits_ & ~blocking_mask) | blocking_never);
+  }
+
+  /// Obtain an executor with the @c relationship.fork property.
+  /**
+   * Do not call this function directly. It is intended for use with the
+   * asio::require customisation point.
+   *
+   * For example:
+   * @code auto ex1 = my_thread_pool.executor();
+   * auto ex2 = asio::require(ex1,
+   *     asio::execution::relationship.fork); @endcode
+   */
+  ASIO_CONSTEXPR basic_executor_type require(
+      execution::relationship_t::fork_t) const
+  {
+    return basic_executor_type(pool_,
+        allocator_, bits_ & ~relationship_continuation);
+  }
+
+  /// Obtain an executor with the @c relationship.continuation property.
+  /**
+   * Do not call this function directly. It is intended for use with the
+   * asio::require customisation point.
+   *
+   * For example:
+   * @code auto ex1 = my_thread_pool.executor();
+   * auto ex2 = asio::require(ex1,
+   *     asio::execution::relationship.continuation); @endcode
+   */
+  ASIO_CONSTEXPR basic_executor_type require(
+      execution::relationship_t::continuation_t) const
+  {
+    return basic_executor_type(pool_,
+        allocator_, bits_ | relationship_continuation);
+  }
+
+  /// Obtain an executor with the @c outstanding_work.tracked property.
+  /**
+   * Do not call this function directly. It is intended for use with the
+   * asio::require customisation point.
+   *
+   * For example:
+   * @code auto ex1 = my_thread_pool.executor();
+   * auto ex2 = asio::require(ex1,
+   *     asio::execution::outstanding_work.tracked); @endcode
+   */
+  ASIO_CONSTEXPR basic_executor_type<Allocator,
+      ASIO_UNSPECIFIED(Bits | outstanding_work_tracked)>
+  require(execution::outstanding_work_t::tracked_t) const
+  {
+    return basic_executor_type<Allocator, Bits | outstanding_work_tracked>(
+        pool_, allocator_, bits_);
+  }
+
+  /// Obtain an executor with the @c outstanding_work.untracked property.
+  /**
+   * Do not call this function directly. It is intended for use with the
+   * asio::require customisation point.
+   *
+   * For example:
+   * @code auto ex1 = my_thread_pool.executor();
+   * auto ex2 = asio::require(ex1,
+   *     asio::execution::outstanding_work.untracked); @endcode
+   */
+  ASIO_CONSTEXPR basic_executor_type<Allocator,
+      ASIO_UNSPECIFIED(Bits & ~outstanding_work_tracked)>
+  require(execution::outstanding_work_t::untracked_t) const
+  {
+    return basic_executor_type<Allocator, Bits & ~outstanding_work_tracked>(
+        pool_, allocator_, bits_);
+  }
+
+  /// Obtain an executor with the specified @c allocator property.
+  /**
+   * Do not call this function directly. It is intended for use with the
+   * asio::require customisation point.
+   *
+   * For example:
+   * @code auto ex1 = my_thread_pool.executor();
+   * auto ex2 = asio::require(ex1,
+   *     asio::execution::allocator(my_allocator)); @endcode
+   */
+  template <typename OtherAllocator>
+  ASIO_CONSTEXPR basic_executor_type<OtherAllocator, Bits>
+  require(execution::allocator_t<OtherAllocator> a) const
+  {
+    return basic_executor_type<OtherAllocator, Bits>(
+        pool_, a.value(), bits_);
+  }
+
+  /// Obtain an executor with the default @c allocator property.
+  /**
+   * Do not call this function directly. It is intended for use with the
+   * asio::require customisation point.
+   *
+   * For example:
+   * @code auto ex1 = my_thread_pool.executor();
+   * auto ex2 = asio::require(ex1,
+   *     asio::execution::allocator); @endcode
+   */
+  ASIO_CONSTEXPR basic_executor_type<std::allocator<void>, Bits>
+  require(execution::allocator_t<void>) const
+  {
+    return basic_executor_type<std::allocator<void>, Bits>(
+        pool_, std::allocator<void>(), bits_);
+  }
+
+  /// Query the current value of the @c bulk_guarantee property.
+  /**
+   * Do not call this function directly. It is intended for use with the
+   * asio::query customisation point.
+   *
+   * For example:
+   * @code auto ex = my_thread_pool.executor();
+   * if (asio::query(ex, asio::execution::bulk_guarantee)
+   *       == asio::execution::bulk_guarantee.parallel)
+   *   ... @endcode
+   */
+  static ASIO_CONSTEXPR execution::bulk_guarantee_t query(
+      execution::bulk_guarantee_t) ASIO_NOEXCEPT
+  {
+    return execution::bulk_guarantee.parallel;
+  }
+
+  /// Query the current value of the @c mapping property.
+  /**
+   * Do not call this function directly. It is intended for use with the
+   * asio::query customisation point.
+   *
+   * For example:
+   * @code auto ex = my_thread_pool.executor();
+   * if (asio::query(ex, asio::execution::mapping)
+   *       == asio::execution::mapping.thread)
+   *   ... @endcode
+   */
+  static ASIO_CONSTEXPR execution::mapping_t query(
+      execution::mapping_t) ASIO_NOEXCEPT
+  {
+    return execution::mapping.thread;
+  }
+
+  /// Query the current value of the @c context property.
+  /**
+   * Do not call this function directly. It is intended for use with the
+   * asio::query customisation point.
+   *
+   * For example:
+   * @code auto ex = my_thread_pool.executor();
+   * asio::thread_pool& pool = asio::query(
+   *     ex, asio::execution::context); @endcode
+   */
+  thread_pool& query(execution::context_t) const ASIO_NOEXCEPT
+  {
+    return *pool_;
+  }
+
+  /// Query the current value of the @c blocking property.
+  /**
+   * Do not call this function directly. It is intended for use with the
+   * asio::query customisation point.
+   *
+   * For example:
+   * @code auto ex = my_thread_pool.executor();
+   * if (asio::query(ex, asio::execution::blocking)
+   *       == asio::execution::blocking.always)
+   *   ... @endcode
+   */
+  ASIO_CONSTEXPR execution::blocking_t query(
+      execution::blocking_t) const ASIO_NOEXCEPT
+  {
+    return (bits_ & blocking_never)
+      ? execution::blocking_t(execution::blocking.never)
+      : ((Bits & blocking_always)
+          ? execution::blocking_t(execution::blocking.always)
+          : execution::blocking_t(execution::blocking.possibly));
+  }
+
+  /// Query the current value of the @c relationship property.
+  /**
+   * Do not call this function directly. It is intended for use with the
+   * asio::query customisation point.
+   *
+   * For example:
+   * @code auto ex = my_thread_pool.executor();
+   * if (asio::query(ex, asio::execution::relationship)
+   *       == asio::execution::relationship.continuation)
+   *   ... @endcode
+   */
+  ASIO_CONSTEXPR execution::relationship_t query(
+      execution::relationship_t) const ASIO_NOEXCEPT
+  {
+    return (bits_ & relationship_continuation)
+      ? execution::relationship_t(execution::relationship.continuation)
+      : execution::relationship_t(execution::relationship.fork);
+  }
+
+  /// Query the current value of the @c outstanding_work property.
+  /**
+   * Do not call this function directly. It is intended for use with the
+   * asio::query customisation point.
+   *
+   * For example:
+   * @code auto ex = my_thread_pool.executor();
+   * if (asio::query(ex, asio::execution::outstanding_work)
+   *       == asio::execution::outstanding_work.tracked)
+   *   ... @endcode
+   */
+  static ASIO_CONSTEXPR execution::outstanding_work_t query(
+      execution::outstanding_work_t) ASIO_NOEXCEPT
+  {
+    return (Bits & outstanding_work_tracked)
+      ? execution::outstanding_work_t(execution::outstanding_work.tracked)
+      : execution::outstanding_work_t(execution::outstanding_work.untracked);
+  }
+
+  /// Query the current value of the @c allocator property.
+  /**
+   * Do not call this function directly. It is intended for use with the
+   * asio::query customisation point.
+   *
+   * For example:
+   * @code auto ex = my_thread_pool.executor();
+   * auto alloc = asio::query(ex,
+   *     asio::execution::allocator); @endcode
+   */
+  template <typename OtherAllocator>
+  ASIO_CONSTEXPR Allocator query(
+      execution::allocator_t<OtherAllocator>) const ASIO_NOEXCEPT
+  {
+    return allocator_;
+  }
+
+  /// Query the current value of the @c allocator property.
+  /**
+   * Do not call this function directly. It is intended for use with the
+   * asio::query customisation point.
+   *
+   * For example:
+   * @code auto ex = my_thread_pool.executor();
+   * auto alloc = asio::query(ex,
+   *     asio::execution::allocator); @endcode
+   */
+  ASIO_CONSTEXPR Allocator query(
+      execution::allocator_t<void>) const ASIO_NOEXCEPT
+  {
+    return allocator_;
+  }
+
+  /// Query the occupancy (recommended number of work items) for the pool.
+  /**
+   * Do not call this function directly. It is intended for use with the
+   * asio::query customisation point.
+   *
+   * For example:
+   * @code auto ex = my_thread_pool.executor();
+   * std::size_t occupancy = asio::query(
+   *     ex, asio::execution::occupancy); @endcode
+   */
+  std::size_t query(execution::occupancy_t) const ASIO_NOEXCEPT
+  {
+    return static_cast<std::size_t>(pool_->num_threads_);
+  }
+
+  /// Determine whether the thread pool is running in the current thread.
+  /**
+   * @return @c true if the current thread is running the thread pool. Otherwise
+   * returns @c false.
+   */
+  bool running_in_this_thread() const ASIO_NOEXCEPT;
+
+  /// Compare two executors for equality.
+  /**
+   * Two executors are equal if they refer to the same underlying thread pool.
+   */
+  friend bool operator==(const basic_executor_type& a,
+      const basic_executor_type& b) ASIO_NOEXCEPT
+  {
+    return a.pool_ == b.pool_
+      && a.allocator_ == b.allocator_
+      && a.bits_ == b.bits_;
+  }
+
+  /// Compare two executors for inequality.
+  /**
+   * Two executors are equal if they refer to the same underlying thread pool.
+   */
+  friend bool operator!=(const basic_executor_type& a,
+      const basic_executor_type& b) ASIO_NOEXCEPT
+  {
+    return a.pool_ != b.pool_
+      || a.allocator_ != b.allocator_
+      || a.bits_ != b.bits_;
+  }
+
+  /// Execution function.
+  /**
+   * Do not call this function directly. It is intended for use with the
+   * execution::execute customisation point.
+   *
+   * For example:
+   * @code auto ex = my_thread_pool.executor();
+   * execution::execute(ex, my_function_object); @endcode
+   */
+  template <typename Function>
+  void execute(ASIO_MOVE_ARG(Function) f) const
+  {
+    this->do_execute(ASIO_MOVE_CAST(Function)(f),
+        integral_constant<bool, (Bits & blocking_always) != 0>());
+  }
+
+  /// Bulk execution function.
+  template <typename Function>
+  void bulk_execute(ASIO_MOVE_ARG(Function) f, std::size_t n) const
+  {
+    this->do_bulk_execute(ASIO_MOVE_CAST(Function)(f), n,
+        integral_constant<bool, (Bits & blocking_always) != 0>());
+  }
+
+  /// Schedule function.
+  /**
+   * Do not call this function directly. It is intended for use with the
+   * execution::schedule customisation point.
+   *
+   * @return An object that satisfies the sender concept.
+   */
+  sender_type schedule() const ASIO_NOEXCEPT
+  {
+    return *this;
+  }
+
+  /// Connect function.
+  /**
+   * Do not call this function directly. It is intended for use with the
+   * execution::connect customisation point.
+   *
+   * @return An object of an unspecified type that satisfies the @c
+   * operation_state concept.
+   */
+  template <ASIO_EXECUTION_RECEIVER_OF_0 Receiver>
+#if defined(GENERATING_DOCUMENTATION)
+  unspecified
+#else // defined(GENERATING_DOCUMENTATION)
+  execution::detail::as_operation<basic_executor_type, Receiver>
+#endif // defined(GENERATING_DOCUMENTATION)
+  connect(ASIO_MOVE_ARG(Receiver) r) const
+  {
+    return execution::detail::as_operation<basic_executor_type, Receiver>(
+        *this, ASIO_MOVE_CAST(Receiver)(r));
+  }
+
+#if !defined(ASIO_NO_TS_EXECUTORS)
+  /// Obtain the underlying execution context.
+  thread_pool& context() const ASIO_NOEXCEPT;
+
+  /// Inform the thread pool that it has some outstanding work to do.
+  /**
+   * This function is used to inform the thread pool that some work has begun.
+   * This ensures that the thread pool's join() function will not return while
+   * the work is underway.
+   */
+  void on_work_started() const ASIO_NOEXCEPT;
+
+  /// Inform the thread pool that some work is no longer outstanding.
+  /**
+   * This function is used to inform the thread pool that some work has
+   * finished. Once the count of unfinished work reaches zero, the thread
+   * pool's join() function is permitted to exit.
+   */
+  void on_work_finished() const ASIO_NOEXCEPT;
+
+  /// Request the thread pool to invoke the given function object.
+  /**
+   * This function is used to ask the thread pool to execute the given function
+   * object. If the current thread belongs to the pool, @c dispatch() executes
+   * the function before returning. Otherwise, the function will be scheduled
+   * to run on the thread pool.
+   *
+   * @param f The function object to be called. The executor will make
+   * a copy of the handler object as required. The function signature of the
+   * function object must be: @code void function(); @endcode
+   *
+   * @param a An allocator that may be used by the executor to allocate the
+   * internal storage needed for function invocation.
+   */
+  template <typename Function, typename OtherAllocator>
+  void dispatch(ASIO_MOVE_ARG(Function) f,
+      const OtherAllocator& a) const;
+
+  /// Request the thread pool to invoke the given function object.
+  /**
+   * This function is used to ask the thread pool to execute the given function
+   * object. The function object will never be executed inside @c post().
+   * Instead, it will be scheduled to run on the thread pool.
+   *
+   * @param f The function object to be called. The executor will make
+   * a copy of the handler object as required. The function signature of the
+   * function object must be: @code void function(); @endcode
+   *
+   * @param a An allocator that may be used by the executor to allocate the
+   * internal storage needed for function invocation.
+   */
+  template <typename Function, typename OtherAllocator>
+  void post(ASIO_MOVE_ARG(Function) f,
+      const OtherAllocator& a) const;
+
+  /// Request the thread pool to invoke the given function object.
+  /**
+   * This function is used to ask the thread pool to execute the given function
+   * object. The function object will never be executed inside @c defer().
+   * Instead, it will be scheduled to run on the thread pool.
+   *
+   * If the current thread belongs to the thread pool, @c defer() will delay
+   * scheduling the function object until the current thread returns control to
+   * the pool.
+   *
+   * @param f The function object to be called. The executor will make
+   * a copy of the handler object as required. The function signature of the
+   * function object must be: @code void function(); @endcode
+   *
+   * @param a An allocator that may be used by the executor to allocate the
+   * internal storage needed for function invocation.
+   */
+  template <typename Function, typename OtherAllocator>
+  void defer(ASIO_MOVE_ARG(Function) f,
+      const OtherAllocator& a) const;
+#endif // !defined(ASIO_NO_TS_EXECUTORS)
+
+private:
+  friend class thread_pool;
+  template <typename, unsigned int> friend class basic_executor_type;
+
+  // Constructor used by thread_pool::get_executor().
+  explicit basic_executor_type(thread_pool& p) ASIO_NOEXCEPT
+    : pool_(&p),
+      allocator_(),
+      bits_(0)
+  {
+    if (Bits & outstanding_work_tracked)
+      pool_->scheduler_.work_started();
+  }
+
+  // Constructor used by require().
+  basic_executor_type(thread_pool* p,
+      const Allocator& a, unsigned int bits) ASIO_NOEXCEPT
+    : pool_(p),
+      allocator_(a),
+      bits_(bits)
+  {
+    if (Bits & outstanding_work_tracked)
+      if (pool_)
+        pool_->scheduler_.work_started();
+  }
+
+  /// Execution helper implementation for possibly and never blocking.
+  template <typename Function>
+  void do_execute(ASIO_MOVE_ARG(Function) f, false_type) const;
+
+  /// Execution helper implementation for always blocking.
+  template <typename Function>
+  void do_execute(ASIO_MOVE_ARG(Function) f, true_type) const;
+
+  /// Bulk execution helper implementation for possibly and never blocking.
+  template <typename Function>
+  void do_bulk_execute(ASIO_MOVE_ARG(Function) f,
+      std::size_t n, false_type) const;
+
+  /// Bulk execution helper implementation for always blocking.
+  template <typename Function>
+  void do_bulk_execute(ASIO_MOVE_ARG(Function) f,
+      std::size_t n, true_type) const;
+
+  // The underlying thread pool.
+  thread_pool* pool_;
+
+  // The allocator used for execution functions.
+  Allocator allocator_;
+
+  // The runtime-switched properties of the thread pool executor.
+  unsigned int bits_;
+};
+
+#if !defined(GENERATING_DOCUMENTATION)
+
+namespace traits {
+
+#if !defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)
+
+template <typename Allocator, unsigned int Bits>
+struct equality_comparable<
+    asio::thread_pool::basic_executor_type<Allocator, Bits>
+  >
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
+};
+
+#endif // !defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)
+
+#if !defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)
+
+template <typename Allocator, unsigned int Bits, typename Function>
+struct execute_member<
+    asio::thread_pool::basic_executor_type<Allocator, Bits>,
+    Function
+  >
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
+  typedef void result_type;
+};
+
+#endif // !defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)
+
+#if !defined(ASIO_HAS_DEDUCED_SCHEDULE_MEMBER_TRAIT)
+
+template <typename Allocator, unsigned int Bits>
+struct schedule_member<
+    const asio::thread_pool::basic_executor_type<Allocator, Bits>
+  >
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
+  typedef asio::thread_pool::basic_executor_type<
+      Allocator, Bits> result_type;
+};
+
+#endif // !defined(ASIO_HAS_DEDUCED_SCHEDULE_MEMBER_TRAIT)
+
+#if !defined(ASIO_HAS_DEDUCED_CONNECT_MEMBER_TRAIT)
+
+template <typename Allocator, unsigned int Bits, typename Receiver>
+struct connect_member<
+    const asio::thread_pool::basic_executor_type<Allocator, Bits>,
+    Receiver
+  >
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
+  typedef asio::execution::detail::as_operation<
+      asio::thread_pool::basic_executor_type<Allocator, Bits>,
+      Receiver> result_type;
+};
+
+#endif // !defined(ASIO_HAS_DEDUCED_CONNECT_MEMBER_TRAIT)
+
+#if !defined(ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT)
+
+template <typename Allocator, unsigned int Bits>
+struct require_member<
+    asio::thread_pool::basic_executor_type<Allocator, Bits>,
+    asio::execution::blocking_t::possibly_t
+  > : asio::detail::thread_pool_bits
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
+  typedef asio::thread_pool::basic_executor_type<
+      Allocator, Bits & ~blocking_mask> result_type;
+};
+
+template <typename Allocator, unsigned int Bits>
+struct require_member<
+    asio::thread_pool::basic_executor_type<Allocator, Bits>,
+    asio::execution::blocking_t::always_t
+  > : asio::detail::thread_pool_bits
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
+  typedef asio::thread_pool::basic_executor_type<Allocator,
+      (Bits & ~blocking_mask) | blocking_always> result_type;
+};
+
+template <typename Allocator, unsigned int Bits>
+struct require_member<
+    asio::thread_pool::basic_executor_type<Allocator, Bits>,
+    asio::execution::blocking_t::never_t
+  > : asio::detail::thread_pool_bits
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
+  typedef asio::thread_pool::basic_executor_type<
+      Allocator, Bits & ~blocking_mask> result_type;
+};
+
+template <typename Allocator, unsigned int Bits>
+struct require_member<
+    asio::thread_pool::basic_executor_type<Allocator, Bits>,
+    asio::execution::relationship_t::fork_t
+  >
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
+  typedef asio::thread_pool::basic_executor_type<
+      Allocator, Bits> result_type;
+};
+
+template <typename Allocator, unsigned int Bits>
+struct require_member<
+    asio::thread_pool::basic_executor_type<Allocator, Bits>,
+    asio::execution::relationship_t::continuation_t
+  >
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
+  typedef asio::thread_pool::basic_executor_type<
+      Allocator, Bits> result_type;
+};
+
+template <typename Allocator, unsigned int Bits>
+struct require_member<
+    asio::thread_pool::basic_executor_type<Allocator, Bits>,
+    asio::execution::outstanding_work_t::tracked_t
+  > : asio::detail::thread_pool_bits
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
+  typedef asio::thread_pool::basic_executor_type<
+      Allocator, Bits | outstanding_work_tracked> result_type;
+};
+
+template <typename Allocator, unsigned int Bits>
+struct require_member<
+    asio::thread_pool::basic_executor_type<Allocator, Bits>,
+    asio::execution::outstanding_work_t::untracked_t
+  > : asio::detail::thread_pool_bits
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
+  typedef asio::thread_pool::basic_executor_type<
+      Allocator, Bits & ~outstanding_work_tracked> result_type;
+};
+
+template <typename Allocator, unsigned int Bits>
+struct require_member<
+    asio::thread_pool::basic_executor_type<Allocator, Bits>,
+    asio::execution::allocator_t<void>
+  >
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
+  typedef asio::thread_pool::basic_executor_type<
+      std::allocator<void>, Bits> result_type;
+};
+
+template <unsigned int Bits,
+    typename Allocator, typename OtherAllocator>
+struct require_member<
+    asio::thread_pool::basic_executor_type<Allocator, Bits>,
+    asio::execution::allocator_t<OtherAllocator>
+  >
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
+  typedef asio::thread_pool::basic_executor_type<
+      OtherAllocator, Bits> result_type;
+};
+
+#endif // !defined(ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT)
+
+#if !defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT)
+
+template <typename Allocator, unsigned int Bits, typename Property>
+struct query_static_constexpr_member<
+    asio::thread_pool::basic_executor_type<Allocator, Bits>,
+    Property,
+    typename asio::enable_if<
+      asio::is_convertible<
+        Property,
+        asio::execution::bulk_guarantee_t
+      >::value
+    >::type
+  >
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
+  typedef asio::execution::bulk_guarantee_t::parallel_t result_type;
+
+  static ASIO_CONSTEXPR result_type value() ASIO_NOEXCEPT
+  {
+    return result_type();
+  }
+};
+
+template <typename Allocator, unsigned int Bits, typename Property>
+struct query_static_constexpr_member<
+    asio::thread_pool::basic_executor_type<Allocator, Bits>,
+    Property,
+    typename asio::enable_if<
+      asio::is_convertible<
+        Property,
+        asio::execution::outstanding_work_t
+      >::value
+    >::type
+  > : asio::detail::thread_pool_bits
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
+  typedef asio::execution::outstanding_work_t result_type;
+
+  static ASIO_CONSTEXPR result_type value() ASIO_NOEXCEPT
+  {
+    return (Bits & outstanding_work_tracked)
+      ? execution::outstanding_work_t(execution::outstanding_work.tracked)
+      : execution::outstanding_work_t(execution::outstanding_work.untracked);
+  }
+};
+
+template <typename Allocator, unsigned int Bits, typename Property>
+struct query_static_constexpr_member<
+    asio::thread_pool::basic_executor_type<Allocator, Bits>,
+    Property,
+    typename asio::enable_if<
+      asio::is_convertible<
+        Property,
+        asio::execution::mapping_t
+      >::value
+    >::type
+  >
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
+  typedef asio::execution::mapping_t::thread_t result_type;
+
+  static ASIO_CONSTEXPR result_type value() ASIO_NOEXCEPT
+  {
+    return result_type();
+  }
+};
+
+#endif // !defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT)
+
+#if !defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT)
+
+template <typename Allocator, unsigned int Bits, typename Property>
+struct query_member<
+    asio::thread_pool::basic_executor_type<Allocator, Bits>,
+    Property,
+    typename asio::enable_if<
+      asio::is_convertible<
+        Property,
+        asio::execution::blocking_t
+      >::value
+    >::type
+  >
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
+  typedef asio::execution::blocking_t result_type;
+};
+
+template <typename Allocator, unsigned int Bits, typename Property>
+struct query_member<
+    asio::thread_pool::basic_executor_type<Allocator, Bits>,
+    Property,
+    typename asio::enable_if<
+      asio::is_convertible<
+        Property,
+        asio::execution::relationship_t
+      >::value
+    >::type
+  >
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
+  typedef asio::execution::relationship_t result_type;
+};
+
+template <typename Allocator, unsigned int Bits>
+struct query_member<
+    asio::thread_pool::basic_executor_type<Allocator, Bits>,
+    asio::execution::occupancy_t
+  >
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
+  typedef std::size_t result_type;
+};
+
+template <typename Allocator, unsigned int Bits>
+struct query_member<
+    asio::thread_pool::basic_executor_type<Allocator, Bits>,
+    asio::execution::context_t
+  >
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
+  typedef asio::thread_pool& result_type;
+};
+
+template <typename Allocator, unsigned int Bits>
+struct query_member<
+    asio::thread_pool::basic_executor_type<Allocator, Bits>,
+    asio::execution::allocator_t<void>
+  >
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
+  typedef Allocator result_type;
+};
+
+template <typename Allocator, unsigned int Bits, typename OtherAllocator>
+struct query_member<
+    asio::thread_pool::basic_executor_type<Allocator, Bits>,
+    asio::execution::allocator_t<OtherAllocator>
+  >
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
+  typedef Allocator result_type;
+};
+
+#endif // !defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT)
+
+} // namespace traits
+
+#endif // !defined(GENERATING_DOCUMENTATION)
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/impl/thread_pool.hpp"
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/impl/thread_pool.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // ASIO_THREAD_POOL_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/time_traits.hpp b/link/modules/asio-standalone/asio/include/asio/time_traits.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/time_traits.hpp
@@ -0,0 +1,86 @@
+//
+// time_traits.hpp
+// ~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_TIME_TRAITS_HPP
+#define ASIO_TIME_TRAITS_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/socket_types.hpp" // Must come before posix_time.
+
+#if defined(ASIO_HAS_BOOST_DATE_TIME) \
+  || defined(GENERATING_DOCUMENTATION)
+
+#include <boost/date_time/posix_time/posix_time_types.hpp>
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+/// Time traits suitable for use with the deadline timer.
+template <typename Time>
+struct time_traits;
+
+/// Time traits specialised for posix_time.
+template <>
+struct time_traits<boost::posix_time::ptime>
+{
+  /// The time type.
+  typedef boost::posix_time::ptime time_type;
+
+  /// The duration type.
+  typedef boost::posix_time::time_duration duration_type;
+
+  /// Get the current time.
+  static time_type now()
+  {
+#if defined(BOOST_DATE_TIME_HAS_HIGH_PRECISION_CLOCK)
+    return boost::posix_time::microsec_clock::universal_time();
+#else // defined(BOOST_DATE_TIME_HAS_HIGH_PRECISION_CLOCK)
+    return boost::posix_time::second_clock::universal_time();
+#endif // defined(BOOST_DATE_TIME_HAS_HIGH_PRECISION_CLOCK)
+  }
+
+  /// Add a duration to a time.
+  static time_type add(const time_type& t, const duration_type& d)
+  {
+    return t + d;
+  }
+
+  /// Subtract one time from another.
+  static duration_type subtract(const time_type& t1, const time_type& t2)
+  {
+    return t1 - t2;
+  }
+
+  /// Test whether one time is less than another.
+  static bool less_than(const time_type& t1, const time_type& t2)
+  {
+    return t1 < t2;
+  }
+
+  /// Convert to POSIX duration type.
+  static boost::posix_time::time_duration to_posix_duration(
+      const duration_type& d)
+  {
+    return d;
+  }
+};
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_BOOST_DATE_TIME)
+       // || defined(GENERATING_DOCUMENTATION)
+
+#endif // ASIO_TIME_TRAITS_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/traits/bulk_execute_free.hpp b/link/modules/asio-standalone/asio/include/asio/traits/bulk_execute_free.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/traits/bulk_execute_free.hpp
@@ -0,0 +1,114 @@
+//
+// traits/bulk_execute_free.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_TRAITS_BULK_EXECUTE_FREE_HPP
+#define ASIO_TRAITS_BULK_EXECUTE_FREE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/type_traits.hpp"
+
+#if defined(ASIO_HAS_DECLTYPE) \
+  && defined(ASIO_HAS_NOEXCEPT) \
+  && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)
+# define ASIO_HAS_DEDUCED_BULK_EXECUTE_FREE_TRAIT 1
+#endif // defined(ASIO_HAS_DECLTYPE)
+       //   && defined(ASIO_HAS_NOEXCEPT)
+       //   && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace traits {
+
+template <typename T, typename F, typename N, typename = void>
+struct bulk_execute_free_default;
+
+template <typename T, typename F, typename N, typename = void>
+struct bulk_execute_free;
+
+} // namespace traits
+namespace detail {
+
+struct no_bulk_execute_free
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = false);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
+};
+
+#if defined(ASIO_HAS_DEDUCED_BULK_EXECUTE_FREE_TRAIT)
+
+template <typename T, typename F, typename N, typename = void>
+struct bulk_execute_free_trait : no_bulk_execute_free
+{
+};
+
+template <typename T, typename F, typename N>
+struct bulk_execute_free_trait<T, F, N,
+  typename void_type<
+    decltype(bulk_execute(declval<T>(), declval<F>(), declval<N>()))
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+
+  using result_type = decltype(
+    bulk_execute(declval<T>(), declval<F>(), declval<N>()));
+
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = noexcept(
+    bulk_execute(declval<T>(), declval<F>(), declval<N>())));
+};
+
+#else // defined(ASIO_HAS_DEDUCED_BULK_EXECUTE_FREE_TRAIT)
+
+template <typename T, typename F, typename N, typename = void>
+struct bulk_execute_free_trait :
+  conditional<
+    is_same<T, typename remove_reference<T>::type>::value
+      && is_same<F, typename decay<F>::type>::value
+      && is_same<N, typename decay<N>::type>::value,
+    typename conditional<
+      is_same<T, typename add_const<T>::type>::value,
+      no_bulk_execute_free,
+      traits::bulk_execute_free<typename add_const<T>::type, F, N>
+    >::type,
+    traits::bulk_execute_free<
+      typename remove_reference<T>::type,
+      typename decay<F>::type,
+      typename decay<N>::type>
+  >::type
+{
+};
+
+#endif // defined(ASIO_HAS_DEDUCED_BULK_EXECUTE_FREE_TRAIT)
+
+} // namespace detail
+namespace traits {
+
+template <typename T, typename F, typename N, typename>
+struct bulk_execute_free_default :
+  detail::bulk_execute_free_trait<T, F, N>
+{
+};
+
+template <typename T, typename F, typename N, typename>
+struct bulk_execute_free :
+  bulk_execute_free_default<T, F, N>
+{
+};
+
+} // namespace traits
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_TRAITS_BULK_EXECUTE_FREE_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/traits/bulk_execute_member.hpp b/link/modules/asio-standalone/asio/include/asio/traits/bulk_execute_member.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/traits/bulk_execute_member.hpp
@@ -0,0 +1,114 @@
+//
+// traits/bulk_execute_member.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_TRAITS_BULK_EXECUTE_MEMBER_HPP
+#define ASIO_TRAITS_BULK_EXECUTE_MEMBER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/type_traits.hpp"
+
+#if defined(ASIO_HAS_DECLTYPE) \
+  && defined(ASIO_HAS_NOEXCEPT) \
+  && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)
+# define ASIO_HAS_DEDUCED_BULK_EXECUTE_MEMBER_TRAIT 1
+#endif // defined(ASIO_HAS_DECLTYPE)
+       //   && defined(ASIO_HAS_NOEXCEPT)
+       //   && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace traits {
+
+template <typename T, typename F, typename N, typename = void>
+struct bulk_execute_member_default;
+
+template <typename T, typename F, typename N, typename = void>
+struct bulk_execute_member;
+
+} // namespace traits
+namespace detail {
+
+struct no_bulk_execute_member
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = false);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
+};
+
+#if defined(ASIO_HAS_DEDUCED_BULK_EXECUTE_MEMBER_TRAIT)
+
+template <typename T, typename F, typename N, typename = void>
+struct bulk_execute_member_trait : no_bulk_execute_member
+{
+};
+
+template <typename T, typename F, typename N>
+struct bulk_execute_member_trait<T, F, N,
+  typename void_type<
+    decltype(declval<T>().bulk_execute(declval<F>(), declval<N>()))
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+
+  using result_type = decltype(
+    declval<T>().bulk_execute(declval<F>(), declval<N>()));
+
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = noexcept(
+    declval<T>().bulk_execute(declval<F>(), declval<N>())));
+};
+
+#else // defined(ASIO_HAS_DEDUCED_BULK_EXECUTE_MEMBER_TRAIT)
+
+template <typename T, typename F, typename N, typename = void>
+struct bulk_execute_member_trait :
+  conditional<
+    is_same<T, typename remove_reference<T>::type>::value
+      && is_same<F, typename decay<F>::type>::value
+      && is_same<N, typename decay<N>::type>::value,
+    typename conditional<
+      is_same<T, typename add_const<T>::type>::value,
+      no_bulk_execute_member,
+      traits::bulk_execute_member<typename add_const<T>::type, F, N>
+    >::type,
+    traits::bulk_execute_member<
+      typename remove_reference<T>::type,
+      typename decay<F>::type,
+      typename decay<N>::type>
+  >::type
+{
+};
+
+#endif // defined(ASIO_HAS_DEDUCED_BULK_EXECUTE_MEMBER_TRAIT)
+
+} // namespace detail
+namespace traits {
+
+template <typename T, typename F, typename N, typename>
+struct bulk_execute_member_default :
+  detail::bulk_execute_member_trait<T, F, N>
+{
+};
+
+template <typename T, typename F, typename N, typename>
+struct bulk_execute_member :
+  bulk_execute_member_default<T, F, N>
+{
+};
+
+} // namespace traits
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_TRAITS_BULK_EXECUTE_MEMBER_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/traits/connect_free.hpp b/link/modules/asio-standalone/asio/include/asio/traits/connect_free.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/traits/connect_free.hpp
@@ -0,0 +1,112 @@
+//
+// traits/connect_free.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_TRAITS_CONNECT_FREE_HPP
+#define ASIO_TRAITS_CONNECT_FREE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/type_traits.hpp"
+
+#if defined(ASIO_HAS_DECLTYPE) \
+  && defined(ASIO_HAS_NOEXCEPT) \
+  && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)
+# define ASIO_HAS_DEDUCED_CONNECT_FREE_TRAIT 1
+#endif // defined(ASIO_HAS_DECLTYPE)
+       //   && defined(ASIO_HAS_NOEXCEPT)
+       //   && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace traits {
+
+template <typename S, typename R, typename = void>
+struct connect_free_default;
+
+template <typename S, typename R, typename = void>
+struct connect_free;
+
+} // namespace traits
+namespace detail {
+
+struct no_connect_free
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = false);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
+};
+
+#if defined(ASIO_HAS_DEDUCED_CONNECT_FREE_TRAIT)
+
+template <typename S, typename R, typename = void>
+struct connect_free_trait : no_connect_free
+{
+};
+
+template <typename S, typename R>
+struct connect_free_trait<S, R,
+  typename void_type<
+    decltype(connect(declval<S>(), declval<R>()))
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+
+  using result_type = decltype(
+    connect(declval<S>(), declval<R>()));
+
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = noexcept(
+    connect(declval<S>(), declval<R>())));
+};
+
+#else // defined(ASIO_HAS_DEDUCED_CONNECT_FREE_TRAIT)
+
+template <typename S, typename R, typename = void>
+struct connect_free_trait :
+  conditional<
+    is_same<S, typename remove_reference<S>::type>::value
+      && is_same<R, typename decay<R>::type>::value,
+    typename conditional<
+      is_same<S, typename add_const<S>::type>::value,
+      no_connect_free,
+      traits::connect_free<typename add_const<S>::type, R>
+    >::type,
+    traits::connect_free<
+      typename remove_reference<S>::type,
+      typename decay<R>::type>
+  >::type
+{
+};
+
+#endif // defined(ASIO_HAS_DEDUCED_CONNECT_FREE_TRAIT)
+
+} // namespace detail
+namespace traits {
+
+template <typename S, typename R, typename>
+struct connect_free_default :
+  detail::connect_free_trait<S, R>
+{
+};
+
+template <typename S, typename R, typename>
+struct connect_free :
+  connect_free_default<S, R>
+{
+};
+
+} // namespace traits
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_TRAITS_CONNECT_FREE_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/traits/connect_member.hpp b/link/modules/asio-standalone/asio/include/asio/traits/connect_member.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/traits/connect_member.hpp
@@ -0,0 +1,112 @@
+//
+// traits/connect_member.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_TRAITS_CONNECT_MEMBER_HPP
+#define ASIO_TRAITS_CONNECT_MEMBER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/type_traits.hpp"
+
+#if defined(ASIO_HAS_DECLTYPE) \
+  && defined(ASIO_HAS_NOEXCEPT) \
+  && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)
+# define ASIO_HAS_DEDUCED_CONNECT_MEMBER_TRAIT 1
+#endif // defined(ASIO_HAS_DECLTYPE)
+       //   && defined(ASIO_HAS_NOEXCEPT)
+       //   && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace traits {
+
+template <typename S, typename R, typename = void>
+struct connect_member_default;
+
+template <typename S, typename R, typename = void>
+struct connect_member;
+
+} // namespace traits
+namespace detail {
+
+struct no_connect_member
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = false);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
+};
+
+#if defined(ASIO_HAS_DEDUCED_CONNECT_MEMBER_TRAIT)
+
+template <typename S, typename R, typename = void>
+struct connect_member_trait : no_connect_member
+{
+};
+
+template <typename S, typename R>
+struct connect_member_trait<S, R,
+  typename void_type<
+    decltype(declval<S>().connect(declval<R>()))
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+
+  using result_type = decltype(
+    declval<S>().connect(declval<R>()));
+
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = noexcept(
+    declval<S>().connect(declval<R>())));
+};
+
+#else // defined(ASIO_HAS_DEDUCED_CONNECT_MEMBER_TRAIT)
+
+template <typename S, typename R, typename = void>
+struct connect_member_trait :
+  conditional<
+    is_same<S, typename remove_reference<S>::type>::value
+      && is_same<R, typename decay<R>::type>::value,
+    typename conditional<
+      is_same<S, typename add_const<S>::type>::value,
+      no_connect_member,
+      traits::connect_member<typename add_const<S>::type, R>
+    >::type,
+    traits::connect_member<
+      typename remove_reference<S>::type,
+      typename decay<R>::type>
+  >::type
+{
+};
+
+#endif // defined(ASIO_HAS_DEDUCED_CONNECT_MEMBER_TRAIT)
+
+} // namespace detail
+namespace traits {
+
+template <typename S, typename R, typename>
+struct connect_member_default :
+  detail::connect_member_trait<S, R>
+{
+};
+
+template <typename S, typename R, typename>
+struct connect_member :
+  connect_member_default<S, R>
+{
+};
+
+} // namespace traits
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_TRAITS_CONNECT_MEMBER_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/traits/equality_comparable.hpp b/link/modules/asio-standalone/asio/include/asio/traits/equality_comparable.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/traits/equality_comparable.hpp
@@ -0,0 +1,100 @@
+//
+// traits/equality_comparable.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_TRAITS_EQUALITY_COMPARABLE_HPP
+#define ASIO_TRAITS_EQUALITY_COMPARABLE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/type_traits.hpp"
+
+#if defined(ASIO_HAS_DECLTYPE) \
+  && defined(ASIO_HAS_NOEXCEPT) \
+  && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)
+# define ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT 1
+#endif // defined(ASIO_HAS_DECLTYPE)
+       //   && defined(ASIO_HAS_NOEXCEPT)
+       //   && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)
+
+namespace asio {
+namespace traits {
+
+template <typename T, typename = void>
+struct equality_comparable_default;
+
+template <typename T, typename = void>
+struct equality_comparable;
+
+} // namespace traits
+namespace detail {
+
+struct no_equality_comparable
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = false);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
+};
+
+#if defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)
+
+template <typename T, typename = void>
+struct equality_comparable_trait : no_equality_comparable
+{
+};
+
+template <typename T>
+struct equality_comparable_trait<T,
+  typename void_type<
+    decltype(
+      static_cast<bool>(declval<const T>() == declval<const T>()),
+      static_cast<bool>(declval<const T>() != declval<const T>())
+    )
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept =
+    noexcept(declval<const T>() == declval<const T>())
+      && noexcept(declval<const T>() != declval<const T>()));
+};
+
+#else // defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)
+
+template <typename T, typename = void>
+struct equality_comparable_trait :
+  conditional<
+    is_same<T, typename decay<T>::type>::value,
+    no_equality_comparable,
+    traits::equality_comparable<typename decay<T>::type>
+  >::type
+{
+};
+
+#endif // defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)
+
+} // namespace detail
+namespace traits {
+
+template <typename T, typename>
+struct equality_comparable_default : detail::equality_comparable_trait<T>
+{
+};
+
+template <typename T, typename>
+struct equality_comparable : equality_comparable_default<T>
+{
+};
+
+} // namespace traits
+} // namespace asio
+
+#endif // ASIO_TRAITS_EQUALITY_COMPARABLE_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/traits/execute_free.hpp b/link/modules/asio-standalone/asio/include/asio/traits/execute_free.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/traits/execute_free.hpp
@@ -0,0 +1,108 @@
+//
+// traits/execute_free.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_TRAITS_EXECUTE_FREE_HPP
+#define ASIO_TRAITS_EXECUTE_FREE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/type_traits.hpp"
+
+#if defined(ASIO_HAS_DECLTYPE) \
+  && defined(ASIO_HAS_NOEXCEPT) \
+  && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)
+# define ASIO_HAS_DEDUCED_EXECUTE_FREE_TRAIT 1
+#endif // defined(ASIO_HAS_DECLTYPE)
+       //   && defined(ASIO_HAS_NOEXCEPT)
+       //   && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace traits {
+
+template <typename T, typename F, typename = void>
+struct execute_free_default;
+
+template <typename T, typename F, typename = void>
+struct execute_free;
+
+} // namespace traits
+namespace detail {
+
+struct no_execute_free
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = false);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
+};
+
+#if defined(ASIO_HAS_DEDUCED_EXECUTE_FREE_TRAIT)
+
+template <typename T, typename F, typename = void>
+struct execute_free_trait : no_execute_free
+{
+};
+
+template <typename T, typename F>
+struct execute_free_trait<T, F,
+  typename void_type<
+    decltype(execute(declval<T>(), declval<F>()))
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+
+  using result_type = decltype(
+    execute(declval<T>(), declval<F>()));
+
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = noexcept(
+    execute(declval<T>(), declval<F>())));
+};
+
+#else // defined(ASIO_HAS_DEDUCED_EXECUTE_FREE_TRAIT)
+
+template <typename T, typename F, typename = void>
+struct execute_free_trait :
+  conditional<
+    is_same<T, typename decay<T>::type>::value
+      && is_same<F, typename decay<F>::type>::value,
+    no_execute_free,
+    traits::execute_free<
+      typename decay<T>::type,
+      typename decay<F>::type>
+  >::type
+{
+};
+
+#endif // defined(ASIO_HAS_DEDUCED_EXECUTE_FREE_TRAIT)
+
+} // namespace detail
+namespace traits {
+
+template <typename T, typename F, typename>
+struct execute_free_default :
+  detail::execute_free_trait<T, F>
+{
+};
+
+template <typename T, typename F, typename>
+struct execute_free :
+  execute_free_default<T, F>
+{
+};
+
+} // namespace traits
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_TRAITS_EXECUTE_FREE_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/traits/execute_member.hpp b/link/modules/asio-standalone/asio/include/asio/traits/execute_member.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/traits/execute_member.hpp
@@ -0,0 +1,108 @@
+//
+// traits/execute_member.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_TRAITS_EXECUTE_MEMBER_HPP
+#define ASIO_TRAITS_EXECUTE_MEMBER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/type_traits.hpp"
+
+#if defined(ASIO_HAS_DECLTYPE) \
+  && defined(ASIO_HAS_NOEXCEPT) \
+  && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)
+# define ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT 1
+#endif // defined(ASIO_HAS_DECLTYPE)
+       //   && defined(ASIO_HAS_NOEXCEPT)
+       //   && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace traits {
+
+template <typename T, typename F, typename = void>
+struct execute_member_default;
+
+template <typename T, typename F, typename = void>
+struct execute_member;
+
+} // namespace traits
+namespace detail {
+
+struct no_execute_member
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = false);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
+};
+
+#if defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)
+
+template <typename T, typename F, typename = void>
+struct execute_member_trait : no_execute_member
+{
+};
+
+template <typename T, typename F>
+struct execute_member_trait<T, F,
+  typename void_type<
+    decltype(declval<T>().execute(declval<F>()))
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+
+  using result_type = decltype(
+    declval<T>().execute(declval<F>()));
+
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = noexcept(
+    declval<T>().execute(declval<F>())));
+};
+
+#else // defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)
+
+template <typename T, typename F, typename = void>
+struct execute_member_trait :
+  conditional<
+    is_same<T, typename decay<T>::type>::value
+      && is_same<F, typename decay<F>::type>::value,
+    no_execute_member,
+    traits::execute_member<
+      typename decay<T>::type,
+      typename decay<F>::type>
+  >::type
+{
+};
+
+#endif // defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)
+
+} // namespace detail
+namespace traits {
+
+template <typename T, typename F, typename>
+struct execute_member_default :
+  detail::execute_member_trait<T, F>
+{
+};
+
+template <typename T, typename F, typename>
+struct execute_member :
+  execute_member_default<T, F>
+{
+};
+
+} // namespace traits
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_TRAITS_EXECUTE_MEMBER_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/traits/prefer_free.hpp b/link/modules/asio-standalone/asio/include/asio/traits/prefer_free.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/traits/prefer_free.hpp
@@ -0,0 +1,108 @@
+//
+// traits/prefer_free.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_TRAITS_PREFER_FREE_HPP
+#define ASIO_TRAITS_PREFER_FREE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/type_traits.hpp"
+
+#if defined(ASIO_HAS_DECLTYPE) \
+  && defined(ASIO_HAS_NOEXCEPT) \
+  && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)
+# define ASIO_HAS_DEDUCED_PREFER_FREE_TRAIT 1
+#endif // defined(ASIO_HAS_DECLTYPE)
+       //   && defined(ASIO_HAS_NOEXCEPT)
+       //   && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace traits {
+
+template <typename T, typename Property, typename = void>
+struct prefer_free_default;
+
+template <typename T, typename Property, typename = void>
+struct prefer_free;
+
+} // namespace traits
+namespace detail {
+
+struct no_prefer_free
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = false);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
+};
+
+#if defined(ASIO_HAS_DEDUCED_PREFER_FREE_TRAIT)
+
+template <typename T, typename Property, typename = void>
+struct prefer_free_trait : no_prefer_free
+{
+};
+
+template <typename T, typename Property>
+struct prefer_free_trait<T, Property,
+  typename void_type<
+    decltype(prefer(declval<T>(), declval<Property>()))
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+
+  using result_type = decltype(
+    prefer(declval<T>(), declval<Property>()));
+
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = noexcept(
+    prefer(declval<T>(), declval<Property>())));
+};
+
+#else // defined(ASIO_HAS_DEDUCED_PREFER_FREE_TRAIT)
+
+template <typename T, typename Property, typename = void>
+struct prefer_free_trait :
+  conditional<
+    is_same<T, typename decay<T>::type>::value
+      && is_same<Property, typename decay<Property>::type>::value,
+    no_prefer_free,
+    traits::prefer_free<
+      typename decay<T>::type,
+      typename decay<Property>::type>
+  >::type
+{
+};
+
+#endif // defined(ASIO_HAS_DEDUCED_PREFER_FREE_TRAIT)
+
+} // namespace detail
+namespace traits {
+
+template <typename T, typename Property, typename>
+struct prefer_free_default :
+  detail::prefer_free_trait<T, Property>
+{
+};
+
+template <typename T, typename Property, typename>
+struct prefer_free :
+  prefer_free_default<T, Property>
+{
+};
+
+} // namespace traits
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_TRAITS_PREFER_FREE_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/traits/prefer_member.hpp b/link/modules/asio-standalone/asio/include/asio/traits/prefer_member.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/traits/prefer_member.hpp
@@ -0,0 +1,108 @@
+//
+// traits/prefer_member.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_TRAITS_PREFER_MEMBER_HPP
+#define ASIO_TRAITS_PREFER_MEMBER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/type_traits.hpp"
+
+#if defined(ASIO_HAS_DECLTYPE) \
+  && defined(ASIO_HAS_NOEXCEPT) \
+  && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)
+# define ASIO_HAS_DEDUCED_PREFER_MEMBER_TRAIT 1
+#endif // defined(ASIO_HAS_DECLTYPE)
+       //   && defined(ASIO_HAS_NOEXCEPT)
+       //   && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace traits {
+
+template <typename T, typename Property, typename = void>
+struct prefer_member_default;
+
+template <typename T, typename Property, typename = void>
+struct prefer_member;
+
+} // namespace traits
+namespace detail {
+
+struct no_prefer_member
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = false);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
+};
+
+#if defined(ASIO_HAS_DEDUCED_PREFER_MEMBER_TRAIT)
+
+template <typename T, typename Property, typename = void>
+struct prefer_member_trait : no_prefer_member
+{
+};
+
+template <typename T, typename Property>
+struct prefer_member_trait<T, Property,
+  typename void_type<
+    decltype(declval<T>().prefer(declval<Property>()))
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+
+  using result_type = decltype(
+    declval<T>().prefer(declval<Property>()));
+
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = noexcept(
+    declval<T>().prefer(declval<Property>())));
+};
+
+#else // defined(ASIO_HAS_DEDUCED_PREFER_MEMBER_TRAIT)
+
+template <typename T, typename Property, typename = void>
+struct prefer_member_trait :
+  conditional<
+    is_same<T, typename decay<T>::type>::value
+      && is_same<Property, typename decay<Property>::type>::value,
+    no_prefer_member,
+    traits::prefer_member<
+      typename decay<T>::type,
+      typename decay<Property>::type>
+  >::type
+{
+};
+
+#endif // defined(ASIO_HAS_DEDUCED_PREFER_MEMBER_TRAIT)
+
+} // namespace detail
+namespace traits {
+
+template <typename T, typename Property, typename>
+struct prefer_member_default :
+  detail::prefer_member_trait<T, Property>
+{
+};
+
+template <typename T, typename Property, typename>
+struct prefer_member :
+  prefer_member_default<T, Property>
+{
+};
+
+} // namespace traits
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_TRAITS_PREFER_MEMBER_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/traits/query_free.hpp b/link/modules/asio-standalone/asio/include/asio/traits/query_free.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/traits/query_free.hpp
@@ -0,0 +1,108 @@
+//
+// traits/query_free.hpp
+// ~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_TRAITS_QUERY_FREE_HPP
+#define ASIO_TRAITS_QUERY_FREE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/type_traits.hpp"
+
+#if defined(ASIO_HAS_DECLTYPE) \
+  && defined(ASIO_HAS_NOEXCEPT) \
+  && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)
+# define ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT 1
+#endif // defined(ASIO_HAS_DECLTYPE)
+       //   && defined(ASIO_HAS_NOEXCEPT)
+       //   && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace traits {
+
+template <typename T, typename Property, typename = void>
+struct query_free_default;
+
+template <typename T, typename Property, typename = void>
+struct query_free;
+
+} // namespace traits
+namespace detail {
+
+struct no_query_free
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = false);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
+};
+
+#if defined(ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT)
+
+template <typename T, typename Property, typename = void>
+struct query_free_trait : no_query_free
+{
+};
+
+template <typename T, typename Property>
+struct query_free_trait<T, Property,
+  typename void_type<
+    decltype(query(declval<T>(), declval<Property>()))
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+
+  using result_type = decltype(
+    query(declval<T>(), declval<Property>()));
+
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = noexcept(
+    query(declval<T>(), declval<Property>())));
+};
+
+#else // defined(ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT)
+
+template <typename T, typename Property, typename = void>
+struct query_free_trait :
+  conditional<
+    is_same<T, typename decay<T>::type>::value
+      && is_same<Property, typename decay<Property>::type>::value,
+    no_query_free,
+    traits::query_free<
+      typename decay<T>::type,
+      typename decay<Property>::type>
+  >::type
+{
+};
+
+#endif // defined(ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT)
+
+} // namespace detail
+namespace traits {
+
+template <typename T, typename Property, typename>
+struct query_free_default :
+  detail::query_free_trait<T, Property>
+{
+};
+
+template <typename T, typename Property, typename>
+struct query_free :
+  query_free_default<T, Property>
+{
+};
+
+} // namespace traits
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_TRAITS_QUERY_FREE_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/traits/query_member.hpp b/link/modules/asio-standalone/asio/include/asio/traits/query_member.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/traits/query_member.hpp
@@ -0,0 +1,108 @@
+//
+// traits/query_member.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_TRAITS_QUERY_MEMBER_HPP
+#define ASIO_TRAITS_QUERY_MEMBER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/type_traits.hpp"
+
+#if defined(ASIO_HAS_DECLTYPE) \
+  && defined(ASIO_HAS_NOEXCEPT) \
+  && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)
+# define ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT 1
+#endif // defined(ASIO_HAS_DECLTYPE)
+       //   && defined(ASIO_HAS_NOEXCEPT)
+       //   && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace traits {
+
+template <typename T, typename Property, typename = void>
+struct query_member_default;
+
+template <typename T, typename Property, typename = void>
+struct query_member;
+
+} // namespace traits
+namespace detail {
+
+struct no_query_member
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = false);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
+};
+
+#if defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT)
+
+template <typename T, typename Property, typename = void>
+struct query_member_trait : no_query_member
+{
+};
+
+template <typename T, typename Property>
+struct query_member_trait<T, Property,
+  typename void_type<
+    decltype(declval<T>().query(declval<Property>()))
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+
+  using result_type = decltype(
+    declval<T>().query(declval<Property>()));
+
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = noexcept(
+    declval<T>().query(declval<Property>())));
+};
+
+#else // defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT)
+
+template <typename T, typename Property, typename = void>
+struct query_member_trait :
+  conditional<
+    is_same<T, typename decay<T>::type>::value
+      && is_same<Property, typename decay<Property>::type>::value,
+    no_query_member,
+    traits::query_member<
+      typename decay<T>::type,
+      typename decay<Property>::type>
+  >::type
+{
+};
+
+#endif // defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT)
+
+} // namespace detail
+namespace traits {
+
+template <typename T, typename Property, typename>
+struct query_member_default :
+  detail::query_member_trait<T, Property>
+{
+};
+
+template <typename T, typename Property, typename>
+struct query_member :
+  query_member_default<T, Property>
+{
+};
+
+} // namespace traits
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_TRAITS_QUERY_MEMBER_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/traits/query_static_constexpr_member.hpp b/link/modules/asio-standalone/asio/include/asio/traits/query_static_constexpr_member.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/traits/query_static_constexpr_member.hpp
@@ -0,0 +1,108 @@
+//
+// traits/query_static_constexpr_member.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_TRAITS_QUERY_STATIC_CONSTEXPR_MEMBER_HPP
+#define ASIO_TRAITS_QUERY_STATIC_CONSTEXPR_MEMBER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/type_traits.hpp"
+
+#if defined(ASIO_HAS_DECLTYPE) \
+  && defined(ASIO_HAS_NOEXCEPT) \
+  && defined(ASIO_HAS_CONSTEXPR) \
+  && defined(ASIO_HAS_CONSTANT_EXPRESSION_SFINAE) \
+  && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)
+# define ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT 1
+#endif // defined(ASIO_HAS_DECLTYPE)
+       //   && defined(ASIO_HAS_NOEXCEPT)
+       //   && defined(ASIO_HAS_CONSTEXPR)
+       //   && defined(ASIO_HAS_CONSTANT_EXPRESSION_SFINAE)
+       //   && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace traits {
+
+template <typename T, typename Property, typename = void>
+struct query_static_constexpr_member_default;
+
+template <typename T, typename Property, typename = void>
+struct query_static_constexpr_member;
+
+} // namespace traits
+namespace detail {
+
+struct no_query_static_constexpr_member
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = false);
+};
+
+template <typename T, typename Property, typename = void>
+struct query_static_constexpr_member_trait :
+  conditional<
+    is_same<T, typename decay<T>::type>::value
+      && is_same<Property, typename decay<Property>::type>::value,
+    no_query_static_constexpr_member,
+    traits::query_static_constexpr_member<
+      typename decay<T>::type,
+      typename decay<Property>::type>
+  >::type
+{
+};
+
+#if defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT)
+
+template <typename T, typename Property>
+struct query_static_constexpr_member_trait<T, Property,
+  typename enable_if<
+    (static_cast<void>(T::query(Property{})), true)
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+
+  using result_type = decltype(T::query(Property{}));
+
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept =
+    noexcept(T::query(Property{})));
+
+  static ASIO_CONSTEXPR result_type value() noexcept(is_noexcept)
+  {
+    return T::query(Property{});
+  }
+};
+
+#endif // defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT)
+
+} // namespace detail
+namespace traits {
+
+template <typename T, typename Property, typename>
+struct query_static_constexpr_member_default :
+  detail::query_static_constexpr_member_trait<T, Property>
+{
+};
+
+template <typename T, typename Property, typename>
+struct query_static_constexpr_member :
+  query_static_constexpr_member_default<T, Property>
+{
+};
+
+} // namespace traits
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_TRAITS_QUERY_STATIC_CONSTEXPR_MEMBER_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/traits/require_concept_free.hpp b/link/modules/asio-standalone/asio/include/asio/traits/require_concept_free.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/traits/require_concept_free.hpp
@@ -0,0 +1,108 @@
+//
+// traits/require_concept_free.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_TRAITS_REQUIRE_CONCEPT_FREE_HPP
+#define ASIO_TRAITS_REQUIRE_CONCEPT_FREE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/type_traits.hpp"
+
+#if defined(ASIO_HAS_DECLTYPE) \
+  && defined(ASIO_HAS_NOEXCEPT) \
+  && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)
+# define ASIO_HAS_DEDUCED_REQUIRE_CONCEPT_FREE_TRAIT 1
+#endif // defined(ASIO_HAS_DECLTYPE)
+       //   && defined(ASIO_HAS_NOEXCEPT)
+       //   && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace traits {
+
+template <typename T, typename Property, typename = void>
+struct require_concept_free_default;
+
+template <typename T, typename Property, typename = void>
+struct require_concept_free;
+
+} // namespace traits
+namespace detail {
+
+struct no_require_concept_free
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = false);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
+};
+
+#if defined(ASIO_HAS_DEDUCED_REQUIRE_CONCEPT_FREE_TRAIT)
+
+template <typename T, typename Property, typename = void>
+struct require_concept_free_trait : no_require_concept_free
+{
+};
+
+template <typename T, typename Property>
+struct require_concept_free_trait<T, Property,
+  typename void_type<
+    decltype(require_concept(declval<T>(), declval<Property>()))
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+
+  using result_type = decltype(
+    require_concept(declval<T>(), declval<Property>()));
+
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = noexcept(
+    require_concept(declval<T>(), declval<Property>())));
+};
+
+#else // defined(ASIO_HAS_DEDUCED_REQUIRE_CONCEPT_FREE_TRAIT)
+
+template <typename T, typename Property, typename = void>
+struct require_concept_free_trait :
+  conditional<
+    is_same<T, typename decay<T>::type>::value
+      && is_same<Property, typename decay<Property>::type>::value,
+    no_require_concept_free,
+    traits::require_concept_free<
+      typename decay<T>::type,
+      typename decay<Property>::type>
+  >::type
+{
+};
+
+#endif // defined(ASIO_HAS_DEDUCED_REQUIRE_CONCEPT_FREE_TRAIT)
+
+} // namespace detail
+namespace traits {
+
+template <typename T, typename Property, typename>
+struct require_concept_free_default :
+  detail::require_concept_free_trait<T, Property>
+{
+};
+
+template <typename T, typename Property, typename>
+struct require_concept_free :
+  require_concept_free_default<T, Property>
+{
+};
+
+} // namespace traits
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_TRAITS_REQUIRE_CONCEPT_FREE_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/traits/require_concept_member.hpp b/link/modules/asio-standalone/asio/include/asio/traits/require_concept_member.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/traits/require_concept_member.hpp
@@ -0,0 +1,108 @@
+//
+// traits/require_concept_member.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_TRAITS_REQUIRE_CONCEPT_MEMBER_HPP
+#define ASIO_TRAITS_REQUIRE_CONCEPT_MEMBER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/type_traits.hpp"
+
+#if defined(ASIO_HAS_DECLTYPE) \
+  && defined(ASIO_HAS_NOEXCEPT) \
+  && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)
+# define ASIO_HAS_DEDUCED_REQUIRE_CONCEPT_MEMBER_TRAIT 1
+#endif // defined(ASIO_HAS_DECLTYPE)
+       //   && defined(ASIO_HAS_NOEXCEPT)
+       //   && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace traits {
+
+template <typename T, typename Property, typename = void>
+struct require_concept_member_default;
+
+template <typename T, typename Property, typename = void>
+struct require_concept_member;
+
+} // namespace traits
+namespace detail {
+
+struct no_require_concept_member
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = false);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
+};
+
+#if defined(ASIO_HAS_DEDUCED_REQUIRE_CONCEPT_MEMBER_TRAIT)
+
+template <typename T, typename Property, typename = void>
+struct require_concept_member_trait : no_require_concept_member
+{
+};
+
+template <typename T, typename Property>
+struct require_concept_member_trait<T, Property,
+  typename void_type<
+    decltype(declval<T>().require_concept(declval<Property>()))
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+
+  using result_type = decltype(
+    declval<T>().require_concept(declval<Property>()));
+
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = noexcept(
+    declval<T>().require_concept(declval<Property>())));
+};
+
+#else // defined(ASIO_HAS_DEDUCED_REQUIRE_CONCEPT_MEMBER_TRAIT)
+
+template <typename T, typename Property, typename = void>
+struct require_concept_member_trait :
+  conditional<
+    is_same<T, typename decay<T>::type>::value
+      && is_same<Property, typename decay<Property>::type>::value,
+    no_require_concept_member,
+    traits::require_concept_member<
+      typename decay<T>::type,
+      typename decay<Property>::type>
+  >::type
+{
+};
+
+#endif // defined(ASIO_HAS_DEDUCED_REQUIRE_CONCEPT_MEMBER_TRAIT)
+
+} // namespace detail
+namespace traits {
+
+template <typename T, typename Property, typename>
+struct require_concept_member_default :
+  detail::require_concept_member_trait<T, Property>
+{
+};
+
+template <typename T, typename Property, typename>
+struct require_concept_member :
+  require_concept_member_default<T, Property>
+{
+};
+
+} // namespace traits
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_TRAITS_REQUIRE_CONCEPT_MEMBER_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/traits/require_free.hpp b/link/modules/asio-standalone/asio/include/asio/traits/require_free.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/traits/require_free.hpp
@@ -0,0 +1,108 @@
+//
+// traits/require_free.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_TRAITS_REQUIRE_FREE_HPP
+#define ASIO_TRAITS_REQUIRE_FREE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/type_traits.hpp"
+
+#if defined(ASIO_HAS_DECLTYPE) \
+  && defined(ASIO_HAS_NOEXCEPT) \
+  && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)
+# define ASIO_HAS_DEDUCED_REQUIRE_FREE_TRAIT 1
+#endif // defined(ASIO_HAS_DECLTYPE)
+       //   && defined(ASIO_HAS_NOEXCEPT)
+       //   && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace traits {
+
+template <typename T, typename Property, typename = void>
+struct require_free_default;
+
+template <typename T, typename Property, typename = void>
+struct require_free;
+
+} // namespace traits
+namespace detail {
+
+struct no_require_free
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = false);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
+};
+
+#if defined(ASIO_HAS_DEDUCED_REQUIRE_FREE_TRAIT)
+
+template <typename T, typename Property, typename = void>
+struct require_free_trait : no_require_free
+{
+};
+
+template <typename T, typename Property>
+struct require_free_trait<T, Property,
+  typename void_type<
+    decltype(require(declval<T>(), declval<Property>()))
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+
+  using result_type = decltype(
+    require(declval<T>(), declval<Property>()));
+
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = noexcept(
+    require(declval<T>(), declval<Property>())));
+};
+
+#else // defined(ASIO_HAS_DEDUCED_REQUIRE_FREE_TRAIT)
+
+template <typename T, typename Property, typename = void>
+struct require_free_trait :
+  conditional<
+    is_same<T, typename decay<T>::type>::value
+      && is_same<Property, typename decay<Property>::type>::value,
+    no_require_free,
+    traits::require_free<
+      typename decay<T>::type,
+      typename decay<Property>::type>
+  >::type
+{
+};
+
+#endif // defined(ASIO_HAS_DEDUCED_REQUIRE_FREE_TRAIT)
+
+} // namespace detail
+namespace traits {
+
+template <typename T, typename Property, typename>
+struct require_free_default :
+  detail::require_free_trait<T, Property>
+{
+};
+
+template <typename T, typename Property, typename>
+struct require_free :
+  require_free_default<T, Property>
+{
+};
+
+} // namespace traits
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_TRAITS_REQUIRE_FREE_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/traits/require_member.hpp b/link/modules/asio-standalone/asio/include/asio/traits/require_member.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/traits/require_member.hpp
@@ -0,0 +1,108 @@
+//
+// traits/require_member.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_TRAITS_REQUIRE_MEMBER_HPP
+#define ASIO_TRAITS_REQUIRE_MEMBER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/type_traits.hpp"
+
+#if defined(ASIO_HAS_DECLTYPE) \
+  && defined(ASIO_HAS_NOEXCEPT) \
+  && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)
+# define ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT 1
+#endif // defined(ASIO_HAS_DECLTYPE)
+       //   && defined(ASIO_HAS_NOEXCEPT)
+       //   && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace traits {
+
+template <typename T, typename Property, typename = void>
+struct require_member_default;
+
+template <typename T, typename Property, typename = void>
+struct require_member;
+
+} // namespace traits
+namespace detail {
+
+struct no_require_member
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = false);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
+};
+
+#if defined(ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT)
+
+template <typename T, typename Property, typename = void>
+struct require_member_trait : no_require_member
+{
+};
+
+template <typename T, typename Property>
+struct require_member_trait<T, Property,
+  typename void_type<
+    decltype(declval<T>().require(declval<Property>()))
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+
+  using result_type = decltype(
+    declval<T>().require(declval<Property>()));
+
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = noexcept(
+    declval<T>().require(declval<Property>())));
+};
+
+#else // defined(ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT)
+
+template <typename T, typename Property, typename = void>
+struct require_member_trait :
+  conditional<
+    is_same<T, typename decay<T>::type>::value
+      && is_same<Property, typename decay<Property>::type>::value,
+    no_require_member,
+    traits::require_member<
+      typename decay<T>::type,
+      typename decay<Property>::type>
+  >::type
+{
+};
+
+#endif // defined(ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT)
+
+} // namespace detail
+namespace traits {
+
+template <typename T, typename Property, typename>
+struct require_member_default :
+  detail::require_member_trait<T, Property>
+{
+};
+
+template <typename T, typename Property, typename>
+struct require_member :
+  require_member_default<T, Property>
+{
+};
+
+} // namespace traits
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_TRAITS_REQUIRE_MEMBER_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/traits/schedule_free.hpp b/link/modules/asio-standalone/asio/include/asio/traits/schedule_free.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/traits/schedule_free.hpp
@@ -0,0 +1,108 @@
+//
+// traits/schedule_free.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_TRAITS_SCHEDULE_FREE_HPP
+#define ASIO_TRAITS_SCHEDULE_FREE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/type_traits.hpp"
+
+#if defined(ASIO_HAS_DECLTYPE) \
+  && defined(ASIO_HAS_NOEXCEPT) \
+  && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)
+# define ASIO_HAS_DEDUCED_SCHEDULE_FREE_TRAIT 1
+#endif // defined(ASIO_HAS_DECLTYPE)
+       //   && defined(ASIO_HAS_NOEXCEPT)
+       //   && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace traits {
+
+template <typename T, typename = void>
+struct schedule_free_default;
+
+template <typename T, typename = void>
+struct schedule_free;
+
+} // namespace traits
+namespace detail {
+
+struct no_schedule_free
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = false);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
+};
+
+#if defined(ASIO_HAS_DEDUCED_SCHEDULE_FREE_TRAIT)
+
+template <typename T, typename = void>
+struct schedule_free_trait : no_schedule_free
+{
+};
+
+template <typename T>
+struct schedule_free_trait<T,
+  typename void_type<
+    decltype(schedule(declval<T>()))
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+
+  using result_type = decltype(schedule(declval<T>()));
+
+  ASIO_STATIC_CONSTEXPR(bool,
+    is_noexcept = noexcept(schedule(declval<T>())));
+};
+
+#else // defined(ASIO_HAS_DEDUCED_SCHEDULE_FREE_TRAIT)
+
+template <typename T, typename = void>
+struct schedule_free_trait :
+  conditional<
+    is_same<T, typename remove_reference<T>::type>::value,
+    typename conditional<
+      is_same<T, typename add_const<T>::type>::value,
+      no_schedule_free,
+      traits::schedule_free<typename add_const<T>::type>
+    >::type,
+    traits::schedule_free<typename remove_reference<T>::type>
+  >::type
+{
+};
+
+#endif // defined(ASIO_HAS_DEDUCED_SCHEDULE_FREE_TRAIT)
+
+} // namespace detail
+namespace traits {
+
+template <typename T, typename>
+struct schedule_free_default :
+  detail::schedule_free_trait<T>
+{
+};
+
+template <typename T, typename>
+struct schedule_free :
+  schedule_free_default<T>
+{
+};
+
+} // namespace traits
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_TRAITS_SCHEDULE_FREE_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/traits/schedule_member.hpp b/link/modules/asio-standalone/asio/include/asio/traits/schedule_member.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/traits/schedule_member.hpp
@@ -0,0 +1,108 @@
+//
+// traits/schedule_member.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_TRAITS_SCHEDULE_MEMBER_HPP
+#define ASIO_TRAITS_SCHEDULE_MEMBER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/type_traits.hpp"
+
+#if defined(ASIO_HAS_DECLTYPE) \
+  && defined(ASIO_HAS_NOEXCEPT) \
+  && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)
+# define ASIO_HAS_DEDUCED_SCHEDULE_MEMBER_TRAIT 1
+#endif // defined(ASIO_HAS_DECLTYPE)
+       //   && defined(ASIO_HAS_NOEXCEPT)
+       //   && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace traits {
+
+template <typename T, typename = void>
+struct schedule_member_default;
+
+template <typename T, typename = void>
+struct schedule_member;
+
+} // namespace traits
+namespace detail {
+
+struct no_schedule_member
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = false);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
+};
+
+#if defined(ASIO_HAS_DEDUCED_SCHEDULE_MEMBER_TRAIT)
+
+template <typename T, typename = void>
+struct schedule_member_trait : no_schedule_member
+{
+};
+
+template <typename T>
+struct schedule_member_trait<T,
+  typename void_type<
+    decltype(declval<T>().schedule())
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+
+  using result_type = decltype(declval<T>().schedule());
+
+  ASIO_STATIC_CONSTEXPR(bool,
+    is_noexcept = noexcept(declval<T>().schedule()));
+};
+
+#else // defined(ASIO_HAS_DEDUCED_SCHEDULE_MEMBER_TRAIT)
+
+template <typename T, typename = void>
+struct schedule_member_trait :
+  conditional<
+    is_same<T, typename remove_reference<T>::type>::value,
+    typename conditional<
+      is_same<T, typename add_const<T>::type>::value,
+      no_schedule_member,
+      traits::schedule_member<typename add_const<T>::type>
+    >::type,
+    traits::schedule_member<typename remove_reference<T>::type>
+  >::type
+{
+};
+
+#endif // defined(ASIO_HAS_DEDUCED_SCHEDULE_MEMBER_TRAIT)
+
+} // namespace detail
+namespace traits {
+
+template <typename T, typename>
+struct schedule_member_default :
+  detail::schedule_member_trait<T>
+{
+};
+
+template <typename T, typename>
+struct schedule_member :
+  schedule_member_default<T>
+{
+};
+
+} // namespace traits
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_TRAITS_SCHEDULE_MEMBER_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/traits/set_done_free.hpp b/link/modules/asio-standalone/asio/include/asio/traits/set_done_free.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/traits/set_done_free.hpp
@@ -0,0 +1,108 @@
+//
+// traits/set_done_free.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_TRAITS_SET_DONE_FREE_HPP
+#define ASIO_TRAITS_SET_DONE_FREE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/type_traits.hpp"
+
+#if defined(ASIO_HAS_DECLTYPE) \
+  && defined(ASIO_HAS_NOEXCEPT) \
+  && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)
+# define ASIO_HAS_DEDUCED_SET_DONE_FREE_TRAIT 1
+#endif // defined(ASIO_HAS_DECLTYPE)
+       //   && defined(ASIO_HAS_NOEXCEPT)
+       //   && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace traits {
+
+template <typename T, typename = void>
+struct set_done_free_default;
+
+template <typename T, typename = void>
+struct set_done_free;
+
+} // namespace traits
+namespace detail {
+
+struct no_set_done_free
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = false);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
+};
+
+#if defined(ASIO_HAS_DEDUCED_SET_DONE_FREE_TRAIT)
+
+template <typename T, typename = void>
+struct set_done_free_trait : no_set_done_free
+{
+};
+
+template <typename T>
+struct set_done_free_trait<T,
+  typename void_type<
+    decltype(set_done(declval<T>()))
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+
+  using result_type = decltype(set_done(declval<T>()));
+
+  ASIO_STATIC_CONSTEXPR(bool,
+    is_noexcept = noexcept(set_done(declval<T>())));
+};
+
+#else // defined(ASIO_HAS_DEDUCED_SET_DONE_FREE_TRAIT)
+
+template <typename T, typename = void>
+struct set_done_free_trait :
+  conditional<
+    is_same<T, typename remove_reference<T>::type>::value,
+    typename conditional<
+      is_same<T, typename add_const<T>::type>::value,
+      no_set_done_free,
+      traits::set_done_free<typename add_const<T>::type>
+    >::type,
+    traits::set_done_free<typename remove_reference<T>::type>
+  >::type
+{
+};
+
+#endif // defined(ASIO_HAS_DEDUCED_SET_DONE_FREE_TRAIT)
+
+} // namespace detail
+namespace traits {
+
+template <typename T, typename>
+struct set_done_free_default :
+  detail::set_done_free_trait<T>
+{
+};
+
+template <typename T, typename>
+struct set_done_free :
+  set_done_free_default<T>
+{
+};
+
+} // namespace traits
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_TRAITS_SET_DONE_FREE_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/traits/set_done_member.hpp b/link/modules/asio-standalone/asio/include/asio/traits/set_done_member.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/traits/set_done_member.hpp
@@ -0,0 +1,108 @@
+//
+// traits/set_done_member.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_TRAITS_SET_DONE_MEMBER_HPP
+#define ASIO_TRAITS_SET_DONE_MEMBER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/type_traits.hpp"
+
+#if defined(ASIO_HAS_DECLTYPE) \
+  && defined(ASIO_HAS_NOEXCEPT) \
+  && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)
+# define ASIO_HAS_DEDUCED_SET_DONE_MEMBER_TRAIT 1
+#endif // defined(ASIO_HAS_DECLTYPE)
+       //   && defined(ASIO_HAS_NOEXCEPT)
+       //   && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace traits {
+
+template <typename T, typename = void>
+struct set_done_member_default;
+
+template <typename T, typename = void>
+struct set_done_member;
+
+} // namespace traits
+namespace detail {
+
+struct no_set_done_member
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = false);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
+};
+
+#if defined(ASIO_HAS_DEDUCED_SET_DONE_MEMBER_TRAIT)
+
+template <typename T, typename = void>
+struct set_done_member_trait : no_set_done_member
+{
+};
+
+template <typename T>
+struct set_done_member_trait<T,
+  typename void_type<
+    decltype(declval<T>().set_done())
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+
+  using result_type = decltype(declval<T>().set_done());
+
+  ASIO_STATIC_CONSTEXPR(bool,
+    is_noexcept = noexcept(declval<T>().set_done()));
+};
+
+#else // defined(ASIO_HAS_DEDUCED_SET_DONE_MEMBER_TRAIT)
+
+template <typename T, typename = void>
+struct set_done_member_trait :
+  conditional<
+    is_same<T, typename remove_reference<T>::type>::value,
+    typename conditional<
+      is_same<T, typename add_const<T>::type>::value,
+      no_set_done_member,
+      traits::set_done_member<typename add_const<T>::type>
+    >::type,
+    traits::set_done_member<typename remove_reference<T>::type>
+  >::type
+{
+};
+
+#endif // defined(ASIO_HAS_DEDUCED_SET_DONE_MEMBER_TRAIT)
+
+} // namespace detail
+namespace traits {
+
+template <typename T, typename>
+struct set_done_member_default :
+  detail::set_done_member_trait<T>
+{
+};
+
+template <typename T, typename>
+struct set_done_member :
+  set_done_member_default<T>
+{
+};
+
+} // namespace traits
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_TRAITS_SET_DONE_MEMBER_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/traits/set_error_free.hpp b/link/modules/asio-standalone/asio/include/asio/traits/set_error_free.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/traits/set_error_free.hpp
@@ -0,0 +1,112 @@
+//
+// traits/set_error_free.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_TRAITS_SET_ERROR_FREE_HPP
+#define ASIO_TRAITS_SET_ERROR_FREE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/type_traits.hpp"
+
+#if defined(ASIO_HAS_DECLTYPE) \
+  && defined(ASIO_HAS_NOEXCEPT) \
+  && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)
+# define ASIO_HAS_DEDUCED_SET_ERROR_FREE_TRAIT 1
+#endif // defined(ASIO_HAS_DECLTYPE)
+       //   && defined(ASIO_HAS_NOEXCEPT)
+       //   && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace traits {
+
+template <typename T, typename E, typename = void>
+struct set_error_free_default;
+
+template <typename T, typename E, typename = void>
+struct set_error_free;
+
+} // namespace traits
+namespace detail {
+
+struct no_set_error_free
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = false);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
+};
+
+#if defined(ASIO_HAS_DEDUCED_SET_ERROR_FREE_TRAIT)
+
+template <typename T, typename E, typename = void>
+struct set_error_free_trait : no_set_error_free
+{
+};
+
+template <typename T, typename E>
+struct set_error_free_trait<T, E,
+  typename void_type<
+    decltype(set_error(declval<T>(), declval<E>()))
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+
+  using result_type = decltype(
+    set_error(declval<T>(), declval<E>()));
+
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = noexcept(
+    set_error(declval<T>(), declval<E>())));
+};
+
+#else // defined(ASIO_HAS_DEDUCED_SET_ERROR_FREE_TRAIT)
+
+template <typename T, typename E, typename = void>
+struct set_error_free_trait :
+  conditional<
+    is_same<T, typename remove_reference<T>::type>::value
+      && is_same<E, typename decay<E>::type>::value,
+    typename conditional<
+      is_same<T, typename add_const<T>::type>::value,
+      no_set_error_free,
+      traits::set_error_free<typename add_const<T>::type, E>
+    >::type,
+    traits::set_error_free<
+      typename remove_reference<T>::type,
+      typename decay<E>::type>
+  >::type
+{
+};
+
+#endif // defined(ASIO_HAS_DEDUCED_SET_ERROR_FREE_TRAIT)
+
+} // namespace detail
+namespace traits {
+
+template <typename T, typename E, typename>
+struct set_error_free_default :
+  detail::set_error_free_trait<T, E>
+{
+};
+
+template <typename T, typename E, typename>
+struct set_error_free :
+  set_error_free_default<T, E>
+{
+};
+
+} // namespace traits
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_TRAITS_SET_ERROR_FREE_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/traits/set_error_member.hpp b/link/modules/asio-standalone/asio/include/asio/traits/set_error_member.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/traits/set_error_member.hpp
@@ -0,0 +1,112 @@
+//
+// traits/set_error_member.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_TRAITS_SET_ERROR_MEMBER_HPP
+#define ASIO_TRAITS_SET_ERROR_MEMBER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/type_traits.hpp"
+
+#if defined(ASIO_HAS_DECLTYPE) \
+  && defined(ASIO_HAS_NOEXCEPT) \
+  && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)
+# define ASIO_HAS_DEDUCED_SET_ERROR_MEMBER_TRAIT 1
+#endif // defined(ASIO_HAS_DECLTYPE)
+       //   && defined(ASIO_HAS_NOEXCEPT)
+       //   && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace traits {
+
+template <typename T, typename E, typename = void>
+struct set_error_member_default;
+
+template <typename T, typename E, typename = void>
+struct set_error_member;
+
+} // namespace traits
+namespace detail {
+
+struct no_set_error_member
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = false);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
+};
+
+#if defined(ASIO_HAS_DEDUCED_SET_ERROR_MEMBER_TRAIT)
+
+template <typename T, typename E, typename = void>
+struct set_error_member_trait : no_set_error_member
+{
+};
+
+template <typename T, typename E>
+struct set_error_member_trait<T, E,
+  typename void_type<
+    decltype(declval<T>().set_error(declval<E>()))
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+
+  using result_type = decltype(
+    declval<T>().set_error(declval<E>()));
+
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = noexcept(
+    declval<T>().set_error(declval<E>())));
+};
+
+#else // defined(ASIO_HAS_DEDUCED_SET_ERROR_MEMBER_TRAIT)
+
+template <typename T, typename E, typename = void>
+struct set_error_member_trait :
+  conditional<
+    is_same<T, typename remove_reference<T>::type>::value
+      && is_same<E, typename decay<E>::type>::value,
+    typename conditional<
+      is_same<T, typename add_const<T>::type>::value,
+      no_set_error_member,
+      traits::set_error_member<typename add_const<T>::type, E>
+    >::type,
+    traits::set_error_member<
+      typename remove_reference<T>::type,
+      typename decay<E>::type>
+  >::type
+{
+};
+
+#endif // defined(ASIO_HAS_DEDUCED_SET_ERROR_MEMBER_TRAIT)
+
+} // namespace detail
+namespace traits {
+
+template <typename T, typename E, typename>
+struct set_error_member_default :
+  detail::set_error_member_trait<T, E>
+{
+};
+
+template <typename T, typename E, typename>
+struct set_error_member :
+  set_error_member_default<T, E>
+{
+};
+
+} // namespace traits
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_TRAITS_SET_ERROR_MEMBER_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/traits/set_value_free.hpp b/link/modules/asio-standalone/asio/include/asio/traits/set_value_free.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/traits/set_value_free.hpp
@@ -0,0 +1,234 @@
+//
+// traits/set_value_free.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_TRAITS_SET_VALUE_FREE_HPP
+#define ASIO_TRAITS_SET_VALUE_FREE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/type_traits.hpp"
+#include "asio/detail/variadic_templates.hpp"
+
+#if defined(ASIO_HAS_DECLTYPE) \
+  && defined(ASIO_HAS_NOEXCEPT) \
+  && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)
+# define ASIO_HAS_DEDUCED_SET_VALUE_FREE_TRAIT 1
+#endif // defined(ASIO_HAS_DECLTYPE)
+       //   && defined(ASIO_HAS_NOEXCEPT)
+       //   && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace traits {
+
+template <typename T, typename Vs, typename = void>
+struct set_value_free_default;
+
+template <typename T, typename Vs, typename = void>
+struct set_value_free;
+
+} // namespace traits
+namespace detail {
+
+struct no_set_value_free
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = false);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
+};
+
+#if defined(ASIO_HAS_DEDUCED_SET_VALUE_FREE_TRAIT)
+
+template <typename T, typename Vs, typename = void>
+struct set_value_free_trait : no_set_value_free
+{
+};
+
+#if defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+template <typename T, typename... Vs>
+struct set_value_free_trait<T, void(Vs...),
+  typename void_type<
+    decltype(set_value(declval<T>(), declval<Vs>()...))
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+
+  using result_type = decltype(
+    set_value(declval<T>(), declval<Vs>()...));
+
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = noexcept(
+    set_value(declval<T>(), declval<Vs>()...)));
+};
+
+#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+template <typename T>
+struct set_value_free_trait<T, void(),
+  typename void_type<
+    decltype(set_value(declval<T>()))
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+
+  using result_type = decltype(set_value(declval<T>()));
+
+  ASIO_STATIC_CONSTEXPR(bool,
+    is_noexcept = noexcept(set_value(declval<T>())));
+};
+
+#define ASIO_PRIVATE_SET_VALUE_FREE_TRAIT_DEF(n) \
+  template <typename T, ASIO_VARIADIC_TPARAMS(n)> \
+  struct set_value_free_trait<T, void(ASIO_VARIADIC_TARGS(n)), \
+    typename void_type< \
+      decltype(set_value(declval<T>(), ASIO_VARIADIC_DECLVAL(n))) \
+    >::type> \
+  { \
+    ASIO_STATIC_CONSTEXPR(bool, is_valid = true); \
+  \
+    using result_type = decltype( \
+      set_value(declval<T>(), ASIO_VARIADIC_DECLVAL(n))); \
+  \
+    ASIO_STATIC_CONSTEXPR(bool, is_noexcept = noexcept( \
+      set_value(declval<T>(), ASIO_VARIADIC_DECLVAL(n)))); \
+  }; \
+  /**/
+ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_SET_VALUE_FREE_TRAIT_DEF)
+#undef ASIO_PRIVATE_SET_VALUE_FREE_TRAIT_DEF
+
+#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+#else // defined(ASIO_HAS_DEDUCED_SET_VALUE_FREE_TRAIT)
+
+template <typename T, typename Vs, typename = void>
+struct set_value_free_trait;
+
+#if defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+template <typename T, typename... Vs>
+struct set_value_free_trait<T, void(Vs...)> :
+  conditional<
+    is_same<T, typename remove_reference<T>::type>::value
+      && conjunction<is_same<Vs, typename decay<Vs>::type>...>::value,
+    typename conditional<
+      is_same<T, typename add_const<T>::type>::value,
+      no_set_value_free,
+      traits::set_value_free<typename add_const<T>::type, void(Vs...)>
+    >::type,
+    traits::set_value_free<
+      typename remove_reference<T>::type,
+      void(typename decay<Vs>::type...)>
+  >::type
+{
+};
+
+#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+template <typename T>
+struct set_value_free_trait<T, void()> :
+  conditional<
+    is_same<T, typename remove_reference<T>::type>::value,
+    typename conditional<
+      is_same<T, typename add_const<T>::type>::value,
+      no_set_value_free,
+      traits::set_value_free<typename add_const<T>::type, void()>
+    >::type,
+    traits::set_value_free<typename remove_reference<T>::type, void()>
+  >::type
+{
+};
+
+#define ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME(n) \
+  ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_##n
+
+#define ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_1 \
+  && is_same<T1, typename decay<T1>::type>::value
+#define ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_2 \
+  ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_1 \
+  && is_same<T2, typename decay<T2>::type>::value
+#define ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_3 \
+  ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_2 \
+  && is_same<T3, typename decay<T3>::type>::value
+#define ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_4 \
+  ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_3 \
+  && is_same<T4, typename decay<T4>::type>::value
+#define ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_5 \
+  ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_4 \
+  && is_same<T5, typename decay<T5>::type>::value
+#define ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_6 \
+  ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_5 \
+  && is_same<T6, typename decay<T6>::type>::value
+#define ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_7 \
+  ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_6 \
+  && is_same<T7, typename decay<T7>::type>::value
+#define ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_8 \
+  ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_7 \
+  && is_same<T8, typename decay<T8>::type>::value
+
+#define ASIO_PRIVATE_SET_VALUE_MEMBER_TRAIT_DEF(n) \
+  template <typename T, ASIO_VARIADIC_TPARAMS(n)> \
+  struct set_value_free_trait<T, void(ASIO_VARIADIC_TARGS(n))> : \
+    conditional< \
+      is_same<T, typename remove_reference<T>::type>::value \
+        ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME(n), \
+      typename conditional< \
+        is_same<T, typename add_const<T>::type>::value, \
+        no_set_value_free, \
+        traits::set_value_free< \
+          typename add_const<T>::type, \
+          void(ASIO_VARIADIC_TARGS(n))> \
+      >::type, \
+      traits::set_value_free< \
+        typename remove_reference<T>::type, \
+        void(ASIO_VARIADIC_DECAY(n))> \
+    >::type \
+  { \
+  }; \
+  /**/
+ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_SET_VALUE_MEMBER_TRAIT_DEF)
+#undef ASIO_PRIVATE_SET_VALUE_MEMBER_TRAIT_DEF
+#undef ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME
+#undef ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_1
+#undef ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_2
+#undef ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_3
+#undef ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_4
+#undef ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_5
+#undef ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_6
+#undef ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_7
+#undef ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_8
+
+#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+#endif // defined(ASIO_HAS_DEDUCED_SET_VALUE_FREE_TRAIT)
+
+} // namespace detail
+namespace traits {
+
+template <typename T, typename Vs, typename>
+struct set_value_free_default :
+  detail::set_value_free_trait<T, Vs>
+{
+};
+
+template <typename T, typename Vs, typename>
+struct set_value_free :
+  set_value_free_default<T, Vs>
+{
+};
+
+} // namespace traits
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_TRAITS_SET_VALUE_FREE_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/traits/set_value_member.hpp b/link/modules/asio-standalone/asio/include/asio/traits/set_value_member.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/traits/set_value_member.hpp
@@ -0,0 +1,234 @@
+//
+// traits/set_value_member.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_TRAITS_SET_VALUE_MEMBER_HPP
+#define ASIO_TRAITS_SET_VALUE_MEMBER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/type_traits.hpp"
+#include "asio/detail/variadic_templates.hpp"
+
+#if defined(ASIO_HAS_DECLTYPE) \
+  && defined(ASIO_HAS_NOEXCEPT) \
+  && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)
+# define ASIO_HAS_DEDUCED_SET_VALUE_MEMBER_TRAIT 1
+#endif // defined(ASIO_HAS_DECLTYPE)
+       //   && defined(ASIO_HAS_NOEXCEPT)
+       //   && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace traits {
+
+template <typename T, typename Vs, typename = void>
+struct set_value_member_default;
+
+template <typename T, typename Vs, typename = void>
+struct set_value_member;
+
+} // namespace traits
+namespace detail {
+
+struct no_set_value_member
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = false);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
+};
+
+#if defined(ASIO_HAS_DEDUCED_SET_VALUE_MEMBER_TRAIT)
+
+template <typename T, typename Vs, typename = void>
+struct set_value_member_trait : no_set_value_member
+{
+};
+
+#if defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+template <typename T, typename... Vs>
+struct set_value_member_trait<T, void(Vs...),
+  typename void_type<
+    decltype(declval<T>().set_value(declval<Vs>()...))
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+
+  using result_type = decltype(
+    declval<T>().set_value(declval<Vs>()...));
+
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = noexcept(
+    declval<T>().set_value(declval<Vs>()...)));
+};
+
+#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+template <typename T>
+struct set_value_member_trait<T, void(),
+  typename void_type<
+    decltype(declval<T>().set_value())
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+
+  using result_type = decltype(declval<T>().set_value());
+
+  ASIO_STATIC_CONSTEXPR(bool,
+    is_noexcept = noexcept(declval<T>().set_value()));
+};
+
+#define ASIO_PRIVATE_SET_VALUE_MEMBER_TRAIT_DEF(n) \
+  template <typename T, ASIO_VARIADIC_TPARAMS(n)> \
+  struct set_value_member_trait<T, void(ASIO_VARIADIC_TARGS(n)), \
+    typename void_type< \
+      decltype(declval<T>().set_value(ASIO_VARIADIC_DECLVAL(n))) \
+    >::type> \
+  { \
+    ASIO_STATIC_CONSTEXPR(bool, is_valid = true); \
+  \
+    using result_type = decltype( \
+      declval<T>().set_value(ASIO_VARIADIC_DECLVAL(n))); \
+  \
+    ASIO_STATIC_CONSTEXPR(bool, is_noexcept = noexcept( \
+      declval<T>().set_value(ASIO_VARIADIC_DECLVAL(n)))); \
+  }; \
+  /**/
+ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_SET_VALUE_MEMBER_TRAIT_DEF)
+#undef ASIO_PRIVATE_SET_VALUE_MEMBER_TRAIT_DEF
+
+#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+#else // defined(ASIO_HAS_DEDUCED_SET_VALUE_MEMBER_TRAIT)
+
+template <typename T, typename Vs, typename = void>
+struct set_value_member_trait;
+
+#if defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+template <typename T, typename... Vs>
+struct set_value_member_trait<T, void(Vs...)> :
+  conditional<
+    is_same<T, typename remove_reference<T>::type>::value
+      && conjunction<is_same<Vs, typename decay<Vs>::type>...>::value,
+    typename conditional<
+      is_same<T, typename add_const<T>::type>::value,
+      no_set_value_member,
+      traits::set_value_member<typename add_const<T>::type, void(Vs...)>
+    >::type,
+    traits::set_value_member<
+      typename remove_reference<T>::type,
+      void(typename decay<Vs>::type...)>
+  >::type
+{
+};
+
+#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+template <typename T>
+struct set_value_member_trait<T, void()> :
+  conditional<
+    is_same<T, typename remove_reference<T>::type>::value,
+    typename conditional<
+      is_same<T, typename add_const<T>::type>::value,
+      no_set_value_member,
+      traits::set_value_member<typename add_const<T>::type, void()>
+    >::type,
+    traits::set_value_member<typename remove_reference<T>::type, void()>
+  >::type
+{
+};
+
+#define ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME(n) \
+  ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_##n
+
+#define ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_1 \
+  && is_same<T1, typename decay<T1>::type>::value
+#define ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_2 \
+  ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_1 \
+  && is_same<T2, typename decay<T2>::type>::value
+#define ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_3 \
+  ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_2 \
+  && is_same<T3, typename decay<T3>::type>::value
+#define ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_4 \
+  ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_3 \
+  && is_same<T4, typename decay<T4>::type>::value
+#define ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_5 \
+  ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_4 \
+  && is_same<T5, typename decay<T5>::type>::value
+#define ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_6 \
+  ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_5 \
+  && is_same<T6, typename decay<T6>::type>::value
+#define ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_7 \
+  ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_6 \
+  && is_same<T7, typename decay<T7>::type>::value
+#define ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_8 \
+  ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_7 \
+  && is_same<T8, typename decay<T8>::type>::value
+
+#define ASIO_PRIVATE_SET_VALUE_MEMBER_TRAIT_DEF(n) \
+  template <typename T, ASIO_VARIADIC_TPARAMS(n)> \
+  struct set_value_member_trait<T, void(ASIO_VARIADIC_TARGS(n))> : \
+    conditional< \
+      is_same<T, typename remove_reference<T>::type>::value \
+        ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME(n), \
+      typename conditional< \
+        is_same<T, typename add_const<T>::type>::value, \
+        no_set_value_member, \
+        traits::set_value_member< \
+          typename add_const<T>::type, \
+          void(ASIO_VARIADIC_TARGS(n))> \
+      >::type, \
+      traits::set_value_member< \
+        typename remove_reference<T>::type, \
+        void(ASIO_VARIADIC_DECAY(n))> \
+    >::type \
+  { \
+  }; \
+  /**/
+ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_SET_VALUE_MEMBER_TRAIT_DEF)
+#undef ASIO_PRIVATE_SET_VALUE_MEMBER_TRAIT_DEF
+#undef ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME
+#undef ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_1
+#undef ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_2
+#undef ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_3
+#undef ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_4
+#undef ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_5
+#undef ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_6
+#undef ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_7
+#undef ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_8
+
+#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+#endif // defined(ASIO_HAS_DEDUCED_SET_VALUE_MEMBER_TRAIT)
+
+} // namespace detail
+namespace traits {
+
+template <typename T, typename Vs, typename>
+struct set_value_member_default :
+  detail::set_value_member_trait<T, Vs>
+{
+};
+
+template <typename T, typename Vs, typename>
+struct set_value_member :
+  set_value_member_default<T, Vs>
+{
+};
+
+} // namespace traits
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_TRAITS_SET_VALUE_MEMBER_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/traits/start_free.hpp b/link/modules/asio-standalone/asio/include/asio/traits/start_free.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/traits/start_free.hpp
@@ -0,0 +1,108 @@
+//
+// traits/start_free.hpp
+// ~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_TRAITS_START_FREE_HPP
+#define ASIO_TRAITS_START_FREE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/type_traits.hpp"
+
+#if defined(ASIO_HAS_DECLTYPE) \
+  && defined(ASIO_HAS_NOEXCEPT) \
+  && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)
+# define ASIO_HAS_DEDUCED_START_FREE_TRAIT 1
+#endif // defined(ASIO_HAS_DECLTYPE)
+       //   && defined(ASIO_HAS_NOEXCEPT)
+       //   && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace traits {
+
+template <typename T, typename = void>
+struct start_free_default;
+
+template <typename T, typename = void>
+struct start_free;
+
+} // namespace traits
+namespace detail {
+
+struct no_start_free
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = false);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
+};
+
+#if defined(ASIO_HAS_DEDUCED_START_FREE_TRAIT)
+
+template <typename T, typename = void>
+struct start_free_trait : no_start_free
+{
+};
+
+template <typename T>
+struct start_free_trait<T,
+  typename void_type<
+    decltype(start(declval<T>()))
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+
+  using result_type = decltype(start(declval<T>()));
+
+  ASIO_STATIC_CONSTEXPR(bool,
+    is_noexcept = noexcept(start(declval<T>())));
+};
+
+#else // defined(ASIO_HAS_DEDUCED_START_FREE_TRAIT)
+
+template <typename T, typename = void>
+struct start_free_trait :
+  conditional<
+    is_same<T, typename remove_reference<T>::type>::value,
+    typename conditional<
+      is_same<T, typename add_const<T>::type>::value,
+      no_start_free,
+      traits::start_free<typename add_const<T>::type>
+    >::type,
+    traits::start_free<typename remove_reference<T>::type>
+  >::type
+{
+};
+
+#endif // defined(ASIO_HAS_DEDUCED_START_FREE_TRAIT)
+
+} // namespace detail
+namespace traits {
+
+template <typename T, typename>
+struct start_free_default :
+  detail::start_free_trait<T>
+{
+};
+
+template <typename T, typename>
+struct start_free :
+  start_free_default<T>
+{
+};
+
+} // namespace traits
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_TRAITS_START_FREE_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/traits/start_member.hpp b/link/modules/asio-standalone/asio/include/asio/traits/start_member.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/traits/start_member.hpp
@@ -0,0 +1,108 @@
+//
+// traits/start_member.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_TRAITS_START_MEMBER_HPP
+#define ASIO_TRAITS_START_MEMBER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/type_traits.hpp"
+
+#if defined(ASIO_HAS_DECLTYPE) \
+  && defined(ASIO_HAS_NOEXCEPT) \
+  && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)
+# define ASIO_HAS_DEDUCED_START_MEMBER_TRAIT 1
+#endif // defined(ASIO_HAS_DECLTYPE)
+       //   && defined(ASIO_HAS_NOEXCEPT)
+       //   && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace traits {
+
+template <typename T, typename = void>
+struct start_member_default;
+
+template <typename T, typename = void>
+struct start_member;
+
+} // namespace traits
+namespace detail {
+
+struct no_start_member
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = false);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
+};
+
+#if defined(ASIO_HAS_DEDUCED_START_MEMBER_TRAIT)
+
+template <typename T, typename = void>
+struct start_member_trait : no_start_member
+{
+};
+
+template <typename T>
+struct start_member_trait<T,
+  typename void_type<
+    decltype(declval<T>().start())
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+
+  using result_type = decltype(declval<T>().start());
+
+  ASIO_STATIC_CONSTEXPR(bool,
+    is_noexcept = noexcept(declval<T>().start()));
+};
+
+#else // defined(ASIO_HAS_DEDUCED_START_MEMBER_TRAIT)
+
+template <typename T, typename = void>
+struct start_member_trait :
+  conditional<
+    is_same<T, typename remove_reference<T>::type>::value,
+    typename conditional<
+      is_same<T, typename add_const<T>::type>::value,
+      no_start_member,
+      traits::start_member<typename add_const<T>::type>
+    >::type,
+    traits::start_member<typename remove_reference<T>::type>
+  >::type
+{
+};
+
+#endif // defined(ASIO_HAS_DEDUCED_START_MEMBER_TRAIT)
+
+} // namespace detail
+namespace traits {
+
+template <typename T, typename>
+struct start_member_default :
+  detail::start_member_trait<T>
+{
+};
+
+template <typename T, typename>
+struct start_member :
+  start_member_default<T>
+{
+};
+
+} // namespace traits
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_TRAITS_START_MEMBER_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/traits/static_query.hpp b/link/modules/asio-standalone/asio/include/asio/traits/static_query.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/traits/static_query.hpp
@@ -0,0 +1,108 @@
+//
+// traits/static_query.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_TRAITS_STATIC_QUERY_HPP
+#define ASIO_TRAITS_STATIC_QUERY_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/type_traits.hpp"
+
+#if defined(ASIO_HAS_DECLTYPE) \
+  && defined(ASIO_HAS_NOEXCEPT) \
+  && defined(ASIO_HAS_CONSTEXPR) \
+  && defined(ASIO_HAS_VARIABLE_TEMPLATES) \
+  && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)
+# define ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT 1
+#endif // defined(ASIO_HAS_DECLTYPE)
+       //   && defined(ASIO_HAS_NOEXCEPT)
+       //   && defined(ASIO_HAS_CONSTEXPR)
+       //   && defined(ASIO_HAS_VARIABLE_TEMPLATES)
+       //   && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace traits {
+
+template <typename T, typename Property, typename = void>
+struct static_query_default;
+
+template <typename T, typename Property, typename = void>
+struct static_query;
+
+} // namespace traits
+namespace detail {
+
+struct no_static_query
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = false);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
+};
+
+template <typename T, typename Property, typename = void>
+struct static_query_trait :
+  conditional<
+    is_same<T, typename decay<T>::type>::value
+      && is_same<Property, typename decay<Property>::type>::value,
+    no_static_query,
+    traits::static_query<
+      typename decay<T>::type,
+      typename decay<Property>::type>
+  >::type
+{
+};
+
+#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)
+
+template <typename T, typename Property>
+struct static_query_trait<T, Property,
+  typename void_type<
+    decltype(decay<Property>::type::template static_query_v<T>)
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+
+  using result_type = decltype(
+      decay<Property>::type::template static_query_v<T>);
+
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept =
+    noexcept(decay<Property>::type::template static_query_v<T>));
+
+  static ASIO_CONSTEXPR result_type value() noexcept(is_noexcept)
+  {
+    return decay<Property>::type::template static_query_v<T>;
+  }
+};
+
+#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)
+
+} // namespace detail
+namespace traits {
+
+template <typename T, typename Property, typename>
+struct static_query_default : detail::static_query_trait<T, Property>
+{
+};
+
+template <typename T, typename Property, typename>
+struct static_query : static_query_default<T, Property>
+{
+};
+
+} // namespace traits
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_TRAITS_STATIC_QUERY_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/traits/static_require.hpp b/link/modules/asio-standalone/asio/include/asio/traits/static_require.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/traits/static_require.hpp
@@ -0,0 +1,123 @@
+//
+// traits/static_require.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_TRAITS_STATIC_REQUIRE_HPP
+#define ASIO_TRAITS_STATIC_REQUIRE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/type_traits.hpp"
+#include "asio/traits/static_query.hpp"
+
+#if defined(ASIO_HAS_DECLTYPE) \
+  && defined(ASIO_HAS_NOEXCEPT)
+# define ASIO_HAS_DEDUCED_STATIC_REQUIRE_TRAIT 1
+#endif // defined(ASIO_HAS_DECLTYPE)
+       //   && defined(ASIO_HAS_NOEXCEPT)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace traits {
+
+template <typename T, typename Property, typename = void>
+struct static_require_default;
+
+template <typename T, typename Property, typename = void>
+struct static_require;
+
+} // namespace traits
+namespace detail {
+
+struct no_static_require
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = false);
+};
+
+template <typename T, typename Property, typename = void>
+struct static_require_trait :
+  conditional<
+    is_same<T, typename decay<T>::type>::value
+      && is_same<Property, typename decay<Property>::type>::value,
+    no_static_require,
+    traits::static_require<
+      typename decay<T>::type,
+      typename decay<Property>::type>
+  >::type
+{
+};
+
+#if defined(ASIO_HAS_DEDUCED_STATIC_REQUIRE_TRAIT)
+
+#if defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)
+
+template <typename T, typename Property>
+struct static_require_trait<T, Property,
+  typename enable_if<
+    decay<Property>::type::value() == traits::static_query<T, Property>::value()
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+};
+
+#else // defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)
+
+false_type static_require_test(...);
+
+template <typename T, typename Property>
+true_type static_require_test(T*, Property*,
+    typename enable_if<
+      Property::value() == traits::static_query<T, Property>::value()
+    >::type* = 0);
+
+template <typename T, typename Property>
+struct has_static_require
+{
+  ASIO_STATIC_CONSTEXPR(bool, value =
+    decltype((static_require_test)(
+      static_cast<T*>(0), static_cast<Property*>(0)))::value);
+};
+
+template <typename T, typename Property>
+struct static_require_trait<T, Property,
+  typename enable_if<
+    has_static_require<typename decay<T>::type,
+      typename decay<Property>::type>::value
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+};
+
+#endif // defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)
+
+#endif // defined(ASIO_HAS_DEDUCED_STATIC_REQUIRE_TRAIT)
+
+} // namespace detail
+namespace traits {
+
+template <typename T, typename Property, typename>
+struct static_require_default : detail::static_require_trait<T, Property>
+{
+};
+
+template <typename T, typename Property, typename>
+struct static_require : static_require_default<T, Property>
+{
+};
+
+} // namespace traits
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_TRAITS_STATIC_REQUIRE_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/traits/static_require_concept.hpp b/link/modules/asio-standalone/asio/include/asio/traits/static_require_concept.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/traits/static_require_concept.hpp
@@ -0,0 +1,123 @@
+//
+// traits/static_require_concept.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_TRAITS_STATIC_REQUIRE_CONCEPT_HPP
+#define ASIO_TRAITS_STATIC_REQUIRE_CONCEPT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/type_traits.hpp"
+#include "asio/traits/static_query.hpp"
+
+#if defined(ASIO_HAS_DECLTYPE) \
+  && defined(ASIO_HAS_NOEXCEPT)
+# define ASIO_HAS_DEDUCED_STATIC_REQUIRE_CONCEPT_TRAIT 1
+#endif // defined(ASIO_HAS_DECLTYPE)
+       //   && defined(ASIO_HAS_NOEXCEPT)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace traits {
+
+template <typename T, typename Property, typename = void>
+struct static_require_concept_default;
+
+template <typename T, typename Property, typename = void>
+struct static_require_concept;
+
+} // namespace traits
+namespace detail {
+
+struct no_static_require_concept
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = false);
+};
+
+template <typename T, typename Property, typename = void>
+struct static_require_concept_trait :
+  conditional<
+    is_same<T, typename decay<T>::type>::value
+      && is_same<Property, typename decay<Property>::type>::value,
+    no_static_require_concept,
+    traits::static_require_concept<
+      typename decay<T>::type,
+      typename decay<Property>::type>
+  >::type
+{
+};
+
+#if defined(ASIO_HAS_DEDUCED_STATIC_REQUIRE_CONCEPT_TRAIT)
+
+#if defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)
+
+template <typename T, typename Property>
+struct static_require_concept_trait<T, Property,
+  typename enable_if<
+    decay<Property>::type::value() == traits::static_query<T, Property>::value()
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+};
+
+#else // defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)
+
+false_type static_require_concept_test(...);
+
+template <typename T, typename Property>
+true_type static_require_concept_test(T*, Property*,
+    typename enable_if<
+      Property::value() == traits::static_query<T, Property>::value()
+    >::type* = 0);
+
+template <typename T, typename Property>
+struct has_static_require_concept
+{
+  ASIO_STATIC_CONSTEXPR(bool, value =
+    decltype((static_require_concept_test)(
+      static_cast<T*>(0), static_cast<Property*>(0)))::value);
+};
+
+template <typename T, typename Property>
+struct static_require_concept_trait<T, Property,
+  typename enable_if<
+    has_static_require_concept<T, typename decay<Property>::type>::value
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+};
+
+#endif // defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)
+
+#endif // defined(ASIO_HAS_DEDUCED_STATIC_REQUIRE_CONCEPT_TRAIT)
+
+} // namespace detail
+namespace traits {
+
+template <typename T, typename Property, typename>
+struct static_require_concept_default :
+  detail::static_require_concept_trait<T, Property>
+{
+};
+
+template <typename T, typename Property, typename>
+struct static_require_concept : static_require_concept_default<T, Property>
+{
+};
+
+} // namespace traits
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_TRAITS_STATIC_REQUIRE_CONCEPT_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/traits/submit_free.hpp b/link/modules/asio-standalone/asio/include/asio/traits/submit_free.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/traits/submit_free.hpp
@@ -0,0 +1,112 @@
+//
+// traits/submit_free.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_TRAITS_SUBMIT_FREE_HPP
+#define ASIO_TRAITS_SUBMIT_FREE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/type_traits.hpp"
+
+#if defined(ASIO_HAS_DECLTYPE) \
+  && defined(ASIO_HAS_NOEXCEPT) \
+  && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)
+# define ASIO_HAS_DEDUCED_SUBMIT_FREE_TRAIT 1
+#endif // defined(ASIO_HAS_DECLTYPE)
+       //   && defined(ASIO_HAS_NOEXCEPT)
+       //   && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace traits {
+
+template <typename S, typename R, typename = void>
+struct submit_free_default;
+
+template <typename S, typename R, typename = void>
+struct submit_free;
+
+} // namespace traits
+namespace detail {
+
+struct no_submit_free
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = false);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
+};
+
+#if defined(ASIO_HAS_DEDUCED_SUBMIT_FREE_TRAIT)
+
+template <typename S, typename R, typename = void>
+struct submit_free_trait : no_submit_free
+{
+};
+
+template <typename S, typename R>
+struct submit_free_trait<S, R,
+  typename void_type<
+    decltype(submit(declval<S>(), declval<R>()))
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+
+  using result_type = decltype(
+    submit(declval<S>(), declval<R>()));
+
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = noexcept(
+    submit(declval<S>(), declval<R>())));
+};
+
+#else // defined(ASIO_HAS_DEDUCED_SUBMIT_FREE_TRAIT)
+
+template <typename S, typename R, typename = void>
+struct submit_free_trait :
+  conditional<
+    is_same<S, typename remove_reference<S>::type>::value
+      && is_same<R, typename decay<R>::type>::value,
+    typename conditional<
+      is_same<S, typename add_const<S>::type>::value,
+      no_submit_free,
+      traits::submit_free<typename add_const<S>::type, R>
+    >::type,
+    traits::submit_free<
+      typename remove_reference<S>::type,
+      typename decay<R>::type>
+  >::type
+{
+};
+
+#endif // defined(ASIO_HAS_DEDUCED_SUBMIT_FREE_TRAIT)
+
+} // namespace detail
+namespace traits {
+
+template <typename S, typename R, typename>
+struct submit_free_default :
+  detail::submit_free_trait<S, R>
+{
+};
+
+template <typename S, typename R, typename>
+struct submit_free :
+  submit_free_default<S, R>
+{
+};
+
+} // namespace traits
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_TRAITS_SUBMIT_FREE_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/traits/submit_member.hpp b/link/modules/asio-standalone/asio/include/asio/traits/submit_member.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/traits/submit_member.hpp
@@ -0,0 +1,112 @@
+//
+// traits/submit_member.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_TRAITS_SUBMIT_MEMBER_HPP
+#define ASIO_TRAITS_SUBMIT_MEMBER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/type_traits.hpp"
+
+#if defined(ASIO_HAS_DECLTYPE) \
+  && defined(ASIO_HAS_NOEXCEPT) \
+  && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)
+# define ASIO_HAS_DEDUCED_SUBMIT_MEMBER_TRAIT 1
+#endif // defined(ASIO_HAS_DECLTYPE)
+       //   && defined(ASIO_HAS_NOEXCEPT)
+       //   && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace traits {
+
+template <typename S, typename R, typename = void>
+struct submit_member_default;
+
+template <typename S, typename R, typename = void>
+struct submit_member;
+
+} // namespace traits
+namespace detail {
+
+struct no_submit_member
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = false);
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
+};
+
+#if defined(ASIO_HAS_DEDUCED_SUBMIT_MEMBER_TRAIT)
+
+template <typename S, typename R, typename = void>
+struct submit_member_trait : no_submit_member
+{
+};
+
+template <typename S, typename R>
+struct submit_member_trait<S, R,
+  typename void_type<
+    decltype(declval<S>().submit(declval<R>()))
+  >::type>
+{
+  ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
+
+  using result_type = decltype(
+    declval<S>().submit(declval<R>()));
+
+  ASIO_STATIC_CONSTEXPR(bool, is_noexcept = noexcept(
+    declval<S>().submit(declval<R>())));
+};
+
+#else // defined(ASIO_HAS_DEDUCED_SUBMIT_MEMBER_TRAIT)
+
+template <typename S, typename R, typename = void>
+struct submit_member_trait :
+  conditional<
+    is_same<S, typename remove_reference<S>::type>::value
+      && is_same<R, typename decay<R>::type>::value,
+    typename conditional<
+      is_same<S, typename add_const<S>::type>::value,
+      no_submit_member,
+      traits::submit_member<typename add_const<S>::type, R>
+    >::type,
+    traits::submit_member<
+      typename remove_reference<S>::type,
+      typename decay<R>::type>
+  >::type
+{
+};
+
+#endif // defined(ASIO_HAS_DEDUCED_SUBMIT_MEMBER_TRAIT)
+
+} // namespace detail
+namespace traits {
+
+template <typename S, typename R, typename>
+struct submit_member_default :
+  detail::submit_member_trait<S, R>
+{
+};
+
+template <typename S, typename R, typename>
+struct submit_member :
+  submit_member_default<S, R>
+{
+};
+
+} // namespace traits
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_TRAITS_SUBMIT_MEMBER_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/ts/buffer.hpp b/link/modules/asio-standalone/asio/include/asio/ts/buffer.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/ts/buffer.hpp
@@ -0,0 +1,24 @@
+//
+// ts/buffer.hpp
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_TS_BUFFER_HPP
+#define ASIO_TS_BUFFER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/buffer.hpp"
+#include "asio/completion_condition.hpp"
+#include "asio/read.hpp"
+#include "asio/write.hpp"
+#include "asio/read_until.hpp"
+
+#endif // ASIO_TS_BUFFER_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/ts/executor.hpp b/link/modules/asio-standalone/asio/include/asio/ts/executor.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/ts/executor.hpp
@@ -0,0 +1,35 @@
+//
+// ts/executor.hpp
+// ~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_TS_EXECUTOR_HPP
+#define ASIO_TS_EXECUTOR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/async_result.hpp"
+#include "asio/associated_allocator.hpp"
+#include "asio/execution_context.hpp"
+#include "asio/is_executor.hpp"
+#include "asio/associated_executor.hpp"
+#include "asio/bind_executor.hpp"
+#include "asio/executor_work_guard.hpp"
+#include "asio/system_executor.hpp"
+#include "asio/executor.hpp"
+#include "asio/any_io_executor.hpp"
+#include "asio/dispatch.hpp"
+#include "asio/post.hpp"
+#include "asio/defer.hpp"
+#include "asio/strand.hpp"
+#include "asio/packaged_task.hpp"
+#include "asio/use_future.hpp"
+
+#endif // ASIO_TS_EXECUTOR_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/ts/internet.hpp b/link/modules/asio-standalone/asio/include/asio/ts/internet.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/ts/internet.hpp
@@ -0,0 +1,40 @@
+//
+// ts/internet.hpp
+// ~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_TS_INTERNET_HPP
+#define ASIO_TS_INTERNET_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/ip/address.hpp"
+#include "asio/ip/address_v4.hpp"
+#include "asio/ip/address_v4_iterator.hpp"
+#include "asio/ip/address_v4_range.hpp"
+#include "asio/ip/address_v6.hpp"
+#include "asio/ip/address_v6_iterator.hpp"
+#include "asio/ip/address_v6_range.hpp"
+#include "asio/ip/bad_address_cast.hpp"
+#include "asio/ip/basic_endpoint.hpp"
+#include "asio/ip/basic_resolver_query.hpp"
+#include "asio/ip/basic_resolver_entry.hpp"
+#include "asio/ip/basic_resolver_iterator.hpp"
+#include "asio/ip/basic_resolver.hpp"
+#include "asio/ip/host_name.hpp"
+#include "asio/ip/network_v4.hpp"
+#include "asio/ip/network_v6.hpp"
+#include "asio/ip/tcp.hpp"
+#include "asio/ip/udp.hpp"
+#include "asio/ip/v6_only.hpp"
+#include "asio/ip/unicast.hpp"
+#include "asio/ip/multicast.hpp"
+
+#endif // ASIO_TS_INTERNET_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/ts/io_context.hpp b/link/modules/asio-standalone/asio/include/asio/ts/io_context.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/ts/io_context.hpp
@@ -0,0 +1,20 @@
+//
+// ts/io_context.hpp
+// ~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_TS_IO_CONTEXT_HPP
+#define ASIO_TS_IO_CONTEXT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/io_context.hpp"
+
+#endif // ASIO_TS_IO_CONTEXT_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/ts/net.hpp b/link/modules/asio-standalone/asio/include/asio/ts/net.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/ts/net.hpp
@@ -0,0 +1,26 @@
+//
+// ts/net.hpp
+// ~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_TS_NET_HPP
+#define ASIO_TS_NET_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/ts/netfwd.hpp"
+#include "asio/ts/executor.hpp"
+#include "asio/ts/io_context.hpp"
+#include "asio/ts/timer.hpp"
+#include "asio/ts/buffer.hpp"
+#include "asio/ts/socket.hpp"
+#include "asio/ts/internet.hpp"
+
+#endif // ASIO_TS_NET_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/ts/netfwd.hpp b/link/modules/asio-standalone/asio/include/asio/ts/netfwd.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/ts/netfwd.hpp
@@ -0,0 +1,262 @@
+//
+// ts/netfwd.hpp
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_TS_NETFWD_HPP
+#define ASIO_TS_NETFWD_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_CHRONO)
+# include "asio/detail/chrono.hpp"
+#endif // defined(ASIO_HAS_CHRONO)
+
+#if defined(ASIO_HAS_BOOST_DATE_TIME)
+# include "asio/detail/date_time_fwd.hpp"
+#endif // defined(ASIO_HAS_BOOST_DATE_TIME)
+
+#if !defined(ASIO_USE_TS_EXECUTOR_AS_DEFAULT)
+#include "asio/execution/blocking.hpp"
+#include "asio/execution/outstanding_work.hpp"
+#include "asio/execution/relationship.hpp"
+#endif // !defined(ASIO_USE_TS_EXECUTOR_AS_DEFAULT)
+
+#if !defined(GENERATING_DOCUMENTATION)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+class execution_context;
+
+template <typename T, typename Executor>
+class executor_binder;
+
+#if !defined(ASIO_EXECUTOR_WORK_GUARD_DECL)
+#define ASIO_EXECUTOR_WORK_GUARD_DECL
+
+template <typename Executor, typename = void>
+class executor_work_guard;
+
+#endif // !defined(ASIO_EXECUTOR_WORK_GUARD_DECL)
+
+template <typename Blocking, typename Relationship, typename Allocator>
+class basic_system_executor;
+
+#if defined(ASIO_USE_TS_EXECUTOR_AS_DEFAULT)
+
+class executor;
+
+typedef executor any_io_executor;
+
+#else // defined(ASIO_USE_TS_EXECUTOR_AS_DEFAULT)
+
+namespace execution {
+
+#if !defined(ASIO_EXECUTION_ANY_EXECUTOR_FWD_DECL)
+#define ASIO_EXECUTION_ANY_EXECUTOR_FWD_DECL
+
+#if defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+template <typename... SupportableProperties>
+class any_executor;
+
+#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+template <typename = void, typename = void, typename = void,
+    typename = void, typename = void, typename = void,
+    typename = void, typename = void, typename = void>
+class any_executor;
+
+#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+#endif // !defined(ASIO_EXECUTION_ANY_EXECUTOR_FWD_DECL)
+
+template <typename U>
+struct context_as_t;
+
+template <typename Property>
+struct prefer_only;
+
+} // namespace execution
+
+typedef execution::any_executor<
+    execution::context_as_t<execution_context&>,
+    execution::blocking_t::never_t,
+    execution::prefer_only<execution::blocking_t::possibly_t>,
+    execution::prefer_only<execution::outstanding_work_t::tracked_t>,
+    execution::prefer_only<execution::outstanding_work_t::untracked_t>,
+    execution::prefer_only<execution::relationship_t::fork_t>,
+    execution::prefer_only<execution::relationship_t::continuation_t>
+  > any_io_executor;
+
+#endif // defined(ASIO_USE_TS_EXECUTOR_AS_DEFAULT)
+
+template <typename Executor>
+class strand;
+
+class io_context;
+
+template <typename Clock>
+struct wait_traits;
+
+#if defined(ASIO_HAS_BOOST_DATE_TIME)
+
+template <typename Time>
+struct time_traits;
+
+#endif // defined(ASIO_HAS_BOOST_DATE_TIME)
+
+#if !defined(ASIO_BASIC_WAITABLE_TIMER_FWD_DECL)
+#define ASIO_BASIC_WAITABLE_TIMER_FWD_DECL
+
+template <typename Clock,
+    typename WaitTraits = wait_traits<Clock>,
+    typename Executor = any_io_executor>
+class basic_waitable_timer;
+
+#endif // !defined(ASIO_BASIC_WAITABLE_TIMER_FWD_DECL)
+
+#if defined(ASIO_HAS_CHRONO)
+
+typedef basic_waitable_timer<chrono::system_clock> system_timer;
+
+typedef basic_waitable_timer<chrono::steady_clock> steady_timer;
+
+typedef basic_waitable_timer<chrono::high_resolution_clock>
+  high_resolution_timer;
+
+#endif // defined(ASIO_HAS_CHRONO)
+
+#if !defined(ASIO_BASIC_SOCKET_FWD_DECL)
+#define ASIO_BASIC_SOCKET_FWD_DECL
+
+template <typename Protocol, typename Executor = any_io_executor>
+class basic_socket;
+
+#endif // !defined(ASIO_BASIC_SOCKET_FWD_DECL)
+
+#if !defined(ASIO_BASIC_DATAGRAM_SOCKET_FWD_DECL)
+#define ASIO_BASIC_DATAGRAM_SOCKET_FWD_DECL
+
+template <typename Protocol, typename Executor = any_io_executor>
+class basic_datagram_socket;
+
+#endif // !defined(ASIO_BASIC_DATAGRAM_SOCKET_FWD_DECL)
+
+#if !defined(ASIO_BASIC_STREAM_SOCKET_FWD_DECL)
+#define ASIO_BASIC_STREAM_SOCKET_FWD_DECL
+
+// Forward declaration with defaulted arguments.
+template <typename Protocol, typename Executor = any_io_executor>
+class basic_stream_socket;
+
+#endif // !defined(ASIO_BASIC_STREAM_SOCKET_FWD_DECL)
+
+#if !defined(ASIO_BASIC_SOCKET_ACCEPTOR_FWD_DECL)
+#define ASIO_BASIC_SOCKET_ACCEPTOR_FWD_DECL
+
+template <typename Protocol, typename Executor = any_io_executor>
+class basic_socket_acceptor;
+
+#endif // !defined(ASIO_BASIC_SOCKET_ACCEPTOR_FWD_DECL)
+
+#if !defined(ASIO_BASIC_SOCKET_STREAMBUF_FWD_DECL)
+#define ASIO_BASIC_SOCKET_STREAMBUF_FWD_DECL
+
+// Forward declaration with defaulted arguments.
+template <typename Protocol,
+#if defined(ASIO_HAS_BOOST_DATE_TIME) \
+  || defined(GENERATING_DOCUMENTATION)
+    typename Clock = boost::posix_time::ptime,
+    typename WaitTraits = time_traits<Clock> >
+#else
+    typename Clock = chrono::steady_clock,
+    typename WaitTraits = wait_traits<Clock> >
+#endif
+class basic_socket_streambuf;
+
+#endif // !defined(ASIO_BASIC_SOCKET_STREAMBUF_FWD_DECL)
+
+#if !defined(ASIO_BASIC_SOCKET_IOSTREAM_FWD_DECL)
+#define ASIO_BASIC_SOCKET_IOSTREAM_FWD_DECL
+
+// Forward declaration with defaulted arguments.
+template <typename Protocol,
+#if defined(ASIO_HAS_BOOST_DATE_TIME) \
+  || defined(GENERATING_DOCUMENTATION)
+    typename Clock = boost::posix_time::ptime,
+    typename WaitTraits = time_traits<Clock> >
+#else
+    typename Clock = chrono::steady_clock,
+    typename WaitTraits = wait_traits<Clock> >
+#endif
+class basic_socket_iostream;
+
+#endif // !defined(ASIO_BASIC_SOCKET_IOSTREAM_FWD_DECL)
+
+namespace ip {
+
+class address;
+
+class address_v4;
+
+class address_v6;
+
+template <typename Address>
+class basic_address_iterator;
+
+typedef basic_address_iterator<address_v4> address_v4_iterator;
+
+typedef basic_address_iterator<address_v6> address_v6_iterator;
+
+template <typename Address>
+class basic_address_range;
+
+typedef basic_address_range<address_v4> address_v4_range;
+
+typedef basic_address_range<address_v6> address_v6_range;
+
+class network_v4;
+
+class network_v6;
+
+template <typename InternetProtocol>
+class basic_endpoint;
+
+template <typename InternetProtocol>
+class basic_resolver_entry;
+
+template <typename InternetProtocol>
+class basic_resolver_results;
+
+#if !defined(ASIO_IP_BASIC_RESOLVER_FWD_DECL)
+#define ASIO_IP_BASIC_RESOLVER_FWD_DECL
+
+template <typename InternetProtocol, typename Executor = any_io_executor>
+class basic_resolver;
+
+#endif // !defined(ASIO_IP_BASIC_RESOLVER_FWD_DECL)
+
+class tcp;
+
+class udp;
+
+} // namespace ip
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // !defined(GENERATING_DOCUMENTATION)
+
+#endif // ASIO_TS_NETFWD_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/ts/socket.hpp b/link/modules/asio-standalone/asio/include/asio/ts/socket.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/ts/socket.hpp
@@ -0,0 +1,27 @@
+//
+// ts/socket.hpp
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_TS_SOCKET_HPP
+#define ASIO_TS_SOCKET_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/socket_base.hpp"
+#include "asio/basic_socket.hpp"
+#include "asio/basic_datagram_socket.hpp"
+#include "asio/basic_stream_socket.hpp"
+#include "asio/basic_socket_acceptor.hpp"
+#include "asio/basic_socket_streambuf.hpp"
+#include "asio/basic_socket_iostream.hpp"
+#include "asio/connect.hpp"
+
+#endif // ASIO_TS_SOCKET_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/ts/timer.hpp b/link/modules/asio-standalone/asio/include/asio/ts/timer.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/ts/timer.hpp
@@ -0,0 +1,26 @@
+//
+// ts/timer.hpp
+// ~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_TS_TIMER_HPP
+#define ASIO_TS_TIMER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/chrono.hpp"
+
+#include "asio/wait_traits.hpp"
+#include "asio/basic_waitable_timer.hpp"
+#include "asio/system_timer.hpp"
+#include "asio/steady_timer.hpp"
+#include "asio/high_resolution_timer.hpp"
+
+#endif // ASIO_TS_TIMER_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/unyield.hpp b/link/modules/asio-standalone/asio/include/asio/unyield.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/unyield.hpp
@@ -0,0 +1,21 @@
+//
+// unyield.hpp
+// ~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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)
+//
+
+#ifdef reenter
+# undef reenter
+#endif
+
+#ifdef yield
+# undef yield
+#endif
+
+#ifdef fork
+# undef fork
+#endif
diff --git a/link/modules/asio-standalone/asio/include/asio/use_awaitable.hpp b/link/modules/asio-standalone/asio/include/asio/use_awaitable.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/use_awaitable.hpp
@@ -0,0 +1,169 @@
+//
+// use_awaitable.hpp
+// ~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_USE_AWAITABLE_HPP
+#define ASIO_USE_AWAITABLE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_CO_AWAIT) || defined(GENERATING_DOCUMENTATION)
+
+#include "asio/awaitable.hpp"
+#include "asio/detail/handler_tracking.hpp"
+
+#if defined(ASIO_ENABLE_HANDLER_TRACKING)
+# if defined(ASIO_HAS_SOURCE_LOCATION)
+#  include "asio/detail/source_location.hpp"
+# endif // defined(ASIO_HAS_SOURCE_LOCATION)
+#endif // defined(ASIO_ENABLE_HANDLER_TRACKING)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+/// A completion token that represents the currently executing coroutine.
+/**
+ * The @c use_awaitable_t class, with its value @c use_awaitable, is used to
+ * represent the currently executing coroutine. This completion token may be
+ * passed as a handler to an asynchronous operation. For example:
+ *
+ * @code awaitable<void> my_coroutine()
+ * {
+ *   std::size_t n = co_await my_socket.async_read_some(buffer, use_awaitable);
+ *   ...
+ * } @endcode
+ *
+ * When used with co_await, the initiating function (@c async_read_some in the
+ * above example) suspends the current coroutine. The coroutine is resumed when
+ * the asynchronous operation completes, and the result of the operation is
+ * returned.
+ */
+template <typename Executor = any_io_executor>
+struct use_awaitable_t
+{
+  /// Default constructor.
+  ASIO_CONSTEXPR use_awaitable_t(
+#if defined(ASIO_ENABLE_HANDLER_TRACKING)
+# if defined(ASIO_HAS_SOURCE_LOCATION)
+      detail::source_location location = detail::source_location::current()
+# endif // defined(ASIO_HAS_SOURCE_LOCATION)
+#endif // defined(ASIO_ENABLE_HANDLER_TRACKING)
+    )
+#if defined(ASIO_ENABLE_HANDLER_TRACKING)
+# if defined(ASIO_HAS_SOURCE_LOCATION)
+    : file_name_(location.file_name()),
+      line_(location.line()),
+      function_name_(location.function_name())
+# else // defined(ASIO_HAS_SOURCE_LOCATION)
+    : file_name_(0),
+      line_(0),
+      function_name_(0)
+# endif // defined(ASIO_HAS_SOURCE_LOCATION)
+#endif // defined(ASIO_ENABLE_HANDLER_TRACKING)
+  {
+  }
+
+  /// Constructor used to specify file name, line, and function name.
+  ASIO_CONSTEXPR use_awaitable_t(const char* file_name,
+      int line, const char* function_name)
+#if defined(ASIO_ENABLE_HANDLER_TRACKING)
+    : file_name_(file_name),
+      line_(line),
+      function_name_(function_name)
+#endif // defined(ASIO_ENABLE_HANDLER_TRACKING)
+  {
+#if !defined(ASIO_ENABLE_HANDLER_TRACKING)
+    (void)file_name;
+    (void)line;
+    (void)function_name;
+#endif // !defined(ASIO_ENABLE_HANDLER_TRACKING)
+  }
+
+  /// Adapts an executor to add the @c use_awaitable_t completion token as the
+  /// default.
+  template <typename InnerExecutor>
+  struct executor_with_default : InnerExecutor
+  {
+    /// Specify @c use_awaitable_t as the default completion token type.
+    typedef use_awaitable_t default_completion_token_type;
+
+    /// Construct the adapted executor from the inner executor type.
+    executor_with_default(const InnerExecutor& ex) ASIO_NOEXCEPT
+      : InnerExecutor(ex)
+    {
+    }
+
+    /// Convert the specified executor to the inner executor type, then use
+    /// that to construct the adapted executor.
+    template <typename OtherExecutor>
+    executor_with_default(const OtherExecutor& ex,
+        typename enable_if<
+          is_convertible<OtherExecutor, InnerExecutor>::value
+        >::type* = 0) ASIO_NOEXCEPT
+      : InnerExecutor(ex)
+    {
+    }
+  };
+
+  /// Type alias to adapt an I/O object to use @c use_awaitable_t as its
+  /// default completion token type.
+#if defined(ASIO_HAS_ALIAS_TEMPLATES) \
+  || defined(GENERATING_DOCUMENTATION)
+  template <typename T>
+  using as_default_on_t = typename T::template rebind_executor<
+      executor_with_default<typename T::executor_type> >::other;
+#endif // defined(ASIO_HAS_ALIAS_TEMPLATES)
+       //   || defined(GENERATING_DOCUMENTATION)
+
+  /// Function helper to adapt an I/O object to use @c use_awaitable_t as its
+  /// default completion token type.
+  template <typename T>
+  static typename decay<T>::type::template rebind_executor<
+      executor_with_default<typename decay<T>::type::executor_type>
+    >::other
+  as_default_on(ASIO_MOVE_ARG(T) object)
+  {
+    return typename decay<T>::type::template rebind_executor<
+        executor_with_default<typename decay<T>::type::executor_type>
+      >::other(ASIO_MOVE_CAST(T)(object));
+  }
+
+#if defined(ASIO_ENABLE_HANDLER_TRACKING)
+  const char* file_name_;
+  int line_;
+  const char* function_name_;
+#endif // defined(ASIO_ENABLE_HANDLER_TRACKING)
+};
+
+/// A completion token object that represents the currently executing coroutine.
+/**
+ * See the documentation for asio::use_awaitable_t for a usage example.
+ */
+#if defined(GENERATING_DOCUMENTATION)
+constexpr use_awaitable_t<> use_awaitable;
+#elif defined(ASIO_HAS_CONSTEXPR)
+constexpr use_awaitable_t<> use_awaitable(0, 0, 0);
+#elif defined(ASIO_MSVC)
+__declspec(selectany) use_awaitable_t<> use_awaitable(0, 0, 0);
+#endif
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/impl/use_awaitable.hpp"
+
+#endif // defined(ASIO_HAS_CO_AWAIT) || defined(GENERATING_DOCUMENTATION)
+
+#endif // ASIO_USE_AWAITABLE_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/use_future.hpp b/link/modules/asio-standalone/asio/include/asio/use_future.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/use_future.hpp
@@ -0,0 +1,160 @@
+//
+// use_future.hpp
+// ~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_USE_FUTURE_HPP
+#define ASIO_USE_FUTURE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/future.hpp"
+
+#if defined(ASIO_HAS_STD_FUTURE_CLASS) \
+  || defined(GENERATING_DOCUMENTATION)
+
+#include <memory>
+#include "asio/detail/type_traits.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Function, typename Allocator>
+class packaged_token;
+
+template <typename Function, typename Allocator, typename Result>
+class packaged_handler;
+
+} // namespace detail
+
+/// Class used to specify that an asynchronous operation should return a future.
+/**
+ * The use_future_t class is used to indicate that an asynchronous operation
+ * should return a std::future object. A use_future_t object may be passed as a
+ * handler to an asynchronous operation, typically using the special value @c
+ * asio::use_future. For example:
+ *
+ * @code std::future<std::size_t> my_future
+ *   = my_socket.async_read_some(my_buffer, asio::use_future); @endcode
+ *
+ * The initiating function (async_read_some in the above example) returns a
+ * future that will receive the result of the operation. If the operation
+ * completes with an error_code indicating failure, it is converted into a
+ * system_error and passed back to the caller via the future.
+ */
+template <typename Allocator = std::allocator<void> >
+class use_future_t
+{
+public:
+  /// The allocator type. The allocator is used when constructing the
+  /// @c std::promise object for a given asynchronous operation.
+  typedef Allocator allocator_type;
+
+  /// Construct using default-constructed allocator.
+  ASIO_CONSTEXPR use_future_t()
+  {
+  }
+
+  /// Construct using specified allocator.
+  explicit use_future_t(const Allocator& allocator)
+    : allocator_(allocator)
+  {
+  }
+
+#if !defined(ASIO_NO_DEPRECATED)
+  /// (Deprecated: Use rebind().) Specify an alternate allocator.
+  template <typename OtherAllocator>
+  use_future_t<OtherAllocator> operator[](const OtherAllocator& allocator) const
+  {
+    return use_future_t<OtherAllocator>(allocator);
+  }
+#endif // !defined(ASIO_NO_DEPRECATED)
+
+  /// Specify an alternate allocator.
+  template <typename OtherAllocator>
+  use_future_t<OtherAllocator> rebind(const OtherAllocator& allocator) const
+  {
+    return use_future_t<OtherAllocator>(allocator);
+  }
+
+  /// Obtain allocator.
+  allocator_type get_allocator() const
+  {
+    return allocator_;
+  }
+
+  /// Wrap a function object in a packaged task.
+  /**
+   * The @c package function is used to adapt a function object as a packaged
+   * task. When this adapter is passed as a completion token to an asynchronous
+   * operation, the result of the function object is retuned via a std::future.
+   *
+   * @par Example
+   *
+   * @code std::future<std::size_t> fut =
+   *   my_socket.async_read_some(buffer,
+   *     use_future([](asio::error_code ec, std::size_t n)
+   *       {
+   *         return ec ? 0 : n;
+   *       }));
+   * ...
+   * std::size_t n = fut.get(); @endcode
+   */
+  template <typename Function>
+#if defined(GENERATING_DOCUMENTATION)
+  unspecified
+#else // defined(GENERATING_DOCUMENTATION)
+  detail::packaged_token<typename decay<Function>::type, Allocator>
+#endif // defined(GENERATING_DOCUMENTATION)
+  operator()(ASIO_MOVE_ARG(Function) f) const;
+
+private:
+  // Helper type to ensure that use_future can be constexpr default-constructed
+  // even when std::allocator<void> can't be.
+  struct std_allocator_void
+  {
+    ASIO_CONSTEXPR std_allocator_void()
+    {
+    }
+
+    operator std::allocator<void>() const
+    {
+      return std::allocator<void>();
+    }
+  };
+
+  typename conditional<
+    is_same<std::allocator<void>, Allocator>::value,
+    std_allocator_void, Allocator>::type allocator_;
+};
+
+/// A special value, similar to std::nothrow.
+/**
+ * See the documentation for asio::use_future_t for a usage example.
+ */
+#if defined(ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION)
+constexpr use_future_t<> use_future;
+#elif defined(ASIO_MSVC)
+__declspec(selectany) use_future_t<> use_future;
+#endif
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/impl/use_future.hpp"
+
+#endif // defined(ASIO_HAS_STD_FUTURE_CLASS)
+       //   || defined(GENERATING_DOCUMENTATION)
+
+#endif // ASIO_USE_FUTURE_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/uses_executor.hpp b/link/modules/asio-standalone/asio/include/asio/uses_executor.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/uses_executor.hpp
@@ -0,0 +1,71 @@
+//
+// uses_executor.hpp
+// ~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_USES_EXECUTOR_HPP
+#define ASIO_USES_EXECUTOR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/type_traits.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+/// A special type, similar to std::nothrow_t, used to disambiguate
+/// constructors that accept executor arguments.
+/**
+ * The executor_arg_t struct is an empty structure type used as a unique type
+ * to disambiguate constructor and function overloading. Specifically, some
+ * types have constructors with executor_arg_t as the first argument,
+ * immediately followed by an argument of a type that satisfies the Executor
+ * type requirements.
+ */
+struct executor_arg_t
+{
+  /// Constructor.
+  ASIO_CONSTEXPR executor_arg_t() ASIO_NOEXCEPT
+  {
+  }
+};
+
+/// A special value, similar to std::nothrow, used to disambiguate constructors
+/// that accept executor arguments.
+/**
+ * See asio::executor_arg_t and asio::uses_executor
+ * for more information.
+ */
+#if defined(ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION)
+constexpr executor_arg_t executor_arg;
+#elif defined(ASIO_MSVC)
+__declspec(selectany) executor_arg_t executor_arg;
+#endif
+
+/// The uses_executor trait detects whether a type T has an associated executor
+/// that is convertible from type Executor.
+/**
+ * Meets the BinaryTypeTrait requirements. The Asio library provides a
+ * definition that is derived from false_type. A program may specialize this
+ * template to derive from true_type for a user-defined type T that can be
+ * constructed with an executor, where the first argument of a constructor has
+ * type executor_arg_t and the second argument is convertible from type
+ * Executor.
+ */
+template <typename T, typename Executor>
+struct uses_executor : false_type {};
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_USES_EXECUTOR_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/version.hpp b/link/modules/asio-standalone/asio/include/asio/version.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/version.hpp
@@ -0,0 +1,23 @@
+//
+// version.hpp
+// ~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_VERSION_HPP
+#define ASIO_VERSION_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+// ASIO_VERSION % 100 is the sub-minor version
+// ASIO_VERSION / 100 % 1000 is the minor version
+// ASIO_VERSION / 100000 is the major version
+#define ASIO_VERSION 101700 // 1.17.0
+
+#endif // ASIO_VERSION_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/wait_traits.hpp b/link/modules/asio-standalone/asio/include/asio/wait_traits.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/wait_traits.hpp
@@ -0,0 +1,56 @@
+//
+// wait_traits.hpp
+// ~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_WAIT_TRAITS_HPP
+#define ASIO_WAIT_TRAITS_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+/// Wait traits suitable for use with the basic_waitable_timer class template.
+template <typename Clock>
+struct wait_traits
+{
+  /// Convert a clock duration into a duration used for waiting.
+  /**
+   * @returns @c d.
+   */
+  static typename Clock::duration to_wait_duration(
+      const typename Clock::duration& d)
+  {
+    return d;
+  }
+
+  /// Convert a clock duration into a duration used for waiting.
+  /**
+   * @returns @c d.
+   */
+  static typename Clock::duration to_wait_duration(
+      const typename Clock::time_point& t)
+  {
+    typename Clock::time_point now = Clock::now();
+    if (now + (Clock::duration::max)() < t)
+      return (Clock::duration::max)();
+    if (now + (Clock::duration::min)() > t)
+      return (Clock::duration::min)();
+    return t - now;
+  }
+};
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_WAIT_TRAITS_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/windows/basic_object_handle.hpp b/link/modules/asio-standalone/asio/include/asio/windows/basic_object_handle.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/windows/basic_object_handle.hpp
@@ -0,0 +1,435 @@
+//
+// windows/basic_object_handle.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2011 Boris Schaeling (boris@highscore.de)
+//
+// 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 ASIO_WINDOWS_BASIC_OBJECT_HANDLE_HPP
+#define ASIO_WINDOWS_BASIC_OBJECT_HANDLE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_WINDOWS_OBJECT_HANDLE) \
+  || defined(GENERATING_DOCUMENTATION)
+
+#include "asio/any_io_executor.hpp"
+#include "asio/async_result.hpp"
+#include "asio/detail/io_object_impl.hpp"
+#include "asio/detail/throw_error.hpp"
+#include "asio/detail/win_object_handle_service.hpp"
+#include "asio/error.hpp"
+#include "asio/execution_context.hpp"
+
+#if defined(ASIO_HAS_MOVE)
+# include <utility>
+#endif // defined(ASIO_HAS_MOVE)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace windows {
+
+/// Provides object-oriented handle functionality.
+/**
+ * The windows::basic_object_handle class provides asynchronous and blocking
+ * object-oriented handle functionality.
+ *
+ * @par Thread Safety
+ * @e Distinct @e objects: Safe.@n
+ * @e Shared @e objects: Unsafe.
+ */
+template <typename Executor = any_io_executor>
+class basic_object_handle
+{
+public:
+  /// The type of the executor associated with the object.
+  typedef Executor executor_type;
+
+  /// Rebinds the handle type to another executor.
+  template <typename Executor1>
+  struct rebind_executor
+  {
+    /// The handle type when rebound to the specified executor.
+    typedef basic_object_handle<Executor1> other;
+  };
+
+  /// The native representation of a handle.
+#if defined(GENERATING_DOCUMENTATION)
+  typedef implementation_defined native_handle_type;
+#else
+  typedef asio::detail::win_object_handle_service::native_handle_type
+    native_handle_type;
+#endif
+
+  /// An object handle is always the lowest layer.
+  typedef basic_object_handle lowest_layer_type;
+
+  /// Construct an object handle without opening it.
+  /**
+   * This constructor creates an object handle without opening it.
+   *
+   * @param ex The I/O executor that the object handle will use, by default, to
+   * dispatch handlers for any asynchronous operations performed on the
+   * object handle.
+   */
+  explicit basic_object_handle(const executor_type& ex)
+    : impl_(ex)
+  {
+  }
+
+  /// Construct an object handle without opening it.
+  /**
+   * This constructor creates an object handle without opening it.
+   *
+   * @param context An execution context which provides the I/O executor that
+   * the object handle will use, by default, to dispatch handlers for any
+   * asynchronous operations performed on the object handle.
+   */
+  template <typename ExecutionContext>
+  explicit basic_object_handle(ExecutionContext& context,
+      typename enable_if<
+        is_convertible<ExecutionContext&, execution_context&>::value,
+        basic_object_handle
+      >::type* = 0)
+    : impl_(context)
+  {
+  }
+
+  /// Construct an object handle on an existing native handle.
+  /**
+   * This constructor creates an object handle object to hold an existing native
+   * handle.
+   *
+   * @param ex The I/O executor that the object handle will use, by default, to
+   * dispatch handlers for any asynchronous operations performed on the
+   * object handle.
+   *
+   * @param native_handle The new underlying handle implementation.
+   *
+   * @throws asio::system_error Thrown on failure.
+   */
+  basic_object_handle(const executor_type& ex,
+      const native_handle_type& native_handle)
+    : impl_(ex)
+  {
+    asio::error_code ec;
+    impl_.get_service().assign(impl_.get_implementation(), native_handle, ec);
+    asio::detail::throw_error(ec, "assign");
+  }
+
+  /// Construct an object handle on an existing native handle.
+  /**
+   * This constructor creates an object handle object to hold an existing native
+   * handle.
+   *
+   * @param context An execution context which provides the I/O executor that
+   * the object handle will use, by default, to dispatch handlers for any
+   * asynchronous operations performed on the object handle.
+   *
+   * @param native_handle The new underlying handle implementation.
+   *
+   * @throws asio::system_error Thrown on failure.
+   */
+  template <typename ExecutionContext>
+  basic_object_handle(ExecutionContext& context,
+      const native_handle_type& native_handle,
+      typename enable_if<
+        is_convertible<ExecutionContext&, execution_context&>::value
+      >::type* = 0)
+    : impl_(context)
+  {
+    asio::error_code ec;
+    impl_.get_service().assign(impl_.get_implementation(), native_handle, ec);
+    asio::detail::throw_error(ec, "assign");
+  }
+
+#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+  /// Move-construct an object handle from another.
+  /**
+   * This constructor moves an object handle from one object to another.
+   *
+   * @param other The other object handle object from which the move will
+   * occur.
+   *
+   * @note Following the move, the moved-from object is in the same state as if
+   * constructed using the @c basic_object_handle(const executor_type&)
+   * constructor.
+   */
+  basic_object_handle(basic_object_handle&& other)
+    : impl_(std::move(other.impl_))
+  {
+  }
+
+  /// Move-assign an object handle from another.
+  /**
+   * This assignment operator moves an object handle from one object to another.
+   *
+   * @param other The other object handle object from which the move will
+   * occur.
+   *
+   * @note Following the move, the moved-from object is in the same state as if
+   * constructed using the @c basic_object_handle(const executor_type&)
+   * constructor.
+   */
+  basic_object_handle& operator=(basic_object_handle&& other)
+  {
+    impl_ = std::move(other.impl_);
+    return *this;
+  }
+#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+
+  /// Get the executor associated with the object.
+  executor_type get_executor() ASIO_NOEXCEPT
+  {
+    return impl_.get_executor();
+  }
+
+  /// Get a reference to the lowest layer.
+  /**
+   * This function returns a reference to the lowest layer in a stack of
+   * layers. Since an object handle cannot contain any further layers, it simply
+   * returns a reference to itself.
+   *
+   * @return A reference to the lowest layer in the stack of layers. Ownership
+   * is not transferred to the caller.
+   */
+  lowest_layer_type& lowest_layer()
+  {
+    return *this;
+  }
+
+  /// Get a const reference to the lowest layer.
+  /**
+   * This function returns a const reference to the lowest layer in a stack of
+   * layers. Since an object handle cannot contain any further layers, it simply
+   * returns a reference to itself.
+   *
+   * @return A const reference to the lowest layer in the stack of layers.
+   * Ownership is not transferred to the caller.
+   */
+  const lowest_layer_type& lowest_layer() const
+  {
+    return *this;
+  }
+
+  /// Assign an existing native handle to the handle.
+  /*
+   * This function opens the handle to hold an existing native handle.
+   *
+   * @param handle A native handle.
+   *
+   * @throws asio::system_error Thrown on failure.
+   */
+  void assign(const native_handle_type& handle)
+  {
+    asio::error_code ec;
+    impl_.get_service().assign(impl_.get_implementation(), handle, ec);
+    asio::detail::throw_error(ec, "assign");
+  }
+
+  /// Assign an existing native handle to the handle.
+  /*
+   * This function opens the handle to hold an existing native handle.
+   *
+   * @param handle A native handle.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   */
+  ASIO_SYNC_OP_VOID assign(const native_handle_type& handle,
+      asio::error_code& ec)
+  {
+    impl_.get_service().assign(impl_.get_implementation(), handle, ec);
+    ASIO_SYNC_OP_VOID_RETURN(ec);
+  }
+
+  /// Determine whether the handle is open.
+  bool is_open() const
+  {
+    return impl_.get_service().is_open(impl_.get_implementation());
+  }
+
+  /// Close the handle.
+  /**
+   * This function is used to close the handle. Any asynchronous read or write
+   * operations will be cancelled immediately, and will complete with the
+   * asio::error::operation_aborted error.
+   *
+   * @throws asio::system_error Thrown on failure.
+   */
+  void close()
+  {
+    asio::error_code ec;
+    impl_.get_service().close(impl_.get_implementation(), ec);
+    asio::detail::throw_error(ec, "close");
+  }
+
+  /// Close the handle.
+  /**
+   * This function is used to close the handle. Any asynchronous read or write
+   * operations will be cancelled immediately, and will complete with the
+   * asio::error::operation_aborted error.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   */
+  ASIO_SYNC_OP_VOID close(asio::error_code& ec)
+  {
+    impl_.get_service().close(impl_.get_implementation(), ec);
+    ASIO_SYNC_OP_VOID_RETURN(ec);
+  }
+
+  /// Get the native handle representation.
+  /**
+   * This function may be used to obtain the underlying representation of the
+   * handle. This is intended to allow access to native handle functionality
+   * that is not otherwise provided.
+   */
+  native_handle_type native_handle()
+  {
+    return impl_.get_service().native_handle(impl_.get_implementation());
+  }
+
+  /// Cancel all asynchronous operations associated with the handle.
+  /**
+   * This function causes all outstanding asynchronous read or write operations
+   * to finish immediately, and the handlers for cancelled operations will be
+   * passed the asio::error::operation_aborted error.
+   *
+   * @throws asio::system_error Thrown on failure.
+   */
+  void cancel()
+  {
+    asio::error_code ec;
+    impl_.get_service().cancel(impl_.get_implementation(), ec);
+    asio::detail::throw_error(ec, "cancel");
+  }
+
+  /// Cancel all asynchronous operations associated with the handle.
+  /**
+   * This function causes all outstanding asynchronous read or write operations
+   * to finish immediately, and the handlers for cancelled operations will be
+   * passed the asio::error::operation_aborted error.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   */
+  ASIO_SYNC_OP_VOID cancel(asio::error_code& ec)
+  {
+    impl_.get_service().cancel(impl_.get_implementation(), ec);
+    ASIO_SYNC_OP_VOID_RETURN(ec);
+  }
+
+  /// Perform a blocking wait on the object handle.
+  /**
+   * This function is used to wait for the object handle to be set to the
+   * signalled state. This function blocks and does not return until the object
+   * handle has been set to the signalled state.
+   *
+   * @throws asio::system_error Thrown on failure.
+   */
+  void wait()
+  {
+    asio::error_code ec;
+    impl_.get_service().wait(impl_.get_implementation(), ec);
+    asio::detail::throw_error(ec, "wait");
+  }
+
+  /// Perform a blocking wait on the object handle.
+  /**
+   * This function is used to wait for the object handle to be set to the
+   * signalled state. This function blocks and does not return until the object
+   * handle has been set to the signalled state.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   */
+  void wait(asio::error_code& ec)
+  {
+    impl_.get_service().wait(impl_.get_implementation(), ec);
+  }
+
+  /// Start an asynchronous wait on the object handle.
+  /**
+   * This function is be used to initiate an asynchronous wait against the
+   * object handle. It always returns immediately.
+   *
+   * @param handler The handler to be called when the object handle is set to
+   * the signalled state. Copies will be made of the handler as required. The
+   * function signature of the handler must be:
+   * @code void handler(
+   *   const asio::error_code& error // Result of operation.
+   * ); @endcode
+   * Regardless of whether the asynchronous operation completes immediately or
+   * not, the handler will not be invoked from within this function. On
+   * immediate completion, invocation of the handler will be performed in a
+   * manner equivalent to using asio::post().
+   */
+  template <
+      ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code))
+        WaitHandler ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
+  ASIO_INITFN_AUTO_RESULT_TYPE(WaitHandler,
+      void (asio::error_code))
+  async_wait(
+      ASIO_MOVE_ARG(WaitHandler) handler
+        ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
+  {
+    return async_initiate<WaitHandler, void (asio::error_code)>(
+        initiate_async_wait(this), handler);
+  }
+
+private:
+  // Disallow copying and assignment.
+  basic_object_handle(const basic_object_handle&) ASIO_DELETED;
+  basic_object_handle& operator=(const basic_object_handle&) ASIO_DELETED;
+
+  class initiate_async_wait
+  {
+  public:
+    typedef Executor executor_type;
+
+    explicit initiate_async_wait(basic_object_handle* self)
+      : self_(self)
+    {
+    }
+
+    executor_type get_executor() const ASIO_NOEXCEPT
+    {
+      return self_->get_executor();
+    }
+
+    template <typename WaitHandler>
+    void operator()(ASIO_MOVE_ARG(WaitHandler) handler) const
+    {
+      // If you get an error on the following line it means that your handler
+      // does not meet the documented type requirements for a WaitHandler.
+      ASIO_WAIT_HANDLER_CHECK(WaitHandler, handler) type_check;
+
+      detail::non_const_lvalue<WaitHandler> handler2(handler);
+      self_->impl_.get_service().async_wait(
+          self_->impl_.get_implementation(),
+          handler2.value, self_->impl_.get_executor());
+    }
+
+  private:
+    basic_object_handle* self_;
+  };
+
+  asio::detail::io_object_impl<
+    asio::detail::win_object_handle_service, Executor> impl_;
+};
+
+} // namespace windows
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_WINDOWS_OBJECT_HANDLE)
+       //   || defined(GENERATING_DOCUMENTATION)
+
+#endif // ASIO_WINDOWS_BASIC_OBJECT_HANDLE_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/windows/basic_overlapped_handle.hpp b/link/modules/asio-standalone/asio/include/asio/windows/basic_overlapped_handle.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/windows/basic_overlapped_handle.hpp
@@ -0,0 +1,361 @@
+//
+// windows/basic_overlapped_handle.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_WINDOWS_BASIC_OVERLAPPED_HANDLE_HPP
+#define ASIO_WINDOWS_BASIC_OVERLAPPED_HANDLE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) \
+  || defined(ASIO_HAS_WINDOWS_STREAM_HANDLE) \
+  || defined(GENERATING_DOCUMENTATION)
+
+#include <cstddef>
+#include "asio/any_io_executor.hpp"
+#include "asio/async_result.hpp"
+#include "asio/detail/io_object_impl.hpp"
+#include "asio/detail/throw_error.hpp"
+#include "asio/detail/win_iocp_handle_service.hpp"
+#include "asio/error.hpp"
+#include "asio/execution_context.hpp"
+
+#if defined(ASIO_HAS_MOVE)
+# include <utility>
+#endif // defined(ASIO_HAS_MOVE)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace windows {
+
+/// Provides Windows handle functionality for objects that support
+/// overlapped I/O.
+/**
+ * The windows::overlapped_handle class provides the ability to wrap a Windows
+ * handle. The underlying object referred to by the handle must support
+ * overlapped I/O.
+ *
+ * @par Thread Safety
+ * @e Distinct @e objects: Safe.@n
+ * @e Shared @e objects: Unsafe.
+ */
+template <typename Executor = any_io_executor>
+class basic_overlapped_handle
+{
+public:
+  /// The type of the executor associated with the object.
+  typedef Executor executor_type;
+
+  /// Rebinds the handle type to another executor.
+  template <typename Executor1>
+  struct rebind_executor
+  {
+    /// The handle type when rebound to the specified executor.
+    typedef basic_overlapped_handle<Executor1> other;
+  };
+
+  /// The native representation of a handle.
+#if defined(GENERATING_DOCUMENTATION)
+  typedef implementation_defined native_handle_type;
+#else
+  typedef asio::detail::win_iocp_handle_service::native_handle_type
+    native_handle_type;
+#endif
+
+  /// An overlapped_handle is always the lowest layer.
+  typedef basic_overlapped_handle lowest_layer_type;
+
+  /// Construct an overlapped handle without opening it.
+  /**
+   * This constructor creates an overlapped handle without opening it.
+   *
+   * @param ex The I/O executor that the overlapped handle will use, by default,
+   * to dispatch handlers for any asynchronous operations performed on the
+   * overlapped handle.
+   */
+  explicit basic_overlapped_handle(const executor_type& ex)
+    : impl_(ex)
+  {
+  }
+
+  /// Construct an overlapped handle without opening it.
+  /**
+   * This constructor creates an overlapped handle without opening it.
+   *
+   * @param context An execution context which provides the I/O executor that
+   * the overlapped handle will use, by default, to dispatch handlers for any
+   * asynchronous operations performed on the overlapped handle.
+   */
+  template <typename ExecutionContext>
+  explicit basic_overlapped_handle(ExecutionContext& context,
+      typename enable_if<
+        is_convertible<ExecutionContext&, execution_context&>::value,
+        basic_overlapped_handle
+      >::type* = 0)
+    : impl_(context)
+  {
+  }
+
+  /// Construct an overlapped handle on an existing native handle.
+  /**
+   * This constructor creates an overlapped handle object to hold an existing
+   * native handle.
+   *
+   * @param ex The I/O executor that the overlapped handle will use, by default,
+   * to dispatch handlers for any asynchronous operations performed on the
+   * overlapped handle.
+   *
+   * @param native_handle The new underlying handle implementation.
+   *
+   * @throws asio::system_error Thrown on failure.
+   */
+  basic_overlapped_handle(const executor_type& ex,
+      const native_handle_type& native_handle)
+    : impl_(ex)
+  {
+    asio::error_code ec;
+    impl_.get_service().assign(impl_.get_implementation(), native_handle, ec);
+    asio::detail::throw_error(ec, "assign");
+  }
+
+  /// Construct an overlapped handle on an existing native handle.
+  /**
+   * This constructor creates an overlapped handle object to hold an existing
+   * native handle.
+   *
+   * @param context An execution context which provides the I/O executor that
+   * the overlapped handle will use, by default, to dispatch handlers for any
+   * asynchronous operations performed on the overlapped handle.
+   *
+   * @param native_handle The new underlying handle implementation.
+   *
+   * @throws asio::system_error Thrown on failure.
+   */
+  template <typename ExecutionContext>
+  basic_overlapped_handle(ExecutionContext& context,
+      const native_handle_type& native_handle,
+      typename enable_if<
+        is_convertible<ExecutionContext&, execution_context&>::value
+      >::type* = 0)
+    : impl_(context)
+  {
+    asio::error_code ec;
+    impl_.get_service().assign(impl_.get_implementation(), native_handle, ec);
+    asio::detail::throw_error(ec, "assign");
+  }
+
+#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+  /// Move-construct an overlapped handle from another.
+  /**
+   * This constructor moves a handle from one object to another.
+   *
+   * @param other The other overlapped handle object from which the move will
+   * occur.
+   *
+   * @note Following the move, the moved-from object is in the same state as if
+   * constructed using the @c overlapped_handle(const executor_type&)
+   * constructor.
+   */
+  basic_overlapped_handle(basic_overlapped_handle&& other)
+    : impl_(std::move(other.impl_))
+  {
+  }
+
+  /// Move-assign an overlapped handle from another.
+  /**
+   * This assignment operator moves a handle from one object to another.
+   *
+   * @param other The other overlapped handle object from which the move will
+   * occur.
+   *
+   * @note Following the move, the moved-from object is in the same state as if
+   * constructed using the @c overlapped_handle(const executor_type&)
+   * constructor.
+   */
+  basic_overlapped_handle& operator=(basic_overlapped_handle&& other)
+  {
+    impl_ = std::move(other.impl_);
+    return *this;
+  }
+#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+
+  /// Get the executor associated with the object.
+  executor_type get_executor() ASIO_NOEXCEPT
+  {
+    return impl_.get_executor();
+  }
+
+  /// Get a reference to the lowest layer.
+  /**
+   * This function returns a reference to the lowest layer in a stack of
+   * layers. Since an overlapped_handle cannot contain any further layers, it
+   * simply returns a reference to itself.
+   *
+   * @return A reference to the lowest layer in the stack of layers. Ownership
+   * is not transferred to the caller.
+   */
+  lowest_layer_type& lowest_layer()
+  {
+    return *this;
+  }
+
+  /// Get a const reference to the lowest layer.
+  /**
+   * This function returns a const reference to the lowest layer in a stack of
+   * layers. Since an overlapped_handle cannot contain any further layers, it
+   * simply returns a reference to itself.
+   *
+   * @return A const reference to the lowest layer in the stack of layers.
+   * Ownership is not transferred to the caller.
+   */
+  const lowest_layer_type& lowest_layer() const
+  {
+    return *this;
+  }
+
+  /// Assign an existing native handle to the handle.
+  /*
+   * This function opens the handle to hold an existing native handle.
+   *
+   * @param handle A native handle.
+   *
+   * @throws asio::system_error Thrown on failure.
+   */
+  void assign(const native_handle_type& handle)
+  {
+    asio::error_code ec;
+    impl_.get_service().assign(impl_.get_implementation(), handle, ec);
+    asio::detail::throw_error(ec, "assign");
+  }
+
+  /// Assign an existing native handle to the handle.
+  /*
+   * This function opens the handle to hold an existing native handle.
+   *
+   * @param handle A native handle.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   */
+  ASIO_SYNC_OP_VOID assign(const native_handle_type& handle,
+      asio::error_code& ec)
+  {
+    impl_.get_service().assign(impl_.get_implementation(), handle, ec);
+    ASIO_SYNC_OP_VOID_RETURN(ec);
+  }
+
+  /// Determine whether the handle is open.
+  bool is_open() const
+  {
+    return impl_.get_service().is_open(impl_.get_implementation());
+  }
+
+  /// Close the handle.
+  /**
+   * This function is used to close the handle. Any asynchronous read or write
+   * operations will be cancelled immediately, and will complete with the
+   * asio::error::operation_aborted error.
+   *
+   * @throws asio::system_error Thrown on failure.
+   */
+  void close()
+  {
+    asio::error_code ec;
+    impl_.get_service().close(impl_.get_implementation(), ec);
+    asio::detail::throw_error(ec, "close");
+  }
+
+  /// Close the handle.
+  /**
+   * This function is used to close the handle. Any asynchronous read or write
+   * operations will be cancelled immediately, and will complete with the
+   * asio::error::operation_aborted error.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   */
+  ASIO_SYNC_OP_VOID close(asio::error_code& ec)
+  {
+    impl_.get_service().close(impl_.get_implementation(), ec);
+    ASIO_SYNC_OP_VOID_RETURN(ec);
+  }
+
+  /// Get the native handle representation.
+  /**
+   * This function may be used to obtain the underlying representation of the
+   * handle. This is intended to allow access to native handle functionality
+   * that is not otherwise provided.
+   */
+  native_handle_type native_handle()
+  {
+    return impl_.get_service().native_handle(impl_.get_implementation());
+  }
+
+  /// Cancel all asynchronous operations associated with the handle.
+  /**
+   * This function causes all outstanding asynchronous read or write operations
+   * to finish immediately, and the handlers for cancelled operations will be
+   * passed the asio::error::operation_aborted error.
+   *
+   * @throws asio::system_error Thrown on failure.
+   */
+  void cancel()
+  {
+    asio::error_code ec;
+    impl_.get_service().cancel(impl_.get_implementation(), ec);
+    asio::detail::throw_error(ec, "cancel");
+  }
+
+  /// Cancel all asynchronous operations associated with the handle.
+  /**
+   * This function causes all outstanding asynchronous read or write operations
+   * to finish immediately, and the handlers for cancelled operations will be
+   * passed the asio::error::operation_aborted error.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   */
+  ASIO_SYNC_OP_VOID cancel(asio::error_code& ec)
+  {
+    impl_.get_service().cancel(impl_.get_implementation(), ec);
+    ASIO_SYNC_OP_VOID_RETURN(ec);
+  }
+
+protected:
+  /// Protected destructor to prevent deletion through this type.
+  /**
+   * This function destroys the handle, cancelling any outstanding asynchronous
+   * wait operations associated with the handle as if by calling @c cancel.
+   */
+  ~basic_overlapped_handle()
+  {
+  }
+
+  asio::detail::io_object_impl<
+    asio::detail::win_iocp_handle_service, Executor> impl_;
+
+private:
+  // Disallow copying and assignment.
+  basic_overlapped_handle(const basic_overlapped_handle&) ASIO_DELETED;
+  basic_overlapped_handle& operator=(
+      const basic_overlapped_handle&) ASIO_DELETED;
+};
+
+} // namespace windows
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE)
+       //   || defined(ASIO_HAS_WINDOWS_STREAM_HANDLE)
+       //   || defined(GENERATING_DOCUMENTATION)
+
+#endif // ASIO_WINDOWS_BASIC_OVERLAPPED_HANDLE_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/windows/basic_random_access_handle.hpp b/link/modules/asio-standalone/asio/include/asio/windows/basic_random_access_handle.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/windows/basic_random_access_handle.hpp
@@ -0,0 +1,490 @@
+//
+// windows/basic_random_access_handle.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_WINDOWS_BASIC_RANDOM_ACCESS_HANDLE_HPP
+#define ASIO_WINDOWS_BASIC_RANDOM_ACCESS_HANDLE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/windows/basic_overlapped_handle.hpp"
+
+#if defined(ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) \
+  || defined(GENERATING_DOCUMENTATION)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace windows {
+
+/// Provides random-access handle functionality.
+/**
+ * The windows::basic_random_access_handle class provides asynchronous and
+ * blocking random-access handle functionality.
+ *
+ * @par Thread Safety
+ * @e Distinct @e objects: Safe.@n
+ * @e Shared @e objects: Unsafe.
+ */
+template <typename Executor = any_io_executor>
+class basic_random_access_handle
+  : public basic_overlapped_handle<Executor>
+{
+public:
+  /// The type of the executor associated with the object.
+  typedef Executor executor_type;
+
+  /// Rebinds the handle type to another executor.
+  template <typename Executor1>
+  struct rebind_executor
+  {
+    /// The handle type when rebound to the specified executor.
+    typedef basic_random_access_handle<Executor1> other;
+  };
+
+  /// The native representation of a handle.
+#if defined(GENERATING_DOCUMENTATION)
+  typedef implementation_defined native_handle_type;
+#else
+  typedef asio::detail::win_iocp_handle_service::native_handle_type
+    native_handle_type;
+#endif
+
+  /// Construct a random-access handle without opening it.
+  /**
+   * This constructor creates a random-access handle without opening it.
+   *
+   * @param ex The I/O executor that the random-access handle will use, by
+   * default, to dispatch handlers for any asynchronous operations performed on
+   * the random-access handle.
+   */
+  explicit basic_random_access_handle(const executor_type& ex)
+    : basic_overlapped_handle<Executor>(ex)
+  {
+  }
+
+  /// Construct a random-access handle without opening it.
+  /**
+   * This constructor creates a random-access handle without opening it. The
+   * handle needs to be opened or assigned before data can be sent or received
+   * on it.
+   *
+   * @param context An execution context which provides the I/O executor that
+   * the random-access handle will use, by default, to dispatch handlers for any
+   * asynchronous operations performed on the random-access handle.
+   */
+  template <typename ExecutionContext>
+  explicit basic_random_access_handle(ExecutionContext& context,
+      typename enable_if<
+        is_convertible<ExecutionContext&, execution_context&>::value,
+        basic_random_access_handle
+      >::type* = 0)
+    : basic_overlapped_handle<Executor>(context)
+  {
+  }
+
+  /// Construct a random-access handle on an existing native handle.
+  /**
+   * This constructor creates a random-access handle object to hold an existing
+   * native handle.
+   *
+   * @param ex The I/O executor that the random-access handle will use, by
+   * default, to dispatch handlers for any asynchronous operations performed on
+   * the random-access handle.
+   *
+   * @param handle The new underlying handle implementation.
+   *
+   * @throws asio::system_error Thrown on failure.
+   */
+  basic_random_access_handle(const executor_type& ex,
+      const native_handle_type& handle)
+    : basic_overlapped_handle<Executor>(ex, handle)
+  {
+  }
+
+  /// Construct a random-access handle on an existing native handle.
+  /**
+   * This constructor creates a random-access handle object to hold an existing
+   * native handle.
+   *
+   * @param context An execution context which provides the I/O executor that
+   * the random-access handle will use, by default, to dispatch handlers for any
+   * asynchronous operations performed on the random-access handle.
+   *
+   * @param handle The new underlying handle implementation.
+   *
+   * @throws asio::system_error Thrown on failure.
+   */
+  template <typename ExecutionContext>
+  basic_random_access_handle(ExecutionContext& context,
+      const native_handle_type& handle,
+      typename enable_if<
+        is_convertible<ExecutionContext&, execution_context&>::value
+      >::type* = 0)
+    : basic_overlapped_handle<Executor>(context, handle)
+  {
+  }
+
+#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+  /// Move-construct a random-access handle from another.
+  /**
+   * This constructor moves a random-access handle from one object to another.
+   *
+   * @param other The other random-access handle object from which the
+   * move will occur.
+   *
+   * @note Following the move, the moved-from object is in the same state as if
+   * constructed using the @c basic_random_access_handle(const executor_type&)
+   * constructor.
+   */
+  basic_random_access_handle(basic_random_access_handle&& other)
+    : basic_overlapped_handle<Executor>(std::move(other))
+  {
+  }
+
+  /// Move-assign a random-access handle from another.
+  /**
+   * This assignment operator moves a random-access handle from one object to
+   * another.
+   *
+   * @param other The other random-access handle object from which the
+   * move will occur.
+   *
+   * @note Following the move, the moved-from object is in the same state as if
+   * constructed using the @c basic_random_access_handle(const executor_type&)
+   * constructor.
+   */
+  basic_random_access_handle& operator=(basic_random_access_handle&& other)
+  {
+    basic_overlapped_handle<Executor>::operator=(std::move(other));
+    return *this;
+  }
+#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+
+  /// Write some data to the handle at the specified offset.
+  /**
+   * This function is used to write data to the random-access handle. The
+   * function call will block until one or more bytes of the data has been
+   * written successfully, or until an error occurs.
+   *
+   * @param offset The offset at which the data will be written.
+   *
+   * @param buffers One or more data buffers to be written to the handle.
+   *
+   * @returns The number of bytes written.
+   *
+   * @throws asio::system_error Thrown on failure. An error code of
+   * asio::error::eof indicates that the connection was closed by the
+   * peer.
+   *
+   * @note The write_some_at operation may not write all of the data. Consider
+   * using the @ref write_at function if you need to ensure that all data is
+   * written before the blocking operation completes.
+   *
+   * @par Example
+   * To write a single data buffer use the @ref buffer function as follows:
+   * @code
+   * handle.write_some_at(42, asio::buffer(data, size));
+   * @endcode
+   * See the @ref buffer documentation for information on writing multiple
+   * buffers in one go, and how to use it with arrays, boost::array or
+   * std::vector.
+   */
+  template <typename ConstBufferSequence>
+  std::size_t write_some_at(uint64_t offset,
+      const ConstBufferSequence& buffers)
+  {
+    asio::error_code ec;
+    std::size_t s = this->impl_.get_service().write_some_at(
+        this->impl_.get_implementation(), offset, buffers, ec);
+    asio::detail::throw_error(ec, "write_some_at");
+    return s;
+  }
+
+  /// Write some data to the handle at the specified offset.
+  /**
+   * This function is used to write data to the random-access handle. The
+   * function call will block until one or more bytes of the data has been
+   * written successfully, or until an error occurs.
+   *
+   * @param offset The offset at which the data will be written.
+   *
+   * @param buffers One or more data buffers to be written to the handle.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   *
+   * @returns The number of bytes written. Returns 0 if an error occurred.
+   *
+   * @note The write_some operation may not transmit all of the data to the
+   * peer. Consider using the @ref write_at function if you need to ensure that
+   * all data is written before the blocking operation completes.
+   */
+  template <typename ConstBufferSequence>
+  std::size_t write_some_at(uint64_t offset,
+      const ConstBufferSequence& buffers, asio::error_code& ec)
+  {
+    return this->impl_.get_service().write_some_at(
+        this->impl_.get_implementation(), offset, buffers, ec);
+  }
+
+  /// Start an asynchronous write at the specified offset.
+  /**
+   * This function is used to asynchronously write data to the random-access
+   * handle. The function call always returns immediately.
+   *
+   * @param offset The offset at which the data will be written.
+   *
+   * @param buffers One or more data buffers to be written to the handle.
+   * Although the buffers object may be copied as necessary, ownership of the
+   * underlying memory blocks is retained by the caller, which must guarantee
+   * that they remain valid until the handler is called.
+   *
+   * @param handler The handler to be called when the write operation completes.
+   * Copies will be made of the handler as required. The function signature of
+   * the handler must be:
+   * @code void handler(
+   *   const asio::error_code& error, // Result of operation.
+   *   std::size_t bytes_transferred           // Number of bytes written.
+   * ); @endcode
+   * Regardless of whether the asynchronous operation completes immediately or
+   * not, the handler will not be invoked from within this function. On
+   * immediate completion, invocation of the handler will be performed in a
+   * manner equivalent to using asio::post().
+   *
+   * @note The write operation may not transmit all of the data to the peer.
+   * Consider using the @ref async_write_at function if you need to ensure that
+   * all data is written before the asynchronous operation completes.
+   *
+   * @par Example
+   * To write a single data buffer use the @ref buffer function as follows:
+   * @code
+   * handle.async_write_some_at(42, asio::buffer(data, size), handler);
+   * @endcode
+   * See the @ref buffer documentation for information on writing multiple
+   * buffers in one go, and how to use it with arrays, boost::array or
+   * std::vector.
+   */
+  template <typename ConstBufferSequence,
+      ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+        std::size_t)) WriteHandler
+          ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
+  ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,
+      void (asio::error_code, std::size_t))
+  async_write_some_at(uint64_t offset,
+      const ConstBufferSequence& buffers,
+      ASIO_MOVE_ARG(WriteHandler) handler
+        ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
+  {
+    return async_initiate<WriteHandler,
+      void (asio::error_code, std::size_t)>(
+        initiate_async_write_some_at(this), handler, offset, buffers);
+  }
+
+  /// Read some data from the handle at the specified offset.
+  /**
+   * This function is used to read data from the random-access handle. The
+   * function call will block until one or more bytes of data has been read
+   * successfully, or until an error occurs.
+   *
+   * @param offset The offset at which the data will be read.
+   *
+   * @param buffers One or more buffers into which the data will be read.
+   *
+   * @returns The number of bytes read.
+   *
+   * @throws asio::system_error Thrown on failure. An error code of
+   * asio::error::eof indicates that the connection was closed by the
+   * peer.
+   *
+   * @note The read_some operation may not read all of the requested number of
+   * bytes. Consider using the @ref read_at function if you need to ensure that
+   * the requested amount of data is read before the blocking operation
+   * completes.
+   *
+   * @par Example
+   * To read into a single data buffer use the @ref buffer function as follows:
+   * @code
+   * handle.read_some_at(42, asio::buffer(data, size));
+   * @endcode
+   * See the @ref buffer documentation for information on reading into multiple
+   * buffers in one go, and how to use it with arrays, boost::array or
+   * std::vector.
+   */
+  template <typename MutableBufferSequence>
+  std::size_t read_some_at(uint64_t offset,
+      const MutableBufferSequence& buffers)
+  {
+    asio::error_code ec;
+    std::size_t s = this->impl_.get_service().read_some_at(
+        this->impl_.get_implementation(), offset, buffers, ec);
+    asio::detail::throw_error(ec, "read_some_at");
+    return s;
+  }
+
+  /// Read some data from the handle at the specified offset.
+  /**
+   * This function is used to read data from the random-access handle. The
+   * function call will block until one or more bytes of data has been read
+   * successfully, or until an error occurs.
+   *
+   * @param offset The offset at which the data will be read.
+   *
+   * @param buffers One or more buffers into which the data will be read.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   *
+   * @returns The number of bytes read. Returns 0 if an error occurred.
+   *
+   * @note The read_some operation may not read all of the requested number of
+   * bytes. Consider using the @ref read_at function if you need to ensure that
+   * the requested amount of data is read before the blocking operation
+   * completes.
+   */
+  template <typename MutableBufferSequence>
+  std::size_t read_some_at(uint64_t offset,
+      const MutableBufferSequence& buffers, asio::error_code& ec)
+  {
+    return this->impl_.get_service().read_some_at(
+        this->impl_.get_implementation(), offset, buffers, ec);
+  }
+
+  /// Start an asynchronous read at the specified offset.
+  /**
+   * This function is used to asynchronously read data from the random-access
+   * handle. The function call always returns immediately.
+   *
+   * @param offset The offset at which the data will be read.
+   *
+   * @param buffers One or more buffers into which the data will be read.
+   * Although the buffers object may be copied as necessary, ownership of the
+   * underlying memory blocks is retained by the caller, which must guarantee
+   * that they remain valid until the handler is called.
+   *
+   * @param handler The handler to be called when the read operation completes.
+   * Copies will be made of the handler as required. The function signature of
+   * the handler must be:
+   * @code void handler(
+   *   const asio::error_code& error, // Result of operation.
+   *   std::size_t bytes_transferred           // Number of bytes read.
+   * ); @endcode
+   * Regardless of whether the asynchronous operation completes immediately or
+   * not, the handler will not be invoked from within this function. On
+   * immediate completion, invocation of the handler will be performed in a
+   * manner equivalent to using asio::post().
+   *
+   * @note The read operation may not read all of the requested number of bytes.
+   * Consider using the @ref async_read_at function if you need to ensure that
+   * the requested amount of data is read before the asynchronous operation
+   * completes.
+   *
+   * @par Example
+   * To read into a single data buffer use the @ref buffer function as follows:
+   * @code
+   * handle.async_read_some_at(42, asio::buffer(data, size), handler);
+   * @endcode
+   * See the @ref buffer documentation for information on reading into multiple
+   * buffers in one go, and how to use it with arrays, boost::array or
+   * std::vector.
+   */
+  template <typename MutableBufferSequence,
+      ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+        std::size_t)) ReadHandler
+          ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
+  ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,
+      void (asio::error_code, std::size_t))
+  async_read_some_at(uint64_t offset,
+      const MutableBufferSequence& buffers,
+      ASIO_MOVE_ARG(ReadHandler) handler
+        ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
+  {
+    return async_initiate<ReadHandler,
+      void (asio::error_code, std::size_t)>(
+        initiate_async_read_some_at(this), handler, offset, buffers);
+  }
+
+private:
+  class initiate_async_write_some_at
+  {
+  public:
+    typedef Executor executor_type;
+
+    explicit initiate_async_write_some_at(basic_random_access_handle* self)
+      : self_(self)
+    {
+    }
+
+    executor_type get_executor() const ASIO_NOEXCEPT
+    {
+      return self_->get_executor();
+    }
+
+    template <typename WriteHandler, typename ConstBufferSequence>
+    void operator()(ASIO_MOVE_ARG(WriteHandler) handler,
+        uint64_t offset, const ConstBufferSequence& buffers) const
+    {
+      // If you get an error on the following line it means that your handler
+      // does not meet the documented type requirements for a WriteHandler.
+      ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check;
+
+      detail::non_const_lvalue<WriteHandler> handler2(handler);
+      self_->impl_.get_service().async_write_some_at(
+          self_->impl_.get_implementation(), offset, buffers,
+          handler2.value, self_->impl_.get_executor());
+    }
+
+  private:
+    basic_random_access_handle* self_;
+  };
+
+  class initiate_async_read_some_at
+  {
+  public:
+    typedef Executor executor_type;
+
+    explicit initiate_async_read_some_at(basic_random_access_handle* self)
+      : self_(self)
+    {
+    }
+
+    executor_type get_executor() const ASIO_NOEXCEPT
+    {
+      return self_->get_executor();
+    }
+
+    template <typename ReadHandler, typename MutableBufferSequence>
+    void operator()(ASIO_MOVE_ARG(ReadHandler) handler,
+        uint64_t offset, const MutableBufferSequence& buffers) const
+    {
+      // If you get an error on the following line it means that your handler
+      // does not meet the documented type requirements for a ReadHandler.
+      ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
+
+      detail::non_const_lvalue<ReadHandler> handler2(handler);
+      self_->impl_.get_service().async_read_some_at(
+          self_->impl_.get_implementation(), offset, buffers,
+          handler2.value, self_->impl_.get_executor());
+    }
+
+  private:
+    basic_random_access_handle* self_;
+  };
+};
+
+} // namespace windows
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE)
+       //   || defined(GENERATING_DOCUMENTATION)
+
+#endif // ASIO_WINDOWS_BASIC_RANDOM_ACCESS_HANDLE_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/windows/basic_stream_handle.hpp b/link/modules/asio-standalone/asio/include/asio/windows/basic_stream_handle.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/windows/basic_stream_handle.hpp
@@ -0,0 +1,474 @@
+//
+// windows/basic_stream_handle.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_WINDOWS_BASIC_STREAM_HANDLE_HPP
+#define ASIO_WINDOWS_BASIC_STREAM_HANDLE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/windows/basic_overlapped_handle.hpp"
+
+#if defined(ASIO_HAS_WINDOWS_STREAM_HANDLE) \
+  || defined(GENERATING_DOCUMENTATION)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace windows {
+
+/// Provides stream-oriented handle functionality.
+/**
+ * The windows::basic_stream_handle class provides asynchronous and blocking
+ * stream-oriented handle functionality.
+ *
+ * @par Thread Safety
+ * @e Distinct @e objects: Safe.@n
+ * @e Shared @e objects: Unsafe.
+ *
+ * @par Concepts:
+ * AsyncReadStream, AsyncWriteStream, Stream, SyncReadStream, SyncWriteStream.
+ */
+template <typename Executor = any_io_executor>
+class basic_stream_handle
+  : public basic_overlapped_handle<Executor>
+{
+public:
+  /// The type of the executor associated with the object.
+  typedef Executor executor_type;
+
+  /// Rebinds the handle type to another executor.
+  template <typename Executor1>
+  struct rebind_executor
+  {
+    /// The handle type when rebound to the specified executor.
+    typedef basic_stream_handle<Executor1> other;
+  };
+
+  /// The native representation of a handle.
+#if defined(GENERATING_DOCUMENTATION)
+  typedef implementation_defined native_handle_type;
+#else
+  typedef asio::detail::win_iocp_handle_service::native_handle_type
+    native_handle_type;
+#endif
+
+  /// Construct a stream handle without opening it.
+  /**
+   * This constructor creates a stream handle without opening it.
+   *
+   * @param ex The I/O executor that the stream handle will use, by default, to
+   * dispatch handlers for any asynchronous operations performed on the stream
+   * handle.
+   */
+  explicit basic_stream_handle(const executor_type& ex)
+    : basic_overlapped_handle<Executor>(ex)
+  {
+  }
+
+  /// Construct a stream handle without opening it.
+  /**
+   * This constructor creates a stream handle without opening it. The handle
+   * needs to be opened or assigned before data can be sent or received on it.
+   *
+   * @param context An execution context which provides the I/O executor that
+   * the stream handle will use, by default, to dispatch handlers for any
+   * asynchronous operations performed on the stream handle.
+   */
+  template <typename ExecutionContext>
+  explicit basic_stream_handle(ExecutionContext& context,
+      typename enable_if<
+        is_convertible<ExecutionContext&, execution_context&>::value,
+        basic_stream_handle
+      >::type* = 0)
+    : basic_overlapped_handle<Executor>(context)
+  {
+  }
+
+  /// Construct a stream handle on an existing native handle.
+  /**
+   * This constructor creates a stream handle object to hold an existing native
+   * handle.
+   *
+   * @param ex The I/O executor that the stream handle will use, by default, to
+   * dispatch handlers for any asynchronous operations performed on the stream
+   * handle.
+   *
+   * @param handle The new underlying handle implementation.
+   *
+   * @throws asio::system_error Thrown on failure.
+   */
+  basic_stream_handle(const executor_type& ex, const native_handle_type& handle)
+    : basic_overlapped_handle<Executor>(ex, handle)
+  {
+  }
+
+  /// Construct a stream handle on an existing native handle.
+  /**
+   * This constructor creates a stream handle object to hold an existing native
+   * handle.
+   *
+   * @param context An execution context which provides the I/O executor that
+   * the stream handle will use, by default, to dispatch handlers for any
+   * asynchronous operations performed on the stream handle.
+   *
+   * @param handle The new underlying handle implementation.
+   *
+   * @throws asio::system_error Thrown on failure.
+   */
+  template <typename ExecutionContext>
+  basic_stream_handle(ExecutionContext& context,
+      const native_handle_type& handle,
+      typename enable_if<
+        is_convertible<ExecutionContext&, execution_context&>::value
+      >::type* = 0)
+    : basic_overlapped_handle<Executor>(context, handle)
+  {
+  }
+
+#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+  /// Move-construct a stream handle from another.
+  /**
+   * This constructor moves a stream handle from one object to another.
+   *
+   * @param other The other stream handle object from which the move
+   * will occur.
+   *
+   * @note Following the move, the moved-from object is in the same state as if
+   * constructed using the @c basic_stream_handle(const executor_type&)
+   * constructor.
+   */
+  basic_stream_handle(basic_stream_handle&& other)
+    : basic_overlapped_handle<Executor>(std::move(other))
+  {
+  }
+
+  /// Move-assign a stream handle from another.
+  /**
+   * This assignment operator moves a stream handle from one object to
+   * another.
+   *
+   * @param other The other stream handle object from which the move will occur.
+   *
+   * @note Following the move, the moved-from object is in the same state as if
+   * constructed using the @c basic_stream_handle(const executor_type&)
+   * constructor.
+   */
+  basic_stream_handle& operator=(basic_stream_handle&& other)
+  {
+    basic_overlapped_handle<Executor>::operator=(std::move(other));
+    return *this;
+  }
+#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+
+  /// Write some data to the handle.
+  /**
+   * This function is used to write data to the stream handle. The function call
+   * will block until one or more bytes of the data has been written
+   * successfully, or until an error occurs.
+   *
+   * @param buffers One or more data buffers to be written to the handle.
+   *
+   * @returns The number of bytes written.
+   *
+   * @throws asio::system_error Thrown on failure. An error code of
+   * asio::error::eof indicates that the connection was closed by the
+   * peer.
+   *
+   * @note The write_some operation may not transmit all of the data to the
+   * peer. Consider using the @ref write function if you need to ensure that
+   * all data is written before the blocking operation completes.
+   *
+   * @par Example
+   * To write a single data buffer use the @ref buffer function as follows:
+   * @code
+   * handle.write_some(asio::buffer(data, size));
+   * @endcode
+   * See the @ref buffer documentation for information on writing multiple
+   * buffers in one go, and how to use it with arrays, boost::array or
+   * std::vector.
+   */
+  template <typename ConstBufferSequence>
+  std::size_t write_some(const ConstBufferSequence& buffers)
+  {
+    asio::error_code ec;
+    std::size_t s = this->impl_.get_service().write_some(
+        this->impl_.get_implementation(), buffers, ec);
+    asio::detail::throw_error(ec, "write_some");
+    return s;
+  }
+
+  /// Write some data to the handle.
+  /**
+   * This function is used to write data to the stream handle. The function call
+   * will block until one or more bytes of the data has been written
+   * successfully, or until an error occurs.
+   *
+   * @param buffers One or more data buffers to be written to the handle.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   *
+   * @returns The number of bytes written. Returns 0 if an error occurred.
+   *
+   * @note The write_some operation may not transmit all of the data to the
+   * peer. Consider using the @ref write function if you need to ensure that
+   * all data is written before the blocking operation completes.
+   */
+  template <typename ConstBufferSequence>
+  std::size_t write_some(const ConstBufferSequence& buffers,
+      asio::error_code& ec)
+  {
+    return this->impl_.get_service().write_some(
+        this->impl_.get_implementation(), buffers, ec);
+  }
+
+  /// Start an asynchronous write.
+  /**
+   * This function is used to asynchronously write data to the stream handle.
+   * The function call always returns immediately.
+   *
+   * @param buffers One or more data buffers to be written to the handle.
+   * Although the buffers object may be copied as necessary, ownership of the
+   * underlying memory blocks is retained by the caller, which must guarantee
+   * that they remain valid until the handler is called.
+   *
+   * @param handler The handler to be called when the write operation completes.
+   * Copies will be made of the handler as required. The function signature of
+   * the handler must be:
+   * @code void handler(
+   *   const asio::error_code& error, // Result of operation.
+   *   std::size_t bytes_transferred           // Number of bytes written.
+   * ); @endcode
+   * Regardless of whether the asynchronous operation completes immediately or
+   * not, the handler will not be invoked from within this function. On
+   * immediate completion, invocation of the handler will be performed in a
+   * manner equivalent to using asio::post().
+   *
+   * @note The write operation may not transmit all of the data to the peer.
+   * Consider using the @ref async_write function if you need to ensure that all
+   * data is written before the asynchronous operation completes.
+   *
+   * @par Example
+   * To write a single data buffer use the @ref buffer function as follows:
+   * @code
+   * handle.async_write_some(asio::buffer(data, size), handler);
+   * @endcode
+   * See the @ref buffer documentation for information on writing multiple
+   * buffers in one go, and how to use it with arrays, boost::array or
+   * std::vector.
+   */
+  template <typename ConstBufferSequence,
+      ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+        std::size_t)) WriteHandler
+          ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
+  ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,
+      void (asio::error_code, std::size_t))
+  async_write_some(const ConstBufferSequence& buffers,
+      ASIO_MOVE_ARG(WriteHandler) handler
+        ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
+  {
+    return async_initiate<WriteHandler,
+      void (asio::error_code, std::size_t)>(
+        initiate_async_write_some(this), handler, buffers);
+  }
+
+  /// Read some data from the handle.
+  /**
+   * This function is used to read data from the stream handle. The function
+   * call will block until one or more bytes of data has been read successfully,
+   * or until an error occurs.
+   *
+   * @param buffers One or more buffers into which the data will be read.
+   *
+   * @returns The number of bytes read.
+   *
+   * @throws asio::system_error Thrown on failure. An error code of
+   * asio::error::eof indicates that the connection was closed by the
+   * peer.
+   *
+   * @note The read_some operation may not read all of the requested number of
+   * bytes. Consider using the @ref read function if you need to ensure that
+   * the requested amount of data is read before the blocking operation
+   * completes.
+   *
+   * @par Example
+   * To read into a single data buffer use the @ref buffer function as follows:
+   * @code
+   * handle.read_some(asio::buffer(data, size));
+   * @endcode
+   * See the @ref buffer documentation for information on reading into multiple
+   * buffers in one go, and how to use it with arrays, boost::array or
+   * std::vector.
+   */
+  template <typename MutableBufferSequence>
+  std::size_t read_some(const MutableBufferSequence& buffers)
+  {
+    asio::error_code ec;
+    std::size_t s = this->impl_.get_service().read_some(
+        this->impl_.get_implementation(), buffers, ec);
+    asio::detail::throw_error(ec, "read_some");
+    return s;
+  }
+
+  /// Read some data from the handle.
+  /**
+   * This function is used to read data from the stream handle. The function
+   * call will block until one or more bytes of data has been read successfully,
+   * or until an error occurs.
+   *
+   * @param buffers One or more buffers into which the data will be read.
+   *
+   * @param ec Set to indicate what error occurred, if any.
+   *
+   * @returns The number of bytes read. Returns 0 if an error occurred.
+   *
+   * @note The read_some operation may not read all of the requested number of
+   * bytes. Consider using the @ref read function if you need to ensure that
+   * the requested amount of data is read before the blocking operation
+   * completes.
+   */
+  template <typename MutableBufferSequence>
+  std::size_t read_some(const MutableBufferSequence& buffers,
+      asio::error_code& ec)
+  {
+    return this->impl_.get_service().read_some(
+        this->impl_.get_implementation(), buffers, ec);
+  }
+
+  /// Start an asynchronous read.
+  /**
+   * This function is used to asynchronously read data from the stream handle.
+   * The function call always returns immediately.
+   *
+   * @param buffers One or more buffers into which the data will be read.
+   * Although the buffers object may be copied as necessary, ownership of the
+   * underlying memory blocks is retained by the caller, which must guarantee
+   * that they remain valid until the handler is called.
+   *
+   * @param handler The handler to be called when the read operation completes.
+   * Copies will be made of the handler as required. The function signature of
+   * the handler must be:
+   * @code void handler(
+   *   const asio::error_code& error, // Result of operation.
+   *   std::size_t bytes_transferred           // Number of bytes read.
+   * ); @endcode
+   * Regardless of whether the asynchronous operation completes immediately or
+   * not, the handler will not be invoked from within this function. On
+   * immediate completion, invocation of the handler will be performed in a
+   * manner equivalent to using asio::post().
+   *
+   * @note The read operation may not read all of the requested number of bytes.
+   * Consider using the @ref async_read function if you need to ensure that the
+   * requested amount of data is read before the asynchronous operation
+   * completes.
+   *
+   * @par Example
+   * To read into a single data buffer use the @ref buffer function as follows:
+   * @code
+   * handle.async_read_some(asio::buffer(data, size), handler);
+   * @endcode
+   * See the @ref buffer documentation for information on reading into multiple
+   * buffers in one go, and how to use it with arrays, boost::array or
+   * std::vector.
+   */
+  template <typename MutableBufferSequence,
+      ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+        std::size_t)) ReadHandler
+          ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
+  ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,
+      void (asio::error_code, std::size_t))
+  async_read_some(const MutableBufferSequence& buffers,
+      ASIO_MOVE_ARG(ReadHandler) handler
+        ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
+  {
+    return async_initiate<ReadHandler,
+      void (asio::error_code, std::size_t)>(
+        initiate_async_read_some(this), handler, buffers);
+  }
+
+private:
+  class initiate_async_write_some
+  {
+  public:
+    typedef Executor executor_type;
+
+    explicit initiate_async_write_some(basic_stream_handle* self)
+      : self_(self)
+    {
+    }
+
+    executor_type get_executor() const ASIO_NOEXCEPT
+    {
+      return self_->get_executor();
+    }
+
+    template <typename WriteHandler, typename ConstBufferSequence>
+    void operator()(ASIO_MOVE_ARG(WriteHandler) handler,
+        const ConstBufferSequence& buffers) const
+    {
+      // If you get an error on the following line it means that your handler
+      // does not meet the documented type requirements for a WriteHandler.
+      ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check;
+
+      detail::non_const_lvalue<WriteHandler> handler2(handler);
+      self_->impl_.get_service().async_write_some(
+          self_->impl_.get_implementation(), buffers,
+          handler2.value, self_->impl_.get_executor());
+    }
+
+  private:
+    basic_stream_handle* self_;
+  };
+
+  class initiate_async_read_some
+  {
+  public:
+    typedef Executor executor_type;
+
+    explicit initiate_async_read_some(basic_stream_handle* self)
+      : self_(self)
+    {
+    }
+
+    executor_type get_executor() const ASIO_NOEXCEPT
+    {
+      return self_->get_executor();
+    }
+
+    template <typename ReadHandler, typename MutableBufferSequence>
+    void operator()(ASIO_MOVE_ARG(ReadHandler) handler,
+        const MutableBufferSequence& buffers) const
+    {
+      // If you get an error on the following line it means that your handler
+      // does not meet the documented type requirements for a ReadHandler.
+      ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
+
+      detail::non_const_lvalue<ReadHandler> handler2(handler);
+      self_->impl_.get_service().async_read_some(
+          self_->impl_.get_implementation(), buffers,
+          handler2.value, self_->impl_.get_executor());
+    }
+
+  private:
+    basic_stream_handle* self_;
+  };
+};
+
+} // namespace windows
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_WINDOWS_STREAM_HANDLE)
+       //   || defined(GENERATING_DOCUMENTATION)
+
+#endif // ASIO_WINDOWS_BASIC_STREAM_HANDLE_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/windows/object_handle.hpp b/link/modules/asio-standalone/asio/include/asio/windows/object_handle.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/windows/object_handle.hpp
@@ -0,0 +1,38 @@
+//
+// windows/object_handle.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2011 Boris Schaeling (boris@highscore.de)
+//
+// 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 ASIO_WINDOWS_OBJECT_HANDLE_HPP
+#define ASIO_WINDOWS_OBJECT_HANDLE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_WINDOWS_OBJECT_HANDLE) \
+  || defined(GENERATING_DOCUMENTATION)
+
+#include "asio/windows/basic_object_handle.hpp"
+
+namespace asio {
+namespace windows {
+
+/// Typedef for the typical usage of an object handle.
+typedef basic_object_handle<> object_handle;
+
+} // namespace windows
+} // namespace asio
+
+#endif // defined(ASIO_HAS_WINDOWS_OBJECT_HANDLE)
+       //   || defined(GENERATING_DOCUMENTATION)
+
+#endif // ASIO_WINDOWS_OBJECT_HANDLE_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/windows/overlapped_handle.hpp b/link/modules/asio-standalone/asio/include/asio/windows/overlapped_handle.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/windows/overlapped_handle.hpp
@@ -0,0 +1,39 @@
+//
+// windows/overlapped_handle.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_WINDOWS_OVERLAPPED_HANDLE_HPP
+#define ASIO_WINDOWS_OVERLAPPED_HANDLE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) \
+  || defined(ASIO_HAS_WINDOWS_STREAM_HANDLE) \
+  || defined(GENERATING_DOCUMENTATION)
+
+#include "asio/windows/basic_overlapped_handle.hpp"
+
+namespace asio {
+namespace windows {
+
+/// Typedef for the typical usage of an overlapped handle.
+typedef basic_overlapped_handle<> overlapped_handle;
+
+} // namespace windows
+} // namespace asio
+
+#endif // defined(ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE)
+       //   || defined(ASIO_HAS_WINDOWS_STREAM_HANDLE)
+       //   || defined(GENERATING_DOCUMENTATION)
+
+#endif // ASIO_WINDOWS_OVERLAPPED_HANDLE_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/windows/overlapped_ptr.hpp b/link/modules/asio-standalone/asio/include/asio/windows/overlapped_ptr.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/windows/overlapped_ptr.hpp
@@ -0,0 +1,145 @@
+//
+// windows/overlapped_ptr.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_WINDOWS_OVERLAPPED_PTR_HPP
+#define ASIO_WINDOWS_OVERLAPPED_PTR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_WINDOWS_OVERLAPPED_PTR) \
+  || defined(GENERATING_DOCUMENTATION)
+
+#include "asio/detail/noncopyable.hpp"
+#include "asio/detail/win_iocp_overlapped_ptr.hpp"
+#include "asio/io_context.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace windows {
+
+/// Wraps a handler to create an OVERLAPPED object for use with overlapped I/O.
+/**
+ * A special-purpose smart pointer used to wrap an application handler so that
+ * it can be passed as the LPOVERLAPPED argument to overlapped I/O functions.
+ *
+ * @par Thread Safety
+ * @e Distinct @e objects: Safe.@n
+ * @e Shared @e objects: Unsafe.
+ */
+class overlapped_ptr
+  : private noncopyable
+{
+public:
+  /// Construct an empty overlapped_ptr.
+  overlapped_ptr()
+    : impl_()
+  {
+  }
+
+  /// Construct an overlapped_ptr to contain the specified handler.
+  template <typename ExecutionContext, typename Handler>
+  explicit overlapped_ptr(ExecutionContext& context,
+      ASIO_MOVE_ARG(Handler) handler,
+      typename enable_if<
+        is_convertible<ExecutionContext&, execution_context&>::value
+      >::type* = 0)
+    : impl_(context.get_executor(), ASIO_MOVE_CAST(Handler)(handler))
+  {
+  }
+
+  /// Construct an overlapped_ptr to contain the specified handler.
+  template <typename Executor, typename Handler>
+  explicit overlapped_ptr(const Executor& ex,
+      ASIO_MOVE_ARG(Handler) handler,
+      typename enable_if<
+        execution::is_executor<Executor>::value
+          || is_executor<Executor>::value
+      >::type* = 0)
+    : impl_(ex, ASIO_MOVE_CAST(Handler)(handler))
+  {
+  }
+
+  /// Destructor automatically frees the OVERLAPPED object unless released.
+  ~overlapped_ptr()
+  {
+  }
+
+  /// Reset to empty.
+  void reset()
+  {
+    impl_.reset();
+  }
+
+  /// Reset to contain the specified handler, freeing any current OVERLAPPED
+  /// object.
+  template <typename ExecutionContext, typename Handler>
+  void reset(ExecutionContext& context, ASIO_MOVE_ARG(Handler) handler,
+      typename enable_if<
+        is_convertible<ExecutionContext&, execution_context&>::value
+      >::type* = 0)
+  {
+    impl_.reset(context.get_executor(), ASIO_MOVE_CAST(Handler)(handler));
+  }
+
+  /// Reset to contain the specified handler, freeing any current OVERLAPPED
+  /// object.
+  template <typename Executor, typename Handler>
+  void reset(const Executor& ex, ASIO_MOVE_ARG(Handler) handler,
+      typename enable_if<
+        execution::is_executor<Executor>::value
+          || is_executor<Executor>::value
+      >::type* = 0)
+  {
+    impl_.reset(ex, ASIO_MOVE_CAST(Handler)(handler));
+  }
+
+  /// Get the contained OVERLAPPED object.
+  OVERLAPPED* get()
+  {
+    return impl_.get();
+  }
+
+  /// Get the contained OVERLAPPED object.
+  const OVERLAPPED* get() const
+  {
+    return impl_.get();
+  }
+
+  /// Release ownership of the OVERLAPPED object.
+  OVERLAPPED* release()
+  {
+    return impl_.release();
+  }
+
+  /// Post completion notification for overlapped operation. Releases ownership.
+  void complete(const asio::error_code& ec,
+      std::size_t bytes_transferred)
+  {
+    impl_.complete(ec, bytes_transferred);
+  }
+
+private:
+  detail::win_iocp_overlapped_ptr impl_;
+};
+
+} // namespace windows
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_WINDOWS_OVERLAPPED_PTR)
+       //   || defined(GENERATING_DOCUMENTATION)
+
+#endif // ASIO_WINDOWS_OVERLAPPED_PTR_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/windows/random_access_handle.hpp b/link/modules/asio-standalone/asio/include/asio/windows/random_access_handle.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/windows/random_access_handle.hpp
@@ -0,0 +1,37 @@
+//
+// windows/random_access_handle.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_WINDOWS_RANDOM_ACCESS_HANDLE_HPP
+#define ASIO_WINDOWS_RANDOM_ACCESS_HANDLE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) \
+  || defined(GENERATING_DOCUMENTATION)
+
+#include "asio/windows/basic_random_access_handle.hpp"
+
+namespace asio {
+namespace windows {
+
+/// Typedef for the typical usage of a random-access handle.
+typedef basic_random_access_handle<> random_access_handle;
+
+} // namespace windows
+} // namespace asio
+
+#endif // defined(ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE)
+       //   || defined(GENERATING_DOCUMENTATION)
+
+#endif // ASIO_WINDOWS_RANDOM_ACCESS_HANDLE_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/windows/stream_handle.hpp b/link/modules/asio-standalone/asio/include/asio/windows/stream_handle.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/windows/stream_handle.hpp
@@ -0,0 +1,37 @@
+//
+// windows/stream_handle.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_WINDOWS_STREAM_HANDLE_HPP
+#define ASIO_WINDOWS_STREAM_HANDLE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_WINDOWS_STREAM_HANDLE) \
+  || defined(GENERATING_DOCUMENTATION)
+
+#include "asio/windows/basic_stream_handle.hpp"
+
+namespace asio {
+namespace windows {
+
+/// Typedef for the typical usage of a stream-oriented handle.
+typedef basic_stream_handle<> stream_handle;
+
+} // namespace windows
+} // namespace asio
+
+#endif // defined(ASIO_HAS_WINDOWS_STREAM_HANDLE)
+       //   || defined(GENERATING_DOCUMENTATION)
+
+#endif // ASIO_WINDOWS_STREAM_HANDLE_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/write.hpp b/link/modules/asio-standalone/asio/include/asio/write.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/write.hpp
@@ -0,0 +1,1246 @@
+//
+// write.hpp
+// ~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_WRITE_HPP
+#define ASIO_WRITE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <cstddef>
+#include "asio/async_result.hpp"
+#include "asio/buffer.hpp"
+#include "asio/error.hpp"
+
+#if !defined(ASIO_NO_EXTENSIONS)
+# include "asio/basic_streambuf_fwd.hpp"
+#endif // !defined(ASIO_NO_EXTENSIONS)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+/**
+ * @defgroup write asio::write
+ *
+ * @brief The @c write function is a composed operation that writes a certain
+ * amount of data to a stream before returning.
+ */
+/*@{*/
+
+/// Write all of the supplied data to a stream before returning.
+/**
+ * This function is used to write a certain number of bytes of data to a stream.
+ * The call will block until one of the following conditions is true:
+ *
+ * @li All of the data in the supplied buffers has been written. That is, the
+ * bytes transferred is equal to the sum of the buffer sizes.
+ *
+ * @li An error occurred.
+ *
+ * This operation is implemented in terms of zero or more calls to the stream's
+ * write_some function.
+ *
+ * @param s The stream to which the data is to be written. The type must support
+ * the SyncWriteStream concept.
+ *
+ * @param buffers One or more buffers containing the data to be written. The sum
+ * of the buffer sizes indicates the maximum number of bytes to write to the
+ * stream.
+ *
+ * @returns The number of bytes transferred.
+ *
+ * @throws asio::system_error Thrown on failure.
+ *
+ * @par Example
+ * To write a single data buffer use the @ref buffer function as follows:
+ * @code asio::write(s, asio::buffer(data, size)); @endcode
+ * See the @ref buffer documentation for information on writing multiple
+ * buffers in one go, and how to use it with arrays, boost::array or
+ * std::vector.
+ *
+ * @note This overload is equivalent to calling:
+ * @code asio::write(
+ *     s, buffers,
+ *     asio::transfer_all()); @endcode
+ */
+template <typename SyncWriteStream, typename ConstBufferSequence>
+std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers,
+    typename enable_if<
+      is_const_buffer_sequence<ConstBufferSequence>::value
+    >::type* = 0);
+
+/// Write all of the supplied data to a stream before returning.
+/**
+ * This function is used to write a certain number of bytes of data to a stream.
+ * The call will block until one of the following conditions is true:
+ *
+ * @li All of the data in the supplied buffers has been written. That is, the
+ * bytes transferred is equal to the sum of the buffer sizes.
+ *
+ * @li An error occurred.
+ *
+ * This operation is implemented in terms of zero or more calls to the stream's
+ * write_some function.
+ *
+ * @param s The stream to which the data is to be written. The type must support
+ * the SyncWriteStream concept.
+ *
+ * @param buffers One or more buffers containing the data to be written. The sum
+ * of the buffer sizes indicates the maximum number of bytes to write to the
+ * stream.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @returns The number of bytes transferred.
+ *
+ * @par Example
+ * To write a single data buffer use the @ref buffer function as follows:
+ * @code asio::write(s, asio::buffer(data, size), ec); @endcode
+ * See the @ref buffer documentation for information on writing multiple
+ * buffers in one go, and how to use it with arrays, boost::array or
+ * std::vector.
+ *
+ * @note This overload is equivalent to calling:
+ * @code asio::write(
+ *     s, buffers,
+ *     asio::transfer_all(), ec); @endcode
+ */
+template <typename SyncWriteStream, typename ConstBufferSequence>
+std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers,
+    asio::error_code& ec,
+    typename enable_if<
+      is_const_buffer_sequence<ConstBufferSequence>::value
+    >::type* = 0);
+
+/// Write a certain amount of data to a stream before returning.
+/**
+ * This function is used to write a certain number of bytes of data to a stream.
+ * The call will block until one of the following conditions is true:
+ *
+ * @li All of the data in the supplied buffers has been written. That is, the
+ * bytes transferred is equal to the sum of the buffer sizes.
+ *
+ * @li The completion_condition function object returns 0.
+ *
+ * This operation is implemented in terms of zero or more calls to the stream's
+ * write_some function.
+ *
+ * @param s The stream to which the data is to be written. The type must support
+ * the SyncWriteStream concept.
+ *
+ * @param buffers One or more buffers containing the data to be written. The sum
+ * of the buffer sizes indicates the maximum number of bytes to write to the
+ * stream.
+ *
+ * @param completion_condition The function object to be called to determine
+ * whether the write operation is complete. The signature of the function object
+ * must be:
+ * @code std::size_t completion_condition(
+ *   // Result of latest write_some operation.
+ *   const asio::error_code& error,
+ *
+ *   // Number of bytes transferred so far.
+ *   std::size_t bytes_transferred
+ * ); @endcode
+ * A return value of 0 indicates that the write operation is complete. A
+ * non-zero return value indicates the maximum number of bytes to be written on
+ * the next call to the stream's write_some function.
+ *
+ * @returns The number of bytes transferred.
+ *
+ * @throws asio::system_error Thrown on failure.
+ *
+ * @par Example
+ * To write a single data buffer use the @ref buffer function as follows:
+ * @code asio::write(s, asio::buffer(data, size),
+ *     asio::transfer_at_least(32)); @endcode
+ * See the @ref buffer documentation for information on writing multiple
+ * buffers in one go, and how to use it with arrays, boost::array or
+ * std::vector.
+ */
+template <typename SyncWriteStream, typename ConstBufferSequence,
+    typename CompletionCondition>
+std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers,
+    CompletionCondition completion_condition,
+    typename enable_if<
+      is_const_buffer_sequence<ConstBufferSequence>::value
+    >::type* = 0);
+
+/// Write a certain amount of data to a stream before returning.
+/**
+ * This function is used to write a certain number of bytes of data to a stream.
+ * The call will block until one of the following conditions is true:
+ *
+ * @li All of the data in the supplied buffers has been written. That is, the
+ * bytes transferred is equal to the sum of the buffer sizes.
+ *
+ * @li The completion_condition function object returns 0.
+ *
+ * This operation is implemented in terms of zero or more calls to the stream's
+ * write_some function.
+ *
+ * @param s The stream to which the data is to be written. The type must support
+ * the SyncWriteStream concept.
+ *
+ * @param buffers One or more buffers containing the data to be written. The sum
+ * of the buffer sizes indicates the maximum number of bytes to write to the
+ * stream.
+ *
+ * @param completion_condition The function object to be called to determine
+ * whether the write operation is complete. The signature of the function object
+ * must be:
+ * @code std::size_t completion_condition(
+ *   // Result of latest write_some operation.
+ *   const asio::error_code& error,
+ *
+ *   // Number of bytes transferred so far.
+ *   std::size_t bytes_transferred
+ * ); @endcode
+ * A return value of 0 indicates that the write operation is complete. A
+ * non-zero return value indicates the maximum number of bytes to be written on
+ * the next call to the stream's write_some function.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @returns The number of bytes written. If an error occurs, returns the total
+ * number of bytes successfully transferred prior to the error.
+ */
+template <typename SyncWriteStream, typename ConstBufferSequence,
+    typename CompletionCondition>
+std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers,
+    CompletionCondition completion_condition, asio::error_code& ec,
+    typename enable_if<
+      is_const_buffer_sequence<ConstBufferSequence>::value
+    >::type* = 0);
+
+#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1)
+
+/// Write all of the supplied data to a stream before returning.
+/**
+ * This function is used to write a certain number of bytes of data to a stream.
+ * The call will block until one of the following conditions is true:
+ *
+ * @li All of the data in the supplied dynamic buffer sequence has been written.
+ *
+ * @li An error occurred.
+ *
+ * This operation is implemented in terms of zero or more calls to the stream's
+ * write_some function.
+ *
+ * @param s The stream to which the data is to be written. The type must support
+ * the SyncWriteStream concept.
+ *
+ * @param buffers The dynamic buffer sequence from which data will be written.
+ * Successfully written data is automatically consumed from the buffers.
+ *
+ * @returns The number of bytes transferred.
+ *
+ * @throws asio::system_error Thrown on failure.
+ *
+ * @note This overload is equivalent to calling:
+ * @code asio::write(
+ *     s, buffers,
+ *     asio::transfer_all()); @endcode
+ */
+template <typename SyncWriteStream, typename DynamicBuffer_v1>
+std::size_t write(SyncWriteStream& s,
+    ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,
+    typename enable_if<
+      is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value
+        && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value
+    >::type* = 0);
+
+/// Write all of the supplied data to a stream before returning.
+/**
+ * This function is used to write a certain number of bytes of data to a stream.
+ * The call will block until one of the following conditions is true:
+ *
+ * @li All of the data in the supplied dynamic buffer sequence has been written.
+ *
+ * @li An error occurred.
+ *
+ * This operation is implemented in terms of zero or more calls to the stream's
+ * write_some function.
+ *
+ * @param s The stream to which the data is to be written. The type must support
+ * the SyncWriteStream concept.
+ *
+ * @param buffers The dynamic buffer sequence from which data will be written.
+ * Successfully written data is automatically consumed from the buffers.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @returns The number of bytes transferred.
+ *
+ * @note This overload is equivalent to calling:
+ * @code asio::write(
+ *     s, buffers,
+ *     asio::transfer_all(), ec); @endcode
+ */
+template <typename SyncWriteStream, typename DynamicBuffer_v1>
+std::size_t write(SyncWriteStream& s,
+    ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,
+    asio::error_code& ec,
+    typename enable_if<
+      is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value
+        && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value
+    >::type* = 0);
+
+/// Write a certain amount of data to a stream before returning.
+/**
+ * This function is used to write a certain number of bytes of data to a stream.
+ * The call will block until one of the following conditions is true:
+ *
+ * @li All of the data in the supplied dynamic buffer sequence has been written.
+ *
+ * @li The completion_condition function object returns 0.
+ *
+ * This operation is implemented in terms of zero or more calls to the stream's
+ * write_some function.
+ *
+ * @param s The stream to which the data is to be written. The type must support
+ * the SyncWriteStream concept.
+ *
+ * @param buffers The dynamic buffer sequence from which data will be written.
+ * Successfully written data is automatically consumed from the buffers.
+ *
+ * @param completion_condition The function object to be called to determine
+ * whether the write operation is complete. The signature of the function object
+ * must be:
+ * @code std::size_t completion_condition(
+ *   // Result of latest write_some operation.
+ *   const asio::error_code& error,
+ *
+ *   // Number of bytes transferred so far.
+ *   std::size_t bytes_transferred
+ * ); @endcode
+ * A return value of 0 indicates that the write operation is complete. A
+ * non-zero return value indicates the maximum number of bytes to be written on
+ * the next call to the stream's write_some function.
+ *
+ * @returns The number of bytes transferred.
+ *
+ * @throws asio::system_error Thrown on failure.
+ */
+template <typename SyncWriteStream, typename DynamicBuffer_v1,
+    typename CompletionCondition>
+std::size_t write(SyncWriteStream& s,
+    ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,
+    CompletionCondition completion_condition,
+    typename enable_if<
+      is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value
+        && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value
+    >::type* = 0);
+
+/// Write a certain amount of data to a stream before returning.
+/**
+ * This function is used to write a certain number of bytes of data to a stream.
+ * The call will block until one of the following conditions is true:
+ *
+ * @li All of the data in the supplied dynamic buffer sequence has been written.
+ *
+ * @li The completion_condition function object returns 0.
+ *
+ * This operation is implemented in terms of zero or more calls to the stream's
+ * write_some function.
+ *
+ * @param s The stream to which the data is to be written. The type must support
+ * the SyncWriteStream concept.
+ *
+ * @param buffers The dynamic buffer sequence from which data will be written.
+ * Successfully written data is automatically consumed from the buffers.
+ *
+ * @param completion_condition The function object to be called to determine
+ * whether the write operation is complete. The signature of the function object
+ * must be:
+ * @code std::size_t completion_condition(
+ *   // Result of latest write_some operation.
+ *   const asio::error_code& error,
+ *
+ *   // Number of bytes transferred so far.
+ *   std::size_t bytes_transferred
+ * ); @endcode
+ * A return value of 0 indicates that the write operation is complete. A
+ * non-zero return value indicates the maximum number of bytes to be written on
+ * the next call to the stream's write_some function.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @returns The number of bytes written. If an error occurs, returns the total
+ * number of bytes successfully transferred prior to the error.
+ */
+template <typename SyncWriteStream, typename DynamicBuffer_v1,
+    typename CompletionCondition>
+std::size_t write(SyncWriteStream& s,
+    ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,
+    CompletionCondition completion_condition, asio::error_code& ec,
+    typename enable_if<
+      is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value
+        && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value
+    >::type* = 0);
+
+#if !defined(ASIO_NO_EXTENSIONS)
+#if !defined(ASIO_NO_IOSTREAM)
+
+/// Write all of the supplied data to a stream before returning.
+/**
+ * This function is used to write a certain number of bytes of data to a stream.
+ * The call will block until one of the following conditions is true:
+ *
+ * @li All of the data in the supplied basic_streambuf has been written.
+ *
+ * @li An error occurred.
+ *
+ * This operation is implemented in terms of zero or more calls to the stream's
+ * write_some function.
+ *
+ * @param s The stream to which the data is to be written. The type must support
+ * the SyncWriteStream concept.
+ *
+ * @param b The basic_streambuf object from which data will be written.
+ *
+ * @returns The number of bytes transferred.
+ *
+ * @throws asio::system_error Thrown on failure.
+ *
+ * @note This overload is equivalent to calling:
+ * @code asio::write(
+ *     s, b,
+ *     asio::transfer_all()); @endcode
+ */
+template <typename SyncWriteStream, typename Allocator>
+std::size_t write(SyncWriteStream& s, basic_streambuf<Allocator>& b);
+
+/// Write all of the supplied data to a stream before returning.
+/**
+ * This function is used to write a certain number of bytes of data to a stream.
+ * The call will block until one of the following conditions is true:
+ *
+ * @li All of the data in the supplied basic_streambuf has been written.
+ *
+ * @li An error occurred.
+ *
+ * This operation is implemented in terms of zero or more calls to the stream's
+ * write_some function.
+ *
+ * @param s The stream to which the data is to be written. The type must support
+ * the SyncWriteStream concept.
+ *
+ * @param b The basic_streambuf object from which data will be written.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @returns The number of bytes transferred.
+ *
+ * @note This overload is equivalent to calling:
+ * @code asio::write(
+ *     s, b,
+ *     asio::transfer_all(), ec); @endcode
+ */
+template <typename SyncWriteStream, typename Allocator>
+std::size_t write(SyncWriteStream& s, basic_streambuf<Allocator>& b,
+    asio::error_code& ec);
+
+/// Write a certain amount of data to a stream before returning.
+/**
+ * This function is used to write a certain number of bytes of data to a stream.
+ * The call will block until one of the following conditions is true:
+ *
+ * @li All of the data in the supplied basic_streambuf has been written.
+ *
+ * @li The completion_condition function object returns 0.
+ *
+ * This operation is implemented in terms of zero or more calls to the stream's
+ * write_some function.
+ *
+ * @param s The stream to which the data is to be written. The type must support
+ * the SyncWriteStream concept.
+ *
+ * @param b The basic_streambuf object from which data will be written.
+ *
+ * @param completion_condition The function object to be called to determine
+ * whether the write operation is complete. The signature of the function object
+ * must be:
+ * @code std::size_t completion_condition(
+ *   // Result of latest write_some operation.
+ *   const asio::error_code& error,
+ *
+ *   // Number of bytes transferred so far.
+ *   std::size_t bytes_transferred
+ * ); @endcode
+ * A return value of 0 indicates that the write operation is complete. A
+ * non-zero return value indicates the maximum number of bytes to be written on
+ * the next call to the stream's write_some function.
+ *
+ * @returns The number of bytes transferred.
+ *
+ * @throws asio::system_error Thrown on failure.
+ */
+template <typename SyncWriteStream, typename Allocator,
+    typename CompletionCondition>
+std::size_t write(SyncWriteStream& s, basic_streambuf<Allocator>& b,
+    CompletionCondition completion_condition);
+
+/// Write a certain amount of data to a stream before returning.
+/**
+ * This function is used to write a certain number of bytes of data to a stream.
+ * The call will block until one of the following conditions is true:
+ *
+ * @li All of the data in the supplied basic_streambuf has been written.
+ *
+ * @li The completion_condition function object returns 0.
+ *
+ * This operation is implemented in terms of zero or more calls to the stream's
+ * write_some function.
+ *
+ * @param s The stream to which the data is to be written. The type must support
+ * the SyncWriteStream concept.
+ *
+ * @param b The basic_streambuf object from which data will be written.
+ *
+ * @param completion_condition The function object to be called to determine
+ * whether the write operation is complete. The signature of the function object
+ * must be:
+ * @code std::size_t completion_condition(
+ *   // Result of latest write_some operation.
+ *   const asio::error_code& error,
+ *
+ *   // Number of bytes transferred so far.
+ *   std::size_t bytes_transferred
+ * ); @endcode
+ * A return value of 0 indicates that the write operation is complete. A
+ * non-zero return value indicates the maximum number of bytes to be written on
+ * the next call to the stream's write_some function.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @returns The number of bytes written. If an error occurs, returns the total
+ * number of bytes successfully transferred prior to the error.
+ */
+template <typename SyncWriteStream, typename Allocator,
+    typename CompletionCondition>
+std::size_t write(SyncWriteStream& s, basic_streambuf<Allocator>& b,
+    CompletionCondition completion_condition, asio::error_code& ec);
+
+#endif // !defined(ASIO_NO_IOSTREAM)
+#endif // !defined(ASIO_NO_EXTENSIONS)
+#endif // !defined(ASIO_NO_DYNAMIC_BUFFER_V1)
+
+/// Write all of the supplied data to a stream before returning.
+/**
+ * This function is used to write a certain number of bytes of data to a stream.
+ * The call will block until one of the following conditions is true:
+ *
+ * @li All of the data in the supplied dynamic buffer sequence has been written.
+ *
+ * @li An error occurred.
+ *
+ * This operation is implemented in terms of zero or more calls to the stream's
+ * write_some function.
+ *
+ * @param s The stream to which the data is to be written. The type must support
+ * the SyncWriteStream concept.
+ *
+ * @param buffers The dynamic buffer sequence from which data will be written.
+ * Successfully written data is automatically consumed from the buffers.
+ *
+ * @returns The number of bytes transferred.
+ *
+ * @throws asio::system_error Thrown on failure.
+ *
+ * @note This overload is equivalent to calling:
+ * @code asio::write(
+ *     s, buffers,
+ *     asio::transfer_all()); @endcode
+ */
+template <typename SyncWriteStream, typename DynamicBuffer_v2>
+std::size_t write(SyncWriteStream& s, DynamicBuffer_v2 buffers,
+    typename enable_if<
+      is_dynamic_buffer_v2<DynamicBuffer_v2>::value
+    >::type* = 0);
+
+/// Write all of the supplied data to a stream before returning.
+/**
+ * This function is used to write a certain number of bytes of data to a stream.
+ * The call will block until one of the following conditions is true:
+ *
+ * @li All of the data in the supplied dynamic buffer sequence has been written.
+ *
+ * @li An error occurred.
+ *
+ * This operation is implemented in terms of zero or more calls to the stream's
+ * write_some function.
+ *
+ * @param s The stream to which the data is to be written. The type must support
+ * the SyncWriteStream concept.
+ *
+ * @param buffers The dynamic buffer sequence from which data will be written.
+ * Successfully written data is automatically consumed from the buffers.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @returns The number of bytes transferred.
+ *
+ * @note This overload is equivalent to calling:
+ * @code asio::write(
+ *     s, buffers,
+ *     asio::transfer_all(), ec); @endcode
+ */
+template <typename SyncWriteStream, typename DynamicBuffer_v2>
+std::size_t write(SyncWriteStream& s, DynamicBuffer_v2 buffers,
+    asio::error_code& ec,
+    typename enable_if<
+      is_dynamic_buffer_v2<DynamicBuffer_v2>::value
+    >::type* = 0);
+
+/// Write a certain amount of data to a stream before returning.
+/**
+ * This function is used to write a certain number of bytes of data to a stream.
+ * The call will block until one of the following conditions is true:
+ *
+ * @li All of the data in the supplied dynamic buffer sequence has been written.
+ *
+ * @li The completion_condition function object returns 0.
+ *
+ * This operation is implemented in terms of zero or more calls to the stream's
+ * write_some function.
+ *
+ * @param s The stream to which the data is to be written. The type must support
+ * the SyncWriteStream concept.
+ *
+ * @param buffers The dynamic buffer sequence from which data will be written.
+ * Successfully written data is automatically consumed from the buffers.
+ *
+ * @param completion_condition The function object to be called to determine
+ * whether the write operation is complete. The signature of the function object
+ * must be:
+ * @code std::size_t completion_condition(
+ *   // Result of latest write_some operation.
+ *   const asio::error_code& error,
+ *
+ *   // Number of bytes transferred so far.
+ *   std::size_t bytes_transferred
+ * ); @endcode
+ * A return value of 0 indicates that the write operation is complete. A
+ * non-zero return value indicates the maximum number of bytes to be written on
+ * the next call to the stream's write_some function.
+ *
+ * @returns The number of bytes transferred.
+ *
+ * @throws asio::system_error Thrown on failure.
+ */
+template <typename SyncWriteStream, typename DynamicBuffer_v2,
+    typename CompletionCondition>
+std::size_t write(SyncWriteStream& s, DynamicBuffer_v2 buffers,
+    CompletionCondition completion_condition,
+    typename enable_if<
+      is_dynamic_buffer_v2<DynamicBuffer_v2>::value
+    >::type* = 0);
+
+/// Write a certain amount of data to a stream before returning.
+/**
+ * This function is used to write a certain number of bytes of data to a stream.
+ * The call will block until one of the following conditions is true:
+ *
+ * @li All of the data in the supplied dynamic buffer sequence has been written.
+ *
+ * @li The completion_condition function object returns 0.
+ *
+ * This operation is implemented in terms of zero or more calls to the stream's
+ * write_some function.
+ *
+ * @param s The stream to which the data is to be written. The type must support
+ * the SyncWriteStream concept.
+ *
+ * @param buffers The dynamic buffer sequence from which data will be written.
+ * Successfully written data is automatically consumed from the buffers.
+ *
+ * @param completion_condition The function object to be called to determine
+ * whether the write operation is complete. The signature of the function object
+ * must be:
+ * @code std::size_t completion_condition(
+ *   // Result of latest write_some operation.
+ *   const asio::error_code& error,
+ *
+ *   // Number of bytes transferred so far.
+ *   std::size_t bytes_transferred
+ * ); @endcode
+ * A return value of 0 indicates that the write operation is complete. A
+ * non-zero return value indicates the maximum number of bytes to be written on
+ * the next call to the stream's write_some function.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @returns The number of bytes written. If an error occurs, returns the total
+ * number of bytes successfully transferred prior to the error.
+ */
+template <typename SyncWriteStream, typename DynamicBuffer_v2,
+    typename CompletionCondition>
+std::size_t write(SyncWriteStream& s, DynamicBuffer_v2 buffers,
+    CompletionCondition completion_condition, asio::error_code& ec,
+    typename enable_if<
+      is_dynamic_buffer_v2<DynamicBuffer_v2>::value
+    >::type* = 0);
+
+/*@}*/
+/**
+ * @defgroup async_write asio::async_write
+ *
+ * @brief The @c async_write function is a composed asynchronous operation that
+ * writes a certain amount of data to a stream before completion.
+ */
+/*@{*/
+
+/// Start an asynchronous operation to write all of the supplied data to a
+/// stream.
+/**
+ * This function is used to asynchronously write a certain number of bytes of
+ * data to a stream. The function call always returns immediately. The
+ * asynchronous operation will continue until one of the following conditions
+ * is true:
+ *
+ * @li All of the data in the supplied buffers has been written. That is, the
+ * bytes transferred is equal to the sum of the buffer sizes.
+ *
+ * @li An error occurred.
+ *
+ * This operation is implemented in terms of zero or more calls to the stream's
+ * async_write_some function, and is known as a <em>composed operation</em>. The
+ * program must ensure that the stream performs no other write operations (such
+ * as async_write, the stream's async_write_some function, or any other composed
+ * operations that perform writes) until this operation completes.
+ *
+ * @param s The stream to which the data is to be written. The type must support
+ * the AsyncWriteStream concept.
+ *
+ * @param buffers One or more buffers containing the data to be written.
+ * Although the buffers object may be copied as necessary, ownership of the
+ * underlying memory blocks is retained by the caller, which must guarantee
+ * that they remain valid until the handler is called.
+ *
+ * @param handler The handler to be called when the write operation completes.
+ * Copies will be made of the handler as required. The function signature of
+ * the handler must be:
+ * @code void handler(
+ *   const asio::error_code& error, // Result of operation.
+ *
+ *   std::size_t bytes_transferred           // Number of bytes written from the
+ *                                           // buffers. If an error occurred,
+ *                                           // this will be less than the sum
+ *                                           // of the buffer sizes.
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. On
+ * immediate completion, invocation of the handler will be performed in a
+ * manner equivalent to using asio::post().
+ *
+ * @par Example
+ * To write a single data buffer use the @ref buffer function as follows:
+ * @code
+ * asio::async_write(s, asio::buffer(data, size), handler);
+ * @endcode
+ * See the @ref buffer documentation for information on writing multiple
+ * buffers in one go, and how to use it with arrays, boost::array or
+ * std::vector.
+ */
+template <typename AsyncWriteStream, typename ConstBufferSequence,
+    ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+      std::size_t)) WriteHandler
+        ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(
+          typename AsyncWriteStream::executor_type)>
+ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,
+    void (asio::error_code, std::size_t))
+async_write(AsyncWriteStream& s, const ConstBufferSequence& buffers,
+    ASIO_MOVE_ARG(WriteHandler) handler
+      ASIO_DEFAULT_COMPLETION_TOKEN(
+        typename AsyncWriteStream::executor_type),
+    typename enable_if<
+      is_const_buffer_sequence<ConstBufferSequence>::value
+    >::type* = 0);
+
+/// Start an asynchronous operation to write a certain amount of data to a
+/// stream.
+/**
+ * This function is used to asynchronously write a certain number of bytes of
+ * data to a stream. The function call always returns immediately. The
+ * asynchronous operation will continue until one of the following conditions
+ * is true:
+ *
+ * @li All of the data in the supplied buffers has been written. That is, the
+ * bytes transferred is equal to the sum of the buffer sizes.
+ *
+ * @li The completion_condition function object returns 0.
+ *
+ * This operation is implemented in terms of zero or more calls to the stream's
+ * async_write_some function, and is known as a <em>composed operation</em>. The
+ * program must ensure that the stream performs no other write operations (such
+ * as async_write, the stream's async_write_some function, or any other composed
+ * operations that perform writes) until this operation completes.
+ *
+ * @param s The stream to which the data is to be written. The type must support
+ * the AsyncWriteStream concept.
+ *
+ * @param buffers One or more buffers containing the data to be written.
+ * Although the buffers object may be copied as necessary, ownership of the
+ * underlying memory blocks is retained by the caller, which must guarantee
+ * that they remain valid until the handler is called.
+ *
+ * @param completion_condition The function object to be called to determine
+ * whether the write operation is complete. The signature of the function object
+ * must be:
+ * @code std::size_t completion_condition(
+ *   // Result of latest async_write_some operation.
+ *   const asio::error_code& error,
+ *
+ *   // Number of bytes transferred so far.
+ *   std::size_t bytes_transferred
+ * ); @endcode
+ * A return value of 0 indicates that the write operation is complete. A
+ * non-zero return value indicates the maximum number of bytes to be written on
+ * the next call to the stream's async_write_some function.
+ *
+ * @param handler The handler to be called when the write operation completes.
+ * Copies will be made of the handler as required. The function signature of the
+ * handler must be:
+ * @code void handler(
+ *   const asio::error_code& error, // Result of operation.
+ *
+ *   std::size_t bytes_transferred           // Number of bytes written from the
+ *                                           // buffers. If an error occurred,
+ *                                           // this will be less than the sum
+ *                                           // of the buffer sizes.
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. On
+ * immediate completion, invocation of the handler will be performed in a
+ * manner equivalent to using asio::post().
+ *
+ * @par Example
+ * To write a single data buffer use the @ref buffer function as follows:
+ * @code asio::async_write(s,
+ *     asio::buffer(data, size),
+ *     asio::transfer_at_least(32),
+ *     handler); @endcode
+ * See the @ref buffer documentation for information on writing multiple
+ * buffers in one go, and how to use it with arrays, boost::array or
+ * std::vector.
+ */
+template <typename AsyncWriteStream,
+    typename ConstBufferSequence, typename CompletionCondition,
+    ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+      std::size_t)) WriteHandler>
+ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,
+    void (asio::error_code, std::size_t))
+async_write(AsyncWriteStream& s, const ConstBufferSequence& buffers,
+    CompletionCondition completion_condition,
+    ASIO_MOVE_ARG(WriteHandler) handler,
+    typename enable_if<
+      is_const_buffer_sequence<ConstBufferSequence>::value
+    >::type* = 0);
+
+#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1)
+
+/// Start an asynchronous operation to write all of the supplied data to a
+/// stream.
+/**
+ * This function is used to asynchronously write a certain number of bytes of
+ * data to a stream. The function call always returns immediately. The
+ * asynchronous operation will continue until one of the following conditions
+ * is true:
+ *
+ * @li All of the data in the supplied dynamic buffer sequence has been written.
+ *
+ * @li An error occurred.
+ *
+ * This operation is implemented in terms of zero or more calls to the stream's
+ * async_write_some function, and is known as a <em>composed operation</em>. The
+ * program must ensure that the stream performs no other write operations (such
+ * as async_write, the stream's async_write_some function, or any other composed
+ * operations that perform writes) until this operation completes.
+ *
+ * @param s The stream to which the data is to be written. The type must support
+ * the AsyncWriteStream concept.
+ *
+ * @param buffers The dynamic buffer sequence from which data will be written.
+ * Although the buffers object may be copied as necessary, ownership of the
+ * underlying memory blocks is retained by the caller, which must guarantee
+ * that they remain valid until the handler is called. Successfully written
+ * data is automatically consumed from the buffers.
+ *
+ * @param handler The handler to be called when the write operation completes.
+ * Copies will be made of the handler as required. The function signature of the
+ * handler must be:
+ * @code void handler(
+ *   const asio::error_code& error, // Result of operation.
+ *
+ *   std::size_t bytes_transferred           // Number of bytes written from the
+ *                                           // buffers. If an error occurred,
+ *                                           // this will be less than the sum
+ *                                           // of the buffer sizes.
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. On
+ * immediate completion, invocation of the handler will be performed in a
+ * manner equivalent to using asio::post().
+ */
+template <typename AsyncWriteStream, typename DynamicBuffer_v1,
+    ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+      std::size_t)) WriteHandler
+        ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(
+          typename AsyncWriteStream::executor_type)>
+ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,
+    void (asio::error_code, std::size_t))
+async_write(AsyncWriteStream& s,
+    ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,
+    ASIO_MOVE_ARG(WriteHandler) handler
+      ASIO_DEFAULT_COMPLETION_TOKEN(
+        typename AsyncWriteStream::executor_type),
+    typename enable_if<
+      is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value
+        && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value
+    >::type* = 0);
+
+/// Start an asynchronous operation to write a certain amount of data to a
+/// stream.
+/**
+ * This function is used to asynchronously write a certain number of bytes of
+ * data to a stream. The function call always returns immediately. The
+ * asynchronous operation will continue until one of the following conditions
+ * is true:
+ *
+ * @li All of the data in the supplied dynamic buffer sequence has been written.
+ *
+ * @li The completion_condition function object returns 0.
+ *
+ * This operation is implemented in terms of zero or more calls to the stream's
+ * async_write_some function, and is known as a <em>composed operation</em>. The
+ * program must ensure that the stream performs no other write operations (such
+ * as async_write, the stream's async_write_some function, or any other composed
+ * operations that perform writes) until this operation completes.
+ *
+ * @param s The stream to which the data is to be written. The type must support
+ * the AsyncWriteStream concept.
+ *
+ * @param buffers The dynamic buffer sequence from which data will be written.
+ * Although the buffers object may be copied as necessary, ownership of the
+ * underlying memory blocks is retained by the caller, which must guarantee
+ * that they remain valid until the handler is called. Successfully written
+ * data is automatically consumed from the buffers.
+ *
+ * @param completion_condition The function object to be called to determine
+ * whether the write operation is complete. The signature of the function object
+ * must be:
+ * @code std::size_t completion_condition(
+ *   // Result of latest async_write_some operation.
+ *   const asio::error_code& error,
+ *
+ *   // Number of bytes transferred so far.
+ *   std::size_t bytes_transferred
+ * ); @endcode
+ * A return value of 0 indicates that the write operation is complete. A
+ * non-zero return value indicates the maximum number of bytes to be written on
+ * the next call to the stream's async_write_some function.
+ *
+ * @param handler The handler to be called when the write operation completes.
+ * Copies will be made of the handler as required. The function signature of the
+ * handler must be:
+ * @code void handler(
+ *   const asio::error_code& error, // Result of operation.
+ *
+ *   std::size_t bytes_transferred           // Number of bytes written from the
+ *                                           // buffers. If an error occurred,
+ *                                           // this will be less than the sum
+ *                                           // of the buffer sizes.
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. On
+ * immediate completion, invocation of the handler will be performed in a
+ * manner equivalent to using asio::post().
+ */
+template <typename AsyncWriteStream,
+    typename DynamicBuffer_v1, typename CompletionCondition,
+    ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+      std::size_t)) WriteHandler>
+ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,
+    void (asio::error_code, std::size_t))
+async_write(AsyncWriteStream& s,
+    ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,
+    CompletionCondition completion_condition,
+    ASIO_MOVE_ARG(WriteHandler) handler,
+    typename enable_if<
+      is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value
+        && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value
+    >::type* = 0);
+
+#if !defined(ASIO_NO_EXTENSIONS)
+#if !defined(ASIO_NO_IOSTREAM)
+
+/// Start an asynchronous operation to write all of the supplied data to a
+/// stream.
+/**
+ * This function is used to asynchronously write a certain number of bytes of
+ * data to a stream. The function call always returns immediately. The
+ * asynchronous operation will continue until one of the following conditions
+ * is true:
+ *
+ * @li All of the data in the supplied basic_streambuf has been written.
+ *
+ * @li An error occurred.
+ *
+ * This operation is implemented in terms of zero or more calls to the stream's
+ * async_write_some function, and is known as a <em>composed operation</em>. The
+ * program must ensure that the stream performs no other write operations (such
+ * as async_write, the stream's async_write_some function, or any other composed
+ * operations that perform writes) until this operation completes.
+ *
+ * @param s The stream to which the data is to be written. The type must support
+ * the AsyncWriteStream concept.
+ *
+ * @param b A basic_streambuf object from which data will be written. Ownership
+ * of the streambuf is retained by the caller, which must guarantee that it
+ * remains valid until the handler is called.
+ *
+ * @param handler The handler to be called when the write operation completes.
+ * Copies will be made of the handler as required. The function signature of the
+ * handler must be:
+ * @code void handler(
+ *   const asio::error_code& error, // Result of operation.
+ *
+ *   std::size_t bytes_transferred           // Number of bytes written from the
+ *                                           // buffers. If an error occurred,
+ *                                           // this will be less than the sum
+ *                                           // of the buffer sizes.
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. On
+ * immediate completion, invocation of the handler will be performed in a
+ * manner equivalent to using asio::post().
+ */
+template <typename AsyncWriteStream, typename Allocator,
+    ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+      std::size_t)) WriteHandler
+        ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(
+          typename AsyncWriteStream::executor_type)>
+ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,
+    void (asio::error_code, std::size_t))
+async_write(AsyncWriteStream& s, basic_streambuf<Allocator>& b,
+    ASIO_MOVE_ARG(WriteHandler) handler
+      ASIO_DEFAULT_COMPLETION_TOKEN(
+        typename AsyncWriteStream::executor_type));
+
+/// Start an asynchronous operation to write a certain amount of data to a
+/// stream.
+/**
+ * This function is used to asynchronously write a certain number of bytes of
+ * data to a stream. The function call always returns immediately. The
+ * asynchronous operation will continue until one of the following conditions
+ * is true:
+ *
+ * @li All of the data in the supplied basic_streambuf has been written.
+ *
+ * @li The completion_condition function object returns 0.
+ *
+ * This operation is implemented in terms of zero or more calls to the stream's
+ * async_write_some function, and is known as a <em>composed operation</em>. The
+ * program must ensure that the stream performs no other write operations (such
+ * as async_write, the stream's async_write_some function, or any other composed
+ * operations that perform writes) until this operation completes.
+ *
+ * @param s The stream to which the data is to be written. The type must support
+ * the AsyncWriteStream concept.
+ *
+ * @param b A basic_streambuf object from which data will be written. Ownership
+ * of the streambuf is retained by the caller, which must guarantee that it
+ * remains valid until the handler is called.
+ *
+ * @param completion_condition The function object to be called to determine
+ * whether the write operation is complete. The signature of the function object
+ * must be:
+ * @code std::size_t completion_condition(
+ *   // Result of latest async_write_some operation.
+ *   const asio::error_code& error,
+ *
+ *   // Number of bytes transferred so far.
+ *   std::size_t bytes_transferred
+ * ); @endcode
+ * A return value of 0 indicates that the write operation is complete. A
+ * non-zero return value indicates the maximum number of bytes to be written on
+ * the next call to the stream's async_write_some function.
+ *
+ * @param handler The handler to be called when the write operation completes.
+ * Copies will be made of the handler as required. The function signature of the
+ * handler must be:
+ * @code void handler(
+ *   const asio::error_code& error, // Result of operation.
+ *
+ *   std::size_t bytes_transferred           // Number of bytes written from the
+ *                                           // buffers. If an error occurred,
+ *                                           // this will be less than the sum
+ *                                           // of the buffer sizes.
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. On
+ * immediate completion, invocation of the handler will be performed in a
+ * manner equivalent to using asio::post().
+ */
+template <typename AsyncWriteStream,
+    typename Allocator, typename CompletionCondition,
+    ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+      std::size_t)) WriteHandler>
+ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,
+    void (asio::error_code, std::size_t))
+async_write(AsyncWriteStream& s, basic_streambuf<Allocator>& b,
+    CompletionCondition completion_condition,
+    ASIO_MOVE_ARG(WriteHandler) handler);
+
+#endif // !defined(ASIO_NO_IOSTREAM)
+#endif // !defined(ASIO_NO_EXTENSIONS)
+#endif // !defined(ASIO_NO_DYNAMIC_BUFFER_V1)
+
+/// Start an asynchronous operation to write all of the supplied data to a
+/// stream.
+/**
+ * This function is used to asynchronously write a certain number of bytes of
+ * data to a stream. The function call always returns immediately. The
+ * asynchronous operation will continue until one of the following conditions
+ * is true:
+ *
+ * @li All of the data in the supplied dynamic buffer sequence has been written.
+ *
+ * @li An error occurred.
+ *
+ * This operation is implemented in terms of zero or more calls to the stream's
+ * async_write_some function, and is known as a <em>composed operation</em>. The
+ * program must ensure that the stream performs no other write operations (such
+ * as async_write, the stream's async_write_some function, or any other composed
+ * operations that perform writes) until this operation completes.
+ *
+ * @param s The stream to which the data is to be written. The type must support
+ * the AsyncWriteStream concept.
+ *
+ * @param buffers The dynamic buffer sequence from which data will be written.
+ * Although the buffers object may be copied as necessary, ownership of the
+ * underlying memory blocks is retained by the caller, which must guarantee
+ * that they remain valid until the handler is called. Successfully written
+ * data is automatically consumed from the buffers.
+ *
+ * @param handler The handler to be called when the write operation completes.
+ * Copies will be made of the handler as required. The function signature of the
+ * handler must be:
+ * @code void handler(
+ *   const asio::error_code& error, // Result of operation.
+ *
+ *   std::size_t bytes_transferred           // Number of bytes written from the
+ *                                           // buffers. If an error occurred,
+ *                                           // this will be less than the sum
+ *                                           // of the buffer sizes.
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. On
+ * immediate completion, invocation of the handler will be performed in a
+ * manner equivalent to using asio::post().
+ */
+template <typename AsyncWriteStream, typename DynamicBuffer_v2,
+    ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+      std::size_t)) WriteHandler
+        ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(
+          typename AsyncWriteStream::executor_type)>
+ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,
+    void (asio::error_code, std::size_t))
+async_write(AsyncWriteStream& s, DynamicBuffer_v2 buffers,
+    ASIO_MOVE_ARG(WriteHandler) handler
+      ASIO_DEFAULT_COMPLETION_TOKEN(
+        typename AsyncWriteStream::executor_type),
+    typename enable_if<
+      is_dynamic_buffer_v2<DynamicBuffer_v2>::value
+    >::type* = 0);
+
+/// Start an asynchronous operation to write a certain amount of data to a
+/// stream.
+/**
+ * This function is used to asynchronously write a certain number of bytes of
+ * data to a stream. The function call always returns immediately. The
+ * asynchronous operation will continue until one of the following conditions
+ * is true:
+ *
+ * @li All of the data in the supplied dynamic buffer sequence has been written.
+ *
+ * @li The completion_condition function object returns 0.
+ *
+ * This operation is implemented in terms of zero or more calls to the stream's
+ * async_write_some function, and is known as a <em>composed operation</em>. The
+ * program must ensure that the stream performs no other write operations (such
+ * as async_write, the stream's async_write_some function, or any other composed
+ * operations that perform writes) until this operation completes.
+ *
+ * @param s The stream to which the data is to be written. The type must support
+ * the AsyncWriteStream concept.
+ *
+ * @param buffers The dynamic buffer sequence from which data will be written.
+ * Although the buffers object may be copied as necessary, ownership of the
+ * underlying memory blocks is retained by the caller, which must guarantee
+ * that they remain valid until the handler is called. Successfully written
+ * data is automatically consumed from the buffers.
+ *
+ * @param completion_condition The function object to be called to determine
+ * whether the write operation is complete. The signature of the function object
+ * must be:
+ * @code std::size_t completion_condition(
+ *   // Result of latest async_write_some operation.
+ *   const asio::error_code& error,
+ *
+ *   // Number of bytes transferred so far.
+ *   std::size_t bytes_transferred
+ * ); @endcode
+ * A return value of 0 indicates that the write operation is complete. A
+ * non-zero return value indicates the maximum number of bytes to be written on
+ * the next call to the stream's async_write_some function.
+ *
+ * @param handler The handler to be called when the write operation completes.
+ * Copies will be made of the handler as required. The function signature of the
+ * handler must be:
+ * @code void handler(
+ *   const asio::error_code& error, // Result of operation.
+ *
+ *   std::size_t bytes_transferred           // Number of bytes written from the
+ *                                           // buffers. If an error occurred,
+ *                                           // this will be less than the sum
+ *                                           // of the buffer sizes.
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. On
+ * immediate completion, invocation of the handler will be performed in a
+ * manner equivalent to using asio::post().
+ */
+template <typename AsyncWriteStream,
+    typename DynamicBuffer_v2, typename CompletionCondition,
+    ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+      std::size_t)) WriteHandler>
+ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,
+    void (asio::error_code, std::size_t))
+async_write(AsyncWriteStream& s, DynamicBuffer_v2 buffers,
+    CompletionCondition completion_condition,
+    ASIO_MOVE_ARG(WriteHandler) handler,
+    typename enable_if<
+      is_dynamic_buffer_v2<DynamicBuffer_v2>::value
+    >::type* = 0);
+
+/*@}*/
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/impl/write.hpp"
+
+#endif // ASIO_WRITE_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/write_at.hpp b/link/modules/asio-standalone/asio/include/asio/write_at.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/write_at.hpp
@@ -0,0 +1,702 @@
+//
+// write_at.hpp
+// ~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ASIO_WRITE_AT_HPP
+#define ASIO_WRITE_AT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <cstddef>
+#include "asio/async_result.hpp"
+#include "asio/detail/cstdint.hpp"
+#include "asio/error.hpp"
+
+#if !defined(ASIO_NO_EXTENSIONS)
+# include "asio/basic_streambuf_fwd.hpp"
+#endif // !defined(ASIO_NO_EXTENSIONS)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+/**
+ * @defgroup write_at asio::write_at
+ *
+ * @brief The @c write_at function is a composed operation that writes a
+ * certain amount of data at a specified offset before returning.
+ */
+/*@{*/
+
+/// Write all of the supplied data at the specified offset before returning.
+/**
+ * This function is used to write a certain number of bytes of data to a random
+ * access device at a specified offset. The call will block until one of the
+ * following conditions is true:
+ *
+ * @li All of the data in the supplied buffers has been written. That is, the
+ * bytes transferred is equal to the sum of the buffer sizes.
+ *
+ * @li An error occurred.
+ *
+ * This operation is implemented in terms of zero or more calls to the device's
+ * write_some_at function.
+ *
+ * @param d The device to which the data is to be written. The type must support
+ * the SyncRandomAccessWriteDevice concept.
+ *
+ * @param offset The offset at which the data will be written.
+ *
+ * @param buffers One or more buffers containing the data to be written. The sum
+ * of the buffer sizes indicates the maximum number of bytes to write to the
+ * device.
+ *
+ * @returns The number of bytes transferred.
+ *
+ * @throws asio::system_error Thrown on failure.
+ *
+ * @par Example
+ * To write a single data buffer use the @ref buffer function as follows:
+ * @code asio::write_at(d, 42, asio::buffer(data, size)); @endcode
+ * See the @ref buffer documentation for information on writing multiple
+ * buffers in one go, and how to use it with arrays, boost::array or
+ * std::vector.
+ *
+ * @note This overload is equivalent to calling:
+ * @code asio::write_at(
+ *     d, offset, buffers,
+ *     asio::transfer_all()); @endcode
+ */
+template <typename SyncRandomAccessWriteDevice, typename ConstBufferSequence>
+std::size_t write_at(SyncRandomAccessWriteDevice& d,
+    uint64_t offset, const ConstBufferSequence& buffers);
+
+/// Write all of the supplied data at the specified offset before returning.
+/**
+ * This function is used to write a certain number of bytes of data to a random
+ * access device at a specified offset. The call will block until one of the
+ * following conditions is true:
+ *
+ * @li All of the data in the supplied buffers has been written. That is, the
+ * bytes transferred is equal to the sum of the buffer sizes.
+ *
+ * @li An error occurred.
+ *
+ * This operation is implemented in terms of zero or more calls to the device's
+ * write_some_at function.
+ *
+ * @param d The device to which the data is to be written. The type must support
+ * the SyncRandomAccessWriteDevice concept.
+ *
+ * @param offset The offset at which the data will be written.
+ *
+ * @param buffers One or more buffers containing the data to be written. The sum
+ * of the buffer sizes indicates the maximum number of bytes to write to the
+ * device.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @returns The number of bytes transferred.
+ *
+ * @par Example
+ * To write a single data buffer use the @ref buffer function as follows:
+ * @code asio::write_at(d, 42,
+ *     asio::buffer(data, size), ec); @endcode
+ * See the @ref buffer documentation for information on writing multiple
+ * buffers in one go, and how to use it with arrays, boost::array or
+ * std::vector.
+ *
+ * @note This overload is equivalent to calling:
+ * @code asio::write_at(
+ *     d, offset, buffers,
+ *     asio::transfer_all(), ec); @endcode
+ */
+template <typename SyncRandomAccessWriteDevice, typename ConstBufferSequence>
+std::size_t write_at(SyncRandomAccessWriteDevice& d,
+    uint64_t offset, const ConstBufferSequence& buffers,
+    asio::error_code& ec);
+
+/// Write a certain amount of data at a specified offset before returning.
+/**
+ * This function is used to write a certain number of bytes of data to a random
+ * access device at a specified offset. The call will block until one of the
+ * following conditions is true:
+ *
+ * @li All of the data in the supplied buffers has been written. That is, the
+ * bytes transferred is equal to the sum of the buffer sizes.
+ *
+ * @li The completion_condition function object returns 0.
+ *
+ * This operation is implemented in terms of zero or more calls to the device's
+ * write_some_at function.
+ *
+ * @param d The device to which the data is to be written. The type must support
+ * the SyncRandomAccessWriteDevice concept.
+ *
+ * @param offset The offset at which the data will be written.
+ *
+ * @param buffers One or more buffers containing the data to be written. The sum
+ * of the buffer sizes indicates the maximum number of bytes to write to the
+ * device.
+ *
+ * @param completion_condition The function object to be called to determine
+ * whether the write operation is complete. The signature of the function object
+ * must be:
+ * @code std::size_t completion_condition(
+ *   // Result of latest write_some_at operation.
+ *   const asio::error_code& error,
+ *
+ *   // Number of bytes transferred so far.
+ *   std::size_t bytes_transferred
+ * ); @endcode
+ * A return value of 0 indicates that the write operation is complete. A
+ * non-zero return value indicates the maximum number of bytes to be written on
+ * the next call to the device's write_some_at function.
+ *
+ * @returns The number of bytes transferred.
+ *
+ * @throws asio::system_error Thrown on failure.
+ *
+ * @par Example
+ * To write a single data buffer use the @ref buffer function as follows:
+ * @code asio::write_at(d, 42, asio::buffer(data, size),
+ *     asio::transfer_at_least(32)); @endcode
+ * See the @ref buffer documentation for information on writing multiple
+ * buffers in one go, and how to use it with arrays, boost::array or
+ * std::vector.
+ */
+template <typename SyncRandomAccessWriteDevice, typename ConstBufferSequence,
+    typename CompletionCondition>
+std::size_t write_at(SyncRandomAccessWriteDevice& d,
+    uint64_t offset, const ConstBufferSequence& buffers,
+    CompletionCondition completion_condition);
+
+/// Write a certain amount of data at a specified offset before returning.
+/**
+ * This function is used to write a certain number of bytes of data to a random
+ * access device at a specified offset. The call will block until one of the
+ * following conditions is true:
+ *
+ * @li All of the data in the supplied buffers has been written. That is, the
+ * bytes transferred is equal to the sum of the buffer sizes.
+ *
+ * @li The completion_condition function object returns 0.
+ *
+ * This operation is implemented in terms of zero or more calls to the device's
+ * write_some_at function.
+ *
+ * @param d The device to which the data is to be written. The type must support
+ * the SyncRandomAccessWriteDevice concept.
+ *
+ * @param offset The offset at which the data will be written.
+ *
+ * @param buffers One or more buffers containing the data to be written. The sum
+ * of the buffer sizes indicates the maximum number of bytes to write to the
+ * device.
+ *
+ * @param completion_condition The function object to be called to determine
+ * whether the write operation is complete. The signature of the function object
+ * must be:
+ * @code std::size_t completion_condition(
+ *   // Result of latest write_some_at operation.
+ *   const asio::error_code& error,
+ *
+ *   // Number of bytes transferred so far.
+ *   std::size_t bytes_transferred
+ * ); @endcode
+ * A return value of 0 indicates that the write operation is complete. A
+ * non-zero return value indicates the maximum number of bytes to be written on
+ * the next call to the device's write_some_at function.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @returns The number of bytes written. If an error occurs, returns the total
+ * number of bytes successfully transferred prior to the error.
+ */
+template <typename SyncRandomAccessWriteDevice, typename ConstBufferSequence,
+    typename CompletionCondition>
+std::size_t write_at(SyncRandomAccessWriteDevice& d,
+    uint64_t offset, const ConstBufferSequence& buffers,
+    CompletionCondition completion_condition, asio::error_code& ec);
+
+#if !defined(ASIO_NO_EXTENSIONS)
+#if !defined(ASIO_NO_IOSTREAM)
+
+/// Write all of the supplied data at the specified offset before returning.
+/**
+ * This function is used to write a certain number of bytes of data to a random
+ * access device at a specified offset. The call will block until one of the
+ * following conditions is true:
+ *
+ * @li All of the data in the supplied basic_streambuf has been written.
+ *
+ * @li An error occurred.
+ *
+ * This operation is implemented in terms of zero or more calls to the device's
+ * write_some_at function.
+ *
+ * @param d The device to which the data is to be written. The type must support
+ * the SyncRandomAccessWriteDevice concept.
+ *
+ * @param offset The offset at which the data will be written.
+ *
+ * @param b The basic_streambuf object from which data will be written.
+ *
+ * @returns The number of bytes transferred.
+ *
+ * @throws asio::system_error Thrown on failure.
+ *
+ * @note This overload is equivalent to calling:
+ * @code asio::write_at(
+ *     d, 42, b,
+ *     asio::transfer_all()); @endcode
+ */
+template <typename SyncRandomAccessWriteDevice, typename Allocator>
+std::size_t write_at(SyncRandomAccessWriteDevice& d,
+    uint64_t offset, basic_streambuf<Allocator>& b);
+
+/// Write all of the supplied data at the specified offset before returning.
+/**
+ * This function is used to write a certain number of bytes of data to a random
+ * access device at a specified offset. The call will block until one of the
+ * following conditions is true:
+ *
+ * @li All of the data in the supplied basic_streambuf has been written.
+ *
+ * @li An error occurred.
+ *
+ * This operation is implemented in terms of zero or more calls to the device's
+ * write_some_at function.
+ *
+ * @param d The device to which the data is to be written. The type must support
+ * the SyncRandomAccessWriteDevice concept.
+ *
+ * @param offset The offset at which the data will be written.
+ *
+ * @param b The basic_streambuf object from which data will be written.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @returns The number of bytes transferred.
+ *
+ * @note This overload is equivalent to calling:
+ * @code asio::write_at(
+ *     d, 42, b,
+ *     asio::transfer_all(), ec); @endcode
+ */
+template <typename SyncRandomAccessWriteDevice, typename Allocator>
+std::size_t write_at(SyncRandomAccessWriteDevice& d,
+    uint64_t offset, basic_streambuf<Allocator>& b,
+    asio::error_code& ec);
+
+/// Write a certain amount of data at a specified offset before returning.
+/**
+ * This function is used to write a certain number of bytes of data to a random
+ * access device at a specified offset. The call will block until one of the
+ * following conditions is true:
+ *
+ * @li All of the data in the supplied basic_streambuf has been written.
+ *
+ * @li The completion_condition function object returns 0.
+ *
+ * This operation is implemented in terms of zero or more calls to the device's
+ * write_some_at function.
+ *
+ * @param d The device to which the data is to be written. The type must support
+ * the SyncRandomAccessWriteDevice concept.
+ *
+ * @param offset The offset at which the data will be written.
+ *
+ * @param b The basic_streambuf object from which data will be written.
+ *
+ * @param completion_condition The function object to be called to determine
+ * whether the write operation is complete. The signature of the function object
+ * must be:
+ * @code std::size_t completion_condition(
+ *   // Result of latest write_some_at operation.
+ *   const asio::error_code& error,
+ *
+ *   // Number of bytes transferred so far.
+ *   std::size_t bytes_transferred
+ * ); @endcode
+ * A return value of 0 indicates that the write operation is complete. A
+ * non-zero return value indicates the maximum number of bytes to be written on
+ * the next call to the device's write_some_at function.
+ *
+ * @returns The number of bytes transferred.
+ *
+ * @throws asio::system_error Thrown on failure.
+ */
+template <typename SyncRandomAccessWriteDevice, typename Allocator,
+    typename CompletionCondition>
+std::size_t write_at(SyncRandomAccessWriteDevice& d, uint64_t offset,
+    basic_streambuf<Allocator>& b, CompletionCondition completion_condition);
+
+/// Write a certain amount of data at a specified offset before returning.
+/**
+ * This function is used to write a certain number of bytes of data to a random
+ * access device at a specified offset. The call will block until one of the
+ * following conditions is true:
+ *
+ * @li All of the data in the supplied basic_streambuf has been written.
+ *
+ * @li The completion_condition function object returns 0.
+ *
+ * This operation is implemented in terms of zero or more calls to the device's
+ * write_some_at function.
+ *
+ * @param d The device to which the data is to be written. The type must support
+ * the SyncRandomAccessWriteDevice concept.
+ *
+ * @param offset The offset at which the data will be written.
+ *
+ * @param b The basic_streambuf object from which data will be written.
+ *
+ * @param completion_condition The function object to be called to determine
+ * whether the write operation is complete. The signature of the function object
+ * must be:
+ * @code std::size_t completion_condition(
+ *   // Result of latest write_some_at operation.
+ *   const asio::error_code& error,
+ *
+ *   // Number of bytes transferred so far.
+ *   std::size_t bytes_transferred
+ * ); @endcode
+ * A return value of 0 indicates that the write operation is complete. A
+ * non-zero return value indicates the maximum number of bytes to be written on
+ * the next call to the device's write_some_at function.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @returns The number of bytes written. If an error occurs, returns the total
+ * number of bytes successfully transferred prior to the error.
+ */
+template <typename SyncRandomAccessWriteDevice, typename Allocator,
+    typename CompletionCondition>
+std::size_t write_at(SyncRandomAccessWriteDevice& d, uint64_t offset,
+    basic_streambuf<Allocator>& b, CompletionCondition completion_condition,
+    asio::error_code& ec);
+
+#endif // !defined(ASIO_NO_IOSTREAM)
+#endif // !defined(ASIO_NO_EXTENSIONS)
+
+/*@}*/
+/**
+ * @defgroup async_write_at asio::async_write_at
+ *
+ * @brief The @c async_write_at function is a composed asynchronous operation
+ * that writes a certain amount of data at the specified offset before
+ * completion.
+ */
+/*@{*/
+
+/// Start an asynchronous operation to write all of the supplied data at the
+/// specified offset.
+/**
+ * This function is used to asynchronously write a certain number of bytes of
+ * data to a random access device at a specified offset. The function call
+ * always returns immediately. The asynchronous operation will continue until
+ * one of the following conditions is true:
+ *
+ * @li All of the data in the supplied buffers has been written. That is, the
+ * bytes transferred is equal to the sum of the buffer sizes.
+ *
+ * @li An error occurred.
+ *
+ * This operation is implemented in terms of zero or more calls to the device's
+ * async_write_some_at function, and is known as a <em>composed operation</em>.
+ * The program must ensure that the device performs no <em>overlapping</em>
+ * write operations (such as async_write_at, the device's async_write_some_at
+ * function, or any other composed operations that perform writes) until this
+ * operation completes. Operations are overlapping if the regions defined by
+ * their offsets, and the numbers of bytes to write, intersect.
+ *
+ * @param d The device to which the data is to be written. The type must support
+ * the AsyncRandomAccessWriteDevice concept.
+ *
+ * @param offset The offset at which the data will be written.
+ *
+ * @param buffers One or more buffers containing the data to be written.
+ * Although the buffers object may be copied as necessary, ownership of the
+ * underlying memory blocks is retained by the caller, which must guarantee
+ * that they remain valid until the handler is called.
+ *
+ * @param handler The handler to be called when the write operation completes.
+ * Copies will be made of the handler as required. The function signature of
+ * the handler must be:
+ * @code void handler(
+ *   // Result of operation.
+ *   const asio::error_code& error,
+ *
+ *   // Number of bytes written from the buffers. If an error
+ *   // occurred, this will be less than the sum of the buffer sizes.
+ *   std::size_t bytes_transferred
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. On
+ * immediate completion, invocation of the handler will be performed in a
+ * manner equivalent to using asio::post().
+ *
+ * @par Example
+ * To write a single data buffer use the @ref buffer function as follows:
+ * @code
+ * asio::async_write_at(d, 42, asio::buffer(data, size), handler);
+ * @endcode
+ * See the @ref buffer documentation for information on writing multiple
+ * buffers in one go, and how to use it with arrays, boost::array or
+ * std::vector.
+ */
+template <typename AsyncRandomAccessWriteDevice, typename ConstBufferSequence,
+    ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+      std::size_t)) WriteHandler
+        ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(
+          typename AsyncRandomAccessWriteDevice::executor_type)>
+ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,
+    void (asio::error_code, std::size_t))
+async_write_at(AsyncRandomAccessWriteDevice& d, uint64_t offset,
+    const ConstBufferSequence& buffers,
+    ASIO_MOVE_ARG(WriteHandler) handler
+      ASIO_DEFAULT_COMPLETION_TOKEN(
+        typename AsyncRandomAccessWriteDevice::executor_type));
+
+/// Start an asynchronous operation to write a certain amount of data at the
+/// specified offset.
+/**
+ * This function is used to asynchronously write a certain number of bytes of
+ * data to a random access device at a specified offset. The function call
+ * always returns immediately. The asynchronous operation will continue until
+ * one of the following conditions is true:
+ *
+ * @li All of the data in the supplied buffers has been written. That is, the
+ * bytes transferred is equal to the sum of the buffer sizes.
+ *
+ * @li The completion_condition function object returns 0.
+ *
+ * This operation is implemented in terms of zero or more calls to the device's
+ * async_write_some_at function, and is known as a <em>composed operation</em>.
+ * The program must ensure that the device performs no <em>overlapping</em>
+ * write operations (such as async_write_at, the device's async_write_some_at
+ * function, or any other composed operations that perform writes) until this
+ * operation completes. Operations are overlapping if the regions defined by
+ * their offsets, and the numbers of bytes to write, intersect.
+ *
+ * @param d The device to which the data is to be written. The type must support
+ * the AsyncRandomAccessWriteDevice concept.
+ *
+ * @param offset The offset at which the data will be written.
+ *
+ * @param buffers One or more buffers containing the data to be written.
+ * Although the buffers object may be copied as necessary, ownership of the
+ * underlying memory blocks is retained by the caller, which must guarantee
+ * that they remain valid until the handler is called.
+ *
+ * @param completion_condition The function object to be called to determine
+ * whether the write operation is complete. The signature of the function object
+ * must be:
+ * @code std::size_t completion_condition(
+ *   // Result of latest async_write_some_at operation.
+ *   const asio::error_code& error,
+ *
+ *   // Number of bytes transferred so far.
+ *   std::size_t bytes_transferred
+ * ); @endcode
+ * A return value of 0 indicates that the write operation is complete. A
+ * non-zero return value indicates the maximum number of bytes to be written on
+ * the next call to the device's async_write_some_at function.
+ *
+ * @param handler The handler to be called when the write operation completes.
+ * Copies will be made of the handler as required. The function signature of the
+ * handler must be:
+ * @code void handler(
+ *   // Result of operation.
+ *   const asio::error_code& error,
+ *
+ *   // Number of bytes written from the buffers. If an error
+ *   // occurred, this will be less than the sum of the buffer sizes.
+ *   std::size_t bytes_transferred
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. On
+ * immediate completion, invocation of the handler will be performed in a
+ * manner equivalent to using asio::post().
+ *
+ * @par Example
+ * To write a single data buffer use the @ref buffer function as follows:
+ * @code asio::async_write_at(d, 42,
+ *     asio::buffer(data, size),
+ *     asio::transfer_at_least(32),
+ *     handler); @endcode
+ * See the @ref buffer documentation for information on writing multiple
+ * buffers in one go, and how to use it with arrays, boost::array or
+ * std::vector.
+ */
+template <typename AsyncRandomAccessWriteDevice,
+    typename ConstBufferSequence, typename CompletionCondition,
+    ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+      std::size_t)) WriteHandler
+        ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(
+          typename AsyncRandomAccessWriteDevice::executor_type)>
+ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,
+    void (asio::error_code, std::size_t))
+async_write_at(AsyncRandomAccessWriteDevice& d,
+    uint64_t offset, const ConstBufferSequence& buffers,
+    CompletionCondition completion_condition,
+    ASIO_MOVE_ARG(WriteHandler) handler
+      ASIO_DEFAULT_COMPLETION_TOKEN(
+        typename AsyncRandomAccessWriteDevice::executor_type));
+
+#if !defined(ASIO_NO_EXTENSIONS)
+#if !defined(ASIO_NO_IOSTREAM)
+
+/// Start an asynchronous operation to write all of the supplied data at the
+/// specified offset.
+/**
+ * This function is used to asynchronously write a certain number of bytes of
+ * data to a random access device at a specified offset. The function call
+ * always returns immediately. The asynchronous operation will continue until
+ * one of the following conditions is true:
+ *
+ * @li All of the data in the supplied basic_streambuf has been written.
+ *
+ * @li An error occurred.
+ *
+ * This operation is implemented in terms of zero or more calls to the device's
+ * async_write_some_at function, and is known as a <em>composed operation</em>.
+ * The program must ensure that the device performs no <em>overlapping</em>
+ * write operations (such as async_write_at, the device's async_write_some_at
+ * function, or any other composed operations that perform writes) until this
+ * operation completes. Operations are overlapping if the regions defined by
+ * their offsets, and the numbers of bytes to write, intersect.
+ *
+ * @param d The device to which the data is to be written. The type must support
+ * the AsyncRandomAccessWriteDevice concept.
+ *
+ * @param offset The offset at which the data will be written.
+ *
+ * @param b A basic_streambuf object from which data will be written. Ownership
+ * of the streambuf is retained by the caller, which must guarantee that it
+ * remains valid until the handler is called.
+ *
+ * @param handler The handler to be called when the write operation completes.
+ * Copies will be made of the handler as required. The function signature of the
+ * handler must be:
+ * @code void handler(
+ *   // Result of operation.
+ *   const asio::error_code& error,
+ *
+ *   // Number of bytes written from the buffers. If an error
+ *   // occurred, this will be less than the sum of the buffer sizes.
+ *   std::size_t bytes_transferred
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. On
+ * immediate completion, invocation of the handler will be performed in a
+ * manner equivalent to using asio::post().
+ */
+template <typename AsyncRandomAccessWriteDevice, typename Allocator,
+    ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+      std::size_t)) WriteHandler
+        ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(
+          typename AsyncRandomAccessWriteDevice::executor_type)>
+ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,
+    void (asio::error_code, std::size_t))
+async_write_at(AsyncRandomAccessWriteDevice& d,
+    uint64_t offset, basic_streambuf<Allocator>& b,
+    ASIO_MOVE_ARG(WriteHandler) handler
+      ASIO_DEFAULT_COMPLETION_TOKEN(
+        typename AsyncRandomAccessWriteDevice::executor_type));
+
+/// Start an asynchronous operation to write a certain amount of data at the
+/// specified offset.
+/**
+ * This function is used to asynchronously write a certain number of bytes of
+ * data to a random access device at a specified offset. The function call
+ * always returns immediately. The asynchronous operation will continue until
+ * one of the following conditions is true:
+ *
+ * @li All of the data in the supplied basic_streambuf has been written.
+ *
+ * @li The completion_condition function object returns 0.
+ *
+ * This operation is implemented in terms of zero or more calls to the device's
+ * async_write_some_at function, and is known as a <em>composed operation</em>.
+ * The program must ensure that the device performs no <em>overlapping</em>
+ * write operations (such as async_write_at, the device's async_write_some_at
+ * function, or any other composed operations that perform writes) until this
+ * operation completes. Operations are overlapping if the regions defined by
+ * their offsets, and the numbers of bytes to write, intersect.
+ *
+ * @param d The device to which the data is to be written. The type must support
+ * the AsyncRandomAccessWriteDevice concept.
+ *
+ * @param offset The offset at which the data will be written.
+ *
+ * @param b A basic_streambuf object from which data will be written. Ownership
+ * of the streambuf is retained by the caller, which must guarantee that it
+ * remains valid until the handler is called.
+ *
+ * @param completion_condition The function object to be called to determine
+ * whether the write operation is complete. The signature of the function object
+ * must be:
+ * @code std::size_t completion_condition(
+ *   // Result of latest async_write_some_at operation.
+ *   const asio::error_code& error,
+ *
+ *   // Number of bytes transferred so far.
+ *   std::size_t bytes_transferred
+ * ); @endcode
+ * A return value of 0 indicates that the write operation is complete. A
+ * non-zero return value indicates the maximum number of bytes to be written on
+ * the next call to the device's async_write_some_at function.
+ *
+ * @param handler The handler to be called when the write operation completes.
+ * Copies will be made of the handler as required. The function signature of the
+ * handler must be:
+ * @code void handler(
+ *   // Result of operation.
+ *   const asio::error_code& error,
+ *
+ *   // Number of bytes written from the buffers. If an error
+ *   // occurred, this will be less than the sum of the buffer sizes.
+ *   std::size_t bytes_transferred
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. On
+ * immediate completion, invocation of the handler will be performed in a
+ * manner equivalent to using asio::post().
+ */
+template <typename AsyncRandomAccessWriteDevice,
+    typename Allocator, typename CompletionCondition,
+    ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
+      std::size_t)) WriteHandler
+        ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(
+          typename AsyncRandomAccessWriteDevice::executor_type)>
+ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,
+    void (asio::error_code, std::size_t))
+async_write_at(AsyncRandomAccessWriteDevice& d, uint64_t offset,
+    basic_streambuf<Allocator>& b, CompletionCondition completion_condition,
+    ASIO_MOVE_ARG(WriteHandler) handler
+      ASIO_DEFAULT_COMPLETION_TOKEN(
+        typename AsyncRandomAccessWriteDevice::executor_type));
+
+#endif // !defined(ASIO_NO_IOSTREAM)
+#endif // !defined(ASIO_NO_EXTENSIONS)
+
+/*@}*/
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/impl/write_at.hpp"
+
+#endif // ASIO_WRITE_AT_HPP
diff --git a/link/modules/asio-standalone/asio/include/asio/yield.hpp b/link/modules/asio-standalone/asio/include/asio/yield.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/include/asio/yield.hpp
@@ -0,0 +1,23 @@
+//
+// yield.hpp
+// ~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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)
+//
+
+#include "coroutine.hpp"
+
+#ifndef reenter
+# define reenter(c) ASIO_CORO_REENTER(c)
+#endif
+
+#ifndef yield
+# define yield ASIO_CORO_YIELD
+#endif
+
+#ifndef fork
+# define fork ASIO_CORO_FORK
+#endif
diff --git a/link/modules/asio-standalone/asio/src/examples/cpp03/chat/chat_message.hpp b/link/modules/asio-standalone/asio/src/examples/cpp03/chat/chat_message.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/src/examples/cpp03/chat/chat_message.hpp
@@ -0,0 +1,93 @@
+//
+// chat_message.hpp
+// ~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 CHAT_MESSAGE_HPP
+#define CHAT_MESSAGE_HPP
+
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+
+class chat_message
+{
+public:
+  enum { header_length = 4 };
+  enum { max_body_length = 512 };
+
+  chat_message()
+    : body_length_(0)
+  {
+  }
+
+  const char* data() const
+  {
+    return data_;
+  }
+
+  char* data()
+  {
+    return data_;
+  }
+
+  size_t length() const
+  {
+    return header_length + body_length_;
+  }
+
+  const char* body() const
+  {
+    return data_ + header_length;
+  }
+
+  char* body()
+  {
+    return data_ + header_length;
+  }
+
+  size_t body_length() const
+  {
+    return body_length_;
+  }
+
+  void body_length(size_t new_length)
+  {
+    body_length_ = new_length;
+    if (body_length_ > max_body_length)
+      body_length_ = max_body_length;
+  }
+
+  bool decode_header()
+  {
+    using namespace std; // For strncat and atoi.
+    char header[header_length + 1] = "";
+    strncat(header, data_, header_length);
+    body_length_ = atoi(header);
+    if (body_length_ > max_body_length)
+    {
+      body_length_ = 0;
+      return false;
+    }
+    return true;
+  }
+
+  void encode_header()
+  {
+    using namespace std; // For sprintf and memcpy.
+    char header[header_length + 1] = "";
+    sprintf(header, "%4d", static_cast<int>(body_length_));
+    memcpy(data_, header, header_length);
+  }
+
+private:
+  char data_[header_length + max_body_length];
+  size_t body_length_;
+};
+
+#endif // CHAT_MESSAGE_HPP
diff --git a/link/modules/asio-standalone/asio/src/examples/cpp03/http/server/connection.hpp b/link/modules/asio-standalone/asio/src/examples/cpp03/http/server/connection.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/src/examples/cpp03/http/server/connection.hpp
@@ -0,0 +1,83 @@
+//
+// connection.hpp
+// ~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 HTTP_CONNECTION_HPP
+#define HTTP_CONNECTION_HPP
+
+#include <asio.hpp>
+#include <boost/array.hpp>
+#include <boost/noncopyable.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/enable_shared_from_this.hpp>
+#include "reply.hpp"
+#include "request.hpp"
+#include "request_handler.hpp"
+#include "request_parser.hpp"
+
+namespace http {
+namespace server {
+
+class connection_manager;
+
+/// Represents a single connection from a client.
+class connection
+  : public boost::enable_shared_from_this<connection>,
+    private boost::noncopyable
+{
+public:
+  /// Construct a connection with the given io_context.
+  explicit connection(asio::io_context& io_context,
+      connection_manager& manager, request_handler& handler);
+
+  /// Get the socket associated with the connection.
+  asio::ip::tcp::socket& socket();
+
+  /// Start the first asynchronous operation for the connection.
+  void start();
+
+  /// Stop all asynchronous operations associated with the connection.
+  void stop();
+
+private:
+  /// Handle completion of a read operation.
+  void handle_read(const asio::error_code& e,
+      std::size_t bytes_transferred);
+
+  /// Handle completion of a write operation.
+  void handle_write(const asio::error_code& e);
+
+  /// Socket for the connection.
+  asio::ip::tcp::socket socket_;
+
+  /// The manager for this connection.
+  connection_manager& connection_manager_;
+
+  /// The handler used to process the incoming request.
+  request_handler& request_handler_;
+
+  /// Buffer for incoming data.
+  boost::array<char, 8192> buffer_;
+
+  /// The incoming request.
+  request request_;
+
+  /// The parser for the incoming request.
+  request_parser request_parser_;
+
+  /// The reply to be sent back to the client.
+  reply reply_;
+};
+
+typedef boost::shared_ptr<connection> connection_ptr;
+
+} // namespace server
+} // namespace http
+
+#endif // HTTP_CONNECTION_HPP
diff --git a/link/modules/asio-standalone/asio/src/examples/cpp03/http/server/connection_manager.hpp b/link/modules/asio-standalone/asio/src/examples/cpp03/http/server/connection_manager.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/src/examples/cpp03/http/server/connection_manager.hpp
@@ -0,0 +1,44 @@
+//
+// connection_manager.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 HTTP_CONNECTION_MANAGER_HPP
+#define HTTP_CONNECTION_MANAGER_HPP
+
+#include <set>
+#include <boost/noncopyable.hpp>
+#include "connection.hpp"
+
+namespace http {
+namespace server {
+
+/// Manages open connections so that they may be cleanly stopped when the server
+/// needs to shut down.
+class connection_manager
+  : private boost::noncopyable
+{
+public:
+  /// Add the specified connection to the manager and start it.
+  void start(connection_ptr c);
+
+  /// Stop the specified connection.
+  void stop(connection_ptr c);
+
+  /// Stop all connections.
+  void stop_all();
+
+private:
+  /// The managed connections.
+  std::set<connection_ptr> connections_;
+};
+
+} // namespace server
+} // namespace http
+
+#endif // HTTP_CONNECTION_MANAGER_HPP
diff --git a/link/modules/asio-standalone/asio/src/examples/cpp03/http/server/header.hpp b/link/modules/asio-standalone/asio/src/examples/cpp03/http/server/header.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/src/examples/cpp03/http/server/header.hpp
@@ -0,0 +1,28 @@
+//
+// header.hpp
+// ~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 HTTP_HEADER_HPP
+#define HTTP_HEADER_HPP
+
+#include <string>
+
+namespace http {
+namespace server {
+
+struct header
+{
+  std::string name;
+  std::string value;
+};
+
+} // namespace server
+} // namespace http
+
+#endif // HTTP_HEADER_HPP
diff --git a/link/modules/asio-standalone/asio/src/examples/cpp03/http/server/mime_types.hpp b/link/modules/asio-standalone/asio/src/examples/cpp03/http/server/mime_types.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/src/examples/cpp03/http/server/mime_types.hpp
@@ -0,0 +1,27 @@
+//
+// mime_types.hpp
+// ~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 HTTP_MIME_TYPES_HPP
+#define HTTP_MIME_TYPES_HPP
+
+#include <string>
+
+namespace http {
+namespace server {
+namespace mime_types {
+
+/// Convert a file extension into a MIME type.
+std::string extension_to_type(const std::string& extension);
+
+} // namespace mime_types
+} // namespace server
+} // namespace http
+
+#endif // HTTP_MIME_TYPES_HPP
diff --git a/link/modules/asio-standalone/asio/src/examples/cpp03/http/server/reply.hpp b/link/modules/asio-standalone/asio/src/examples/cpp03/http/server/reply.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/src/examples/cpp03/http/server/reply.hpp
@@ -0,0 +1,64 @@
+//
+// reply.hpp
+// ~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 HTTP_REPLY_HPP
+#define HTTP_REPLY_HPP
+
+#include <string>
+#include <vector>
+#include <asio.hpp>
+#include "header.hpp"
+
+namespace http {
+namespace server {
+
+/// A reply to be sent to a client.
+struct reply
+{
+  /// The status of the reply.
+  enum status_type
+  {
+    ok = 200,
+    created = 201,
+    accepted = 202,
+    no_content = 204,
+    multiple_choices = 300,
+    moved_permanently = 301,
+    moved_temporarily = 302,
+    not_modified = 304,
+    bad_request = 400,
+    unauthorized = 401,
+    forbidden = 403,
+    not_found = 404,
+    internal_server_error = 500,
+    not_implemented = 501,
+    bad_gateway = 502,
+    service_unavailable = 503
+  } status;
+
+  /// The headers to be included in the reply.
+  std::vector<header> headers;
+
+  /// The content to be sent in the reply.
+  std::string content;
+
+  /// Convert the reply into a vector of buffers. The buffers do not own the
+  /// underlying memory blocks, therefore the reply object must remain valid and
+  /// not be changed until the write operation has completed.
+  std::vector<asio::const_buffer> to_buffers();
+
+  /// Get a stock reply.
+  static reply stock_reply(status_type status);
+};
+
+} // namespace server
+} // namespace http
+
+#endif // HTTP_REPLY_HPP
diff --git a/link/modules/asio-standalone/asio/src/examples/cpp03/http/server/request.hpp b/link/modules/asio-standalone/asio/src/examples/cpp03/http/server/request.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/src/examples/cpp03/http/server/request.hpp
@@ -0,0 +1,34 @@
+//
+// request.hpp
+// ~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 HTTP_REQUEST_HPP
+#define HTTP_REQUEST_HPP
+
+#include <string>
+#include <vector>
+#include "header.hpp"
+
+namespace http {
+namespace server {
+
+/// A request received from a client.
+struct request
+{
+  std::string method;
+  std::string uri;
+  int http_version_major;
+  int http_version_minor;
+  std::vector<header> headers;
+};
+
+} // namespace server
+} // namespace http
+
+#endif // HTTP_REQUEST_HPP
diff --git a/link/modules/asio-standalone/asio/src/examples/cpp03/http/server/request_handler.hpp b/link/modules/asio-standalone/asio/src/examples/cpp03/http/server/request_handler.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/src/examples/cpp03/http/server/request_handler.hpp
@@ -0,0 +1,46 @@
+//
+// request_handler.hpp
+// ~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 HTTP_REQUEST_HANDLER_HPP
+#define HTTP_REQUEST_HANDLER_HPP
+
+#include <string>
+#include <boost/noncopyable.hpp>
+
+namespace http {
+namespace server {
+
+struct reply;
+struct request;
+
+/// The common handler for all incoming requests.
+class request_handler
+  : private boost::noncopyable
+{
+public:
+  /// Construct with a directory containing files to be served.
+  explicit request_handler(const std::string& doc_root);
+
+  /// Handle a request and produce a reply.
+  void handle_request(const request& req, reply& rep);
+
+private:
+  /// The directory containing the files to be served.
+  std::string doc_root_;
+
+  /// Perform URL-decoding on a string. Returns false if the encoding was
+  /// invalid.
+  static bool url_decode(const std::string& in, std::string& out);
+};
+
+} // namespace server
+} // namespace http
+
+#endif // HTTP_REQUEST_HANDLER_HPP
diff --git a/link/modules/asio-standalone/asio/src/examples/cpp03/http/server/request_parser.hpp b/link/modules/asio-standalone/asio/src/examples/cpp03/http/server/request_parser.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/src/examples/cpp03/http/server/request_parser.hpp
@@ -0,0 +1,95 @@
+//
+// request_parser.hpp
+// ~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 HTTP_REQUEST_PARSER_HPP
+#define HTTP_REQUEST_PARSER_HPP
+
+#include <boost/logic/tribool.hpp>
+#include <boost/tuple/tuple.hpp>
+
+namespace http {
+namespace server {
+
+struct request;
+
+/// Parser for incoming requests.
+class request_parser
+{
+public:
+  /// Construct ready to parse the request method.
+  request_parser();
+
+  /// Reset to initial parser state.
+  void reset();
+
+  /// Parse some data. The tribool return value is true when a complete request
+  /// has been parsed, false if the data is invalid, indeterminate when more
+  /// data is required. The InputIterator return value indicates how much of the
+  /// input has been consumed.
+  template <typename InputIterator>
+  boost::tuple<boost::tribool, InputIterator> parse(request& req,
+      InputIterator begin, InputIterator end)
+  {
+    while (begin != end)
+    {
+      boost::tribool result = consume(req, *begin++);
+      if (result || !result)
+        return boost::make_tuple(result, begin);
+    }
+    boost::tribool result = boost::indeterminate;
+    return boost::make_tuple(result, begin);
+  }
+
+private:
+  /// Handle the next character of input.
+  boost::tribool consume(request& req, char input);
+
+  /// Check if a byte is an HTTP character.
+  static bool is_char(int c);
+
+  /// Check if a byte is an HTTP control character.
+  static bool is_ctl(int c);
+
+  /// Check if a byte is defined as an HTTP tspecial character.
+  static bool is_tspecial(int c);
+
+  /// Check if a byte is a digit.
+  static bool is_digit(int c);
+
+  /// The current state of the parser.
+  enum state
+  {
+    method_start,
+    method,
+    uri,
+    http_version_h,
+    http_version_t_1,
+    http_version_t_2,
+    http_version_p,
+    http_version_slash,
+    http_version_major_start,
+    http_version_major,
+    http_version_minor_start,
+    http_version_minor,
+    expecting_newline_1,
+    header_line_start,
+    header_lws,
+    header_name,
+    space_before_header_value,
+    header_value,
+    expecting_newline_2,
+    expecting_newline_3
+  } state_;
+};
+
+} // namespace server
+} // namespace http
+
+#endif // HTTP_REQUEST_PARSER_HPP
diff --git a/link/modules/asio-standalone/asio/src/examples/cpp03/http/server/server.hpp b/link/modules/asio-standalone/asio/src/examples/cpp03/http/server/server.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/src/examples/cpp03/http/server/server.hpp
@@ -0,0 +1,69 @@
+//
+// server.hpp
+// ~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 HTTP_SERVER_HPP
+#define HTTP_SERVER_HPP
+
+#include <asio.hpp>
+#include <string>
+#include <boost/noncopyable.hpp>
+#include "connection.hpp"
+#include "connection_manager.hpp"
+#include "request_handler.hpp"
+
+namespace http {
+namespace server {
+
+/// The top-level class of the HTTP server.
+class server
+  : private boost::noncopyable
+{
+public:
+  /// Construct the server to listen on the specified TCP address and port, and
+  /// serve up files from the given directory.
+  explicit server(const std::string& address, const std::string& port,
+      const std::string& doc_root);
+
+  /// Run the server's io_context loop.
+  void run();
+
+private:
+  /// Initiate an asynchronous accept operation.
+  void start_accept();
+
+  /// Handle completion of an asynchronous accept operation.
+  void handle_accept(const asio::error_code& e);
+
+  /// Handle a request to stop the server.
+  void handle_stop();
+
+  /// The io_context used to perform asynchronous operations.
+  asio::io_context io_context_;
+
+  /// The signal_set is used to register for process termination notifications.
+  asio::signal_set signals_;
+
+  /// Acceptor used to listen for incoming connections.
+  asio::ip::tcp::acceptor acceptor_;
+
+  /// The connection manager which owns all live connections.
+  connection_manager connection_manager_;
+
+  /// The next connection to be accepted.
+  connection_ptr new_connection_;
+
+  /// The handler for all incoming requests.
+  request_handler request_handler_;
+};
+
+} // namespace server
+} // namespace http
+
+#endif // HTTP_SERVER_HPP
diff --git a/link/modules/asio-standalone/asio/src/examples/cpp03/http/server2/connection.hpp b/link/modules/asio-standalone/asio/src/examples/cpp03/http/server2/connection.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/src/examples/cpp03/http/server2/connection.hpp
@@ -0,0 +1,75 @@
+//
+// connection.hpp
+// ~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 HTTP_SERVER2_CONNECTION_HPP
+#define HTTP_SERVER2_CONNECTION_HPP
+
+#include <asio.hpp>
+#include <boost/array.hpp>
+#include <boost/noncopyable.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/enable_shared_from_this.hpp>
+#include "reply.hpp"
+#include "request.hpp"
+#include "request_handler.hpp"
+#include "request_parser.hpp"
+
+namespace http {
+namespace server2 {
+
+/// Represents a single connection from a client.
+class connection
+  : public boost::enable_shared_from_this<connection>,
+    private boost::noncopyable
+{
+public:
+  /// Construct a connection with the given io_context.
+  explicit connection(asio::io_context& io_context,
+      request_handler& handler);
+
+  /// Get the socket associated with the connection.
+  asio::ip::tcp::socket& socket();
+
+  /// Start the first asynchronous operation for the connection.
+  void start();
+
+private:
+  /// Handle completion of a read operation.
+  void handle_read(const asio::error_code& e,
+      std::size_t bytes_transferred);
+
+  /// Handle completion of a write operation.
+  void handle_write(const asio::error_code& e);
+
+  /// Socket for the connection.
+  asio::ip::tcp::socket socket_;
+
+  /// The handler used to process the incoming request.
+  request_handler& request_handler_;
+
+  /// Buffer for incoming data.
+  boost::array<char, 8192> buffer_;
+
+  /// The incoming request.
+  request request_;
+
+  /// The parser for the incoming request.
+  request_parser request_parser_;
+
+  /// The reply to be sent back to the client.
+  reply reply_;
+};
+
+typedef boost::shared_ptr<connection> connection_ptr;
+
+} // namespace server2
+} // namespace http
+
+#endif // HTTP_SERVER2_CONNECTION_HPP
diff --git a/link/modules/asio-standalone/asio/src/examples/cpp03/http/server2/header.hpp b/link/modules/asio-standalone/asio/src/examples/cpp03/http/server2/header.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/src/examples/cpp03/http/server2/header.hpp
@@ -0,0 +1,28 @@
+//
+// header.hpp
+// ~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 HTTP_SERVER2_HEADER_HPP
+#define HTTP_SERVER2_HEADER_HPP
+
+#include <string>
+
+namespace http {
+namespace server2 {
+
+struct header
+{
+  std::string name;
+  std::string value;
+};
+
+} // namespace server2
+} // namespace http
+
+#endif // HTTP_SERVER2_HEADER_HPP
diff --git a/link/modules/asio-standalone/asio/src/examples/cpp03/http/server2/io_context_pool.hpp b/link/modules/asio-standalone/asio/src/examples/cpp03/http/server2/io_context_pool.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/src/examples/cpp03/http/server2/io_context_pool.hpp
@@ -0,0 +1,56 @@
+//
+// io_context_pool.hpp
+// ~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 HTTP_SERVER2_IO_SERVICE_POOL_HPP
+#define HTTP_SERVER2_IO_SERVICE_POOL_HPP
+
+#include <asio.hpp>
+#include <list>
+#include <vector>
+#include <boost/noncopyable.hpp>
+#include <boost/shared_ptr.hpp>
+
+namespace http {
+namespace server2 {
+
+/// A pool of io_context objects.
+class io_context_pool
+  : private boost::noncopyable
+{
+public:
+  /// Construct the io_context pool.
+  explicit io_context_pool(std::size_t pool_size);
+
+  /// Run all io_context objects in the pool.
+  void run();
+
+  /// Stop all io_context objects in the pool.
+  void stop();
+
+  /// Get an io_context to use.
+  asio::io_context& get_io_context();
+
+private:
+  typedef boost::shared_ptr<asio::io_context> io_context_ptr;
+
+  /// The pool of io_contexts.
+  std::vector<io_context_ptr> io_contexts_;
+
+  /// The work-tracking executors that keep the io_contexts running.
+  std::list<asio::any_io_executor> work_;
+
+  /// The next io_context to use for a connection.
+  std::size_t next_io_context_;
+};
+
+} // namespace server2
+} // namespace http
+
+#endif // HTTP_SERVER2_IO_SERVICE_POOL_HPP
diff --git a/link/modules/asio-standalone/asio/src/examples/cpp03/http/server2/mime_types.hpp b/link/modules/asio-standalone/asio/src/examples/cpp03/http/server2/mime_types.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/src/examples/cpp03/http/server2/mime_types.hpp
@@ -0,0 +1,27 @@
+//
+// mime_types.hpp
+// ~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 HTTP_SERVER2_MIME_TYPES_HPP
+#define HTTP_SERVER2_MIME_TYPES_HPP
+
+#include <string>
+
+namespace http {
+namespace server2 {
+namespace mime_types {
+
+/// Convert a file extension into a MIME type.
+std::string extension_to_type(const std::string& extension);
+
+} // namespace mime_types
+} // namespace server2
+} // namespace http
+
+#endif // HTTP_SERVER2_MIME_TYPES_HPP
diff --git a/link/modules/asio-standalone/asio/src/examples/cpp03/http/server2/reply.hpp b/link/modules/asio-standalone/asio/src/examples/cpp03/http/server2/reply.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/src/examples/cpp03/http/server2/reply.hpp
@@ -0,0 +1,64 @@
+//
+// reply.hpp
+// ~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 HTTP_SERVER2_REPLY_HPP
+#define HTTP_SERVER2_REPLY_HPP
+
+#include <string>
+#include <vector>
+#include <asio.hpp>
+#include "header.hpp"
+
+namespace http {
+namespace server2 {
+
+/// A reply to be sent to a client.
+struct reply
+{
+  /// The status of the reply.
+  enum status_type
+  {
+    ok = 200,
+    created = 201,
+    accepted = 202,
+    no_content = 204,
+    multiple_choices = 300,
+    moved_permanently = 301,
+    moved_temporarily = 302,
+    not_modified = 304,
+    bad_request = 400,
+    unauthorized = 401,
+    forbidden = 403,
+    not_found = 404,
+    internal_server_error = 500,
+    not_implemented = 501,
+    bad_gateway = 502,
+    service_unavailable = 503
+  } status;
+
+  /// The headers to be included in the reply.
+  std::vector<header> headers;
+
+  /// The content to be sent in the reply.
+  std::string content;
+
+  /// Convert the reply into a vector of buffers. The buffers do not own the
+  /// underlying memory blocks, therefore the reply object must remain valid and
+  /// not be changed until the write operation has completed.
+  std::vector<asio::const_buffer> to_buffers();
+
+  /// Get a stock reply.
+  static reply stock_reply(status_type status);
+};
+
+} // namespace server2
+} // namespace http
+
+#endif // HTTP_SERVER2_REPLY_HPP
diff --git a/link/modules/asio-standalone/asio/src/examples/cpp03/http/server2/request.hpp b/link/modules/asio-standalone/asio/src/examples/cpp03/http/server2/request.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/src/examples/cpp03/http/server2/request.hpp
@@ -0,0 +1,34 @@
+//
+// request.hpp
+// ~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 HTTP_SERVER2_REQUEST_HPP
+#define HTTP_SERVER2_REQUEST_HPP
+
+#include <string>
+#include <vector>
+#include "header.hpp"
+
+namespace http {
+namespace server2 {
+
+/// A request received from a client.
+struct request
+{
+  std::string method;
+  std::string uri;
+  int http_version_major;
+  int http_version_minor;
+  std::vector<header> headers;
+};
+
+} // namespace server2
+} // namespace http
+
+#endif // HTTP_SERVER2_REQUEST_HPP
diff --git a/link/modules/asio-standalone/asio/src/examples/cpp03/http/server2/request_handler.hpp b/link/modules/asio-standalone/asio/src/examples/cpp03/http/server2/request_handler.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/src/examples/cpp03/http/server2/request_handler.hpp
@@ -0,0 +1,46 @@
+//
+// request_handler.hpp
+// ~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 HTTP_SERVER2_REQUEST_HANDLER_HPP
+#define HTTP_SERVER2_REQUEST_HANDLER_HPP
+
+#include <string>
+#include <boost/noncopyable.hpp>
+
+namespace http {
+namespace server2 {
+
+struct reply;
+struct request;
+
+/// The common handler for all incoming requests.
+class request_handler
+  : private boost::noncopyable
+{
+public:
+  /// Construct with a directory containing files to be served.
+  explicit request_handler(const std::string& doc_root);
+
+  /// Handle a request and produce a reply.
+  void handle_request(const request& req, reply& rep);
+
+private:
+  /// The directory containing the files to be served.
+  std::string doc_root_;
+
+  /// Perform URL-decoding on a string. Returns false if the encoding was
+  /// invalid.
+  static bool url_decode(const std::string& in, std::string& out);
+};
+
+} // namespace server2
+} // namespace http
+
+#endif // HTTP_SERVER2_REQUEST_HANDLER_HPP
diff --git a/link/modules/asio-standalone/asio/src/examples/cpp03/http/server2/request_parser.hpp b/link/modules/asio-standalone/asio/src/examples/cpp03/http/server2/request_parser.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/src/examples/cpp03/http/server2/request_parser.hpp
@@ -0,0 +1,95 @@
+//
+// request_parser.hpp
+// ~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 HTTP_SERVER2_REQUEST_PARSER_HPP
+#define HTTP_SERVER2_REQUEST_PARSER_HPP
+
+#include <boost/logic/tribool.hpp>
+#include <boost/tuple/tuple.hpp>
+
+namespace http {
+namespace server2 {
+
+struct request;
+
+/// Parser for incoming requests.
+class request_parser
+{
+public:
+  /// Construct ready to parse the request method.
+  request_parser();
+
+  /// Reset to initial parser state.
+  void reset();
+
+  /// Parse some data. The tribool return value is true when a complete request
+  /// has been parsed, false if the data is invalid, indeterminate when more
+  /// data is required. The InputIterator return value indicates how much of the
+  /// input has been consumed.
+  template <typename InputIterator>
+  boost::tuple<boost::tribool, InputIterator> parse(request& req,
+      InputIterator begin, InputIterator end)
+  {
+    while (begin != end)
+    {
+      boost::tribool result = consume(req, *begin++);
+      if (result || !result)
+        return boost::make_tuple(result, begin);
+    }
+    boost::tribool result = boost::indeterminate;
+    return boost::make_tuple(result, begin);
+  }
+
+private:
+  /// Handle the next character of input.
+  boost::tribool consume(request& req, char input);
+
+  /// Check if a byte is an HTTP character.
+  static bool is_char(int c);
+
+  /// Check if a byte is an HTTP control character.
+  static bool is_ctl(int c);
+
+  /// Check if a byte is defined as an HTTP tspecial character.
+  static bool is_tspecial(int c);
+
+  /// Check if a byte is a digit.
+  static bool is_digit(int c);
+
+  /// The current state of the parser.
+  enum state
+  {
+    method_start,
+    method,
+    uri,
+    http_version_h,
+    http_version_t_1,
+    http_version_t_2,
+    http_version_p,
+    http_version_slash,
+    http_version_major_start,
+    http_version_major,
+    http_version_minor_start,
+    http_version_minor,
+    expecting_newline_1,
+    header_line_start,
+    header_lws,
+    header_name,
+    space_before_header_value,
+    header_value,
+    expecting_newline_2,
+    expecting_newline_3
+  } state_;
+};
+
+} // namespace server2
+} // namespace http
+
+#endif // HTTP_SERVER2_REQUEST_PARSER_HPP
diff --git a/link/modules/asio-standalone/asio/src/examples/cpp03/http/server2/server.hpp b/link/modules/asio-standalone/asio/src/examples/cpp03/http/server2/server.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/src/examples/cpp03/http/server2/server.hpp
@@ -0,0 +1,68 @@
+//
+// server.hpp
+// ~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 HTTP_SERVER2_SERVER_HPP
+#define HTTP_SERVER2_SERVER_HPP
+
+#include <asio.hpp>
+#include <string>
+#include <vector>
+#include <boost/noncopyable.hpp>
+#include <boost/shared_ptr.hpp>
+#include "connection.hpp"
+#include "io_context_pool.hpp"
+#include "request_handler.hpp"
+
+namespace http {
+namespace server2 {
+
+/// The top-level class of the HTTP server.
+class server
+  : private boost::noncopyable
+{
+public:
+  /// Construct the server to listen on the specified TCP address and port, and
+  /// serve up files from the given directory.
+  explicit server(const std::string& address, const std::string& port,
+      const std::string& doc_root, std::size_t io_context_pool_size);
+
+  /// Run the server's io_context loop.
+  void run();
+
+private:
+  /// Initiate an asynchronous accept operation.
+  void start_accept();
+
+  /// Handle completion of an asynchronous accept operation.
+  void handle_accept(const asio::error_code& e);
+
+  /// Handle a request to stop the server.
+  void handle_stop();
+
+  /// The pool of io_context objects used to perform asynchronous operations.
+  io_context_pool io_context_pool_;
+
+  /// The signal_set is used to register for process termination notifications.
+  asio::signal_set signals_;
+
+  /// Acceptor used to listen for incoming connections.
+  asio::ip::tcp::acceptor acceptor_;
+
+  /// The next connection to be accepted.
+  connection_ptr new_connection_;
+
+  /// The handler for all incoming requests.
+  request_handler request_handler_;
+};
+
+} // namespace server2
+} // namespace http
+
+#endif // HTTP_SERVER2_SERVER_HPP
diff --git a/link/modules/asio-standalone/asio/src/examples/cpp03/http/server3/connection.hpp b/link/modules/asio-standalone/asio/src/examples/cpp03/http/server3/connection.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/src/examples/cpp03/http/server3/connection.hpp
@@ -0,0 +1,78 @@
+//
+// connection.hpp
+// ~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 HTTP_SERVER3_CONNECTION_HPP
+#define HTTP_SERVER3_CONNECTION_HPP
+
+#include <asio.hpp>
+#include <boost/array.hpp>
+#include <boost/noncopyable.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/enable_shared_from_this.hpp>
+#include "reply.hpp"
+#include "request.hpp"
+#include "request_handler.hpp"
+#include "request_parser.hpp"
+
+namespace http {
+namespace server3 {
+
+/// Represents a single connection from a client.
+class connection
+  : public boost::enable_shared_from_this<connection>,
+    private boost::noncopyable
+{
+public:
+  /// Construct a connection with the given io_context.
+  explicit connection(asio::io_context& io_context,
+      request_handler& handler);
+
+  /// Get the socket associated with the connection.
+  asio::ip::tcp::socket& socket();
+
+  /// Start the first asynchronous operation for the connection.
+  void start();
+
+private:
+  /// Handle completion of a read operation.
+  void handle_read(const asio::error_code& e,
+      std::size_t bytes_transferred);
+
+  /// Handle completion of a write operation.
+  void handle_write(const asio::error_code& e);
+
+  /// Strand to ensure the connection's handlers are not called concurrently.
+  asio::strand<asio::io_context::executor_type> strand_;
+
+  /// Socket for the connection.
+  asio::ip::tcp::socket socket_;
+
+  /// The handler used to process the incoming request.
+  request_handler& request_handler_;
+
+  /// Buffer for incoming data.
+  boost::array<char, 8192> buffer_;
+
+  /// The incoming request.
+  request request_;
+
+  /// The parser for the incoming request.
+  request_parser request_parser_;
+
+  /// The reply to be sent back to the client.
+  reply reply_;
+};
+
+typedef boost::shared_ptr<connection> connection_ptr;
+
+} // namespace server3
+} // namespace http
+
+#endif // HTTP_SERVER3_CONNECTION_HPP
diff --git a/link/modules/asio-standalone/asio/src/examples/cpp03/http/server3/header.hpp b/link/modules/asio-standalone/asio/src/examples/cpp03/http/server3/header.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/src/examples/cpp03/http/server3/header.hpp
@@ -0,0 +1,28 @@
+//
+// header.hpp
+// ~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 HTTP_SERVER3_HEADER_HPP
+#define HTTP_SERVER3_HEADER_HPP
+
+#include <string>
+
+namespace http {
+namespace server3 {
+
+struct header
+{
+  std::string name;
+  std::string value;
+};
+
+} // namespace server3
+} // namespace http
+
+#endif // HTTP_SERVER3_HEADER_HPP
diff --git a/link/modules/asio-standalone/asio/src/examples/cpp03/http/server3/mime_types.hpp b/link/modules/asio-standalone/asio/src/examples/cpp03/http/server3/mime_types.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/src/examples/cpp03/http/server3/mime_types.hpp
@@ -0,0 +1,27 @@
+//
+// mime_types.hpp
+// ~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 HTTP_SERVER3_MIME_TYPES_HPP
+#define HTTP_SERVER3_MIME_TYPES_HPP
+
+#include <string>
+
+namespace http {
+namespace server3 {
+namespace mime_types {
+
+/// Convert a file extension into a MIME type.
+std::string extension_to_type(const std::string& extension);
+
+} // namespace mime_types
+} // namespace server3
+} // namespace http
+
+#endif // HTTP_SERVER3_MIME_TYPES_HPP
diff --git a/link/modules/asio-standalone/asio/src/examples/cpp03/http/server3/reply.hpp b/link/modules/asio-standalone/asio/src/examples/cpp03/http/server3/reply.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/src/examples/cpp03/http/server3/reply.hpp
@@ -0,0 +1,64 @@
+//
+// reply.hpp
+// ~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 HTTP_SERVER3_REPLY_HPP
+#define HTTP_SERVER3_REPLY_HPP
+
+#include <string>
+#include <vector>
+#include <asio.hpp>
+#include "header.hpp"
+
+namespace http {
+namespace server3 {
+
+/// A reply to be sent to a client.
+struct reply
+{
+  /// The status of the reply.
+  enum status_type
+  {
+    ok = 200,
+    created = 201,
+    accepted = 202,
+    no_content = 204,
+    multiple_choices = 300,
+    moved_permanently = 301,
+    moved_temporarily = 302,
+    not_modified = 304,
+    bad_request = 400,
+    unauthorized = 401,
+    forbidden = 403,
+    not_found = 404,
+    internal_server_error = 500,
+    not_implemented = 501,
+    bad_gateway = 502,
+    service_unavailable = 503
+  } status;
+
+  /// The headers to be included in the reply.
+  std::vector<header> headers;
+
+  /// The content to be sent in the reply.
+  std::string content;
+
+  /// Convert the reply into a vector of buffers. The buffers do not own the
+  /// underlying memory blocks, therefore the reply object must remain valid and
+  /// not be changed until the write operation has completed.
+  std::vector<asio::const_buffer> to_buffers();
+
+  /// Get a stock reply.
+  static reply stock_reply(status_type status);
+};
+
+} // namespace server3
+} // namespace http
+
+#endif // HTTP_SERVER3_REPLY_HPP
diff --git a/link/modules/asio-standalone/asio/src/examples/cpp03/http/server3/request.hpp b/link/modules/asio-standalone/asio/src/examples/cpp03/http/server3/request.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/src/examples/cpp03/http/server3/request.hpp
@@ -0,0 +1,34 @@
+//
+// request.hpp
+// ~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 HTTP_SERVER3_REQUEST_HPP
+#define HTTP_SERVER3_REQUEST_HPP
+
+#include <string>
+#include <vector>
+#include "header.hpp"
+
+namespace http {
+namespace server3 {
+
+/// A request received from a client.
+struct request
+{
+  std::string method;
+  std::string uri;
+  int http_version_major;
+  int http_version_minor;
+  std::vector<header> headers;
+};
+
+} // namespace server3
+} // namespace http
+
+#endif // HTTP_SERVER3_REQUEST_HPP
diff --git a/link/modules/asio-standalone/asio/src/examples/cpp03/http/server3/request_handler.hpp b/link/modules/asio-standalone/asio/src/examples/cpp03/http/server3/request_handler.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/src/examples/cpp03/http/server3/request_handler.hpp
@@ -0,0 +1,46 @@
+//
+// request_handler.hpp
+// ~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 HTTP_SERVER3_REQUEST_HANDLER_HPP
+#define HTTP_SERVER3_REQUEST_HANDLER_HPP
+
+#include <string>
+#include <boost/noncopyable.hpp>
+
+namespace http {
+namespace server3 {
+
+struct reply;
+struct request;
+
+/// The common handler for all incoming requests.
+class request_handler
+  : private boost::noncopyable
+{
+public:
+  /// Construct with a directory containing files to be served.
+  explicit request_handler(const std::string& doc_root);
+
+  /// Handle a request and produce a reply.
+  void handle_request(const request& req, reply& rep);
+
+private:
+  /// The directory containing the files to be served.
+  std::string doc_root_;
+
+  /// Perform URL-decoding on a string. Returns false if the encoding was
+  /// invalid.
+  static bool url_decode(const std::string& in, std::string& out);
+};
+
+} // namespace server3
+} // namespace http
+
+#endif // HTTP_SERVER3_REQUEST_HANDLER_HPP
diff --git a/link/modules/asio-standalone/asio/src/examples/cpp03/http/server3/request_parser.hpp b/link/modules/asio-standalone/asio/src/examples/cpp03/http/server3/request_parser.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/src/examples/cpp03/http/server3/request_parser.hpp
@@ -0,0 +1,95 @@
+//
+// request_parser.hpp
+// ~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 HTTP_SERVER3_REQUEST_PARSER_HPP
+#define HTTP_SERVER3_REQUEST_PARSER_HPP
+
+#include <boost/logic/tribool.hpp>
+#include <boost/tuple/tuple.hpp>
+
+namespace http {
+namespace server3 {
+
+struct request;
+
+/// Parser for incoming requests.
+class request_parser
+{
+public:
+  /// Construct ready to parse the request method.
+  request_parser();
+
+  /// Reset to initial parser state.
+  void reset();
+
+  /// Parse some data. The tribool return value is true when a complete request
+  /// has been parsed, false if the data is invalid, indeterminate when more
+  /// data is required. The InputIterator return value indicates how much of the
+  /// input has been consumed.
+  template <typename InputIterator>
+  boost::tuple<boost::tribool, InputIterator> parse(request& req,
+      InputIterator begin, InputIterator end)
+  {
+    while (begin != end)
+    {
+      boost::tribool result = consume(req, *begin++);
+      if (result || !result)
+        return boost::make_tuple(result, begin);
+    }
+    boost::tribool result = boost::indeterminate;
+    return boost::make_tuple(result, begin);
+  }
+
+private:
+  /// Handle the next character of input.
+  boost::tribool consume(request& req, char input);
+
+  /// Check if a byte is an HTTP character.
+  static bool is_char(int c);
+
+  /// Check if a byte is an HTTP control character.
+  static bool is_ctl(int c);
+
+  /// Check if a byte is defined as an HTTP tspecial character.
+  static bool is_tspecial(int c);
+
+  /// Check if a byte is a digit.
+  static bool is_digit(int c);
+
+  /// The current state of the parser.
+  enum state
+  {
+    method_start,
+    method,
+    uri,
+    http_version_h,
+    http_version_t_1,
+    http_version_t_2,
+    http_version_p,
+    http_version_slash,
+    http_version_major_start,
+    http_version_major,
+    http_version_minor_start,
+    http_version_minor,
+    expecting_newline_1,
+    header_line_start,
+    header_lws,
+    header_name,
+    space_before_header_value,
+    header_value,
+    expecting_newline_2,
+    expecting_newline_3
+  } state_;
+};
+
+} // namespace server3
+} // namespace http
+
+#endif // HTTP_SERVER3_REQUEST_PARSER_HPP
diff --git a/link/modules/asio-standalone/asio/src/examples/cpp03/http/server3/server.hpp b/link/modules/asio-standalone/asio/src/examples/cpp03/http/server3/server.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/src/examples/cpp03/http/server3/server.hpp
@@ -0,0 +1,70 @@
+//
+// server.hpp
+// ~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 HTTP_SERVER3_SERVER_HPP
+#define HTTP_SERVER3_SERVER_HPP
+
+#include <asio.hpp>
+#include <string>
+#include <vector>
+#include <boost/noncopyable.hpp>
+#include <boost/shared_ptr.hpp>
+#include "connection.hpp"
+#include "request_handler.hpp"
+
+namespace http {
+namespace server3 {
+
+/// The top-level class of the HTTP server.
+class server
+  : private boost::noncopyable
+{
+public:
+  /// Construct the server to listen on the specified TCP address and port, and
+  /// serve up files from the given directory.
+  explicit server(const std::string& address, const std::string& port,
+      const std::string& doc_root, std::size_t thread_pool_size);
+
+  /// Run the server's io_context loop.
+  void run();
+
+private:
+  /// Initiate an asynchronous accept operation.
+  void start_accept();
+
+  /// Handle completion of an asynchronous accept operation.
+  void handle_accept(const asio::error_code& e);
+
+  /// Handle a request to stop the server.
+  void handle_stop();
+
+  /// The number of threads that will call io_context::run().
+  std::size_t thread_pool_size_;
+
+  /// The io_context used to perform asynchronous operations.
+  asio::io_context io_context_;
+
+  /// The signal_set is used to register for process termination notifications.
+  asio::signal_set signals_;
+
+  /// Acceptor used to listen for incoming connections.
+  asio::ip::tcp::acceptor acceptor_;
+
+  /// The next connection to be accepted.
+  connection_ptr new_connection_;
+
+  /// The handler for all incoming requests.
+  request_handler request_handler_;
+};
+
+} // namespace server3
+} // namespace http
+
+#endif // HTTP_SERVER3_SERVER_HPP
diff --git a/link/modules/asio-standalone/asio/src/examples/cpp03/http/server4/file_handler.hpp b/link/modules/asio-standalone/asio/src/examples/cpp03/http/server4/file_handler.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/src/examples/cpp03/http/server4/file_handler.hpp
@@ -0,0 +1,44 @@
+//
+// file_handler.hpp
+// ~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 HTTP_SERVER4_FILE_HANDLER_HPP
+#define HTTP_SERVER4_FILE_HANDLER_HPP
+
+#include <string>
+
+namespace http {
+namespace server4 {
+
+struct reply;
+struct request;
+
+/// The common handler for all incoming requests.
+class file_handler
+{
+public:
+  /// Construct with a directory containing files to be served.
+  explicit file_handler(const std::string& doc_root);
+
+  /// Handle a request and produce a reply.
+  void operator()(const request& req, reply& rep);
+
+private:
+  /// The directory containing the files to be served.
+  std::string doc_root_;
+
+  /// Perform URL-decoding on a string. Returns false if the encoding was
+  /// invalid.
+  static bool url_decode(const std::string& in, std::string& out);
+};
+
+} // namespace server4
+} // namespace http
+
+#endif // HTTP_SERVER4_FILE_HANDLER_HPP
diff --git a/link/modules/asio-standalone/asio/src/examples/cpp03/http/server4/header.hpp b/link/modules/asio-standalone/asio/src/examples/cpp03/http/server4/header.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/src/examples/cpp03/http/server4/header.hpp
@@ -0,0 +1,28 @@
+//
+// header.hpp
+// ~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 HTTP_SERVER4_HEADER_HPP
+#define HTTP_SERVER4_HEADER_HPP
+
+#include <string>
+
+namespace http {
+namespace server4 {
+
+struct header
+{
+  std::string name;
+  std::string value;
+};
+
+} // namespace server4
+} // namespace http
+
+#endif // HTTP_SERVER4_HEADER_HPP
diff --git a/link/modules/asio-standalone/asio/src/examples/cpp03/http/server4/mime_types.hpp b/link/modules/asio-standalone/asio/src/examples/cpp03/http/server4/mime_types.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/src/examples/cpp03/http/server4/mime_types.hpp
@@ -0,0 +1,27 @@
+//
+// mime_types.hpp
+// ~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 HTTP_SERVER4_MIME_TYPES_HPP
+#define HTTP_SERVER4_MIME_TYPES_HPP
+
+#include <string>
+
+namespace http {
+namespace server4 {
+namespace mime_types {
+
+/// Convert a file extension into a MIME type.
+std::string extension_to_type(const std::string& extension);
+
+} // namespace mime_types
+} // namespace server4
+} // namespace http
+
+#endif // HTTP_SERVER4_MIME_TYPES_HPP
diff --git a/link/modules/asio-standalone/asio/src/examples/cpp03/http/server4/reply.hpp b/link/modules/asio-standalone/asio/src/examples/cpp03/http/server4/reply.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/src/examples/cpp03/http/server4/reply.hpp
@@ -0,0 +1,64 @@
+//
+// reply.hpp
+// ~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 HTTP_SERVER4_REPLY_HPP
+#define HTTP_SERVER4_REPLY_HPP
+
+#include <string>
+#include <vector>
+#include <asio.hpp>
+#include "header.hpp"
+
+namespace http {
+namespace server4 {
+
+/// A reply to be sent to a client.
+struct reply
+{
+  /// The status of the reply.
+  enum status_type
+  {
+    ok = 200,
+    created = 201,
+    accepted = 202,
+    no_content = 204,
+    multiple_choices = 300,
+    moved_permanently = 301,
+    moved_temporarily = 302,
+    not_modified = 304,
+    bad_request = 400,
+    unauthorized = 401,
+    forbidden = 403,
+    not_found = 404,
+    internal_server_error = 500,
+    not_implemented = 501,
+    bad_gateway = 502,
+    service_unavailable = 503
+  } status;
+
+  /// The headers to be included in the reply.
+  std::vector<header> headers;
+
+  /// The content to be sent in the reply.
+  std::string content;
+
+  /// Convert the reply into a vector of buffers. The buffers do not own the
+  /// underlying memory blocks, therefore the reply object must remain valid and
+  /// not be changed until the write operation has completed.
+  std::vector<asio::const_buffer> to_buffers();
+
+  /// Get a stock reply.
+  static reply stock_reply(status_type status);
+};
+
+} // namespace server4
+} // namespace http
+
+#endif // HTTP_SERVER4_REPLY_HPP
diff --git a/link/modules/asio-standalone/asio/src/examples/cpp03/http/server4/request.hpp b/link/modules/asio-standalone/asio/src/examples/cpp03/http/server4/request.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/src/examples/cpp03/http/server4/request.hpp
@@ -0,0 +1,46 @@
+//
+// request.hpp
+// ~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 HTTP_SERVER4_REQUEST_HPP
+#define HTTP_SERVER4_REQUEST_HPP
+
+#include <string>
+#include <vector>
+#include "header.hpp"
+
+namespace http {
+namespace server4 {
+
+/// A request received from a client.
+struct request
+{
+  /// The request method, e.g. "GET", "POST".
+  std::string method;
+
+  /// The requested URI, such as a path to a file.
+  std::string uri;
+
+  /// Major version number, usually 1.
+  int http_version_major;
+
+  /// Minor version number, usually 0 or 1.
+  int http_version_minor;
+
+  /// The headers included with the request.
+  std::vector<header> headers;
+
+  /// The optional content sent with the request.
+  std::string content;
+};
+
+} // namespace server4
+} // namespace http
+
+#endif // HTTP_SERVER4_REQUEST_HPP
diff --git a/link/modules/asio-standalone/asio/src/examples/cpp03/http/server4/request_parser.hpp b/link/modules/asio-standalone/asio/src/examples/cpp03/http/server4/request_parser.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/src/examples/cpp03/http/server4/request_parser.hpp
@@ -0,0 +1,78 @@
+//
+// request_parser.hpp
+// ~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 HTTP_SERVER4_REQUEST_PARSER_HPP
+#define HTTP_SERVER4_REQUEST_PARSER_HPP
+
+#include <string>
+#include <boost/logic/tribool.hpp>
+#include <boost/tuple/tuple.hpp>
+#include <asio/coroutine.hpp>
+
+namespace http {
+namespace server4 {
+
+struct request;
+
+/// Parser for incoming requests.
+class request_parser : asio::coroutine
+{
+public:
+  /// Parse some data. The tribool return value is true when a complete request
+  /// has been parsed, false if the data is invalid, indeterminate when more
+  /// data is required. The InputIterator return value indicates how much of the
+  /// input has been consumed.
+  template <typename InputIterator>
+  boost::tuple<boost::tribool, InputIterator> parse(request& req,
+      InputIterator begin, InputIterator end)
+  {
+    while (begin != end)
+    {
+      boost::tribool result = consume(req, *begin++);
+      if (result || !result)
+        return boost::make_tuple(result, begin);
+    }
+    boost::tribool result = boost::indeterminate;
+    return boost::make_tuple(result, begin);
+  }
+
+private:
+  /// The name of the content length header.
+  static std::string content_length_name_;
+
+  /// Content length as decoded from headers. Defaults to 0.
+  std::size_t content_length_;
+
+  /// Handle the next character of input.
+  boost::tribool consume(request& req, char input);
+
+  /// Check if a byte is an HTTP character.
+  static bool is_char(int c);
+
+  /// Check if a byte is an HTTP control character.
+  static bool is_ctl(int c);
+
+  /// Check if a byte is defined as an HTTP tspecial character.
+  static bool is_tspecial(int c);
+
+  /// Check if a byte is a digit.
+  static bool is_digit(int c);
+
+  /// Check if two characters are equal, without regard to case.
+  static bool tolower_compare(char a, char b);
+
+  /// Check whether the two request header names match.
+  bool headers_equal(const std::string& a, const std::string& b);
+};
+
+} // namespace server4
+} // namespace http
+
+#endif // HTTP_SERVER4_REQUEST_PARSER_HPP
diff --git a/link/modules/asio-standalone/asio/src/examples/cpp03/http/server4/server.hpp b/link/modules/asio-standalone/asio/src/examples/cpp03/http/server4/server.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/src/examples/cpp03/http/server4/server.hpp
@@ -0,0 +1,73 @@
+//
+// server.hpp
+// ~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 HTTP_SERVER4_SERVER_HPP
+#define HTTP_SERVER4_SERVER_HPP
+
+#include <asio.hpp>
+#include <string>
+#include <boost/array.hpp>
+#include <boost/function.hpp>
+#include <boost/shared_ptr.hpp>
+#include "request_parser.hpp"
+
+namespace http {
+namespace server4 {
+
+struct request;
+struct reply;
+
+/// The top-level coroutine of the HTTP server.
+class server : asio::coroutine
+{
+public:
+  /// Construct the server to listen on the specified TCP address and port, and
+  /// serve up files from the given directory.
+  explicit server(asio::io_context& io_context,
+      const std::string& address, const std::string& port,
+      boost::function<void(const request&, reply&)> request_handler);
+
+  /// Perform work associated with the server.
+  void operator()(
+      asio::error_code ec = asio::error_code(),
+      std::size_t length = 0);
+
+private:
+  typedef asio::ip::tcp tcp;
+
+  /// The user-supplied handler for all incoming requests.
+  boost::function<void(const request&, reply&)> request_handler_;
+
+  /// Acceptor used to listen for incoming connections.
+  boost::shared_ptr<tcp::acceptor> acceptor_;
+
+  /// The current connection from a client.
+  boost::shared_ptr<tcp::socket> socket_;
+
+  /// Buffer for incoming data.
+  boost::shared_ptr<boost::array<char, 8192> > buffer_;
+
+  /// The incoming request.
+  boost::shared_ptr<request> request_;
+
+  /// Whether the request is valid or not.
+  boost::tribool valid_request_;
+
+  /// The parser for the incoming request.
+  request_parser request_parser_;
+
+  /// The reply to be sent back to the client.
+  boost::shared_ptr<reply> reply_;
+};
+
+} // namespace server4
+} // namespace http
+
+#endif // HTTP_SERVER4_SERVER_HPP
diff --git a/link/modules/asio-standalone/asio/src/examples/cpp03/icmp/icmp_header.hpp b/link/modules/asio-standalone/asio/src/examples/cpp03/icmp/icmp_header.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/src/examples/cpp03/icmp/icmp_header.hpp
@@ -0,0 +1,94 @@
+//
+// icmp_header.hpp
+// ~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ICMP_HEADER_HPP
+#define ICMP_HEADER_HPP
+
+#include <istream>
+#include <ostream>
+#include <algorithm>
+
+// ICMP header for both IPv4 and IPv6.
+//
+// The wire format of an ICMP header is:
+// 
+// 0               8               16                             31
+// +---------------+---------------+------------------------------+      ---
+// |               |               |                              |       ^
+// |     type      |     code      |          checksum            |       |
+// |               |               |                              |       |
+// +---------------+---------------+------------------------------+    8 bytes
+// |                               |                              |       |
+// |          identifier           |       sequence number        |       |
+// |                               |                              |       v
+// +-------------------------------+------------------------------+      ---
+
+class icmp_header
+{
+public:
+  enum { echo_reply = 0, destination_unreachable = 3, source_quench = 4,
+    redirect = 5, echo_request = 8, time_exceeded = 11, parameter_problem = 12,
+    timestamp_request = 13, timestamp_reply = 14, info_request = 15,
+    info_reply = 16, address_request = 17, address_reply = 18 };
+
+  icmp_header() { std::fill(rep_, rep_ + sizeof(rep_), 0); }
+
+  unsigned char type() const { return rep_[0]; }
+  unsigned char code() const { return rep_[1]; }
+  unsigned short checksum() const { return decode(2, 3); }
+  unsigned short identifier() const { return decode(4, 5); }
+  unsigned short sequence_number() const { return decode(6, 7); }
+
+  void type(unsigned char n) { rep_[0] = n; }
+  void code(unsigned char n) { rep_[1] = n; }
+  void checksum(unsigned short n) { encode(2, 3, n); }
+  void identifier(unsigned short n) { encode(4, 5, n); }
+  void sequence_number(unsigned short n) { encode(6, 7, n); }
+
+  friend std::istream& operator>>(std::istream& is, icmp_header& header)
+    { return is.read(reinterpret_cast<char*>(header.rep_), 8); }
+
+  friend std::ostream& operator<<(std::ostream& os, const icmp_header& header)
+    { return os.write(reinterpret_cast<const char*>(header.rep_), 8); }
+
+private:
+  unsigned short decode(int a, int b) const
+    { return (rep_[a] << 8) + rep_[b]; }
+
+  void encode(int a, int b, unsigned short n)
+  {
+    rep_[a] = static_cast<unsigned char>(n >> 8);
+    rep_[b] = static_cast<unsigned char>(n & 0xFF);
+  }
+
+  unsigned char rep_[8];
+};
+
+template <typename Iterator>
+void compute_checksum(icmp_header& header,
+    Iterator body_begin, Iterator body_end)
+{
+  unsigned int sum = (header.type() << 8) + header.code()
+    + header.identifier() + header.sequence_number();
+
+  Iterator body_iter = body_begin;
+  while (body_iter != body_end)
+  {
+    sum += (static_cast<unsigned char>(*body_iter++) << 8);
+    if (body_iter != body_end)
+      sum += static_cast<unsigned char>(*body_iter++);
+  }
+
+  sum = (sum >> 16) + (sum & 0xFFFF);
+  sum += (sum >> 16);
+  header.checksum(static_cast<unsigned short>(~sum));
+}
+
+#endif // ICMP_HEADER_HPP
diff --git a/link/modules/asio-standalone/asio/src/examples/cpp03/icmp/ipv4_header.hpp b/link/modules/asio-standalone/asio/src/examples/cpp03/icmp/ipv4_header.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/src/examples/cpp03/icmp/ipv4_header.hpp
@@ -0,0 +1,102 @@
+//
+// ipv4_header.hpp
+// ~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 IPV4_HEADER_HPP
+#define IPV4_HEADER_HPP
+
+#include <algorithm>
+#include <asio/ip/address_v4.hpp>
+
+// Packet header for IPv4.
+//
+// The wire format of an IPv4 header is:
+// 
+// 0               8               16                             31
+// +-------+-------+---------------+------------------------------+      ---
+// |       |       |               |                              |       ^
+// |version|header |    type of    |    total length in bytes     |       |
+// |  (4)  | length|    service    |                              |       |
+// +-------+-------+---------------+-+-+-+------------------------+       |
+// |                               | | | |                        |       |
+// |        identification         |0|D|M|    fragment offset     |       |
+// |                               | |F|F|                        |       |
+// +---------------+---------------+-+-+-+------------------------+       |
+// |               |               |                              |       |
+// | time to live  |   protocol    |       header checksum        |   20 bytes
+// |               |               |                              |       |
+// +---------------+---------------+------------------------------+       |
+// |                                                              |       |
+// |                      source IPv4 address                     |       |
+// |                                                              |       |
+// +--------------------------------------------------------------+       |
+// |                                                              |       |
+// |                   destination IPv4 address                   |       |
+// |                                                              |       v
+// +--------------------------------------------------------------+      ---
+// |                                                              |       ^
+// |                                                              |       |
+// /                        options (if any)                      /    0 - 40
+// /                                                              /     bytes
+// |                                                              |       |
+// |                                                              |       v
+// +--------------------------------------------------------------+      ---
+
+class ipv4_header
+{
+public:
+  ipv4_header() { std::fill(rep_, rep_ + sizeof(rep_), 0); }
+
+  unsigned char version() const { return (rep_[0] >> 4) & 0xF; }
+  unsigned short header_length() const { return (rep_[0] & 0xF) * 4; }
+  unsigned char type_of_service() const { return rep_[1]; }
+  unsigned short total_length() const { return decode(2, 3); }
+  unsigned short identification() const { return decode(4, 5); }
+  bool dont_fragment() const { return (rep_[6] & 0x40) != 0; }
+  bool more_fragments() const { return (rep_[6] & 0x20) != 0; }
+  unsigned short fragment_offset() const { return decode(6, 7) & 0x1FFF; }
+  unsigned int time_to_live() const { return rep_[8]; }
+  unsigned char protocol() const { return rep_[9]; }
+  unsigned short header_checksum() const { return decode(10, 11); }
+
+  asio::ip::address_v4 source_address() const
+  {
+    asio::ip::address_v4::bytes_type bytes
+      = { { rep_[12], rep_[13], rep_[14], rep_[15] } };
+    return asio::ip::address_v4(bytes);
+  }
+
+  asio::ip::address_v4 destination_address() const
+  {
+    asio::ip::address_v4::bytes_type bytes
+      = { { rep_[16], rep_[17], rep_[18], rep_[19] } };
+    return asio::ip::address_v4(bytes);
+  }
+
+  friend std::istream& operator>>(std::istream& is, ipv4_header& header)
+  {
+    is.read(reinterpret_cast<char*>(header.rep_), 20);
+    if (header.version() != 4)
+      is.setstate(std::ios::failbit);
+    std::streamsize options_length = header.header_length() - 20;
+    if (options_length < 0 || options_length > 40)
+      is.setstate(std::ios::failbit);
+    else
+      is.read(reinterpret_cast<char*>(header.rep_) + 20, options_length);
+    return is;
+  }
+
+private:
+  unsigned short decode(int a, int b) const
+    { return (rep_[a] << 8) + rep_[b]; }
+
+  unsigned char rep_[60];
+};
+
+#endif // IPV4_HEADER_HPP
diff --git a/link/modules/asio-standalone/asio/src/examples/cpp03/porthopper/protocol.hpp b/link/modules/asio-standalone/asio/src/examples/cpp03/porthopper/protocol.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/src/examples/cpp03/porthopper/protocol.hpp
@@ -0,0 +1,156 @@
+//
+// protocol.hpp
+// ~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 PORTHOPPER_PROTOCOL_HPP
+#define PORTHOPPER_PROTOCOL_HPP
+
+#include <boost/array.hpp>
+#include <asio.hpp>
+#include <cstring>
+#include <iomanip>
+#include <string>
+#include <strstream>
+
+// This request is sent by the client to the server over a TCP connection.
+// The client uses it to perform three functions:
+// - To request that data start being sent to a given port.
+// - To request that data is no longer sent to a given port.
+// - To change the target port to another.
+class control_request
+{
+public:
+  // Construct an empty request. Used when receiving.
+  control_request()
+  {
+  }
+
+  // Create a request to start sending data to a given port.
+  static const control_request start(unsigned short port)
+  {
+    return control_request(0, port);
+  }
+
+  // Create a request to stop sending data to a given port.
+  static const control_request stop(unsigned short port)
+  {
+    return control_request(port, 0);
+  }
+
+  // Create a request to change the port that data is sent to.
+  static const control_request change(
+      unsigned short old_port, unsigned short new_port)
+  {
+    return control_request(old_port, new_port);
+  }
+
+  // Get the old port. Returns 0 for start requests.
+  unsigned short old_port() const
+  {
+    std::istrstream is(data_, encoded_port_size);
+    unsigned short port = 0;
+    is >> std::setw(encoded_port_size) >> std::hex >> port;
+    return port;
+  }
+
+  // Get the new port. Returns 0 for stop requests.
+  unsigned short new_port() const
+  {
+    std::istrstream is(data_ + encoded_port_size, encoded_port_size);
+    unsigned short port = 0;
+    is >> std::setw(encoded_port_size) >> std::hex >> port;
+    return port;
+  }
+
+  // Obtain buffers for reading from or writing to a socket.
+  boost::array<asio::mutable_buffer, 1> to_buffers()
+  {
+    boost::array<asio::mutable_buffer, 1> buffers
+      = { { asio::buffer(data_) } };
+    return buffers;
+  }
+
+private:
+  // Construct with specified old and new ports.
+  control_request(unsigned short old_port_number,
+      unsigned short new_port_number)
+  {
+    std::ostrstream os(data_, control_request_size);
+    os << std::setw(encoded_port_size) << std::hex << old_port_number;
+    os << std::setw(encoded_port_size) << std::hex << new_port_number;
+  }
+
+  // The length in bytes of a control_request and its components.
+  enum
+  {
+    encoded_port_size = 4, // 16-bit port in hex.
+    control_request_size = encoded_port_size * 2
+  };
+
+  // The encoded request data.
+  char data_[control_request_size];
+};
+
+// This frame is sent from the server to subscribed clients over UDP.
+class frame
+{
+public:
+  // The maximum allowable length of the payload.
+  enum { payload_size = 32 };
+
+  // Construct an empty frame. Used when receiving.
+  frame()
+  {
+  }
+
+  // Construct a frame with specified frame number and payload.
+  frame(unsigned long frame_number, const std::string& payload_data)
+  {
+    std::ostrstream os(data_, frame_size);
+    os << std::setw(encoded_number_size) << std::hex << frame_number;
+    os << std::setw(payload_size)
+      << std::setfill(' ') << payload_data.substr(0, payload_size);
+  }
+
+  // Get the frame number.
+  unsigned long number() const
+  {
+    std::istrstream is(data_, encoded_number_size);
+    unsigned long frame_number = 0;
+    is >> std::setw(encoded_number_size) >> std::hex >> frame_number;
+    return frame_number;
+  }
+
+  // Get the payload data.
+  const std::string payload() const
+  {
+    return std::string(data_ + encoded_number_size, payload_size);
+  }
+
+  // Obtain buffers for reading from or writing to a socket.
+  boost::array<asio::mutable_buffer, 1> to_buffers()
+  {
+    boost::array<asio::mutable_buffer, 1> buffers
+      = { { asio::buffer(data_) } };
+    return buffers;
+  }
+
+private:
+  // The length in bytes of a frame and its components.
+  enum
+  {
+    encoded_number_size = 8, // Frame number in hex.
+    frame_size = encoded_number_size + payload_size
+  };
+
+  // The encoded frame data.
+  char data_[frame_size];
+};
+
+#endif // PORTHOPPER_PROTOCOL_HPP
diff --git a/link/modules/asio-standalone/asio/src/examples/cpp03/serialization/connection.hpp b/link/modules/asio-standalone/asio/src/examples/cpp03/serialization/connection.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/src/examples/cpp03/serialization/connection.hpp
@@ -0,0 +1,188 @@
+//
+// connection.hpp
+// ~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 SERIALIZATION_CONNECTION_HPP
+#define SERIALIZATION_CONNECTION_HPP
+
+#include <asio.hpp>
+#include <boost/archive/text_iarchive.hpp>
+#include <boost/archive/text_oarchive.hpp>
+#include <boost/bind/bind.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/tuple/tuple.hpp>
+#include <iomanip>
+#include <string>
+#include <sstream>
+#include <vector>
+
+namespace s11n_example {
+
+/// The connection class provides serialization primitives on top of a socket.
+/**
+ * Each message sent using this class consists of:
+ * @li An 8-byte header containing the length of the serialized data in
+ * hexadecimal.
+ * @li The serialized data.
+ */
+class connection
+{
+public:
+  /// Constructor.
+  connection(const asio::executor& ex)
+    : socket_(ex)
+  {
+  }
+
+  /// Get the underlying socket. Used for making a connection or for accepting
+  /// an incoming connection.
+  asio::ip::tcp::socket& socket()
+  {
+    return socket_;
+  }
+
+  /// Asynchronously write a data structure to the socket.
+  template <typename T, typename Handler>
+  void async_write(const T& t, Handler handler)
+  {
+    // Serialize the data first so we know how large it is.
+    std::ostringstream archive_stream;
+    boost::archive::text_oarchive archive(archive_stream);
+    archive << t;
+    outbound_data_ = archive_stream.str();
+
+    // Format the header.
+    std::ostringstream header_stream;
+    header_stream << std::setw(header_length)
+      << std::hex << outbound_data_.size();
+    if (!header_stream || header_stream.str().size() != header_length)
+    {
+      // Something went wrong, inform the caller.
+      asio::error_code error(asio::error::invalid_argument);
+      asio::post(socket_.get_executor(), boost::bind(handler, error));
+      return;
+    }
+    outbound_header_ = header_stream.str();
+
+    // Write the serialized data to the socket. We use "gather-write" to send
+    // both the header and the data in a single write operation.
+    std::vector<asio::const_buffer> buffers;
+    buffers.push_back(asio::buffer(outbound_header_));
+    buffers.push_back(asio::buffer(outbound_data_));
+    asio::async_write(socket_, buffers, handler);
+  }
+
+  /// Asynchronously read a data structure from the socket.
+  template <typename T, typename Handler>
+  void async_read(T& t, Handler handler)
+  {
+    // Issue a read operation to read exactly the number of bytes in a header.
+    void (connection::*f)(
+        const asio::error_code&,
+        T&, boost::tuple<Handler>)
+      = &connection::handle_read_header<T, Handler>;
+    asio::async_read(socket_, asio::buffer(inbound_header_),
+        boost::bind(f,
+          this, asio::placeholders::error, boost::ref(t),
+          boost::make_tuple(handler)));
+  }
+
+  /// Handle a completed read of a message header. The handler is passed using
+  /// a tuple since boost::bind seems to have trouble binding a function object
+  /// created using boost::bind as a parameter.
+  template <typename T, typename Handler>
+  void handle_read_header(const asio::error_code& e,
+      T& t, boost::tuple<Handler> handler)
+  {
+    if (e)
+    {
+      boost::get<0>(handler)(e);
+    }
+    else
+    {
+      // Determine the length of the serialized data.
+      std::istringstream is(std::string(inbound_header_, header_length));
+      std::size_t inbound_data_size = 0;
+      if (!(is >> std::hex >> inbound_data_size))
+      {
+        // Header doesn't seem to be valid. Inform the caller.
+        asio::error_code error(asio::error::invalid_argument);
+        boost::get<0>(handler)(error);
+        return;
+      }
+
+      // Start an asynchronous call to receive the data.
+      inbound_data_.resize(inbound_data_size);
+      void (connection::*f)(
+          const asio::error_code&,
+          T&, boost::tuple<Handler>)
+        = &connection::handle_read_data<T, Handler>;
+      asio::async_read(socket_, asio::buffer(inbound_data_),
+        boost::bind(f, this,
+          asio::placeholders::error, boost::ref(t), handler));
+    }
+  }
+
+  /// Handle a completed read of message data.
+  template <typename T, typename Handler>
+  void handle_read_data(const asio::error_code& e,
+      T& t, boost::tuple<Handler> handler)
+  {
+    if (e)
+    {
+      boost::get<0>(handler)(e);
+    }
+    else
+    {
+      // Extract the data structure from the data just received.
+      try
+      {
+        std::string archive_data(&inbound_data_[0], inbound_data_.size());
+        std::istringstream archive_stream(archive_data);
+        boost::archive::text_iarchive archive(archive_stream);
+        archive >> t;
+      }
+      catch (std::exception& e)
+      {
+        // Unable to decode data.
+        asio::error_code error(asio::error::invalid_argument);
+        boost::get<0>(handler)(error);
+        return;
+      }
+
+      // Inform caller that data has been received ok.
+      boost::get<0>(handler)(e);
+    }
+  }
+
+private:
+  /// The underlying socket.
+  asio::ip::tcp::socket socket_;
+
+  /// The size of a fixed length header.
+  enum { header_length = 8 };
+
+  /// Holds an outbound header.
+  std::string outbound_header_;
+
+  /// Holds the outbound data.
+  std::string outbound_data_;
+
+  /// Holds an inbound header.
+  char inbound_header_[header_length];
+
+  /// Holds the inbound data.
+  std::vector<char> inbound_data_;
+};
+
+typedef boost::shared_ptr<connection> connection_ptr;
+
+} // namespace s11n_example
+
+#endif // SERIALIZATION_CONNECTION_HPP
diff --git a/link/modules/asio-standalone/asio/src/examples/cpp03/serialization/stock.hpp b/link/modules/asio-standalone/asio/src/examples/cpp03/serialization/stock.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/src/examples/cpp03/serialization/stock.hpp
@@ -0,0 +1,50 @@
+//
+// stock.hpp
+// ~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 SERIALIZATION_STOCK_HPP
+#define SERIALIZATION_STOCK_HPP
+
+#include <string>
+
+namespace s11n_example {
+
+/// Structure to hold information about a single stock.
+struct stock
+{
+  std::string code;
+  std::string name;
+  double open_price;
+  double high_price;
+  double low_price;
+  double last_price;
+  double buy_price;
+  int buy_quantity;
+  double sell_price;
+  int sell_quantity;
+
+  template <typename Archive>
+  void serialize(Archive& ar, const unsigned int version)
+  {
+    ar & code;
+    ar & name;
+    ar & open_price;
+    ar & high_price;
+    ar & low_price;
+    ar & last_price;
+    ar & buy_price;
+    ar & buy_quantity;
+    ar & sell_price;
+    ar & sell_quantity;
+  }
+};
+
+} // namespace s11n_example
+
+#endif // SERIALIZATION_STOCK_HPP
diff --git a/link/modules/asio-standalone/asio/src/examples/cpp03/services/basic_logger.hpp b/link/modules/asio-standalone/asio/src/examples/cpp03/services/basic_logger.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/src/examples/cpp03/services/basic_logger.hpp
@@ -0,0 +1,77 @@
+//
+// basic_logger.hpp
+// ~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 SERVICES_BASIC_LOGGER_HPP
+#define SERVICES_BASIC_LOGGER_HPP
+
+#include <asio.hpp>
+#include <boost/noncopyable.hpp>
+#include <string>
+
+namespace services {
+
+/// Class to provide simple logging functionality. Use the services::logger
+/// typedef.
+template <typename Service>
+class basic_logger
+  : private boost::noncopyable
+{
+public:
+  /// The type of the service that will be used to provide timer operations.
+  typedef Service service_type;
+
+  /// The native implementation type of the timer.
+  typedef typename service_type::impl_type impl_type;
+
+  /// Constructor.
+  /**
+   * This constructor creates a logger.
+   *
+   * @param context The execution context used to locate the logger service.
+   *
+   * @param identifier An identifier for this logger.
+   */
+  explicit basic_logger(asio::execution_context& context,
+      const std::string& identifier)
+    : service_(asio::use_service<Service>(context)),
+      impl_(service_.null())
+  {
+    service_.create(impl_, identifier);
+  }
+
+  /// Destructor.
+  ~basic_logger()
+  {
+    service_.destroy(impl_);
+  }
+
+  /// Set the output file for all logger instances.
+  void use_file(const std::string& file)
+  {
+    service_.use_file(impl_, file);
+  }
+
+  /// Log a message.
+  void log(const std::string& message)
+  {
+    service_.log(impl_, message);
+  }
+
+private:
+  /// The backend service implementation.
+  service_type& service_;
+
+  /// The underlying native implementation.
+  impl_type impl_;
+};
+
+} // namespace services
+
+#endif // SERVICES_BASIC_LOGGER_HPP
diff --git a/link/modules/asio-standalone/asio/src/examples/cpp03/services/logger.hpp b/link/modules/asio-standalone/asio/src/examples/cpp03/services/logger.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/src/examples/cpp03/services/logger.hpp
@@ -0,0 +1,24 @@
+//
+// logger.hpp
+// ~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 SERVICES_LOGGER_HPP
+#define SERVICES_LOGGER_HPP
+
+#include "basic_logger.hpp"
+#include "logger_service.hpp"
+
+namespace services {
+
+/// Typedef for typical logger usage.
+typedef basic_logger<logger_service> logger;
+
+} // namespace services
+
+#endif // SERVICES_LOGGER_HPP
diff --git a/link/modules/asio-standalone/asio/src/examples/cpp03/services/logger_service.hpp b/link/modules/asio-standalone/asio/src/examples/cpp03/services/logger_service.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/src/examples/cpp03/services/logger_service.hpp
@@ -0,0 +1,145 @@
+//
+// logger_service.hpp
+// ~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 SERVICES_LOGGER_SERVICE_HPP
+#define SERVICES_LOGGER_SERVICE_HPP
+
+#include <asio.hpp>
+#include <boost/bind/bind.hpp>
+#include <boost/date_time/posix_time/posix_time.hpp>
+#include <boost/noncopyable.hpp>
+#include <boost/scoped_ptr.hpp>
+#include <fstream>
+#include <sstream>
+#include <string>
+
+namespace services {
+
+/// Service implementation for the logger.
+class logger_service
+  : public asio::execution_context::service
+{
+public:
+  /// The type used to identify this service in the execution context.
+  typedef logger_service key_type;
+
+  /// The backend implementation of a logger.
+  struct logger_impl
+  {
+    explicit logger_impl(const std::string& ident) : identifier(ident) {}
+    std::string identifier;
+  };
+
+  /// The type for an implementation of the logger.
+  typedef logger_impl* impl_type;
+
+  /// Constructor creates a thread to run a private io_context.
+  logger_service(asio::execution_context& context)
+    : asio::execution_context::service(context),
+      work_io_context_(),
+      work_(asio::require(work_io_context_.get_executor(),
+            asio::execution::outstanding_work.tracked)),
+      work_thread_(new asio::thread(
+            boost::bind(&asio::io_context::run, &work_io_context_)))
+  {
+  }
+
+  /// Destructor shuts down the private io_context.
+  ~logger_service()
+  {
+    /// Indicate that we have finished with the private io_context. Its
+    /// io_context::run() function will exit once all other work has completed.
+    work_ = asio::any_io_executor();
+    if (work_thread_)
+      work_thread_->join();
+  }
+
+  /// Destroy all user-defined handler objects owned by the service.
+  void shutdown()
+  {
+  }
+
+  /// Return a null logger implementation.
+  impl_type null() const
+  {
+    return 0;
+  }
+
+  /// Create a new logger implementation.
+  void create(impl_type& impl, const std::string& identifier)
+  {
+    impl = new logger_impl(identifier);
+  }
+
+  /// Destroy a logger implementation.
+  void destroy(impl_type& impl)
+  {
+    delete impl;
+    impl = null();
+  }
+
+  /// Set the output file for the logger. The current implementation sets the
+  /// output file for all logger instances, and so the impl parameter is not
+  /// actually needed. It is retained here to illustrate how service functions
+  /// are typically defined.
+  void use_file(impl_type& /*impl*/, const std::string& file)
+  {
+    // Pass the work of opening the file to the background thread.
+    asio::post(work_io_context_, boost::bind(
+          &logger_service::use_file_impl, this, file));
+  }
+
+  /// Log a message.
+  void log(impl_type& impl, const std::string& message)
+  {
+    // Format the text to be logged.
+    std::ostringstream os;
+    os << impl->identifier << ": " << message;
+
+    // Pass the work of writing to the file to the background thread.
+    asio::post(work_io_context_, boost::bind(
+          &logger_service::log_impl, this, os.str()));
+  }
+
+private:
+  /// Helper function used to open the output file from within the private
+  /// io_context's thread.
+  void use_file_impl(const std::string& file)
+  {
+    ofstream_.close();
+    ofstream_.clear();
+    ofstream_.open(file.c_str());
+  }
+
+  /// Helper function used to log a message from within the private io_context's
+  /// thread.
+  void log_impl(const std::string& text)
+  {
+    ofstream_ << text << std::endl;
+  }
+
+  /// Private io_context used for performing logging operations.
+  asio::io_context work_io_context_;
+
+  /// A work-tracking executor giving work for the private io_context to
+  /// perform. If we do not give the io_context some work to do then the
+  /// io_context::run() function will exit immediately.
+  asio::any_io_executor work_;
+
+  /// Thread used for running the work io_context's run loop.
+  boost::scoped_ptr<asio::thread> work_thread_;
+
+  /// The file to which log messages will be written.
+  std::ofstream ofstream_;
+};
+
+} // namespace services
+
+#endif // SERVICES_LOGGER_SERVICE_HPP
diff --git a/link/modules/asio-standalone/asio/src/examples/cpp03/socks4/socks4.hpp b/link/modules/asio-standalone/asio/src/examples/cpp03/socks4/socks4.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/src/examples/cpp03/socks4/socks4.hpp
@@ -0,0 +1,144 @@
+//
+// socks4.hpp
+// ~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 SOCKS4_HPP
+#define SOCKS4_HPP
+
+#include <string>
+#include <asio.hpp>
+#include <boost/array.hpp>
+
+namespace socks4 {
+
+const unsigned char version = 0x04;
+
+class request
+{
+public:
+  enum command_type
+  {
+    connect = 0x01,
+    bind = 0x02
+  };
+
+  request(command_type cmd, const asio::ip::tcp::endpoint& endpoint,
+      const std::string& user_id)
+    : version_(version),
+      command_(cmd),
+      user_id_(user_id),
+      null_byte_(0)
+  {
+    // Only IPv4 is supported by the SOCKS 4 protocol.
+    if (endpoint.protocol() != asio::ip::tcp::v4())
+    {
+      throw asio::system_error(
+          asio::error::address_family_not_supported);
+    }
+
+    // Convert port number to network byte order.
+    unsigned short port = endpoint.port();
+    port_high_byte_ = (port >> 8) & 0xff;
+    port_low_byte_ = port & 0xff;
+
+    // Save IP address in network byte order.
+    address_ = endpoint.address().to_v4().to_bytes();
+  }
+
+  boost::array<asio::const_buffer, 7> buffers() const
+  {
+    boost::array<asio::const_buffer, 7> bufs =
+    {
+      {
+        asio::buffer(&version_, 1),
+        asio::buffer(&command_, 1),
+        asio::buffer(&port_high_byte_, 1),
+        asio::buffer(&port_low_byte_, 1),
+        asio::buffer(address_),
+        asio::buffer(user_id_),
+        asio::buffer(&null_byte_, 1)
+      }
+    };
+    return bufs;
+  }
+
+private:
+  unsigned char version_;
+  unsigned char command_;
+  unsigned char port_high_byte_;
+  unsigned char port_low_byte_;
+  asio::ip::address_v4::bytes_type address_;
+  std::string user_id_;
+  unsigned char null_byte_;
+};
+
+class reply
+{
+public:
+  enum status_type
+  {
+    request_granted = 0x5a,
+    request_failed = 0x5b,
+    request_failed_no_identd = 0x5c,
+    request_failed_bad_user_id = 0x5d
+  };
+
+  reply()
+    : null_byte_(0),
+      status_()
+  {
+  }
+
+  boost::array<asio::mutable_buffer, 5> buffers()
+  {
+    boost::array<asio::mutable_buffer, 5> bufs =
+    {
+      {
+        asio::buffer(&null_byte_, 1),
+        asio::buffer(&status_, 1),
+        asio::buffer(&port_high_byte_, 1),
+        asio::buffer(&port_low_byte_, 1),
+        asio::buffer(address_)
+      }
+    };
+    return bufs;
+  }
+
+  bool success() const
+  {
+    return null_byte_ == 0 && status_ == request_granted;
+  }
+
+  unsigned char status() const
+  {
+    return status_;
+  }
+
+  asio::ip::tcp::endpoint endpoint() const
+  {
+    unsigned short port = port_high_byte_;
+    port = (port << 8) & 0xff00;
+    port = port | port_low_byte_;
+
+    asio::ip::address_v4 address(address_);
+
+    return asio::ip::tcp::endpoint(address, port);
+  }
+
+private:
+  unsigned char null_byte_;
+  unsigned char status_;
+  unsigned char port_high_byte_;
+  unsigned char port_low_byte_;
+  asio::ip::address_v4::bytes_type address_;
+};
+
+} // namespace socks4
+
+#endif // SOCKS4_HPP
diff --git a/link/modules/asio-standalone/asio/src/examples/cpp11/chat/chat_message.hpp b/link/modules/asio-standalone/asio/src/examples/cpp11/chat/chat_message.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/src/examples/cpp11/chat/chat_message.hpp
@@ -0,0 +1,91 @@
+//
+// chat_message.hpp
+// ~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 CHAT_MESSAGE_HPP
+#define CHAT_MESSAGE_HPP
+
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+
+class chat_message
+{
+public:
+  enum { header_length = 4 };
+  enum { max_body_length = 512 };
+
+  chat_message()
+    : body_length_(0)
+  {
+  }
+
+  const char* data() const
+  {
+    return data_;
+  }
+
+  char* data()
+  {
+    return data_;
+  }
+
+  std::size_t length() const
+  {
+    return header_length + body_length_;
+  }
+
+  const char* body() const
+  {
+    return data_ + header_length;
+  }
+
+  char* body()
+  {
+    return data_ + header_length;
+  }
+
+  std::size_t body_length() const
+  {
+    return body_length_;
+  }
+
+  void body_length(std::size_t new_length)
+  {
+    body_length_ = new_length;
+    if (body_length_ > max_body_length)
+      body_length_ = max_body_length;
+  }
+
+  bool decode_header()
+  {
+    char header[header_length + 1] = "";
+    std::strncat(header, data_, header_length);
+    body_length_ = std::atoi(header);
+    if (body_length_ > max_body_length)
+    {
+      body_length_ = 0;
+      return false;
+    }
+    return true;
+  }
+
+  void encode_header()
+  {
+    char header[header_length + 1] = "";
+    std::sprintf(header, "%4d", static_cast<int>(body_length_));
+    std::memcpy(data_, header, header_length);
+  }
+
+private:
+  char data_[header_length + max_body_length];
+  std::size_t body_length_;
+};
+
+#endif // CHAT_MESSAGE_HPP
diff --git a/link/modules/asio-standalone/asio/src/examples/cpp11/handler_tracking/custom_tracking.hpp b/link/modules/asio-standalone/asio/src/examples/cpp11/handler_tracking/custom_tracking.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/src/examples/cpp11/handler_tracking/custom_tracking.hpp
@@ -0,0 +1,211 @@
+//
+// custom_tracking.hpp
+// ~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 CUSTOM_TRACKING_HPP
+#define CUSTOM_TRACKING_HPP
+
+#include <cinttypes>
+#include <cstdint>
+#include <cstdio>
+
+# define ASIO_INHERIT_TRACKED_HANDLER \
+  : public ::custom_tracking::tracked_handler
+
+# define ASIO_ALSO_INHERIT_TRACKED_HANDLER \
+  , public ::custom_tracking::tracked_handler
+
+# define ASIO_HANDLER_TRACKING_INIT \
+  ::custom_tracking::init()
+
+# define ASIO_HANDLER_LOCATION(args) \
+  ::custom_tracking::location args
+
+# define ASIO_HANDLER_CREATION(args) \
+  ::custom_tracking::creation args
+
+# define ASIO_HANDLER_COMPLETION(args) \
+  ::custom_tracking::completion tracked_completion args
+
+# define ASIO_HANDLER_INVOCATION_BEGIN(args) \
+  tracked_completion.invocation_begin args
+
+# define ASIO_HANDLER_INVOCATION_END \
+  tracked_completion.invocation_end()
+
+# define ASIO_HANDLER_OPERATION(args) \
+  ::custom_tracking::operation args
+
+# define ASIO_HANDLER_REACTOR_REGISTRATION(args) \
+  ::custom_tracking::reactor_registration args
+
+# define ASIO_HANDLER_REACTOR_DEREGISTRATION(args) \
+  ::custom_tracking::reactor_deregistration args
+
+# define ASIO_HANDLER_REACTOR_READ_EVENT 1
+# define ASIO_HANDLER_REACTOR_WRITE_EVENT 2
+# define ASIO_HANDLER_REACTOR_ERROR_EVENT 4
+
+# define ASIO_HANDLER_REACTOR_EVENTS(args) \
+  ::custom_tracking::reactor_events args
+
+# define ASIO_HANDLER_REACTOR_OPERATION(args) \
+  ::custom_tracking::reactor_operation args
+
+struct custom_tracking
+{
+  // Base class for objects containing tracked handlers.
+  struct tracked_handler
+  {
+    std::uintmax_t handler_id_ = 0; // To uniquely identify a handler.
+    std::uintmax_t tree_id_ = 0; // To identify related handlers.
+    const char* object_type_; // The object type associated with the handler.
+    std::uintmax_t native_handle_; // Native handle, if any.
+  };
+
+  // Initialise the tracking system.
+  static void init()
+  {
+  }
+
+  // Record a source location.
+  static void location(const char* file_name,
+      int line, const char* function_name)
+  {
+    std::printf("At location %s:%d in %s\n", file_name, line, function_name);
+  }
+
+  // Record the creation of a tracked handler.
+  static void creation(asio::execution_context& /*ctx*/,
+      tracked_handler& h, const char* object_type, void* /*object*/,
+      std::uintmax_t native_handle, const char* op_name)
+  {
+    // Generate a unique id for the new handler.
+    static std::atomic<std::uintmax_t> next_handler_id{1};
+    h.handler_id_ = next_handler_id++;
+
+    // Copy the tree identifier forward from the current handler.
+    if (*current_completion())
+      h.tree_id_ = (*current_completion())->handler_.tree_id_;
+
+    // Store various attributes of the operation to use in later output.
+    h.object_type_ = object_type;
+    h.native_handle_ = native_handle;
+
+    std::printf(
+        "Starting operation %s.%s for native_handle = %" PRIuMAX
+        ", handler = %" PRIuMAX ", tree = %" PRIuMAX "\n",
+        object_type, op_name, h.native_handle_, h.handler_id_, h.tree_id_);
+  }
+
+  struct completion
+  {
+    explicit completion(const tracked_handler& h)
+      : handler_(h),
+        next_(*current_completion())
+    {
+      *current_completion() = this;
+    }
+
+    completion(const completion&) = delete;
+    completion& operator=(const completion&) = delete;
+
+    // Destructor records only when an exception is thrown from the handler, or
+    // if the memory is being freed without the handler having been invoked.
+    ~completion()
+    {
+      *current_completion() = next_;
+    }
+
+    // Records that handler is to be invoked with the specified arguments.
+    template <class... Args>
+    void invocation_begin(Args&&... /*args*/)
+    {
+      std::printf("Entering handler %" PRIuMAX " in tree %" PRIuMAX "\n",
+          handler_.handler_id_, handler_.tree_id_);
+    }
+
+    // Record that handler invocation has ended.
+    void invocation_end()
+    {
+      std::printf("Leaving handler %" PRIuMAX " in tree %" PRIuMAX "\n",
+          handler_.handler_id_, handler_.tree_id_);
+    }
+
+    tracked_handler handler_;
+
+    // Completions may nest. Here we stash a pointer to the outer completion.
+    completion* next_;
+  };
+
+  static completion** current_completion()
+  {
+    static ASIO_THREAD_KEYWORD completion* current = nullptr;
+    return &current;
+  }
+
+  // Record an operation that is not directly associated with a handler.
+  static void operation(asio::execution_context& /*ctx*/,
+      const char* /*object_type*/, void* /*object*/,
+      std::uintmax_t /*native_handle*/, const char* /*op_name*/)
+  {
+  }
+
+  // Record that a descriptor has been registered with the reactor.
+  static void reactor_registration(asio::execution_context& context,
+      uintmax_t native_handle, uintmax_t registration)
+  {
+    std::printf("Adding to reactor native_handle = %" PRIuMAX
+        ", registration = %" PRIuMAX "\n", native_handle, registration);
+  }
+
+  // Record that a descriptor has been deregistered from the reactor.
+  static void reactor_deregistration(asio::execution_context& context,
+      uintmax_t native_handle, uintmax_t registration)
+  {
+    std::printf("Removing from reactor native_handle = %" PRIuMAX
+        ", registration = %" PRIuMAX "\n", native_handle, registration);
+  }
+
+  // Record reactor-based readiness events associated with a descriptor.
+  static void reactor_events(asio::execution_context& context,
+      uintmax_t registration, unsigned events)
+  {
+    std::printf(
+        "Reactor readiness for registration = %" PRIuMAX ", events =%s%s%s\n",
+        registration,
+        (events & ASIO_HANDLER_REACTOR_READ_EVENT) ? " read" : "",
+        (events & ASIO_HANDLER_REACTOR_WRITE_EVENT) ? " write" : "",
+        (events & ASIO_HANDLER_REACTOR_ERROR_EVENT) ? " error" : "");
+  }
+
+  // Record a reactor-based operation that is associated with a handler.
+  static void reactor_operation(const tracked_handler& h,
+      const char* op_name, const asio::error_code& ec)
+  {
+    std::printf(
+        "Performed operation %s.%s for native_handle = %" PRIuMAX
+        ", ec = %s:%d\n", h.object_type_, op_name, h.native_handle_,
+        ec.category().name(), ec.value());
+  }
+
+  // Record a reactor-based operation that is associated with a handler.
+  static void reactor_operation(const tracked_handler& h,
+      const char* op_name, const asio::error_code& ec,
+      std::size_t bytes_transferred)
+  {
+    std::printf(
+        "Performed operation %s.%s for native_handle = %" PRIuMAX
+        ", ec = %s:%d, n = %" PRIuMAX "\n", h.object_type_, op_name,
+        h.native_handle_, ec.category().name(), ec.value(),
+        static_cast<uintmax_t>(bytes_transferred));
+  }
+};
+
+#endif // CUSTOM_TRACKING_HPP
diff --git a/link/modules/asio-standalone/asio/src/examples/cpp11/http/server/connection.hpp b/link/modules/asio-standalone/asio/src/examples/cpp11/http/server/connection.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/src/examples/cpp11/http/server/connection.hpp
@@ -0,0 +1,79 @@
+//
+// connection.hpp
+// ~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 HTTP_CONNECTION_HPP
+#define HTTP_CONNECTION_HPP
+
+#include <array>
+#include <memory>
+#include <asio.hpp>
+#include "reply.hpp"
+#include "request.hpp"
+#include "request_handler.hpp"
+#include "request_parser.hpp"
+
+namespace http {
+namespace server {
+
+class connection_manager;
+
+/// Represents a single connection from a client.
+class connection
+  : public std::enable_shared_from_this<connection>
+{
+public:
+  connection(const connection&) = delete;
+  connection& operator=(const connection&) = delete;
+
+  /// Construct a connection with the given socket.
+  explicit connection(asio::ip::tcp::socket socket,
+      connection_manager& manager, request_handler& handler);
+
+  /// Start the first asynchronous operation for the connection.
+  void start();
+
+  /// Stop all asynchronous operations associated with the connection.
+  void stop();
+
+private:
+  /// Perform an asynchronous read operation.
+  void do_read();
+
+  /// Perform an asynchronous write operation.
+  void do_write();
+
+  /// Socket for the connection.
+  asio::ip::tcp::socket socket_;
+
+  /// The manager for this connection.
+  connection_manager& connection_manager_;
+
+  /// The handler used to process the incoming request.
+  request_handler& request_handler_;
+
+  /// Buffer for incoming data.
+  std::array<char, 8192> buffer_;
+
+  /// The incoming request.
+  request request_;
+
+  /// The parser for the incoming request.
+  request_parser request_parser_;
+
+  /// The reply to be sent back to the client.
+  reply reply_;
+};
+
+typedef std::shared_ptr<connection> connection_ptr;
+
+} // namespace server
+} // namespace http
+
+#endif // HTTP_CONNECTION_HPP
diff --git a/link/modules/asio-standalone/asio/src/examples/cpp11/http/server/connection_manager.hpp b/link/modules/asio-standalone/asio/src/examples/cpp11/http/server/connection_manager.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/src/examples/cpp11/http/server/connection_manager.hpp
@@ -0,0 +1,48 @@
+//
+// connection_manager.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 HTTP_CONNECTION_MANAGER_HPP
+#define HTTP_CONNECTION_MANAGER_HPP
+
+#include <set>
+#include "connection.hpp"
+
+namespace http {
+namespace server {
+
+/// Manages open connections so that they may be cleanly stopped when the server
+/// needs to shut down.
+class connection_manager
+{
+public:
+  connection_manager(const connection_manager&) = delete;
+  connection_manager& operator=(const connection_manager&) = delete;
+
+  /// Construct a connection manager.
+  connection_manager();
+
+  /// Add the specified connection to the manager and start it.
+  void start(connection_ptr c);
+
+  /// Stop the specified connection.
+  void stop(connection_ptr c);
+
+  /// Stop all connections.
+  void stop_all();
+
+private:
+  /// The managed connections.
+  std::set<connection_ptr> connections_;
+};
+
+} // namespace server
+} // namespace http
+
+#endif // HTTP_CONNECTION_MANAGER_HPP
diff --git a/link/modules/asio-standalone/asio/src/examples/cpp11/http/server/header.hpp b/link/modules/asio-standalone/asio/src/examples/cpp11/http/server/header.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/src/examples/cpp11/http/server/header.hpp
@@ -0,0 +1,28 @@
+//
+// header.hpp
+// ~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 HTTP_HEADER_HPP
+#define HTTP_HEADER_HPP
+
+#include <string>
+
+namespace http {
+namespace server {
+
+struct header
+{
+  std::string name;
+  std::string value;
+};
+
+} // namespace server
+} // namespace http
+
+#endif // HTTP_HEADER_HPP
diff --git a/link/modules/asio-standalone/asio/src/examples/cpp11/http/server/mime_types.hpp b/link/modules/asio-standalone/asio/src/examples/cpp11/http/server/mime_types.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/src/examples/cpp11/http/server/mime_types.hpp
@@ -0,0 +1,27 @@
+//
+// mime_types.hpp
+// ~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 HTTP_MIME_TYPES_HPP
+#define HTTP_MIME_TYPES_HPP
+
+#include <string>
+
+namespace http {
+namespace server {
+namespace mime_types {
+
+/// Convert a file extension into a MIME type.
+std::string extension_to_type(const std::string& extension);
+
+} // namespace mime_types
+} // namespace server
+} // namespace http
+
+#endif // HTTP_MIME_TYPES_HPP
diff --git a/link/modules/asio-standalone/asio/src/examples/cpp11/http/server/reply.hpp b/link/modules/asio-standalone/asio/src/examples/cpp11/http/server/reply.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/src/examples/cpp11/http/server/reply.hpp
@@ -0,0 +1,64 @@
+//
+// reply.hpp
+// ~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 HTTP_REPLY_HPP
+#define HTTP_REPLY_HPP
+
+#include <string>
+#include <vector>
+#include <asio.hpp>
+#include "header.hpp"
+
+namespace http {
+namespace server {
+
+/// A reply to be sent to a client.
+struct reply
+{
+  /// The status of the reply.
+  enum status_type
+  {
+    ok = 200,
+    created = 201,
+    accepted = 202,
+    no_content = 204,
+    multiple_choices = 300,
+    moved_permanently = 301,
+    moved_temporarily = 302,
+    not_modified = 304,
+    bad_request = 400,
+    unauthorized = 401,
+    forbidden = 403,
+    not_found = 404,
+    internal_server_error = 500,
+    not_implemented = 501,
+    bad_gateway = 502,
+    service_unavailable = 503
+  } status;
+
+  /// The headers to be included in the reply.
+  std::vector<header> headers;
+
+  /// The content to be sent in the reply.
+  std::string content;
+
+  /// Convert the reply into a vector of buffers. The buffers do not own the
+  /// underlying memory blocks, therefore the reply object must remain valid and
+  /// not be changed until the write operation has completed.
+  std::vector<asio::const_buffer> to_buffers();
+
+  /// Get a stock reply.
+  static reply stock_reply(status_type status);
+};
+
+} // namespace server
+} // namespace http
+
+#endif // HTTP_REPLY_HPP
diff --git a/link/modules/asio-standalone/asio/src/examples/cpp11/http/server/request.hpp b/link/modules/asio-standalone/asio/src/examples/cpp11/http/server/request.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/src/examples/cpp11/http/server/request.hpp
@@ -0,0 +1,34 @@
+//
+// request.hpp
+// ~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 HTTP_REQUEST_HPP
+#define HTTP_REQUEST_HPP
+
+#include <string>
+#include <vector>
+#include "header.hpp"
+
+namespace http {
+namespace server {
+
+/// A request received from a client.
+struct request
+{
+  std::string method;
+  std::string uri;
+  int http_version_major;
+  int http_version_minor;
+  std::vector<header> headers;
+};
+
+} // namespace server
+} // namespace http
+
+#endif // HTTP_REQUEST_HPP
diff --git a/link/modules/asio-standalone/asio/src/examples/cpp11/http/server/request_handler.hpp b/link/modules/asio-standalone/asio/src/examples/cpp11/http/server/request_handler.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/src/examples/cpp11/http/server/request_handler.hpp
@@ -0,0 +1,47 @@
+//
+// request_handler.hpp
+// ~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 HTTP_REQUEST_HANDLER_HPP
+#define HTTP_REQUEST_HANDLER_HPP
+
+#include <string>
+
+namespace http {
+namespace server {
+
+struct reply;
+struct request;
+
+/// The common handler for all incoming requests.
+class request_handler
+{
+public:
+  request_handler(const request_handler&) = delete;
+  request_handler& operator=(const request_handler&) = delete;
+
+  /// Construct with a directory containing files to be served.
+  explicit request_handler(const std::string& doc_root);
+
+  /// Handle a request and produce a reply.
+  void handle_request(const request& req, reply& rep);
+
+private:
+  /// The directory containing the files to be served.
+  std::string doc_root_;
+
+  /// Perform URL-decoding on a string. Returns false if the encoding was
+  /// invalid.
+  static bool url_decode(const std::string& in, std::string& out);
+};
+
+} // namespace server
+} // namespace http
+
+#endif // HTTP_REQUEST_HANDLER_HPP
diff --git a/link/modules/asio-standalone/asio/src/examples/cpp11/http/server/request_parser.hpp b/link/modules/asio-standalone/asio/src/examples/cpp11/http/server/request_parser.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/src/examples/cpp11/http/server/request_parser.hpp
@@ -0,0 +1,96 @@
+//
+// request_parser.hpp
+// ~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 HTTP_REQUEST_PARSER_HPP
+#define HTTP_REQUEST_PARSER_HPP
+
+#include <tuple>
+
+namespace http {
+namespace server {
+
+struct request;
+
+/// Parser for incoming requests.
+class request_parser
+{
+public:
+  /// Construct ready to parse the request method.
+  request_parser();
+
+  /// Reset to initial parser state.
+  void reset();
+
+  /// Result of parse.
+  enum result_type { good, bad, indeterminate };
+
+  /// Parse some data. The enum return value is good when a complete request has
+  /// been parsed, bad if the data is invalid, indeterminate when more data is
+  /// required. The InputIterator return value indicates how much of the input
+  /// has been consumed.
+  template <typename InputIterator>
+  std::tuple<result_type, InputIterator> parse(request& req,
+      InputIterator begin, InputIterator end)
+  {
+    while (begin != end)
+    {
+      result_type result = consume(req, *begin++);
+      if (result == good || result == bad)
+        return std::make_tuple(result, begin);
+    }
+    return std::make_tuple(indeterminate, begin);
+  }
+
+private:
+  /// Handle the next character of input.
+  result_type consume(request& req, char input);
+
+  /// Check if a byte is an HTTP character.
+  static bool is_char(int c);
+
+  /// Check if a byte is an HTTP control character.
+  static bool is_ctl(int c);
+
+  /// Check if a byte is defined as an HTTP tspecial character.
+  static bool is_tspecial(int c);
+
+  /// Check if a byte is a digit.
+  static bool is_digit(int c);
+
+  /// The current state of the parser.
+  enum state
+  {
+    method_start,
+    method,
+    uri,
+    http_version_h,
+    http_version_t_1,
+    http_version_t_2,
+    http_version_p,
+    http_version_slash,
+    http_version_major_start,
+    http_version_major,
+    http_version_minor_start,
+    http_version_minor,
+    expecting_newline_1,
+    header_line_start,
+    header_lws,
+    header_name,
+    space_before_header_value,
+    header_value,
+    expecting_newline_2,
+    expecting_newline_3
+  } state_;
+};
+
+} // namespace server
+} // namespace http
+
+#endif // HTTP_REQUEST_PARSER_HPP
diff --git a/link/modules/asio-standalone/asio/src/examples/cpp11/http/server/server.hpp b/link/modules/asio-standalone/asio/src/examples/cpp11/http/server/server.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/src/examples/cpp11/http/server/server.hpp
@@ -0,0 +1,64 @@
+//
+// server.hpp
+// ~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 HTTP_SERVER_HPP
+#define HTTP_SERVER_HPP
+
+#include <asio.hpp>
+#include <string>
+#include "connection.hpp"
+#include "connection_manager.hpp"
+#include "request_handler.hpp"
+
+namespace http {
+namespace server {
+
+/// The top-level class of the HTTP server.
+class server
+{
+public:
+  server(const server&) = delete;
+  server& operator=(const server&) = delete;
+
+  /// Construct the server to listen on the specified TCP address and port, and
+  /// serve up files from the given directory.
+  explicit server(const std::string& address, const std::string& port,
+      const std::string& doc_root);
+
+  /// Run the server's io_context loop.
+  void run();
+
+private:
+  /// Perform an asynchronous accept operation.
+  void do_accept();
+
+  /// Wait for a request to stop the server.
+  void do_await_stop();
+
+  /// The io_context used to perform asynchronous operations.
+  asio::io_context io_context_;
+
+  /// The signal_set is used to register for process termination notifications.
+  asio::signal_set signals_;
+
+  /// Acceptor used to listen for incoming connections.
+  asio::ip::tcp::acceptor acceptor_;
+
+  /// The connection manager which owns all live connections.
+  connection_manager connection_manager_;
+
+  /// The handler for all incoming requests.
+  request_handler request_handler_;
+};
+
+} // namespace server
+} // namespace http
+
+#endif // HTTP_SERVER_HPP
diff --git a/link/modules/asio-standalone/asio/src/examples/cpp11/socks4/socks4.hpp b/link/modules/asio-standalone/asio/src/examples/cpp11/socks4/socks4.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/src/examples/cpp11/socks4/socks4.hpp
@@ -0,0 +1,143 @@
+//
+// socks4.hpp
+// ~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 SOCKS4_HPP
+#define SOCKS4_HPP
+
+#include <array>
+#include <string>
+#include <asio/buffer.hpp>
+#include <asio/ip/tcp.hpp>
+
+namespace socks4 {
+
+const unsigned char version = 0x04;
+
+class request
+{
+public:
+  enum command_type
+  {
+    connect = 0x01,
+    bind = 0x02
+  };
+
+  request(command_type cmd, const asio::ip::tcp::endpoint& endpoint,
+      const std::string& user_id)
+    : version_(version),
+      command_(cmd),
+      user_id_(user_id),
+      null_byte_(0)
+  {
+    // Only IPv4 is supported by the SOCKS 4 protocol.
+    if (endpoint.protocol() != asio::ip::tcp::v4())
+    {
+      throw asio::system_error(
+          asio::error::address_family_not_supported);
+    }
+
+    // Convert port number to network byte order.
+    unsigned short port = endpoint.port();
+    port_high_byte_ = (port >> 8) & 0xff;
+    port_low_byte_ = port & 0xff;
+
+    // Save IP address in network byte order.
+    address_ = endpoint.address().to_v4().to_bytes();
+  }
+
+  std::array<asio::const_buffer, 7> buffers() const
+  {
+    return
+    {
+      {
+        asio::buffer(&version_, 1),
+        asio::buffer(&command_, 1),
+        asio::buffer(&port_high_byte_, 1),
+        asio::buffer(&port_low_byte_, 1),
+        asio::buffer(address_),
+        asio::buffer(user_id_),
+        asio::buffer(&null_byte_, 1)
+      }
+    };
+  }
+
+private:
+  unsigned char version_;
+  unsigned char command_;
+  unsigned char port_high_byte_;
+  unsigned char port_low_byte_;
+  asio::ip::address_v4::bytes_type address_;
+  std::string user_id_;
+  unsigned char null_byte_;
+};
+
+class reply
+{
+public:
+  enum status_type
+  {
+    request_granted = 0x5a,
+    request_failed = 0x5b,
+    request_failed_no_identd = 0x5c,
+    request_failed_bad_user_id = 0x5d
+  };
+
+  reply()
+    : null_byte_(0),
+      status_()
+  {
+  }
+
+  std::array<asio::mutable_buffer, 5> buffers()
+  {
+    return
+    {
+      {
+        asio::buffer(&null_byte_, 1),
+        asio::buffer(&status_, 1),
+        asio::buffer(&port_high_byte_, 1),
+        asio::buffer(&port_low_byte_, 1),
+        asio::buffer(address_)
+      }
+    };
+  }
+
+  bool success() const
+  {
+    return null_byte_ == 0 && status_ == request_granted;
+  }
+
+  unsigned char status() const
+  {
+    return status_;
+  }
+
+  asio::ip::tcp::endpoint endpoint() const
+  {
+    unsigned short port = port_high_byte_;
+    port = (port << 8) & 0xff00;
+    port = port | port_low_byte_;
+
+    asio::ip::address_v4 address(address_);
+
+    return asio::ip::tcp::endpoint(address, port);
+  }
+
+private:
+  unsigned char null_byte_;
+  unsigned char status_;
+  unsigned char port_high_byte_;
+  unsigned char port_low_byte_;
+  asio::ip::address_v4::bytes_type address_;
+};
+
+} // namespace socks4
+
+#endif // SOCKS4_HPP
diff --git a/link/modules/asio-standalone/asio/src/tests/latency/allocator.hpp b/link/modules/asio-standalone/asio/src/tests/latency/allocator.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/src/tests/latency/allocator.hpp
@@ -0,0 +1,52 @@
+//
+// allocator.hpp
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ALLOCATOR_HPP
+#define ALLOCATOR_HPP
+
+#include <boost/aligned_storage.hpp>
+
+// Represents a single connection from a client.
+class allocator
+{
+public:
+  allocator()
+    : in_use_(false)
+  {
+  }
+
+  void* allocate(std::size_t n)
+  {
+    if (in_use_ || n >= 1024)
+      return ::operator new(n);
+    in_use_ = true;
+    return static_cast<void*>(&space_);
+  }
+
+  void deallocate(void* p)
+  {
+    if (p != static_cast<void*>(&space_))
+      ::operator delete(p);
+    else
+      in_use_ = false;
+  }
+
+private:
+  allocator(const allocator&);
+  allocator& operator=(const allocator&);
+
+  // Whether the reusable memory space is currently in use.
+  bool in_use_;
+
+  // The reusable memory space made available by the allocator.
+  boost::aligned_storage<1024>::type space_;
+};
+
+#endif // ALLOCATOR_HPP
diff --git a/link/modules/asio-standalone/asio/src/tests/latency/high_res_clock.hpp b/link/modules/asio-standalone/asio/src/tests/latency/high_res_clock.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/src/tests/latency/high_res_clock.hpp
@@ -0,0 +1,53 @@
+//
+// high_res_clock.hpp
+// ~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 HIGH_RES_CLOCK_HPP
+#define HIGH_RES_CLOCK_HPP
+
+#include <boost/config.hpp>
+#include <boost/cstdint.hpp>
+
+#if defined(ASIO_WINDOWS)
+
+inline boost::uint64_t high_res_clock()
+{
+  LARGE_INTEGER i;
+  QueryPerformanceCounter(&i);
+  return i.QuadPart;
+}
+
+#elif defined(__GNUC__) && defined(__x86_64__)
+
+inline boost::uint64_t high_res_clock()
+{
+  unsigned long low, high;
+  __asm__ __volatile__("rdtsc" : "=a" (low), "=d" (high));
+  return (((boost::uint64_t)high) << 32) | low;
+}
+
+#else
+
+#include <boost/date_time/posix_time/posix_time_types.hpp>
+
+inline boost::uint64_t high_res_clock()
+{
+  boost::posix_time::ptime now =
+    boost::posix_time::microsec_clock::universal_time();
+
+  boost::posix_time::ptime epoch(
+      boost::gregorian::date(1970, 1, 1),
+      boost::posix_time::seconds(0));
+
+  return (now - epoch).total_microseconds();
+}
+
+#endif
+
+#endif // HIGH_RES_CLOCK_HPP
diff --git a/link/modules/asio-standalone/asio/src/tests/performance/handler_allocator.hpp b/link/modules/asio-standalone/asio/src/tests/performance/handler_allocator.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/src/tests/performance/handler_allocator.hpp
@@ -0,0 +1,112 @@
+//
+// handler_allocator.cpp
+// ~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 HANDLER_ALLOCATOR_HPP
+#define HANDLER_ALLOCATOR_HPP
+
+#include "asio.hpp"
+#include <boost/aligned_storage.hpp>
+#include <boost/noncopyable.hpp>
+
+// Class to manage the memory to be used for handler-based custom allocation.
+// It contains a single block of memory which may be returned for allocation
+// requests. If the memory is in use when an allocation request is made, the
+// allocator delegates allocation to the global heap.
+class handler_allocator
+  : private boost::noncopyable
+{
+public:
+  handler_allocator()
+    : in_use_(false)
+  {
+  }
+
+  void* allocate(std::size_t size)
+  {
+    if (!in_use_ && size < storage_.size)
+    {
+      in_use_ = true;
+      return storage_.address();
+    }
+
+    return ::operator new(size);
+  }
+
+  void deallocate(void* pointer)
+  {
+    if (pointer == storage_.address())
+    {
+      in_use_ = false;
+    }
+    else
+    {
+      ::operator delete(pointer);
+    }
+  }
+
+private:
+  // Storage space used for handler-based custom memory allocation.
+  boost::aligned_storage<1024> storage_;
+
+  // Whether the handler-based custom allocation storage has been used.
+  bool in_use_;
+};
+
+// Wrapper class template for handler objects to allow handler memory
+// allocation to be customised. Calls to operator() are forwarded to the
+// encapsulated handler.
+template <typename Handler>
+class custom_alloc_handler
+{
+public:
+  custom_alloc_handler(handler_allocator& a, Handler h)
+    : allocator_(a),
+      handler_(h)
+  {
+  }
+
+  template <typename Arg1>
+  void operator()(Arg1 arg1)
+  {
+    handler_(arg1);
+  }
+
+  template <typename Arg1, typename Arg2>
+  void operator()(Arg1 arg1, Arg2 arg2)
+  {
+    handler_(arg1, arg2);
+  }
+
+  friend void* asio_handler_allocate(std::size_t size,
+      custom_alloc_handler<Handler>* this_handler)
+  {
+    return this_handler->allocator_.allocate(size);
+  }
+
+  friend void asio_handler_deallocate(void* pointer, std::size_t /*size*/,
+      custom_alloc_handler<Handler>* this_handler)
+  {
+    this_handler->allocator_.deallocate(pointer);
+  }
+
+private:
+  handler_allocator& allocator_;
+  Handler handler_;
+};
+
+// Helper function to wrap a handler object to add custom allocation.
+template <typename Handler>
+inline custom_alloc_handler<Handler> make_custom_alloc_handler(
+    handler_allocator& a, Handler h)
+{
+  return custom_alloc_handler<Handler>(a, h);
+}
+
+#endif // HANDLER_ALLOCATOR_HPP
diff --git a/link/modules/asio-standalone/asio/src/tests/unit/archetypes/async_ops.hpp b/link/modules/asio-standalone/asio/src/tests/unit/archetypes/async_ops.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/src/tests/unit/archetypes/async_ops.hpp
@@ -0,0 +1,415 @@
+//
+// async_ops.hpp
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ARCHETYPES_ASYNC_OPS_HPP
+#define ARCHETYPES_ASYNC_OPS_HPP
+
+#include <asio/associated_allocator.hpp>
+#include <asio/associated_executor.hpp>
+#include <asio/async_result.hpp>
+#include <asio/error.hpp>
+
+#if defined(ASIO_HAS_BOOST_BIND)
+# include <boost/bind/bind.hpp>
+#else // defined(ASIO_HAS_BOOST_BIND)
+# include <functional>
+#endif // defined(ASIO_HAS_BOOST_BIND)
+
+namespace archetypes {
+
+#if defined(ASIO_HAS_BOOST_BIND)
+namespace bindns = boost;
+#else // defined(ASIO_HAS_BOOST_BIND)
+namespace bindns = std;
+#endif // defined(ASIO_HAS_BOOST_BIND)
+
+template <typename CompletionToken>
+ASIO_INITFN_RESULT_TYPE(CompletionToken, void())
+async_op_0(ASIO_MOVE_ARG(CompletionToken) token)
+{
+  typedef typename asio::async_completion<CompletionToken,
+    void()>::completion_handler_type handler_type;
+
+  asio::async_completion<CompletionToken,
+    void()> completion(token);
+
+  typename asio::associated_allocator<handler_type>::type a
+    = asio::get_associated_allocator(completion.completion_handler);
+
+  typename asio::associated_executor<handler_type>::type ex
+    = asio::get_associated_executor(completion.completion_handler);
+
+  ex.post(ASIO_MOVE_CAST(handler_type)(completion.completion_handler), a);
+
+  return completion.result.get();
+}
+
+template <typename CompletionToken>
+ASIO_INITFN_RESULT_TYPE(CompletionToken, void(asio::error_code))
+async_op_ec_0(bool ok, ASIO_MOVE_ARG(CompletionToken) token)
+{
+  typedef typename asio::async_completion<CompletionToken,
+    void(asio::error_code)>::completion_handler_type handler_type;
+
+  asio::async_completion<CompletionToken,
+    void(asio::error_code)> completion(token);
+
+  typename asio::associated_allocator<handler_type>::type a
+    = asio::get_associated_allocator(completion.completion_handler);
+
+  typename asio::associated_executor<handler_type>::type ex
+    = asio::get_associated_executor(completion.completion_handler);
+
+  if (ok)
+  {
+    ex.post(
+        bindns::bind(
+          ASIO_MOVE_CAST(handler_type)(completion.completion_handler),
+          asio::error_code()), a);
+  }
+  else
+  {
+    ex.post(
+        bindns::bind(
+          ASIO_MOVE_CAST(handler_type)(completion.completion_handler),
+          asio::error_code(asio::error::operation_aborted)), a);
+  }
+
+  return completion.result.get();
+}
+
+template <typename CompletionToken>
+ASIO_INITFN_RESULT_TYPE(CompletionToken, void(std::exception_ptr))
+async_op_ex_0(bool ok, ASIO_MOVE_ARG(CompletionToken) token)
+{
+  typedef typename asio::async_completion<CompletionToken,
+    void(std::exception_ptr)>::completion_handler_type handler_type;
+
+  asio::async_completion<CompletionToken,
+    void(std::exception_ptr)> completion(token);
+
+  typename asio::associated_allocator<handler_type>::type a
+    = asio::get_associated_allocator(completion.completion_handler);
+
+  typename asio::associated_executor<handler_type>::type ex
+    = asio::get_associated_executor(completion.completion_handler);
+
+  if (ok)
+  {
+    ex.post(
+        bindns::bind(
+          ASIO_MOVE_CAST(handler_type)(completion.completion_handler),
+          std::exception_ptr()), a);
+  }
+  else
+  {
+    ex.post(
+        bindns::bind(
+          ASIO_MOVE_CAST(handler_type)(completion.completion_handler),
+          std::make_exception_ptr(std::runtime_error("blah"))), a);
+  }
+
+  return completion.result.get();
+}
+
+template <typename CompletionToken>
+ASIO_INITFN_RESULT_TYPE(CompletionToken, void(int))
+async_op_1(ASIO_MOVE_ARG(CompletionToken) token)
+{
+  typedef typename asio::async_completion<CompletionToken,
+    void(int)>::completion_handler_type handler_type;
+
+  asio::async_completion<CompletionToken,
+    void(int)> completion(token);
+
+  typename asio::associated_allocator<handler_type>::type a
+    = asio::get_associated_allocator(completion.completion_handler);
+
+  typename asio::associated_executor<handler_type>::type ex
+    = asio::get_associated_executor(completion.completion_handler);
+
+  ex.post(
+      bindns::bind(
+        ASIO_MOVE_CAST(handler_type)(completion.completion_handler),
+        42), a);
+
+  return completion.result.get();
+}
+
+template <typename CompletionToken>
+ASIO_INITFN_RESULT_TYPE(CompletionToken,
+    void(asio::error_code, int))
+async_op_ec_1(bool ok, ASIO_MOVE_ARG(CompletionToken) token)
+{
+  typedef typename asio::async_completion<CompletionToken,
+    void(asio::error_code, int)>::completion_handler_type
+      handler_type;
+
+  asio::async_completion<CompletionToken,
+    void(asio::error_code, int)> completion(token);
+
+  typename asio::associated_allocator<handler_type>::type a
+    = asio::get_associated_allocator(completion.completion_handler);
+
+  typename asio::associated_executor<handler_type>::type ex
+    = asio::get_associated_executor(completion.completion_handler);
+
+  if (ok)
+  {
+    ex.post(
+        bindns::bind(
+          ASIO_MOVE_CAST(handler_type)(completion.completion_handler),
+          asio::error_code(), 42), a);
+  }
+  else
+  {
+    ex.post(
+        bindns::bind(
+          ASIO_MOVE_CAST(handler_type)(completion.completion_handler),
+          asio::error_code(asio::error::operation_aborted),
+          0), a);
+  }
+
+  return completion.result.get();
+}
+
+template <typename CompletionToken>
+ASIO_INITFN_RESULT_TYPE(CompletionToken, void(std::exception_ptr, int))
+async_op_ex_1(bool ok, ASIO_MOVE_ARG(CompletionToken) token)
+{
+  typedef typename asio::async_completion<CompletionToken,
+    void(std::exception_ptr, int)>::completion_handler_type
+      handler_type;
+
+  asio::async_completion<CompletionToken,
+    void(std::exception_ptr, int)> completion(token);
+
+  typename asio::associated_allocator<handler_type>::type a
+    = asio::get_associated_allocator(completion.completion_handler);
+
+  typename asio::associated_executor<handler_type>::type ex
+    = asio::get_associated_executor(completion.completion_handler);
+
+  if (ok)
+  {
+    ex.post(
+        bindns::bind(
+          ASIO_MOVE_CAST(handler_type)(completion.completion_handler),
+          std::exception_ptr(), 42), a);
+  }
+  else
+  {
+    ex.post(
+        bindns::bind(
+          ASIO_MOVE_CAST(handler_type)(completion.completion_handler),
+          std::make_exception_ptr(std::runtime_error("blah")), 0), a);
+  }
+
+  return completion.result.get();
+}
+
+template <typename CompletionToken>
+ASIO_INITFN_RESULT_TYPE(CompletionToken, void(int, double))
+async_op_2(ASIO_MOVE_ARG(CompletionToken) token)
+{
+  typedef typename asio::async_completion<CompletionToken,
+    void(int, double)>::completion_handler_type handler_type;
+
+  asio::async_completion<CompletionToken,
+    void(int, double)> completion(token);
+
+  typename asio::associated_allocator<handler_type>::type a
+    = asio::get_associated_allocator(completion.completion_handler);
+
+  typename asio::associated_executor<handler_type>::type ex
+    = asio::get_associated_executor(completion.completion_handler);
+
+  ex.post(
+      bindns::bind(
+        ASIO_MOVE_CAST(handler_type)(completion.completion_handler),
+        42, 2.0), a);
+
+  return completion.result.get();
+}
+
+template <typename CompletionToken>
+ASIO_INITFN_RESULT_TYPE(CompletionToken,
+    void(asio::error_code, int, double))
+async_op_ec_2(bool ok, ASIO_MOVE_ARG(CompletionToken) token)
+{
+  typedef typename asio::async_completion<CompletionToken,
+    void(asio::error_code, int, double)>::completion_handler_type
+      handler_type;
+
+  asio::async_completion<CompletionToken,
+    void(asio::error_code, int, double)> completion(token);
+
+  typename asio::associated_allocator<handler_type>::type a
+    = asio::get_associated_allocator(completion.completion_handler);
+
+  typename asio::associated_executor<handler_type>::type ex
+    = asio::get_associated_executor(completion.completion_handler);
+
+  if (ok)
+  {
+    ex.post(
+        bindns::bind(
+          ASIO_MOVE_CAST(handler_type)(completion.completion_handler),
+          asio::error_code(), 42, 2.0), a);
+  }
+  else
+  {
+    ex.post(
+        bindns::bind(
+          ASIO_MOVE_CAST(handler_type)(completion.completion_handler),
+          asio::error_code(asio::error::operation_aborted),
+          0, 0.0), a);
+  }
+
+  return completion.result.get();
+}
+
+template <typename CompletionToken>
+ASIO_INITFN_RESULT_TYPE(CompletionToken,
+    void(std::exception_ptr, int, double))
+async_op_ex_2(bool ok, ASIO_MOVE_ARG(CompletionToken) token)
+{
+  typedef typename asio::async_completion<CompletionToken,
+    void(std::exception_ptr, int, double)>::completion_handler_type
+      handler_type;
+
+  asio::async_completion<CompletionToken,
+    void(std::exception_ptr, int, double)> completion(token);
+
+  typename asio::associated_allocator<handler_type>::type a
+    = asio::get_associated_allocator(completion.completion_handler);
+
+  typename asio::associated_executor<handler_type>::type ex
+    = asio::get_associated_executor(completion.completion_handler);
+
+  if (ok)
+  {
+    ex.post(
+        bindns::bind(
+          ASIO_MOVE_CAST(handler_type)(completion.completion_handler),
+          std::exception_ptr(), 42, 2.0), a);
+  }
+  else
+  {
+    ex.post(
+        bindns::bind(
+          ASIO_MOVE_CAST(handler_type)(completion.completion_handler),
+          std::make_exception_ptr(std::runtime_error("blah")), 0, 0.0), a);
+  }
+
+  return completion.result.get();
+}
+
+template <typename CompletionToken>
+ASIO_INITFN_RESULT_TYPE(CompletionToken, void(int, double, char))
+async_op_3(ASIO_MOVE_ARG(CompletionToken) token)
+{
+  typedef typename asio::async_completion<CompletionToken,
+    void(int, double, char)>::completion_handler_type handler_type;
+
+  asio::async_completion<CompletionToken,
+    void(int, double, char)> completion(token);
+
+  typename asio::associated_allocator<handler_type>::type a
+    = asio::get_associated_allocator(completion.completion_handler);
+
+  typename asio::associated_executor<handler_type>::type ex
+    = asio::get_associated_executor(completion.completion_handler);
+
+  ex.post(
+      bindns::bind(
+        ASIO_MOVE_CAST(handler_type)(completion.completion_handler),
+        42, 2.0, 'a'), a);
+
+  return completion.result.get();
+}
+
+template <typename CompletionToken>
+ASIO_INITFN_RESULT_TYPE(CompletionToken,
+    void(asio::error_code, int, double, char))
+async_op_ec_3(bool ok, ASIO_MOVE_ARG(CompletionToken) token)
+{
+  typedef typename asio::async_completion<CompletionToken,
+    void(asio::error_code, int, double, char)>::completion_handler_type
+      handler_type;
+
+  asio::async_completion<CompletionToken,
+    void(asio::error_code, int, double, char)> completion(token);
+
+  typename asio::associated_allocator<handler_type>::type a
+    = asio::get_associated_allocator(completion.completion_handler);
+
+  typename asio::associated_executor<handler_type>::type ex
+    = asio::get_associated_executor(completion.completion_handler);
+
+  if (ok)
+  {
+    ex.post(
+        bindns::bind(
+          ASIO_MOVE_CAST(handler_type)(completion.completion_handler),
+          asio::error_code(), 42, 2.0, 'a'), a);
+  }
+  else
+  {
+    ex.post(
+        bindns::bind(
+          ASIO_MOVE_CAST(handler_type)(completion.completion_handler),
+          asio::error_code(asio::error::operation_aborted),
+          0, 0.0, 'z'), a);
+  }
+
+  return completion.result.get();
+}
+
+template <typename CompletionToken>
+ASIO_INITFN_RESULT_TYPE(CompletionToken,
+    void(std::exception_ptr, int, double, char))
+async_op_ex_3(bool ok, ASIO_MOVE_ARG(CompletionToken) token)
+{
+  typedef typename asio::async_completion<CompletionToken,
+    void(std::exception_ptr, int, double, char)>::completion_handler_type
+      handler_type;
+
+  asio::async_completion<CompletionToken,
+    void(std::exception_ptr, int, double, char)> completion(token);
+
+  typename asio::associated_allocator<handler_type>::type a
+    = asio::get_associated_allocator(completion.completion_handler);
+
+  typename asio::associated_executor<handler_type>::type ex
+    = asio::get_associated_executor(completion.completion_handler);
+
+  if (ok)
+  {
+    ex.post(
+        bindns::bind(
+          ASIO_MOVE_CAST(handler_type)(completion.completion_handler),
+          std::exception_ptr(), 42, 2.0, 'a'), a);
+  }
+  else
+  {
+    ex.post(
+        bindns::bind(
+          ASIO_MOVE_CAST(handler_type)(completion.completion_handler),
+          std::make_exception_ptr(std::runtime_error("blah")),
+          0, 0.0, 'z'), a);
+  }
+
+  return completion.result.get();
+}
+
+} // namespace archetypes
+
+#endif // ARCHETYPES_ASYNC_OPS_HPP
diff --git a/link/modules/asio-standalone/asio/src/tests/unit/archetypes/async_result.hpp b/link/modules/asio-standalone/asio/src/tests/unit/archetypes/async_result.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/src/tests/unit/archetypes/async_result.hpp
@@ -0,0 +1,94 @@
+//
+// async_result.hpp
+// ~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ARCHETYPES_ASYNC_RESULT_HPP
+#define ARCHETYPES_ASYNC_RESULT_HPP
+
+#include <asio/async_result.hpp>
+
+namespace archetypes {
+
+struct lazy_handler
+{
+};
+
+template <typename Signature>
+struct concrete_handler;
+
+template <typename R, typename Arg1>
+struct concrete_handler<R(Arg1)>
+{
+  concrete_handler(lazy_handler)
+  {
+  }
+
+  void operator()(typename asio::decay<Arg1>::type)
+  {
+  }
+
+#if defined(ASIO_HAS_MOVE)
+  concrete_handler(concrete_handler&&) {}
+private:
+  concrete_handler(const concrete_handler&);
+#endif // defined(ASIO_HAS_MOVE)
+};
+
+template <typename R, typename Arg1, typename Arg2>
+struct concrete_handler<R(Arg1, Arg2)>
+{
+  concrete_handler(lazy_handler)
+  {
+  }
+
+  void operator()(typename asio::decay<Arg1>::type, typename asio::decay<Arg2>::type)
+  {
+  }
+
+#if defined(ASIO_HAS_MOVE)
+  concrete_handler(concrete_handler&&) {}
+private:
+  concrete_handler(const concrete_handler&);
+#endif // defined(ASIO_HAS_MOVE)
+};
+
+} // namespace archetypes
+
+namespace asio {
+
+template <typename Signature>
+class async_result<archetypes::lazy_handler, Signature>
+{
+public:
+  // The concrete completion handler type.
+  typedef archetypes::concrete_handler<Signature> completion_handler_type;
+
+  // The return type of the initiating function.
+  typedef int return_type;
+
+  // Construct an async_result from a given handler.
+  explicit async_result(completion_handler_type&)
+  {
+  }
+
+  // Obtain the value to be returned from the initiating function.
+  return_type get()
+  {
+    return 42;
+  }
+
+private:
+  // Disallow copying and assignment.
+  async_result(const async_result&) ASIO_DELETED;
+  async_result& operator=(const async_result&) ASIO_DELETED;
+};
+
+} // namespace asio
+
+#endif // ARCHETYPES_ASYNC_RESULT_HPP
diff --git a/link/modules/asio-standalone/asio/src/tests/unit/archetypes/gettable_socket_option.hpp b/link/modules/asio-standalone/asio/src/tests/unit/archetypes/gettable_socket_option.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/src/tests/unit/archetypes/gettable_socket_option.hpp
@@ -0,0 +1,54 @@
+//
+// gettable_socket_option.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ARCHETYPES_GETTABLE_SOCKET_OPTION_HPP
+#define ARCHETYPES_GETTABLE_SOCKET_OPTION_HPP
+
+#include <cstddef>
+
+namespace archetypes {
+
+template <typename PointerType>
+class gettable_socket_option
+{
+public:
+  template <typename Protocol>
+  int level(const Protocol&) const
+  {
+    return 0;
+  }
+
+  template <typename Protocol>
+  int name(const Protocol&) const
+  {
+    return 0;
+  }
+
+  template <typename Protocol>
+  PointerType* data(const Protocol&)
+  {
+    return 0;
+  }
+
+  template <typename Protocol>
+  std::size_t size(const Protocol&) const
+  {
+    return 0;
+  }
+
+  template <typename Protocol>
+  void resize(const Protocol&, std::size_t)
+  {
+  }
+};
+
+} // namespace archetypes
+
+#endif // ARCHETYPES_GETTABLE_SOCKET_OPTION_HPP
diff --git a/link/modules/asio-standalone/asio/src/tests/unit/archetypes/io_control_command.hpp b/link/modules/asio-standalone/asio/src/tests/unit/archetypes/io_control_command.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/src/tests/unit/archetypes/io_control_command.hpp
@@ -0,0 +1,32 @@
+//
+// io_control_command.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ARCHETYPES_IO_CONTROL_COMMAND_HPP
+#define ARCHETYPES_IO_CONTROL_COMMAND_HPP
+
+namespace archetypes {
+
+class io_control_command
+{
+public:
+  int name() const
+  {
+    return 0;
+  }
+
+  void* data()
+  {
+    return 0;
+  }
+};
+
+} // namespace archetypes
+
+#endif // ARCHETYPES_IO_CONTROL_COMMAND_HPP
diff --git a/link/modules/asio-standalone/asio/src/tests/unit/archetypes/settable_socket_option.hpp b/link/modules/asio-standalone/asio/src/tests/unit/archetypes/settable_socket_option.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/src/tests/unit/archetypes/settable_socket_option.hpp
@@ -0,0 +1,49 @@
+//
+// settable_socket_option.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 ARCHETYPES_SETTABLE_SOCKET_OPTION_HPP
+#define ARCHETYPES_SETTABLE_SOCKET_OPTION_HPP
+
+#include <cstddef>
+
+namespace archetypes {
+
+template <typename PointerType>
+class settable_socket_option
+{
+public:
+  template <typename Protocol>
+  int level(const Protocol&) const
+  {
+    return 0;
+  }
+
+  template <typename Protocol>
+  int name(const Protocol&) const
+  {
+    return 0;
+  }
+
+  template <typename Protocol>
+  const PointerType* data(const Protocol&) const
+  {
+    return 0;
+  }
+
+  template <typename Protocol>
+  std::size_t size(const Protocol&) const
+  {
+    return 0;
+  }
+};
+
+} // namespace archetypes
+
+#endif // ARCHETYPES_SETTABLE_SOCKET_OPTION_HPP
diff --git a/link/modules/asio-standalone/asio/src/tests/unit/unit_test.hpp b/link/modules/asio-standalone/asio/src/tests/unit/unit_test.hpp
new file mode 100644
--- /dev/null
+++ b/link/modules/asio-standalone/asio/src/tests/unit/unit_test.hpp
@@ -0,0 +1,190 @@
+//
+// unit_test.hpp
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2020 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 UNIT_TEST_HPP
+#define UNIT_TEST_HPP
+
+#include "asio/detail/config.hpp"
+#include <iostream>
+#include "asio/detail/atomic_count.hpp"
+
+#if defined(__sun)
+# include <stdlib.h> // Needed for lrand48.
+#endif // defined(__sun)
+
+#if defined(__BORLANDC__) && !defined(__clang__)
+
+// Prevent use of intrinsic for strcmp.
+# include <cstring>
+# undef strcmp
+ 
+// Suppress error about condition always being true.
+# pragma option -w-ccc
+
+#endif // defined(__BORLANDC__) && !defined(__clang__)
+
+#if defined(ASIO_MSVC)
+# pragma warning (disable:4127)
+# pragma warning (push)
+# pragma warning (disable:4244)
+# pragma warning (disable:4702)
+#endif // defined(ASIO_MSVC)
+
+#if !defined(ASIO_TEST_IOSTREAM)
+# define ASIO_TEST_IOSTREAM std::cerr
+#endif // !defined(ASIO_TEST_IOSTREAM)
+
+namespace asio {
+namespace detail {
+
+inline const char*& test_name()
+{
+  static const char* name = 0;
+  return name;
+}
+
+inline atomic_count& test_errors()
+{
+  static atomic_count errors(0);
+  return errors;
+}
+
+inline void begin_test_suite(const char* name)
+{
+  asio::detail::test_name();
+  asio::detail::test_errors();
+  ASIO_TEST_IOSTREAM << name << " test suite begins" << std::endl;
+}
+
+inline int end_test_suite(const char* name)
+{
+  ASIO_TEST_IOSTREAM << name << " test suite ends" << std::endl;
+  ASIO_TEST_IOSTREAM << "\n*** ";
+  long errors = asio::detail::test_errors();
+  if (errors == 0)
+    ASIO_TEST_IOSTREAM << "No errors detected.";
+  else if (errors == 1)
+    ASIO_TEST_IOSTREAM << "1 error detected.";
+  else
+    ASIO_TEST_IOSTREAM << errors << " errors detected." << std::endl;
+  ASIO_TEST_IOSTREAM << std::endl;
+  return errors == 0 ? 0 : 1;
+}
+
+template <void (*Test)()>
+inline void run_test(const char* name)
+{
+  test_name() = name;
+  long errors_before = asio::detail::test_errors();
+  Test();
+  if (test_errors() == errors_before)
+    ASIO_TEST_IOSTREAM << name << " passed" << std::endl;
+  else
+    ASIO_TEST_IOSTREAM << name << " failed" << std::endl;
+}
+
+template <void (*)()>
+inline void compile_test(const char* name)
+{
+  ASIO_TEST_IOSTREAM << name << " passed" << std::endl;
+}
+
+#if defined(ASIO_NO_EXCEPTIONS)
+
+template <typename T>
+void throw_exception(const T& t)
+{
+  ASIO_TEST_IOSTREAM << "Exception: " << t.what() << std::endl;
+  std::abort();
+}
+
+#endif // defined(ASIO_NO_EXCEPTIONS)
+
+} // namespace detail
+} // namespace asio
+
+#define ASIO_CHECK(expr) \
+  do { if (!(expr)) { \
+    ASIO_TEST_IOSTREAM << __FILE__ << "(" << __LINE__ << "): " \
+      << asio::detail::test_name() << ": " \
+      << "check '" << #expr << "' failed" << std::endl; \
+    ++asio::detail::test_errors(); \
+  } } while (0)
+
+#define ASIO_CHECK_MESSAGE(expr, msg) \
+  do { if (!(expr)) { \
+    ASIO_TEST_IOSTREAM << __FILE__ << "(" << __LINE__ << "): " \
+      << asio::detail::test_name() << ": " \
+      << msg << std::endl; \
+    ++asio::detail::test_errors(); \
+  } } while (0)
+
+#define ASIO_WARN_MESSAGE(expr, msg) \
+  do { if (!(expr)) { \
+    ASIO_TEST_IOSTREAM << __FILE__ << "(" << __LINE__ << "): " \
+      << asio::detail::test_name() << ": " \
+      << msg << std::endl; \
+  } } while (0)
+
+#define ASIO_ERROR(msg) \
+  do { \
+    ASIO_TEST_IOSTREAM << __FILE__ << "(" << __LINE__ << "): " \
+      << asio::detail::test_name() << ": " \
+      << msg << std::endl; \
+    ++asio::detail::test_errors(); \
+  } while (0)
+
+#define ASIO_TEST_SUITE(name, tests) \
+  int main() \
+  { \
+    asio::detail::begin_test_suite(name); \
+    tests \
+    return asio::detail::end_test_suite(name); \
+  }
+
+#define ASIO_TEST_CASE(test) \
+  asio::detail::run_test<&test>(#test);
+
+#define ASIO_TEST_CASE2(test1, test2) \
+  asio::detail::run_test<&test1, test2>(#test1 "," #test2);
+
+#define ASIO_TEST_CASE3(test1, test2, test3) \
+  asio::detail::run_test<&test1, test2, test3>( \
+    #test1 "," #test2 "," #test3);
+
+#define ASIO_TEST_CASE4(test1, test2, test3, test4) \
+  asio::detail::run_test<&test1, test2, test3, test4>( \
+    #test1 "," #test2 "," #test3 "," #test4);
+
+#define ASIO_TEST_CASE5(test1, test2, test3, test4, test5) \
+  asio::detail::run_test<&test1, test2, test3, test4, test5>( \
+    #test1 "," #test2 "," #test3 "," #test4 "," #test5);
+
+#define ASIO_COMPILE_TEST_CASE(test) \
+  asio::detail::compile_test<&test>(#test);
+
+inline void null_test()
+{
+}
+
+#if defined(__GNUC__) && defined(_AIX)
+
+// AIX needs this symbol defined in asio, even if it doesn't do anything.
+int test_main(int, char**)
+{
+}
+
+#endif // defined(__GNUC__) && defined(_AIX)
+
+#if defined(ASIO_MSVC)
+# pragma warning (pop)
+#endif // defined(ASIO_MSVC)
+
+#endif // UNIT_TEST_HPP
diff --git a/link/third_party/catch/catch.hpp b/link/third_party/catch/catch.hpp
new file mode 100644
--- /dev/null
+++ b/link/third_party/catch/catch.hpp
@@ -0,0 +1,17959 @@
+/*
+ *  Catch v2.13.7
+ *  Generated: 2021-07-28 20:29:27.753164
+ *  ----------------------------------------------------------
+ *  This file has been merged from multiple headers. Please don't edit it directly
+ *  Copyright (c) 2021 Two Blue Cubes Ltd. All rights reserved.
+ *
+ *  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 TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED
+#define TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED
+// start catch.hpp
+
+
+#define CATCH_VERSION_MAJOR 2
+#define CATCH_VERSION_MINOR 13
+#define CATCH_VERSION_PATCH 7
+
+#ifdef __clang__
+#    pragma clang system_header
+#elif defined __GNUC__
+#    pragma GCC system_header
+#endif
+
+// start catch_suppress_warnings.h
+
+#ifdef __clang__
+#   ifdef __ICC // icpc defines the __clang__ macro
+#       pragma warning(push)
+#       pragma warning(disable: 161 1682)
+#   else // __ICC
+#       pragma clang diagnostic push
+#       pragma clang diagnostic ignored "-Wpadded"
+#       pragma clang diagnostic ignored "-Wswitch-enum"
+#       pragma clang diagnostic ignored "-Wcovered-switch-default"
+#    endif
+#elif defined __GNUC__
+     // Because REQUIREs trigger GCC's -Wparentheses, and because still
+     // supported version of g++ have only buggy support for _Pragmas,
+     // Wparentheses have to be suppressed globally.
+#    pragma GCC diagnostic ignored "-Wparentheses" // See #674 for details
+
+#    pragma GCC diagnostic push
+#    pragma GCC diagnostic ignored "-Wunused-variable"
+#    pragma GCC diagnostic ignored "-Wpadded"
+#endif
+// end catch_suppress_warnings.h
+#if defined(CATCH_CONFIG_MAIN) || defined(CATCH_CONFIG_RUNNER)
+#  define CATCH_IMPL
+#  define CATCH_CONFIG_ALL_PARTS
+#endif
+
+// In the impl file, we want to have access to all parts of the headers
+// Can also be used to sanely support PCHs
+#if defined(CATCH_CONFIG_ALL_PARTS)
+#  define CATCH_CONFIG_EXTERNAL_INTERFACES
+#  if defined(CATCH_CONFIG_DISABLE_MATCHERS)
+#    undef CATCH_CONFIG_DISABLE_MATCHERS
+#  endif
+#  if !defined(CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER)
+#    define CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER
+#  endif
+#endif
+
+#if !defined(CATCH_CONFIG_IMPL_ONLY)
+// start catch_platform.h
+
+// See e.g.:
+// https://opensource.apple.com/source/CarbonHeaders/CarbonHeaders-18.1/TargetConditionals.h.auto.html
+#ifdef __APPLE__
+#  include <TargetConditionals.h>
+#  if (defined(TARGET_OS_OSX) && TARGET_OS_OSX == 1) || \
+      (defined(TARGET_OS_MAC) && TARGET_OS_MAC == 1)
+#    define CATCH_PLATFORM_MAC
+#  elif (defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE == 1)
+#    define CATCH_PLATFORM_IPHONE
+#  endif
+
+#elif defined(linux) || defined(__linux) || defined(__linux__)
+#  define CATCH_PLATFORM_LINUX
+
+#elif defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) || defined(__MINGW32__)
+#  define CATCH_PLATFORM_WINDOWS
+#endif
+
+// end catch_platform.h
+
+#ifdef CATCH_IMPL
+#  ifndef CLARA_CONFIG_MAIN
+#    define CLARA_CONFIG_MAIN_NOT_DEFINED
+#    define CLARA_CONFIG_MAIN
+#  endif
+#endif
+
+// start catch_user_interfaces.h
+
+namespace Catch {
+    unsigned int rngSeed();
+}
+
+// end catch_user_interfaces.h
+// start catch_tag_alias_autoregistrar.h
+
+// start catch_common.h
+
+// start catch_compiler_capabilities.h
+
+// Detect a number of compiler features - by compiler
+// The following features are defined:
+//
+// CATCH_CONFIG_COUNTER : is the __COUNTER__ macro supported?
+// CATCH_CONFIG_WINDOWS_SEH : is Windows SEH supported?
+// CATCH_CONFIG_POSIX_SIGNALS : are POSIX signals supported?
+// CATCH_CONFIG_DISABLE_EXCEPTIONS : Are exceptions enabled?
+// ****************
+// Note to maintainers: if new toggles are added please document them
+// in configuration.md, too
+// ****************
+
+// In general each macro has a _NO_<feature name> form
+// (e.g. CATCH_CONFIG_NO_POSIX_SIGNALS) which disables the feature.
+// Many features, at point of detection, define an _INTERNAL_ macro, so they
+// can be combined, en-mass, with the _NO_ forms later.
+
+#ifdef __cplusplus
+
+#  if (__cplusplus >= 201402L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201402L)
+#    define CATCH_CPP14_OR_GREATER
+#  endif
+
+#  if (__cplusplus >= 201703L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L)
+#    define CATCH_CPP17_OR_GREATER
+#  endif
+
+#endif
+
+// Only GCC compiler should be used in this block, so other compilers trying to
+// mask themselves as GCC should be ignored.
+#if defined(__GNUC__) && !defined(__clang__) && !defined(__ICC) && !defined(__CUDACC__) && !defined(__LCC__)
+#    define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "GCC diagnostic push" )
+#    define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION  _Pragma( "GCC diagnostic pop" )
+
+#    define CATCH_INTERNAL_IGNORE_BUT_WARN(...) (void)__builtin_constant_p(__VA_ARGS__)
+
+#endif
+
+#if defined(__clang__)
+
+#    define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "clang diagnostic push" )
+#    define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION  _Pragma( "clang diagnostic pop" )
+
+// As of this writing, IBM XL's implementation of __builtin_constant_p has a bug
+// which results in calls to destructors being emitted for each temporary,
+// without a matching initialization. In practice, this can result in something
+// like `std::string::~string` being called on an uninitialized value.
+//
+// For example, this code will likely segfault under IBM XL:
+// ```
+// REQUIRE(std::string("12") + "34" == "1234")
+// ```
+//
+// Therefore, `CATCH_INTERNAL_IGNORE_BUT_WARN` is not implemented.
+#  if !defined(__ibmxl__) && !defined(__CUDACC__)
+#    define CATCH_INTERNAL_IGNORE_BUT_WARN(...) (void)__builtin_constant_p(__VA_ARGS__) /* NOLINT(cppcoreguidelines-pro-type-vararg, hicpp-vararg) */
+#  endif
+
+#    define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
+         _Pragma( "clang diagnostic ignored \"-Wexit-time-destructors\"" ) \
+         _Pragma( "clang diagnostic ignored \"-Wglobal-constructors\"")
+
+#    define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \
+         _Pragma( "clang diagnostic ignored \"-Wparentheses\"" )
+
+#    define CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS \
+         _Pragma( "clang diagnostic ignored \"-Wunused-variable\"" )
+
+#    define CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \
+         _Pragma( "clang diagnostic ignored \"-Wgnu-zero-variadic-macro-arguments\"" )
+
+#    define CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \
+         _Pragma( "clang diagnostic ignored \"-Wunused-template\"" )
+
+#endif // __clang__
+
+////////////////////////////////////////////////////////////////////////////////
+// Assume that non-Windows platforms support posix signals by default
+#if !defined(CATCH_PLATFORM_WINDOWS)
+    #define CATCH_INTERNAL_CONFIG_POSIX_SIGNALS
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+// We know some environments not to support full POSIX signals
+#if defined(__CYGWIN__) || defined(__QNX__) || defined(__EMSCRIPTEN__) || defined(__DJGPP__)
+    #define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS
+#endif
+
+#ifdef __OS400__
+#       define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS
+#       define CATCH_CONFIG_COLOUR_NONE
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+// Android somehow still does not support std::to_string
+#if defined(__ANDROID__)
+#    define CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING
+#    define CATCH_INTERNAL_CONFIG_ANDROID_LOGWRITE
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+// Not all Windows environments support SEH properly
+#if defined(__MINGW32__)
+#    define CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+// PS4
+#if defined(__ORBIS__)
+#    define CATCH_INTERNAL_CONFIG_NO_NEW_CAPTURE
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+// Cygwin
+#ifdef __CYGWIN__
+
+// Required for some versions of Cygwin to declare gettimeofday
+// see: http://stackoverflow.com/questions/36901803/gettimeofday-not-declared-in-this-scope-cygwin
+#   define _BSD_SOURCE
+// some versions of cygwin (most) do not support std::to_string. Use the libstd check.
+// https://gcc.gnu.org/onlinedocs/gcc-4.8.2/libstdc++/api/a01053_source.html line 2812-2813
+# if !((__cplusplus >= 201103L) && defined(_GLIBCXX_USE_C99) \
+           && !defined(_GLIBCXX_HAVE_BROKEN_VSWPRINTF))
+
+#    define CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING
+
+# endif
+#endif // __CYGWIN__
+
+////////////////////////////////////////////////////////////////////////////////
+// Visual C++
+#if defined(_MSC_VER)
+
+#  define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION __pragma( warning(push) )
+#  define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION  __pragma( warning(pop) )
+
+// Universal Windows platform does not support SEH
+// Or console colours (or console at all...)
+#  if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP)
+#    define CATCH_CONFIG_COLOUR_NONE
+#  else
+#    define CATCH_INTERNAL_CONFIG_WINDOWS_SEH
+#  endif
+
+// MSVC traditional preprocessor needs some workaround for __VA_ARGS__
+// _MSVC_TRADITIONAL == 0 means new conformant preprocessor
+// _MSVC_TRADITIONAL == 1 means old traditional non-conformant preprocessor
+#  if !defined(__clang__) // Handle Clang masquerading for msvc
+#    if !defined(_MSVC_TRADITIONAL) || (defined(_MSVC_TRADITIONAL) && _MSVC_TRADITIONAL)
+#      define CATCH_INTERNAL_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
+#    endif // MSVC_TRADITIONAL
+#  endif // __clang__
+
+#endif // _MSC_VER
+
+#if defined(_REENTRANT) || defined(_MSC_VER)
+// Enable async processing, as -pthread is specified or no additional linking is required
+# define CATCH_INTERNAL_CONFIG_USE_ASYNC
+#endif // _MSC_VER
+
+////////////////////////////////////////////////////////////////////////////////
+// Check if we are compiled with -fno-exceptions or equivalent
+#if defined(__EXCEPTIONS) || defined(__cpp_exceptions) || defined(_CPPUNWIND)
+#  define CATCH_INTERNAL_CONFIG_EXCEPTIONS_ENABLED
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+// DJGPP
+#ifdef __DJGPP__
+#  define CATCH_INTERNAL_CONFIG_NO_WCHAR
+#endif // __DJGPP__
+
+////////////////////////////////////////////////////////////////////////////////
+// Embarcadero C++Build
+#if defined(__BORLANDC__)
+    #define CATCH_INTERNAL_CONFIG_POLYFILL_ISNAN
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+
+// Use of __COUNTER__ is suppressed during code analysis in
+// CLion/AppCode 2017.2.x and former, because __COUNTER__ is not properly
+// handled by it.
+// Otherwise all supported compilers support COUNTER macro,
+// but user still might want to turn it off
+#if ( !defined(__JETBRAINS_IDE__) || __JETBRAINS_IDE__ >= 20170300L )
+    #define CATCH_INTERNAL_CONFIG_COUNTER
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+
+// RTX is a special version of Windows that is real time.
+// This means that it is detected as Windows, but does not provide
+// the same set of capabilities as real Windows does.
+#if defined(UNDER_RTSS) || defined(RTX64_BUILD)
+    #define CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH
+    #define CATCH_INTERNAL_CONFIG_NO_ASYNC
+    #define CATCH_CONFIG_COLOUR_NONE
+#endif
+
+#if !defined(_GLIBCXX_USE_C99_MATH_TR1)
+#define CATCH_INTERNAL_CONFIG_GLOBAL_NEXTAFTER
+#endif
+
+// Various stdlib support checks that require __has_include
+#if defined(__has_include)
+  // Check if string_view is available and usable
+  #if __has_include(<string_view>) && defined(CATCH_CPP17_OR_GREATER)
+  #    define CATCH_INTERNAL_CONFIG_CPP17_STRING_VIEW
+  #endif
+
+  // Check if optional is available and usable
+  #  if __has_include(<optional>) && defined(CATCH_CPP17_OR_GREATER)
+  #    define CATCH_INTERNAL_CONFIG_CPP17_OPTIONAL
+  #  endif // __has_include(<optional>) && defined(CATCH_CPP17_OR_GREATER)
+
+  // Check if byte is available and usable
+  #  if __has_include(<cstddef>) && defined(CATCH_CPP17_OR_GREATER)
+  #    include <cstddef>
+  #    if defined(__cpp_lib_byte) && (__cpp_lib_byte > 0)
+  #      define CATCH_INTERNAL_CONFIG_CPP17_BYTE
+  #    endif
+  #  endif // __has_include(<cstddef>) && defined(CATCH_CPP17_OR_GREATER)
+
+  // Check if variant is available and usable
+  #  if __has_include(<variant>) && defined(CATCH_CPP17_OR_GREATER)
+  #    if defined(__clang__) && (__clang_major__ < 8)
+         // work around clang bug with libstdc++ https://bugs.llvm.org/show_bug.cgi?id=31852
+         // fix should be in clang 8, workaround in libstdc++ 8.2
+  #      include <ciso646>
+  #      if defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9)
+  #        define CATCH_CONFIG_NO_CPP17_VARIANT
+  #      else
+  #        define CATCH_INTERNAL_CONFIG_CPP17_VARIANT
+  #      endif // defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9)
+  #    else
+  #      define CATCH_INTERNAL_CONFIG_CPP17_VARIANT
+  #    endif // defined(__clang__) && (__clang_major__ < 8)
+  #  endif // __has_include(<variant>) && defined(CATCH_CPP17_OR_GREATER)
+#endif // defined(__has_include)
+
+#if defined(CATCH_INTERNAL_CONFIG_COUNTER) && !defined(CATCH_CONFIG_NO_COUNTER) && !defined(CATCH_CONFIG_COUNTER)
+#   define CATCH_CONFIG_COUNTER
+#endif
+#if defined(CATCH_INTERNAL_CONFIG_WINDOWS_SEH) && !defined(CATCH_CONFIG_NO_WINDOWS_SEH) && !defined(CATCH_CONFIG_WINDOWS_SEH) && !defined(CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH)
+#   define CATCH_CONFIG_WINDOWS_SEH
+#endif
+// This is set by default, because we assume that unix compilers are posix-signal-compatible by default.
+#if defined(CATCH_INTERNAL_CONFIG_POSIX_SIGNALS) && !defined(CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_POSIX_SIGNALS)
+#   define CATCH_CONFIG_POSIX_SIGNALS
+#endif
+// This is set by default, because we assume that compilers with no wchar_t support are just rare exceptions.
+#if !defined(CATCH_INTERNAL_CONFIG_NO_WCHAR) && !defined(CATCH_CONFIG_NO_WCHAR) && !defined(CATCH_CONFIG_WCHAR)
+#   define CATCH_CONFIG_WCHAR
+#endif
+
+#if !defined(CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING) && !defined(CATCH_CONFIG_NO_CPP11_TO_STRING) && !defined(CATCH_CONFIG_CPP11_TO_STRING)
+#    define CATCH_CONFIG_CPP11_TO_STRING
+#endif
+
+#if defined(CATCH_INTERNAL_CONFIG_CPP17_OPTIONAL) && !defined(CATCH_CONFIG_NO_CPP17_OPTIONAL) && !defined(CATCH_CONFIG_CPP17_OPTIONAL)
+#  define CATCH_CONFIG_CPP17_OPTIONAL
+#endif
+
+#if defined(CATCH_INTERNAL_CONFIG_CPP17_STRING_VIEW) && !defined(CATCH_CONFIG_NO_CPP17_STRING_VIEW) && !defined(CATCH_CONFIG_CPP17_STRING_VIEW)
+#  define CATCH_CONFIG_CPP17_STRING_VIEW
+#endif
+
+#if defined(CATCH_INTERNAL_CONFIG_CPP17_VARIANT) && !defined(CATCH_CONFIG_NO_CPP17_VARIANT) && !defined(CATCH_CONFIG_CPP17_VARIANT)
+#  define CATCH_CONFIG_CPP17_VARIANT
+#endif
+
+#if defined(CATCH_INTERNAL_CONFIG_CPP17_BYTE) && !defined(CATCH_CONFIG_NO_CPP17_BYTE) && !defined(CATCH_CONFIG_CPP17_BYTE)
+#  define CATCH_CONFIG_CPP17_BYTE
+#endif
+
+#if defined(CATCH_CONFIG_EXPERIMENTAL_REDIRECT)
+#  define CATCH_INTERNAL_CONFIG_NEW_CAPTURE
+#endif
+
+#if defined(CATCH_INTERNAL_CONFIG_NEW_CAPTURE) && !defined(CATCH_INTERNAL_CONFIG_NO_NEW_CAPTURE) && !defined(CATCH_CONFIG_NO_NEW_CAPTURE) && !defined(CATCH_CONFIG_NEW_CAPTURE)
+#  define CATCH_CONFIG_NEW_CAPTURE
+#endif
+
+#if !defined(CATCH_INTERNAL_CONFIG_EXCEPTIONS_ENABLED) && !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
+#  define CATCH_CONFIG_DISABLE_EXCEPTIONS
+#endif
+
+#if defined(CATCH_INTERNAL_CONFIG_POLYFILL_ISNAN) && !defined(CATCH_CONFIG_NO_POLYFILL_ISNAN) && !defined(CATCH_CONFIG_POLYFILL_ISNAN)
+#  define CATCH_CONFIG_POLYFILL_ISNAN
+#endif
+
+#if defined(CATCH_INTERNAL_CONFIG_USE_ASYNC)  && !defined(CATCH_INTERNAL_CONFIG_NO_ASYNC) && !defined(CATCH_CONFIG_NO_USE_ASYNC) && !defined(CATCH_CONFIG_USE_ASYNC)
+#  define CATCH_CONFIG_USE_ASYNC
+#endif
+
+#if defined(CATCH_INTERNAL_CONFIG_ANDROID_LOGWRITE) && !defined(CATCH_CONFIG_NO_ANDROID_LOGWRITE) && !defined(CATCH_CONFIG_ANDROID_LOGWRITE)
+#  define CATCH_CONFIG_ANDROID_LOGWRITE
+#endif
+
+#if defined(CATCH_INTERNAL_CONFIG_GLOBAL_NEXTAFTER) && !defined(CATCH_CONFIG_NO_GLOBAL_NEXTAFTER) && !defined(CATCH_CONFIG_GLOBAL_NEXTAFTER)
+#  define CATCH_CONFIG_GLOBAL_NEXTAFTER
+#endif
+
+// Even if we do not think the compiler has that warning, we still have
+// to provide a macro that can be used by the code.
+#if !defined(CATCH_INTERNAL_START_WARNINGS_SUPPRESSION)
+#   define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION
+#endif
+#if !defined(CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION)
+#   define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
+#endif
+#if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS)
+#   define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS
+#endif
+#if !defined(CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS)
+#   define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS
+#endif
+#if !defined(CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS)
+#   define CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS
+#endif
+#if !defined(CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS)
+#   define CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS
+#endif
+
+// The goal of this macro is to avoid evaluation of the arguments, but
+// still have the compiler warn on problems inside...
+#if !defined(CATCH_INTERNAL_IGNORE_BUT_WARN)
+#   define CATCH_INTERNAL_IGNORE_BUT_WARN(...)
+#endif
+
+#if defined(__APPLE__) && defined(__apple_build_version__) && (__clang_major__ < 10)
+#   undef CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS
+#elif defined(__clang__) && (__clang_major__ < 5)
+#   undef CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS
+#endif
+
+#if !defined(CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS)
+#   define CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS
+#endif
+
+#if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
+#define CATCH_TRY if ((true))
+#define CATCH_CATCH_ALL if ((false))
+#define CATCH_CATCH_ANON(type) if ((false))
+#else
+#define CATCH_TRY try
+#define CATCH_CATCH_ALL catch (...)
+#define CATCH_CATCH_ANON(type) catch (type)
+#endif
+
+#if defined(CATCH_INTERNAL_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR) && !defined(CATCH_CONFIG_NO_TRADITIONAL_MSVC_PREPROCESSOR) && !defined(CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR)
+#define CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
+#endif
+
+// end catch_compiler_capabilities.h
+#define INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) name##line
+#define INTERNAL_CATCH_UNIQUE_NAME_LINE( name, line ) INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line )
+#ifdef CATCH_CONFIG_COUNTER
+#  define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __COUNTER__ )
+#else
+#  define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __LINE__ )
+#endif
+
+#include <iosfwd>
+#include <string>
+#include <cstdint>
+
+// We need a dummy global operator<< so we can bring it into Catch namespace later
+struct Catch_global_namespace_dummy {};
+std::ostream& operator<<(std::ostream&, Catch_global_namespace_dummy);
+
+namespace Catch {
+
+    struct CaseSensitive { enum Choice {
+        Yes,
+        No
+    }; };
+
+    class NonCopyable {
+        NonCopyable( NonCopyable const& )              = delete;
+        NonCopyable( NonCopyable && )                  = delete;
+        NonCopyable& operator = ( NonCopyable const& ) = delete;
+        NonCopyable& operator = ( NonCopyable && )     = delete;
+
+    protected:
+        NonCopyable();
+        virtual ~NonCopyable();
+    };
+
+    struct SourceLineInfo {
+
+        SourceLineInfo() = delete;
+        SourceLineInfo( char const* _file, std::size_t _line ) noexcept
+        :   file( _file ),
+            line( _line )
+        {}
+
+        SourceLineInfo( SourceLineInfo const& other )            = default;
+        SourceLineInfo& operator = ( SourceLineInfo const& )     = default;
+        SourceLineInfo( SourceLineInfo&& )              noexcept = default;
+        SourceLineInfo& operator = ( SourceLineInfo&& ) noexcept = default;
+
+        bool empty() const noexcept { return file[0] == '\0'; }
+        bool operator == ( SourceLineInfo const& other ) const noexcept;
+        bool operator < ( SourceLineInfo const& other ) const noexcept;
+
+        char const* file;
+        std::size_t line;
+    };
+
+    std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info );
+
+    // Bring in operator<< from global namespace into Catch namespace
+    // This is necessary because the overload of operator<< above makes
+    // lookup stop at namespace Catch
+    using ::operator<<;
+
+    // Use this in variadic streaming macros to allow
+    //    >> +StreamEndStop
+    // as well as
+    //    >> stuff +StreamEndStop
+    struct StreamEndStop {
+        std::string operator+() const;
+    };
+    template<typename T>
+    T const& operator + ( T const& value, StreamEndStop ) {
+        return value;
+    }
+}
+
+#define CATCH_INTERNAL_LINEINFO \
+    ::Catch::SourceLineInfo( __FILE__, static_cast<std::size_t>( __LINE__ ) )
+
+// end catch_common.h
+namespace Catch {
+
+    struct RegistrarForTagAliases {
+        RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo );
+    };
+
+} // end namespace Catch
+
+#define CATCH_REGISTER_TAG_ALIAS( alias, spec ) \
+    CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
+    CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
+    namespace{ Catch::RegistrarForTagAliases INTERNAL_CATCH_UNIQUE_NAME( AutoRegisterTagAlias )( alias, spec, CATCH_INTERNAL_LINEINFO ); } \
+    CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
+
+// end catch_tag_alias_autoregistrar.h
+// start catch_test_registry.h
+
+// start catch_interfaces_testcase.h
+
+#include <vector>
+
+namespace Catch {
+
+    class TestSpec;
+
+    struct ITestInvoker {
+        virtual void invoke () const = 0;
+        virtual ~ITestInvoker();
+    };
+
+    class TestCase;
+    struct IConfig;
+
+    struct ITestCaseRegistry {
+        virtual ~ITestCaseRegistry();
+        virtual std::vector<TestCase> const& getAllTests() const = 0;
+        virtual std::vector<TestCase> const& getAllTestsSorted( IConfig const& config ) const = 0;
+    };
+
+    bool isThrowSafe( TestCase const& testCase, IConfig const& config );
+    bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config );
+    std::vector<TestCase> filterTests( std::vector<TestCase> const& testCases, TestSpec const& testSpec, IConfig const& config );
+    std::vector<TestCase> const& getAllTestCasesSorted( IConfig const& config );
+
+}
+
+// end catch_interfaces_testcase.h
+// start catch_stringref.h
+
+#include <cstddef>
+#include <string>
+#include <iosfwd>
+#include <cassert>
+
+namespace Catch {
+
+    /// A non-owning string class (similar to the forthcoming std::string_view)
+    /// Note that, because a StringRef may be a substring of another string,
+    /// it may not be null terminated.
+    class StringRef {
+    public:
+        using size_type = std::size_t;
+        using const_iterator = const char*;
+
+    private:
+        static constexpr char const* const s_empty = "";
+
+        char const* m_start = s_empty;
+        size_type m_size = 0;
+
+    public: // construction
+        constexpr StringRef() noexcept = default;
+
+        StringRef( char const* rawChars ) noexcept;
+
+        constexpr StringRef( char const* rawChars, size_type size ) noexcept
+        :   m_start( rawChars ),
+            m_size( size )
+        {}
+
+        StringRef( std::string const& stdString ) noexcept
+        :   m_start( stdString.c_str() ),
+            m_size( stdString.size() )
+        {}
+
+        explicit operator std::string() const {
+            return std::string(m_start, m_size);
+        }
+
+    public: // operators
+        auto operator == ( StringRef const& other ) const noexcept -> bool;
+        auto operator != (StringRef const& other) const noexcept -> bool {
+            return !(*this == other);
+        }
+
+        auto operator[] ( size_type index ) const noexcept -> char {
+            assert(index < m_size);
+            return m_start[index];
+        }
+
+    public: // named queries
+        constexpr auto empty() const noexcept -> bool {
+            return m_size == 0;
+        }
+        constexpr auto size() const noexcept -> size_type {
+            return m_size;
+        }
+
+        // Returns the current start pointer. If the StringRef is not
+        // null-terminated, throws std::domain_exception
+        auto c_str() const -> char const*;
+
+    public: // substrings and searches
+        // Returns a substring of [start, start + length).
+        // If start + length > size(), then the substring is [start, size()).
+        // If start > size(), then the substring is empty.
+        auto substr( size_type start, size_type length ) const noexcept -> StringRef;
+
+        // Returns the current start pointer. May not be null-terminated.
+        auto data() const noexcept -> char const*;
+
+        constexpr auto isNullTerminated() const noexcept -> bool {
+            return m_start[m_size] == '\0';
+        }
+
+    public: // iterators
+        constexpr const_iterator begin() const { return m_start; }
+        constexpr const_iterator end() const { return m_start + m_size; }
+    };
+
+    auto operator += ( std::string& lhs, StringRef const& sr ) -> std::string&;
+    auto operator << ( std::ostream& os, StringRef const& sr ) -> std::ostream&;
+
+    constexpr auto operator "" _sr( char const* rawChars, std::size_t size ) noexcept -> StringRef {
+        return StringRef( rawChars, size );
+    }
+} // namespace Catch
+
+constexpr auto operator "" _catch_sr( char const* rawChars, std::size_t size ) noexcept -> Catch::StringRef {
+    return Catch::StringRef( rawChars, size );
+}
+
+// end catch_stringref.h
+// start catch_preprocessor.hpp
+
+
+#define CATCH_RECURSION_LEVEL0(...) __VA_ARGS__
+#define CATCH_RECURSION_LEVEL1(...) CATCH_RECURSION_LEVEL0(CATCH_RECURSION_LEVEL0(CATCH_RECURSION_LEVEL0(__VA_ARGS__)))
+#define CATCH_RECURSION_LEVEL2(...) CATCH_RECURSION_LEVEL1(CATCH_RECURSION_LEVEL1(CATCH_RECURSION_LEVEL1(__VA_ARGS__)))
+#define CATCH_RECURSION_LEVEL3(...) CATCH_RECURSION_LEVEL2(CATCH_RECURSION_LEVEL2(CATCH_RECURSION_LEVEL2(__VA_ARGS__)))
+#define CATCH_RECURSION_LEVEL4(...) CATCH_RECURSION_LEVEL3(CATCH_RECURSION_LEVEL3(CATCH_RECURSION_LEVEL3(__VA_ARGS__)))
+#define CATCH_RECURSION_LEVEL5(...) CATCH_RECURSION_LEVEL4(CATCH_RECURSION_LEVEL4(CATCH_RECURSION_LEVEL4(__VA_ARGS__)))
+
+#ifdef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
+#define INTERNAL_CATCH_EXPAND_VARGS(...) __VA_ARGS__
+// MSVC needs more evaluations
+#define CATCH_RECURSION_LEVEL6(...) CATCH_RECURSION_LEVEL5(CATCH_RECURSION_LEVEL5(CATCH_RECURSION_LEVEL5(__VA_ARGS__)))
+#define CATCH_RECURSE(...)  CATCH_RECURSION_LEVEL6(CATCH_RECURSION_LEVEL6(__VA_ARGS__))
+#else
+#define CATCH_RECURSE(...)  CATCH_RECURSION_LEVEL5(__VA_ARGS__)
+#endif
+
+#define CATCH_REC_END(...)
+#define CATCH_REC_OUT
+
+#define CATCH_EMPTY()
+#define CATCH_DEFER(id) id CATCH_EMPTY()
+
+#define CATCH_REC_GET_END2() 0, CATCH_REC_END
+#define CATCH_REC_GET_END1(...) CATCH_REC_GET_END2
+#define CATCH_REC_GET_END(...) CATCH_REC_GET_END1
+#define CATCH_REC_NEXT0(test, next, ...) next CATCH_REC_OUT
+#define CATCH_REC_NEXT1(test, next) CATCH_DEFER ( CATCH_REC_NEXT0 ) ( test, next, 0)
+#define CATCH_REC_NEXT(test, next)  CATCH_REC_NEXT1(CATCH_REC_GET_END test, next)
+
+#define CATCH_REC_LIST0(f, x, peek, ...) , f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1) ) ( f, peek, __VA_ARGS__ )
+#define CATCH_REC_LIST1(f, x, peek, ...) , f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST0) ) ( f, peek, __VA_ARGS__ )
+#define CATCH_REC_LIST2(f, x, peek, ...)   f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1) ) ( f, peek, __VA_ARGS__ )
+
+#define CATCH_REC_LIST0_UD(f, userdata, x, peek, ...) , f(userdata, x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1_UD) ) ( f, userdata, peek, __VA_ARGS__ )
+#define CATCH_REC_LIST1_UD(f, userdata, x, peek, ...) , f(userdata, x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST0_UD) ) ( f, userdata, peek, __VA_ARGS__ )
+#define CATCH_REC_LIST2_UD(f, userdata, x, peek, ...)   f(userdata, x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1_UD) ) ( f, userdata, peek, __VA_ARGS__ )
+
+// Applies the function macro `f` to each of the remaining parameters, inserts commas between the results,
+// and passes userdata as the first parameter to each invocation,
+// e.g. CATCH_REC_LIST_UD(f, x, a, b, c) evaluates to f(x, a), f(x, b), f(x, c)
+#define CATCH_REC_LIST_UD(f, userdata, ...) CATCH_RECURSE(CATCH_REC_LIST2_UD(f, userdata, __VA_ARGS__, ()()(), ()()(), ()()(), 0))
+
+#define CATCH_REC_LIST(f, ...) CATCH_RECURSE(CATCH_REC_LIST2(f, __VA_ARGS__, ()()(), ()()(), ()()(), 0))
+
+#define INTERNAL_CATCH_EXPAND1(param) INTERNAL_CATCH_EXPAND2(param)
+#define INTERNAL_CATCH_EXPAND2(...) INTERNAL_CATCH_NO## __VA_ARGS__
+#define INTERNAL_CATCH_DEF(...) INTERNAL_CATCH_DEF __VA_ARGS__
+#define INTERNAL_CATCH_NOINTERNAL_CATCH_DEF
+#define INTERNAL_CATCH_STRINGIZE(...) INTERNAL_CATCH_STRINGIZE2(__VA_ARGS__)
+#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
+#define INTERNAL_CATCH_STRINGIZE2(...) #__VA_ARGS__
+#define INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS(param) INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_REMOVE_PARENS(param))
+#else
+// MSVC is adding extra space and needs another indirection to expand INTERNAL_CATCH_NOINTERNAL_CATCH_DEF
+#define INTERNAL_CATCH_STRINGIZE2(...) INTERNAL_CATCH_STRINGIZE3(__VA_ARGS__)
+#define INTERNAL_CATCH_STRINGIZE3(...) #__VA_ARGS__
+#define INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS(param) (INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_REMOVE_PARENS(param)) + 1)
+#endif
+
+#define INTERNAL_CATCH_MAKE_NAMESPACE2(...) ns_##__VA_ARGS__
+#define INTERNAL_CATCH_MAKE_NAMESPACE(name) INTERNAL_CATCH_MAKE_NAMESPACE2(name)
+
+#define INTERNAL_CATCH_REMOVE_PARENS(...) INTERNAL_CATCH_EXPAND1(INTERNAL_CATCH_DEF __VA_ARGS__)
+
+#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
+#define INTERNAL_CATCH_MAKE_TYPE_LIST2(...) decltype(get_wrapper<INTERNAL_CATCH_REMOVE_PARENS_GEN(__VA_ARGS__)>())
+#define INTERNAL_CATCH_MAKE_TYPE_LIST(...) INTERNAL_CATCH_MAKE_TYPE_LIST2(INTERNAL_CATCH_REMOVE_PARENS(__VA_ARGS__))
+#else
+#define INTERNAL_CATCH_MAKE_TYPE_LIST2(...) INTERNAL_CATCH_EXPAND_VARGS(decltype(get_wrapper<INTERNAL_CATCH_REMOVE_PARENS_GEN(__VA_ARGS__)>()))
+#define INTERNAL_CATCH_MAKE_TYPE_LIST(...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_MAKE_TYPE_LIST2(INTERNAL_CATCH_REMOVE_PARENS(__VA_ARGS__)))
+#endif
+
+#define INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(...)\
+    CATCH_REC_LIST(INTERNAL_CATCH_MAKE_TYPE_LIST,__VA_ARGS__)
+
+#define INTERNAL_CATCH_REMOVE_PARENS_1_ARG(_0) INTERNAL_CATCH_REMOVE_PARENS(_0)
+#define INTERNAL_CATCH_REMOVE_PARENS_2_ARG(_0, _1) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_1_ARG(_1)
+#define INTERNAL_CATCH_REMOVE_PARENS_3_ARG(_0, _1, _2) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_2_ARG(_1, _2)
+#define INTERNAL_CATCH_REMOVE_PARENS_4_ARG(_0, _1, _2, _3) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_3_ARG(_1, _2, _3)
+#define INTERNAL_CATCH_REMOVE_PARENS_5_ARG(_0, _1, _2, _3, _4) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_4_ARG(_1, _2, _3, _4)
+#define INTERNAL_CATCH_REMOVE_PARENS_6_ARG(_0, _1, _2, _3, _4, _5) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_5_ARG(_1, _2, _3, _4, _5)
+#define INTERNAL_CATCH_REMOVE_PARENS_7_ARG(_0, _1, _2, _3, _4, _5, _6) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_6_ARG(_1, _2, _3, _4, _5, _6)
+#define INTERNAL_CATCH_REMOVE_PARENS_8_ARG(_0, _1, _2, _3, _4, _5, _6, _7) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_7_ARG(_1, _2, _3, _4, _5, _6, _7)
+#define INTERNAL_CATCH_REMOVE_PARENS_9_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_8_ARG(_1, _2, _3, _4, _5, _6, _7, _8)
+#define INTERNAL_CATCH_REMOVE_PARENS_10_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_9_ARG(_1, _2, _3, _4, _5, _6, _7, _8, _9)
+#define INTERNAL_CATCH_REMOVE_PARENS_11_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_10_ARG(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10)
+
+#define INTERNAL_CATCH_VA_NARGS_IMPL(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, ...) N
+
+#define INTERNAL_CATCH_TYPE_GEN\
+    template<typename...> struct TypeList {};\
+    template<typename...Ts>\
+    constexpr auto get_wrapper() noexcept -> TypeList<Ts...> { return {}; }\
+    template<template<typename...> class...> struct TemplateTypeList{};\
+    template<template<typename...> class...Cs>\
+    constexpr auto get_wrapper() noexcept -> TemplateTypeList<Cs...> { return {}; }\
+    template<typename...>\
+    struct append;\
+    template<typename...>\
+    struct rewrap;\
+    template<template<typename...> class, typename...>\
+    struct create;\
+    template<template<typename...> class, typename>\
+    struct convert;\
+    \
+    template<typename T> \
+    struct append<T> { using type = T; };\
+    template< template<typename...> class L1, typename...E1, template<typename...> class L2, typename...E2, typename...Rest>\
+    struct append<L1<E1...>, L2<E2...>, Rest...> { using type = typename append<L1<E1...,E2...>, Rest...>::type; };\
+    template< template<typename...> class L1, typename...E1, typename...Rest>\
+    struct append<L1<E1...>, TypeList<mpl_::na>, Rest...> { using type = L1<E1...>; };\
+    \
+    template< template<typename...> class Container, template<typename...> class List, typename...elems>\
+    struct rewrap<TemplateTypeList<Container>, List<elems...>> { using type = TypeList<Container<elems...>>; };\
+    template< template<typename...> class Container, template<typename...> class List, class...Elems, typename...Elements>\
+    struct rewrap<TemplateTypeList<Container>, List<Elems...>, Elements...> { using type = typename append<TypeList<Container<Elems...>>, typename rewrap<TemplateTypeList<Container>, Elements...>::type>::type; };\
+    \
+    template<template <typename...> class Final, template< typename...> class...Containers, typename...Types>\
+    struct create<Final, TemplateTypeList<Containers...>, TypeList<Types...>> { using type = typename append<Final<>, typename rewrap<TemplateTypeList<Containers>, Types...>::type...>::type; };\
+    template<template <typename...> class Final, template <typename...> class List, typename...Ts>\
+    struct convert<Final, List<Ts...>> { using type = typename append<Final<>,TypeList<Ts>...>::type; };
+
+#define INTERNAL_CATCH_NTTP_1(signature, ...)\
+    template<INTERNAL_CATCH_REMOVE_PARENS(signature)> struct Nttp{};\
+    template<INTERNAL_CATCH_REMOVE_PARENS(signature)>\
+    constexpr auto get_wrapper() noexcept -> Nttp<__VA_ARGS__> { return {}; } \
+    template<template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class...> struct NttpTemplateTypeList{};\
+    template<template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class...Cs>\
+    constexpr auto get_wrapper() noexcept -> NttpTemplateTypeList<Cs...> { return {}; } \
+    \
+    template< template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class Container, template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class List, INTERNAL_CATCH_REMOVE_PARENS(signature)>\
+    struct rewrap<NttpTemplateTypeList<Container>, List<__VA_ARGS__>> { using type = TypeList<Container<__VA_ARGS__>>; };\
+    template< template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class Container, template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class List, INTERNAL_CATCH_REMOVE_PARENS(signature), typename...Elements>\
+    struct rewrap<NttpTemplateTypeList<Container>, List<__VA_ARGS__>, Elements...> { using type = typename append<TypeList<Container<__VA_ARGS__>>, typename rewrap<NttpTemplateTypeList<Container>, Elements...>::type>::type; };\
+    template<template <typename...> class Final, template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class...Containers, typename...Types>\
+    struct create<Final, NttpTemplateTypeList<Containers...>, TypeList<Types...>> { using type = typename append<Final<>, typename rewrap<NttpTemplateTypeList<Containers>, Types...>::type...>::type; };
+
+#define INTERNAL_CATCH_DECLARE_SIG_TEST0(TestName)
+#define INTERNAL_CATCH_DECLARE_SIG_TEST1(TestName, signature)\
+    template<INTERNAL_CATCH_REMOVE_PARENS(signature)>\
+    static void TestName()
+#define INTERNAL_CATCH_DECLARE_SIG_TEST_X(TestName, signature, ...)\
+    template<INTERNAL_CATCH_REMOVE_PARENS(signature)>\
+    static void TestName()
+
+#define INTERNAL_CATCH_DEFINE_SIG_TEST0(TestName)
+#define INTERNAL_CATCH_DEFINE_SIG_TEST1(TestName, signature)\
+    template<INTERNAL_CATCH_REMOVE_PARENS(signature)>\
+    static void TestName()
+#define INTERNAL_CATCH_DEFINE_SIG_TEST_X(TestName, signature,...)\
+    template<INTERNAL_CATCH_REMOVE_PARENS(signature)>\
+    static void TestName()
+
+#define INTERNAL_CATCH_NTTP_REGISTER0(TestFunc, signature)\
+    template<typename Type>\
+    void reg_test(TypeList<Type>, Catch::NameAndTags nameAndTags)\
+    {\
+        Catch::AutoReg( Catch::makeTestInvoker(&TestFunc<Type>), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), nameAndTags);\
+    }
+
+#define INTERNAL_CATCH_NTTP_REGISTER(TestFunc, signature, ...)\
+    template<INTERNAL_CATCH_REMOVE_PARENS(signature)>\
+    void reg_test(Nttp<__VA_ARGS__>, Catch::NameAndTags nameAndTags)\
+    {\
+        Catch::AutoReg( Catch::makeTestInvoker(&TestFunc<__VA_ARGS__>), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), nameAndTags);\
+    }
+
+#define INTERNAL_CATCH_NTTP_REGISTER_METHOD0(TestName, signature, ...)\
+    template<typename Type>\
+    void reg_test(TypeList<Type>, Catch::StringRef className, Catch::NameAndTags nameAndTags)\
+    {\
+        Catch::AutoReg( Catch::makeTestInvoker(&TestName<Type>::test), CATCH_INTERNAL_LINEINFO, className, nameAndTags);\
+    }
+
+#define INTERNAL_CATCH_NTTP_REGISTER_METHOD(TestName, signature, ...)\
+    template<INTERNAL_CATCH_REMOVE_PARENS(signature)>\
+    void reg_test(Nttp<__VA_ARGS__>, Catch::StringRef className, Catch::NameAndTags nameAndTags)\
+    {\
+        Catch::AutoReg( Catch::makeTestInvoker(&TestName<__VA_ARGS__>::test), CATCH_INTERNAL_LINEINFO, className, nameAndTags);\
+    }
+
+#define INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD0(TestName, ClassName)
+#define INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD1(TestName, ClassName, signature)\
+    template<typename TestType> \
+    struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName)<TestType> { \
+        void test();\
+    }
+
+#define INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X(TestName, ClassName, signature, ...)\
+    template<INTERNAL_CATCH_REMOVE_PARENS(signature)> \
+    struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName)<__VA_ARGS__> { \
+        void test();\
+    }
+
+#define INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD0(TestName)
+#define INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD1(TestName, signature)\
+    template<typename TestType> \
+    void INTERNAL_CATCH_MAKE_NAMESPACE(TestName)::TestName<TestType>::test()
+#define INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X(TestName, signature, ...)\
+    template<INTERNAL_CATCH_REMOVE_PARENS(signature)> \
+    void INTERNAL_CATCH_MAKE_NAMESPACE(TestName)::TestName<__VA_ARGS__>::test()
+
+#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
+#define INTERNAL_CATCH_NTTP_0
+#define INTERNAL_CATCH_NTTP_GEN(...) INTERNAL_CATCH_VA_NARGS_IMPL(__VA_ARGS__, INTERNAL_CATCH_NTTP_1(__VA_ARGS__), INTERNAL_CATCH_NTTP_1(__VA_ARGS__), INTERNAL_CATCH_NTTP_1(__VA_ARGS__), INTERNAL_CATCH_NTTP_1(__VA_ARGS__), INTERNAL_CATCH_NTTP_1(__VA_ARGS__), INTERNAL_CATCH_NTTP_1( __VA_ARGS__), INTERNAL_CATCH_NTTP_1( __VA_ARGS__), INTERNAL_CATCH_NTTP_1( __VA_ARGS__), INTERNAL_CATCH_NTTP_1( __VA_ARGS__),INTERNAL_CATCH_NTTP_1( __VA_ARGS__), INTERNAL_CATCH_NTTP_0)
+#define INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD(TestName, ...) INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD1, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD0)(TestName, __VA_ARGS__)
+#define INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD(TestName, ClassName, ...) INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD1, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD0)(TestName, ClassName, __VA_ARGS__)
+#define INTERNAL_CATCH_NTTP_REG_METHOD_GEN(TestName, ...) INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD0, INTERNAL_CATCH_NTTP_REGISTER_METHOD0)(TestName, __VA_ARGS__)
+#define INTERNAL_CATCH_NTTP_REG_GEN(TestFunc, ...) INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER0, INTERNAL_CATCH_NTTP_REGISTER0)(TestFunc, __VA_ARGS__)
+#define INTERNAL_CATCH_DEFINE_SIG_TEST(TestName, ...) INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X,INTERNAL_CATCH_DEFINE_SIG_TEST_X,INTERNAL_CATCH_DEFINE_SIG_TEST1, INTERNAL_CATCH_DEFINE_SIG_TEST0)(TestName, __VA_ARGS__)
+#define INTERNAL_CATCH_DECLARE_SIG_TEST(TestName, ...) INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_DECLARE_SIG_TEST_X,INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X,INTERNAL_CATCH_DECLARE_SIG_TEST_X,INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST1, INTERNAL_CATCH_DECLARE_SIG_TEST0)(TestName, __VA_ARGS__)
+#define INTERNAL_CATCH_REMOVE_PARENS_GEN(...) INTERNAL_CATCH_VA_NARGS_IMPL(__VA_ARGS__, INTERNAL_CATCH_REMOVE_PARENS_11_ARG,INTERNAL_CATCH_REMOVE_PARENS_10_ARG,INTERNAL_CATCH_REMOVE_PARENS_9_ARG,INTERNAL_CATCH_REMOVE_PARENS_8_ARG,INTERNAL_CATCH_REMOVE_PARENS_7_ARG,INTERNAL_CATCH_REMOVE_PARENS_6_ARG,INTERNAL_CATCH_REMOVE_PARENS_5_ARG,INTERNAL_CATCH_REMOVE_PARENS_4_ARG,INTERNAL_CATCH_REMOVE_PARENS_3_ARG,INTERNAL_CATCH_REMOVE_PARENS_2_ARG,INTERNAL_CATCH_REMOVE_PARENS_1_ARG)(__VA_ARGS__)
+#else
+#define INTERNAL_CATCH_NTTP_0(signature)
+#define INTERNAL_CATCH_NTTP_GEN(...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_VA_NARGS_IMPL(__VA_ARGS__, INTERNAL_CATCH_NTTP_1, INTERNAL_CATCH_NTTP_1, INTERNAL_CATCH_NTTP_1, INTERNAL_CATCH_NTTP_1, INTERNAL_CATCH_NTTP_1, INTERNAL_CATCH_NTTP_1, INTERNAL_CATCH_NTTP_1, INTERNAL_CATCH_NTTP_1, INTERNAL_CATCH_NTTP_1,INTERNAL_CATCH_NTTP_1, INTERNAL_CATCH_NTTP_0)( __VA_ARGS__))
+#define INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD(TestName, ...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD1, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD0)(TestName, __VA_ARGS__))
+#define INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD(TestName, ClassName, ...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD1, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD0)(TestName, ClassName, __VA_ARGS__))
+#define INTERNAL_CATCH_NTTP_REG_METHOD_GEN(TestName, ...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD0, INTERNAL_CATCH_NTTP_REGISTER_METHOD0)(TestName, __VA_ARGS__))
+#define INTERNAL_CATCH_NTTP_REG_GEN(TestFunc, ...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER0, INTERNAL_CATCH_NTTP_REGISTER0)(TestFunc, __VA_ARGS__))
+#define INTERNAL_CATCH_DEFINE_SIG_TEST(TestName, ...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X,INTERNAL_CATCH_DEFINE_SIG_TEST_X,INTERNAL_CATCH_DEFINE_SIG_TEST1, INTERNAL_CATCH_DEFINE_SIG_TEST0)(TestName, __VA_ARGS__))
+#define INTERNAL_CATCH_DECLARE_SIG_TEST(TestName, ...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_DECLARE_SIG_TEST_X,INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X,INTERNAL_CATCH_DECLARE_SIG_TEST_X,INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST1, INTERNAL_CATCH_DECLARE_SIG_TEST0)(TestName, __VA_ARGS__))
+#define INTERNAL_CATCH_REMOVE_PARENS_GEN(...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_VA_NARGS_IMPL(__VA_ARGS__, INTERNAL_CATCH_REMOVE_PARENS_11_ARG,INTERNAL_CATCH_REMOVE_PARENS_10_ARG,INTERNAL_CATCH_REMOVE_PARENS_9_ARG,INTERNAL_CATCH_REMOVE_PARENS_8_ARG,INTERNAL_CATCH_REMOVE_PARENS_7_ARG,INTERNAL_CATCH_REMOVE_PARENS_6_ARG,INTERNAL_CATCH_REMOVE_PARENS_5_ARG,INTERNAL_CATCH_REMOVE_PARENS_4_ARG,INTERNAL_CATCH_REMOVE_PARENS_3_ARG,INTERNAL_CATCH_REMOVE_PARENS_2_ARG,INTERNAL_CATCH_REMOVE_PARENS_1_ARG)(__VA_ARGS__))
+#endif
+
+// end catch_preprocessor.hpp
+// start catch_meta.hpp
+
+
+#include <type_traits>
+
+namespace Catch {
+    template<typename T>
+    struct always_false : std::false_type {};
+
+    template <typename> struct true_given : std::true_type {};
+    struct is_callable_tester {
+        template <typename Fun, typename... Args>
+        true_given<decltype(std::declval<Fun>()(std::declval<Args>()...))> static test(int);
+        template <typename...>
+        std::false_type static test(...);
+    };
+
+    template <typename T>
+    struct is_callable;
+
+    template <typename Fun, typename... Args>
+    struct is_callable<Fun(Args...)> : decltype(is_callable_tester::test<Fun, Args...>(0)) {};
+
+#if defined(__cpp_lib_is_invocable) && __cpp_lib_is_invocable >= 201703
+    // std::result_of is deprecated in C++17 and removed in C++20. Hence, it is
+    // replaced with std::invoke_result here.
+    template <typename Func, typename... U>
+    using FunctionReturnType = std::remove_reference_t<std::remove_cv_t<std::invoke_result_t<Func, U...>>>;
+#else
+    // Keep ::type here because we still support C++11
+    template <typename Func, typename... U>
+    using FunctionReturnType = typename std::remove_reference<typename std::remove_cv<typename std::result_of<Func(U...)>::type>::type>::type;
+#endif
+
+} // namespace Catch
+
+namespace mpl_{
+    struct na;
+}
+
+// end catch_meta.hpp
+namespace Catch {
+
+template<typename C>
+class TestInvokerAsMethod : public ITestInvoker {
+    void (C::*m_testAsMethod)();
+public:
+    TestInvokerAsMethod( void (C::*testAsMethod)() ) noexcept : m_testAsMethod( testAsMethod ) {}
+
+    void invoke() const override {
+        C obj;
+        (obj.*m_testAsMethod)();
+    }
+};
+
+auto makeTestInvoker( void(*testAsFunction)() ) noexcept -> ITestInvoker*;
+
+template<typename C>
+auto makeTestInvoker( void (C::*testAsMethod)() ) noexcept -> ITestInvoker* {
+    return new(std::nothrow) TestInvokerAsMethod<C>( testAsMethod );
+}
+
+struct NameAndTags {
+    NameAndTags( StringRef const& name_ = StringRef(), StringRef const& tags_ = StringRef() ) noexcept;
+    StringRef name;
+    StringRef tags;
+};
+
+struct AutoReg : NonCopyable {
+    AutoReg( ITestInvoker* invoker, SourceLineInfo const& lineInfo, StringRef const& classOrMethod, NameAndTags const& nameAndTags ) noexcept;
+    ~AutoReg();
+};
+
+} // end namespace Catch
+
+#if defined(CATCH_CONFIG_DISABLE)
+    #define INTERNAL_CATCH_TESTCASE_NO_REGISTRATION( TestName, ... ) \
+        static void TestName()
+    #define INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION( TestName, ClassName, ... ) \
+        namespace{                        \
+            struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName) { \
+                void test();              \
+            };                            \
+        }                                 \
+        void TestName::test()
+    #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION_2( TestName, TestFunc, Name, Tags, Signature, ... )  \
+        INTERNAL_CATCH_DEFINE_SIG_TEST(TestFunc, INTERNAL_CATCH_REMOVE_PARENS(Signature))
+    #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION_2( TestNameClass, TestName, ClassName, Name, Tags, Signature, ... )    \
+        namespace{                                                                                  \
+            namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestName) {                                      \
+            INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD(TestName, ClassName, INTERNAL_CATCH_REMOVE_PARENS(Signature));\
+        }                                                                                           \
+        }                                                                                           \
+        INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD(TestName, INTERNAL_CATCH_REMOVE_PARENS(Signature))
+
+    #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
+        #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(Name, Tags, ...) \
+            INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, typename TestType, __VA_ARGS__ )
+    #else
+        #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(Name, Tags, ...) \
+            INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, typename TestType, __VA_ARGS__ ) )
+    #endif
+
+    #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
+        #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG_NO_REGISTRATION(Name, Tags, Signature, ...) \
+            INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, Signature, __VA_ARGS__ )
+    #else
+        #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG_NO_REGISTRATION(Name, Tags, Signature, ...) \
+            INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, Signature, __VA_ARGS__ ) )
+    #endif
+
+    #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
+        #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION( ClassName, Name, Tags,... ) \
+            INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____C_L_A_S_S____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) , ClassName, Name, Tags, typename T, __VA_ARGS__ )
+    #else
+        #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION( ClassName, Name, Tags,... ) \
+            INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____C_L_A_S_S____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) , ClassName, Name, Tags, typename T, __VA_ARGS__ ) )
+    #endif
+
+    #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
+        #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG_NO_REGISTRATION( ClassName, Name, Tags, Signature, ... ) \
+            INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____C_L_A_S_S____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) , ClassName, Name, Tags, Signature, __VA_ARGS__ )
+    #else
+        #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG_NO_REGISTRATION( ClassName, Name, Tags, Signature, ... ) \
+            INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____C_L_A_S_S____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) , ClassName, Name, Tags, Signature, __VA_ARGS__ ) )
+    #endif
+#endif
+
+    ///////////////////////////////////////////////////////////////////////////////
+    #define INTERNAL_CATCH_TESTCASE2( TestName, ... ) \
+        static void TestName(); \
+        CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
+        CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
+        namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( &TestName ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ __VA_ARGS__ } ); } /* NOLINT */ \
+        CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
+        static void TestName()
+    #define INTERNAL_CATCH_TESTCASE( ... ) \
+        INTERNAL_CATCH_TESTCASE2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), __VA_ARGS__ )
+
+    ///////////////////////////////////////////////////////////////////////////////
+    #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, ... ) \
+        CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
+        CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
+        namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( &QualifiedMethod ), CATCH_INTERNAL_LINEINFO, "&" #QualifiedMethod, Catch::NameAndTags{ __VA_ARGS__ } ); } /* NOLINT */ \
+        CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
+
+    ///////////////////////////////////////////////////////////////////////////////
+    #define INTERNAL_CATCH_TEST_CASE_METHOD2( TestName, ClassName, ... )\
+        CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
+        CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
+        namespace{ \
+            struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName) { \
+                void test(); \
+            }; \
+            Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( Catch::makeTestInvoker( &TestName::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ __VA_ARGS__ } ); /* NOLINT */ \
+        } \
+        CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
+        void TestName::test()
+    #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, ... ) \
+        INTERNAL_CATCH_TEST_CASE_METHOD2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), ClassName, __VA_ARGS__ )
+
+    ///////////////////////////////////////////////////////////////////////////////
+    #define INTERNAL_CATCH_REGISTER_TESTCASE( Function, ... ) \
+        CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
+        CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
+        Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( Function ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ __VA_ARGS__ } ); /* NOLINT */ \
+        CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
+
+    ///////////////////////////////////////////////////////////////////////////////
+    #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_2(TestName, TestFunc, Name, Tags, Signature, ... )\
+        CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
+        CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
+        CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \
+        CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \
+        INTERNAL_CATCH_DECLARE_SIG_TEST(TestFunc, INTERNAL_CATCH_REMOVE_PARENS(Signature));\
+        namespace {\
+        namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestName){\
+            INTERNAL_CATCH_TYPE_GEN\
+            INTERNAL_CATCH_NTTP_GEN(INTERNAL_CATCH_REMOVE_PARENS(Signature))\
+            INTERNAL_CATCH_NTTP_REG_GEN(TestFunc,INTERNAL_CATCH_REMOVE_PARENS(Signature))\
+            template<typename...Types> \
+            struct TestName{\
+                TestName(){\
+                    int index = 0;                                    \
+                    constexpr char const* tmpl_types[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, __VA_ARGS__)};\
+                    using expander = int[];\
+                    (void)expander{(reg_test(Types{}, Catch::NameAndTags{ Name " - " + std::string(tmpl_types[index]), Tags } ), index++)... };/* NOLINT */ \
+                }\
+            };\
+            static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\
+            TestName<INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(__VA_ARGS__)>();\
+            return 0;\
+        }();\
+        }\
+        }\
+        CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
+        INTERNAL_CATCH_DEFINE_SIG_TEST(TestFunc,INTERNAL_CATCH_REMOVE_PARENS(Signature))
+
+#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
+    #define INTERNAL_CATCH_TEMPLATE_TEST_CASE(Name, Tags, ...) \
+        INTERNAL_CATCH_TEMPLATE_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, typename TestType, __VA_ARGS__ )
+#else
+    #define INTERNAL_CATCH_TEMPLATE_TEST_CASE(Name, Tags, ...) \
+        INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, typename TestType, __VA_ARGS__ ) )
+#endif
+
+#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
+    #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG(Name, Tags, Signature, ...) \
+        INTERNAL_CATCH_TEMPLATE_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, Signature, __VA_ARGS__ )
+#else
+    #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG(Name, Tags, Signature, ...) \
+        INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, Signature, __VA_ARGS__ ) )
+#endif
+
+    #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2(TestName, TestFuncName, Name, Tags, Signature, TmplTypes, TypesList) \
+        CATCH_INTERNAL_START_WARNINGS_SUPPRESSION                      \
+        CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS                      \
+        CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS                \
+        CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS              \
+        template<typename TestType> static void TestFuncName();       \
+        namespace {\
+        namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestName) {                                     \
+            INTERNAL_CATCH_TYPE_GEN                                                  \
+            INTERNAL_CATCH_NTTP_GEN(INTERNAL_CATCH_REMOVE_PARENS(Signature))         \
+            template<typename... Types>                               \
+            struct TestName {                                         \
+                void reg_tests() {                                          \
+                    int index = 0;                                    \
+                    using expander = int[];                           \
+                    constexpr char const* tmpl_types[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TmplTypes))};\
+                    constexpr char const* types_list[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TypesList))};\
+                    constexpr auto num_types = sizeof(types_list) / sizeof(types_list[0]);\
+                    (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestFuncName<Types> ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ Name " - " + std::string(tmpl_types[index / num_types]) + "<" + std::string(types_list[index % num_types]) + ">", Tags } ), index++)... };/* NOLINT */\
+                }                                                     \
+            };                                                        \
+            static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){ \
+                using TestInit = typename create<TestName, decltype(get_wrapper<INTERNAL_CATCH_REMOVE_PARENS(TmplTypes)>()), TypeList<INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(INTERNAL_CATCH_REMOVE_PARENS(TypesList))>>::type; \
+                TestInit t;                                           \
+                t.reg_tests();                                        \
+                return 0;                                             \
+            }();                                                      \
+        }                                                             \
+        }                                                             \
+        CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION                       \
+        template<typename TestType>                                   \
+        static void TestFuncName()
+
+#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
+    #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE(Name, Tags, ...)\
+        INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, typename T,__VA_ARGS__)
+#else
+    #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE(Name, Tags, ...)\
+        INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, typename T, __VA_ARGS__ ) )
+#endif
+
+#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
+    #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG(Name, Tags, Signature, ...)\
+        INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, Signature, __VA_ARGS__)
+#else
+    #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG(Name, Tags, Signature, ...)\
+        INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, Signature, __VA_ARGS__ ) )
+#endif
+
+    #define INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_2(TestName, TestFunc, Name, Tags, TmplList)\
+        CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
+        CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
+        CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \
+        template<typename TestType> static void TestFunc();       \
+        namespace {\
+        namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestName){\
+        INTERNAL_CATCH_TYPE_GEN\
+        template<typename... Types>                               \
+        struct TestName {                                         \
+            void reg_tests() {                                          \
+                int index = 0;                                    \
+                using expander = int[];                           \
+                (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestFunc<Types> ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ Name " - " + std::string(INTERNAL_CATCH_STRINGIZE(TmplList)) + " - " + std::to_string(index), Tags } ), index++)... };/* NOLINT */\
+            }                                                     \
+        };\
+        static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){ \
+                using TestInit = typename convert<TestName, TmplList>::type; \
+                TestInit t;                                           \
+                t.reg_tests();                                        \
+                return 0;                                             \
+            }();                                                      \
+        }}\
+        CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION                       \
+        template<typename TestType>                                   \
+        static void TestFunc()
+
+    #define INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE(Name, Tags, TmplList) \
+        INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, TmplList )
+
+    #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( TestNameClass, TestName, ClassName, Name, Tags, Signature, ... ) \
+        CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
+        CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
+        CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \
+        CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \
+        namespace {\
+        namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestName){ \
+            INTERNAL_CATCH_TYPE_GEN\
+            INTERNAL_CATCH_NTTP_GEN(INTERNAL_CATCH_REMOVE_PARENS(Signature))\
+            INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD(TestName, ClassName, INTERNAL_CATCH_REMOVE_PARENS(Signature));\
+            INTERNAL_CATCH_NTTP_REG_METHOD_GEN(TestName, INTERNAL_CATCH_REMOVE_PARENS(Signature))\
+            template<typename...Types> \
+            struct TestNameClass{\
+                TestNameClass(){\
+                    int index = 0;                                    \
+                    constexpr char const* tmpl_types[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, __VA_ARGS__)};\
+                    using expander = int[];\
+                    (void)expander{(reg_test(Types{}, #ClassName, Catch::NameAndTags{ Name " - " + std::string(tmpl_types[index]), Tags } ), index++)... };/* NOLINT */ \
+                }\
+            };\
+            static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\
+                TestNameClass<INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(__VA_ARGS__)>();\
+                return 0;\
+        }();\
+        }\
+        }\
+        CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
+        INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD(TestName, INTERNAL_CATCH_REMOVE_PARENS(Signature))
+
+#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
+    #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( ClassName, Name, Tags,... ) \
+        INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____C_L_A_S_S____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) , ClassName, Name, Tags, typename T, __VA_ARGS__ )
+#else
+    #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( ClassName, Name, Tags,... ) \
+        INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____C_L_A_S_S____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) , ClassName, Name, Tags, typename T, __VA_ARGS__ ) )
+#endif
+
+#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
+    #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( ClassName, Name, Tags, Signature, ... ) \
+        INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____C_L_A_S_S____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) , ClassName, Name, Tags, Signature, __VA_ARGS__ )
+#else
+    #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( ClassName, Name, Tags, Signature, ... ) \
+        INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____C_L_A_S_S____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) , ClassName, Name, Tags, Signature, __VA_ARGS__ ) )
+#endif
+
+    #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2(TestNameClass, TestName, ClassName, Name, Tags, Signature, TmplTypes, TypesList)\
+        CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
+        CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
+        CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \
+        CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \
+        template<typename TestType> \
+            struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName <TestType>) { \
+                void test();\
+            };\
+        namespace {\
+        namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestNameClass) {\
+            INTERNAL_CATCH_TYPE_GEN                  \
+            INTERNAL_CATCH_NTTP_GEN(INTERNAL_CATCH_REMOVE_PARENS(Signature))\
+            template<typename...Types>\
+            struct TestNameClass{\
+                void reg_tests(){\
+                    int index = 0;\
+                    using expander = int[];\
+                    constexpr char const* tmpl_types[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TmplTypes))};\
+                    constexpr char const* types_list[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TypesList))};\
+                    constexpr auto num_types = sizeof(types_list) / sizeof(types_list[0]);\
+                    (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestName<Types>::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ Name " - " + std::string(tmpl_types[index / num_types]) + "<" + std::string(types_list[index % num_types]) + ">", Tags } ), index++)... };/* NOLINT */ \
+                }\
+            };\
+            static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\
+                using TestInit = typename create<TestNameClass, decltype(get_wrapper<INTERNAL_CATCH_REMOVE_PARENS(TmplTypes)>()), TypeList<INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(INTERNAL_CATCH_REMOVE_PARENS(TypesList))>>::type;\
+                TestInit t;\
+                t.reg_tests();\
+                return 0;\
+            }(); \
+        }\
+        }\
+        CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
+        template<typename TestType> \
+        void TestName<TestType>::test()
+
+#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
+    #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( ClassName, Name, Tags, ... )\
+        INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), ClassName, Name, Tags, typename T, __VA_ARGS__ )
+#else
+    #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( ClassName, Name, Tags, ... )\
+        INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), ClassName, Name, Tags, typename T,__VA_ARGS__ ) )
+#endif
+
+#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
+    #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( ClassName, Name, Tags, Signature, ... )\
+        INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), ClassName, Name, Tags, Signature, __VA_ARGS__ )
+#else
+    #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( ClassName, Name, Tags, Signature, ... )\
+        INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), ClassName, Name, Tags, Signature,__VA_ARGS__ ) )
+#endif
+
+    #define INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD_2( TestNameClass, TestName, ClassName, Name, Tags, TmplList) \
+        CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
+        CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
+        CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \
+        template<typename TestType> \
+        struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName <TestType>) { \
+            void test();\
+        };\
+        namespace {\
+        namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestName){ \
+            INTERNAL_CATCH_TYPE_GEN\
+            template<typename...Types>\
+            struct TestNameClass{\
+                void reg_tests(){\
+                    int index = 0;\
+                    using expander = int[];\
+                    (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestName<Types>::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ Name " - " + std::string(INTERNAL_CATCH_STRINGIZE(TmplList)) + " - " + std::to_string(index), Tags } ), index++)... };/* NOLINT */ \
+                }\
+            };\
+            static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\
+                using TestInit = typename convert<TestNameClass, TmplList>::type;\
+                TestInit t;\
+                t.reg_tests();\
+                return 0;\
+            }(); \
+        }}\
+        CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
+        template<typename TestType> \
+        void TestName<TestType>::test()
+
+#define INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD(ClassName, Name, Tags, TmplList) \
+        INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), ClassName, Name, Tags, TmplList )
+
+// end catch_test_registry.h
+// start catch_capture.hpp
+
+// start catch_assertionhandler.h
+
+// start catch_assertioninfo.h
+
+// start catch_result_type.h
+
+namespace Catch {
+
+    // ResultWas::OfType enum
+    struct ResultWas { enum OfType {
+        Unknown = -1,
+        Ok = 0,
+        Info = 1,
+        Warning = 2,
+
+        FailureBit = 0x10,
+
+        ExpressionFailed = FailureBit | 1,
+        ExplicitFailure = FailureBit | 2,
+
+        Exception = 0x100 | FailureBit,
+
+        ThrewException = Exception | 1,
+        DidntThrowException = Exception | 2,
+
+        FatalErrorCondition = 0x200 | FailureBit
+
+    }; };
+
+    bool isOk( ResultWas::OfType resultType );
+    bool isJustInfo( int flags );
+
+    // ResultDisposition::Flags enum
+    struct ResultDisposition { enum Flags {
+        Normal = 0x01,
+
+        ContinueOnFailure = 0x02,   // Failures fail test, but execution continues
+        FalseTest = 0x04,           // Prefix expression with !
+        SuppressFail = 0x08         // Failures are reported but do not fail the test
+    }; };
+
+    ResultDisposition::Flags operator | ( ResultDisposition::Flags lhs, ResultDisposition::Flags rhs );
+
+    bool shouldContinueOnFailure( int flags );
+    inline bool isFalseTest( int flags ) { return ( flags & ResultDisposition::FalseTest ) != 0; }
+    bool shouldSuppressFailure( int flags );
+
+} // end namespace Catch
+
+// end catch_result_type.h
+namespace Catch {
+
+    struct AssertionInfo
+    {
+        StringRef macroName;
+        SourceLineInfo lineInfo;
+        StringRef capturedExpression;
+        ResultDisposition::Flags resultDisposition;
+
+        // We want to delete this constructor but a compiler bug in 4.8 means
+        // the struct is then treated as non-aggregate
+        //AssertionInfo() = delete;
+    };
+
+} // end namespace Catch
+
+// end catch_assertioninfo.h
+// start catch_decomposer.h
+
+// start catch_tostring.h
+
+#include <vector>
+#include <cstddef>
+#include <type_traits>
+#include <string>
+// start catch_stream.h
+
+#include <iosfwd>
+#include <cstddef>
+#include <ostream>
+
+namespace Catch {
+
+    std::ostream& cout();
+    std::ostream& cerr();
+    std::ostream& clog();
+
+    class StringRef;
+
+    struct IStream {
+        virtual ~IStream();
+        virtual std::ostream& stream() const = 0;
+    };
+
+    auto makeStream( StringRef const &filename ) -> IStream const*;
+
+    class ReusableStringStream : NonCopyable {
+        std::size_t m_index;
+        std::ostream* m_oss;
+    public:
+        ReusableStringStream();
+        ~ReusableStringStream();
+
+        auto str() const -> std::string;
+
+        template<typename T>
+        auto operator << ( T const& value ) -> ReusableStringStream& {
+            *m_oss << value;
+            return *this;
+        }
+        auto get() -> std::ostream& { return *m_oss; }
+    };
+}
+
+// end catch_stream.h
+// start catch_interfaces_enum_values_registry.h
+
+#include <vector>
+
+namespace Catch {
+
+    namespace Detail {
+        struct EnumInfo {
+            StringRef m_name;
+            std::vector<std::pair<int, StringRef>> m_values;
+
+            ~EnumInfo();
+
+            StringRef lookup( int value ) const;
+        };
+    } // namespace Detail
+
+    struct IMutableEnumValuesRegistry {
+        virtual ~IMutableEnumValuesRegistry();
+
+        virtual Detail::EnumInfo const& registerEnum( StringRef enumName, StringRef allEnums, std::vector<int> const& values ) = 0;
+
+        template<typename E>
+        Detail::EnumInfo const& registerEnum( StringRef enumName, StringRef allEnums, std::initializer_list<E> values ) {
+            static_assert(sizeof(int) >= sizeof(E), "Cannot serialize enum to int");
+            std::vector<int> intValues;
+            intValues.reserve( values.size() );
+            for( auto enumValue : values )
+                intValues.push_back( static_cast<int>( enumValue ) );
+            return registerEnum( enumName, allEnums, intValues );
+        }
+    };
+
+} // Catch
+
+// end catch_interfaces_enum_values_registry.h
+
+#ifdef CATCH_CONFIG_CPP17_STRING_VIEW
+#include <string_view>
+#endif
+
+#ifdef __OBJC__
+// start catch_objc_arc.hpp
+
+#import <Foundation/Foundation.h>
+
+#ifdef __has_feature
+#define CATCH_ARC_ENABLED __has_feature(objc_arc)
+#else
+#define CATCH_ARC_ENABLED 0
+#endif
+
+void arcSafeRelease( NSObject* obj );
+id performOptionalSelector( id obj, SEL sel );
+
+#if !CATCH_ARC_ENABLED
+inline void arcSafeRelease( NSObject* obj ) {
+    [obj release];
+}
+inline id performOptionalSelector( id obj, SEL sel ) {
+    if( [obj respondsToSelector: sel] )
+        return [obj performSelector: sel];
+    return nil;
+}
+#define CATCH_UNSAFE_UNRETAINED
+#define CATCH_ARC_STRONG
+#else
+inline void arcSafeRelease( NSObject* ){}
+inline id performOptionalSelector( id obj, SEL sel ) {
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
+#endif
+    if( [obj respondsToSelector: sel] )
+        return [obj performSelector: sel];
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+    return nil;
+}
+#define CATCH_UNSAFE_UNRETAINED __unsafe_unretained
+#define CATCH_ARC_STRONG __strong
+#endif
+
+// end catch_objc_arc.hpp
+#endif
+
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable:4180) // We attempt to stream a function (address) by const&, which MSVC complains about but is harmless
+#endif
+
+namespace Catch {
+    namespace Detail {
+
+        extern const std::string unprintableString;
+
+        std::string rawMemoryToString( const void *object, std::size_t size );
+
+        template<typename T>
+        std::string rawMemoryToString( const T& object ) {
+          return rawMemoryToString( &object, sizeof(object) );
+        }
+
+        template<typename T>
+        class IsStreamInsertable {
+            template<typename Stream, typename U>
+            static auto test(int)
+                -> decltype(std::declval<Stream&>() << std::declval<U>(), std::true_type());
+
+            template<typename, typename>
+            static auto test(...)->std::false_type;
+
+        public:
+            static const bool value = decltype(test<std::ostream, const T&>(0))::value;
+        };
+
+        template<typename E>
+        std::string convertUnknownEnumToString( E e );
+
+        template<typename T>
+        typename std::enable_if<
+            !std::is_enum<T>::value && !std::is_base_of<std::exception, T>::value,
+        std::string>::type convertUnstreamable( T const& ) {
+            return Detail::unprintableString;
+        }
+        template<typename T>
+        typename std::enable_if<
+            !std::is_enum<T>::value && std::is_base_of<std::exception, T>::value,
+         std::string>::type convertUnstreamable(T const& ex) {
+            return ex.what();
+        }
+
+        template<typename T>
+        typename std::enable_if<
+            std::is_enum<T>::value
+        , std::string>::type convertUnstreamable( T const& value ) {
+            return convertUnknownEnumToString( value );
+        }
+
+#if defined(_MANAGED)
+        //! Convert a CLR string to a utf8 std::string
+        template<typename T>
+        std::string clrReferenceToString( T^ ref ) {
+            if (ref == nullptr)
+                return std::string("null");
+            auto bytes = System::Text::Encoding::UTF8->GetBytes(ref->ToString());
+            cli::pin_ptr<System::Byte> p = &bytes[0];
+            return std::string(reinterpret_cast<char const *>(p), bytes->Length);
+        }
+#endif
+
+    } // namespace Detail
+
+    // If we decide for C++14, change these to enable_if_ts
+    template <typename T, typename = void>
+    struct StringMaker {
+        template <typename Fake = T>
+        static
+        typename std::enable_if<::Catch::Detail::IsStreamInsertable<Fake>::value, std::string>::type
+            convert(const Fake& value) {
+                ReusableStringStream rss;
+                // NB: call using the function-like syntax to avoid ambiguity with
+                // user-defined templated operator<< under clang.
+                rss.operator<<(value);
+                return rss.str();
+        }
+
+        template <typename Fake = T>
+        static
+        typename std::enable_if<!::Catch::Detail::IsStreamInsertable<Fake>::value, std::string>::type
+            convert( const Fake& value ) {
+#if !defined(CATCH_CONFIG_FALLBACK_STRINGIFIER)
+            return Detail::convertUnstreamable(value);
+#else
+            return CATCH_CONFIG_FALLBACK_STRINGIFIER(value);
+#endif
+        }
+    };
+
+    namespace Detail {
+
+        // This function dispatches all stringification requests inside of Catch.
+        // Should be preferably called fully qualified, like ::Catch::Detail::stringify
+        template <typename T>
+        std::string stringify(const T& e) {
+            return ::Catch::StringMaker<typename std::remove_cv<typename std::remove_reference<T>::type>::type>::convert(e);
+        }
+
+        template<typename E>
+        std::string convertUnknownEnumToString( E e ) {
+            return ::Catch::Detail::stringify(static_cast<typename std::underlying_type<E>::type>(e));
+        }
+
+#if defined(_MANAGED)
+        template <typename T>
+        std::string stringify( T^ e ) {
+            return ::Catch::StringMaker<T^>::convert(e);
+        }
+#endif
+
+    } // namespace Detail
+
+    // Some predefined specializations
+
+    template<>
+    struct StringMaker<std::string> {
+        static std::string convert(const std::string& str);
+    };
+
+#ifdef CATCH_CONFIG_CPP17_STRING_VIEW
+    template<>
+    struct StringMaker<std::string_view> {
+        static std::string convert(std::string_view str);
+    };
+#endif
+
+    template<>
+    struct StringMaker<char const *> {
+        static std::string convert(char const * str);
+    };
+    template<>
+    struct StringMaker<char *> {
+        static std::string convert(char * str);
+    };
+
+#ifdef CATCH_CONFIG_WCHAR
+    template<>
+    struct StringMaker<std::wstring> {
+        static std::string convert(const std::wstring& wstr);
+    };
+
+# ifdef CATCH_CONFIG_CPP17_STRING_VIEW
+    template<>
+    struct StringMaker<std::wstring_view> {
+        static std::string convert(std::wstring_view str);
+    };
+# endif
+
+    template<>
+    struct StringMaker<wchar_t const *> {
+        static std::string convert(wchar_t const * str);
+    };
+    template<>
+    struct StringMaker<wchar_t *> {
+        static std::string convert(wchar_t * str);
+    };
+#endif
+
+    // TBD: Should we use `strnlen` to ensure that we don't go out of the buffer,
+    //      while keeping string semantics?
+    template<int SZ>
+    struct StringMaker<char[SZ]> {
+        static std::string convert(char const* str) {
+            return ::Catch::Detail::stringify(std::string{ str });
+        }
+    };
+    template<int SZ>
+    struct StringMaker<signed char[SZ]> {
+        static std::string convert(signed char const* str) {
+            return ::Catch::Detail::stringify(std::string{ reinterpret_cast<char const *>(str) });
+        }
+    };
+    template<int SZ>
+    struct StringMaker<unsigned char[SZ]> {
+        static std::string convert(unsigned char const* str) {
+            return ::Catch::Detail::stringify(std::string{ reinterpret_cast<char const *>(str) });
+        }
+    };
+
+#if defined(CATCH_CONFIG_CPP17_BYTE)
+    template<>
+    struct StringMaker<std::byte> {
+        static std::string convert(std::byte value);
+    };
+#endif // defined(CATCH_CONFIG_CPP17_BYTE)
+    template<>
+    struct StringMaker<int> {
+        static std::string convert(int value);
+    };
+    template<>
+    struct StringMaker<long> {
+        static std::string convert(long value);
+    };
+    template<>
+    struct StringMaker<long long> {
+        static std::string convert(long long value);
+    };
+    template<>
+    struct StringMaker<unsigned int> {
+        static std::string convert(unsigned int value);
+    };
+    template<>
+    struct StringMaker<unsigned long> {
+        static std::string convert(unsigned long value);
+    };
+    template<>
+    struct StringMaker<unsigned long long> {
+        static std::string convert(unsigned long long value);
+    };
+
+    template<>
+    struct StringMaker<bool> {
+        static std::string convert(bool b);
+    };
+
+    template<>
+    struct StringMaker<char> {
+        static std::string convert(char c);
+    };
+    template<>
+    struct StringMaker<signed char> {
+        static std::string convert(signed char c);
+    };
+    template<>
+    struct StringMaker<unsigned char> {
+        static std::string convert(unsigned char c);
+    };
+
+    template<>
+    struct StringMaker<std::nullptr_t> {
+        static std::string convert(std::nullptr_t);
+    };
+
+    template<>
+    struct StringMaker<float> {
+        static std::string convert(float value);
+        static int precision;
+    };
+
+    template<>
+    struct StringMaker<double> {
+        static std::string convert(double value);
+        static int precision;
+    };
+
+    template <typename T>
+    struct StringMaker<T*> {
+        template <typename U>
+        static std::string convert(U* p) {
+            if (p) {
+                return ::Catch::Detail::rawMemoryToString(p);
+            } else {
+                return "nullptr";
+            }
+        }
+    };
+
+    template <typename R, typename C>
+    struct StringMaker<R C::*> {
+        static std::string convert(R C::* p) {
+            if (p) {
+                return ::Catch::Detail::rawMemoryToString(p);
+            } else {
+                return "nullptr";
+            }
+        }
+    };
+
+#if defined(_MANAGED)
+    template <typename T>
+    struct StringMaker<T^> {
+        static std::string convert( T^ ref ) {
+            return ::Catch::Detail::clrReferenceToString(ref);
+        }
+    };
+#endif
+
+    namespace Detail {
+        template<typename InputIterator, typename Sentinel = InputIterator>
+        std::string rangeToString(InputIterator first, Sentinel last) {
+            ReusableStringStream rss;
+            rss << "{ ";
+            if (first != last) {
+                rss << ::Catch::Detail::stringify(*first);
+                for (++first; first != last; ++first)
+                    rss << ", " << ::Catch::Detail::stringify(*first);
+            }
+            rss << " }";
+            return rss.str();
+        }
+    }
+
+#ifdef __OBJC__
+    template<>
+    struct StringMaker<NSString*> {
+        static std::string convert(NSString * nsstring) {
+            if (!nsstring)
+                return "nil";
+            return std::string("@") + [nsstring UTF8String];
+        }
+    };
+    template<>
+    struct StringMaker<NSObject*> {
+        static std::string convert(NSObject* nsObject) {
+            return ::Catch::Detail::stringify([nsObject description]);
+        }
+
+    };
+    namespace Detail {
+        inline std::string stringify( NSString* nsstring ) {
+            return StringMaker<NSString*>::convert( nsstring );
+        }
+
+    } // namespace Detail
+#endif // __OBJC__
+
+} // namespace Catch
+
+//////////////////////////////////////////////////////
+// Separate std-lib types stringification, so it can be selectively enabled
+// This means that we do not bring in
+
+#if defined(CATCH_CONFIG_ENABLE_ALL_STRINGMAKERS)
+#  define CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER
+#  define CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER
+#  define CATCH_CONFIG_ENABLE_VARIANT_STRINGMAKER
+#  define CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER
+#  define CATCH_CONFIG_ENABLE_OPTIONAL_STRINGMAKER
+#endif
+
+// Separate std::pair specialization
+#if defined(CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER)
+#include <utility>
+namespace Catch {
+    template<typename T1, typename T2>
+    struct StringMaker<std::pair<T1, T2> > {
+        static std::string convert(const std::pair<T1, T2>& pair) {
+            ReusableStringStream rss;
+            rss << "{ "
+                << ::Catch::Detail::stringify(pair.first)
+                << ", "
+                << ::Catch::Detail::stringify(pair.second)
+                << " }";
+            return rss.str();
+        }
+    };
+}
+#endif // CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER
+
+#if defined(CATCH_CONFIG_ENABLE_OPTIONAL_STRINGMAKER) && defined(CATCH_CONFIG_CPP17_OPTIONAL)
+#include <optional>
+namespace Catch {
+    template<typename T>
+    struct StringMaker<std::optional<T> > {
+        static std::string convert(const std::optional<T>& optional) {
+            ReusableStringStream rss;
+            if (optional.has_value()) {
+                rss << ::Catch::Detail::stringify(*optional);
+            } else {
+                rss << "{ }";
+            }
+            return rss.str();
+        }
+    };
+}
+#endif // CATCH_CONFIG_ENABLE_OPTIONAL_STRINGMAKER
+
+// Separate std::tuple specialization
+#if defined(CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER)
+#include <tuple>
+namespace Catch {
+    namespace Detail {
+        template<
+            typename Tuple,
+            std::size_t N = 0,
+            bool = (N < std::tuple_size<Tuple>::value)
+            >
+            struct TupleElementPrinter {
+            static void print(const Tuple& tuple, std::ostream& os) {
+                os << (N ? ", " : " ")
+                    << ::Catch::Detail::stringify(std::get<N>(tuple));
+                TupleElementPrinter<Tuple, N + 1>::print(tuple, os);
+            }
+        };
+
+        template<
+            typename Tuple,
+            std::size_t N
+        >
+            struct TupleElementPrinter<Tuple, N, false> {
+            static void print(const Tuple&, std::ostream&) {}
+        };
+
+    }
+
+    template<typename ...Types>
+    struct StringMaker<std::tuple<Types...>> {
+        static std::string convert(const std::tuple<Types...>& tuple) {
+            ReusableStringStream rss;
+            rss << '{';
+            Detail::TupleElementPrinter<std::tuple<Types...>>::print(tuple, rss.get());
+            rss << " }";
+            return rss.str();
+        }
+    };
+}
+#endif // CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER
+
+#if defined(CATCH_CONFIG_ENABLE_VARIANT_STRINGMAKER) && defined(CATCH_CONFIG_CPP17_VARIANT)
+#include <variant>
+namespace Catch {
+    template<>
+    struct StringMaker<std::monostate> {
+        static std::string convert(const std::monostate&) {
+            return "{ }";
+        }
+    };
+
+    template<typename... Elements>
+    struct StringMaker<std::variant<Elements...>> {
+        static std::string convert(const std::variant<Elements...>& variant) {
+            if (variant.valueless_by_exception()) {
+                return "{valueless variant}";
+            } else {
+                return std::visit(
+                    [](const auto& value) {
+                        return ::Catch::Detail::stringify(value);
+                    },
+                    variant
+                );
+            }
+        }
+    };
+}
+#endif // CATCH_CONFIG_ENABLE_VARIANT_STRINGMAKER
+
+namespace Catch {
+    // Import begin/ end from std here
+    using std::begin;
+    using std::end;
+
+    namespace detail {
+        template <typename...>
+        struct void_type {
+            using type = void;
+        };
+
+        template <typename T, typename = void>
+        struct is_range_impl : std::false_type {
+        };
+
+        template <typename T>
+        struct is_range_impl<T, typename void_type<decltype(begin(std::declval<T>()))>::type> : std::true_type {
+        };
+    } // namespace detail
+
+    template <typename T>
+    struct is_range : detail::is_range_impl<T> {
+    };
+
+#if defined(_MANAGED) // Managed types are never ranges
+    template <typename T>
+    struct is_range<T^> {
+        static const bool value = false;
+    };
+#endif
+
+    template<typename Range>
+    std::string rangeToString( Range const& range ) {
+        return ::Catch::Detail::rangeToString( begin( range ), end( range ) );
+    }
+
+    // Handle vector<bool> specially
+    template<typename Allocator>
+    std::string rangeToString( std::vector<bool, Allocator> const& v ) {
+        ReusableStringStream rss;
+        rss << "{ ";
+        bool first = true;
+        for( bool b : v ) {
+            if( first )
+                first = false;
+            else
+                rss << ", ";
+            rss << ::Catch::Detail::stringify( b );
+        }
+        rss << " }";
+        return rss.str();
+    }
+
+    template<typename R>
+    struct StringMaker<R, typename std::enable_if<is_range<R>::value && !::Catch::Detail::IsStreamInsertable<R>::value>::type> {
+        static std::string convert( R const& range ) {
+            return rangeToString( range );
+        }
+    };
+
+    template <typename T, int SZ>
+    struct StringMaker<T[SZ]> {
+        static std::string convert(T const(&arr)[SZ]) {
+            return rangeToString(arr);
+        }
+    };
+
+} // namespace Catch
+
+// Separate std::chrono::duration specialization
+#if defined(CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER)
+#include <ctime>
+#include <ratio>
+#include <chrono>
+
+namespace Catch {
+
+template <class Ratio>
+struct ratio_string {
+    static std::string symbol();
+};
+
+template <class Ratio>
+std::string ratio_string<Ratio>::symbol() {
+    Catch::ReusableStringStream rss;
+    rss << '[' << Ratio::num << '/'
+        << Ratio::den << ']';
+    return rss.str();
+}
+template <>
+struct ratio_string<std::atto> {
+    static std::string symbol();
+};
+template <>
+struct ratio_string<std::femto> {
+    static std::string symbol();
+};
+template <>
+struct ratio_string<std::pico> {
+    static std::string symbol();
+};
+template <>
+struct ratio_string<std::nano> {
+    static std::string symbol();
+};
+template <>
+struct ratio_string<std::micro> {
+    static std::string symbol();
+};
+template <>
+struct ratio_string<std::milli> {
+    static std::string symbol();
+};
+
+    ////////////
+    // std::chrono::duration specializations
+    template<typename Value, typename Ratio>
+    struct StringMaker<std::chrono::duration<Value, Ratio>> {
+        static std::string convert(std::chrono::duration<Value, Ratio> const& duration) {
+            ReusableStringStream rss;
+            rss << duration.count() << ' ' << ratio_string<Ratio>::symbol() << 's';
+            return rss.str();
+        }
+    };
+    template<typename Value>
+    struct StringMaker<std::chrono::duration<Value, std::ratio<1>>> {
+        static std::string convert(std::chrono::duration<Value, std::ratio<1>> const& duration) {
+            ReusableStringStream rss;
+            rss << duration.count() << " s";
+            return rss.str();
+        }
+    };
+    template<typename Value>
+    struct StringMaker<std::chrono::duration<Value, std::ratio<60>>> {
+        static std::string convert(std::chrono::duration<Value, std::ratio<60>> const& duration) {
+            ReusableStringStream rss;
+            rss << duration.count() << " m";
+            return rss.str();
+        }
+    };
+    template<typename Value>
+    struct StringMaker<std::chrono::duration<Value, std::ratio<3600>>> {
+        static std::string convert(std::chrono::duration<Value, std::ratio<3600>> const& duration) {
+            ReusableStringStream rss;
+            rss << duration.count() << " h";
+            return rss.str();
+        }
+    };
+
+    ////////////
+    // std::chrono::time_point specialization
+    // Generic time_point cannot be specialized, only std::chrono::time_point<system_clock>
+    template<typename Clock, typename Duration>
+    struct StringMaker<std::chrono::time_point<Clock, Duration>> {
+        static std::string convert(std::chrono::time_point<Clock, Duration> const& time_point) {
+            return ::Catch::Detail::stringify(time_point.time_since_epoch()) + " since epoch";
+        }
+    };
+    // std::chrono::time_point<system_clock> specialization
+    template<typename Duration>
+    struct StringMaker<std::chrono::time_point<std::chrono::system_clock, Duration>> {
+        static std::string convert(std::chrono::time_point<std::chrono::system_clock, Duration> const& time_point) {
+            auto converted = std::chrono::system_clock::to_time_t(time_point);
+
+#ifdef _MSC_VER
+            std::tm timeInfo = {};
+            gmtime_s(&timeInfo, &converted);
+#else
+            std::tm* timeInfo = std::gmtime(&converted);
+#endif
+
+            auto const timeStampSize = sizeof("2017-01-16T17:06:45Z");
+            char timeStamp[timeStampSize];
+            const char * const fmt = "%Y-%m-%dT%H:%M:%SZ";
+
+#ifdef _MSC_VER
+            std::strftime(timeStamp, timeStampSize, fmt, &timeInfo);
+#else
+            std::strftime(timeStamp, timeStampSize, fmt, timeInfo);
+#endif
+            return std::string(timeStamp);
+        }
+    };
+}
+#endif // CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER
+
+#define INTERNAL_CATCH_REGISTER_ENUM( enumName, ... ) \
+namespace Catch { \
+    template<> struct StringMaker<enumName> { \
+        static std::string convert( enumName value ) { \
+            static const auto& enumInfo = ::Catch::getMutableRegistryHub().getMutableEnumValuesRegistry().registerEnum( #enumName, #__VA_ARGS__, { __VA_ARGS__ } ); \
+            return static_cast<std::string>(enumInfo.lookup( static_cast<int>( value ) )); \
+        } \
+    }; \
+}
+
+#define CATCH_REGISTER_ENUM( enumName, ... ) INTERNAL_CATCH_REGISTER_ENUM( enumName, __VA_ARGS__ )
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+// end catch_tostring.h
+#include <iosfwd>
+
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable:4389) // '==' : signed/unsigned mismatch
+#pragma warning(disable:4018) // more "signed/unsigned mismatch"
+#pragma warning(disable:4312) // Converting int to T* using reinterpret_cast (issue on x64 platform)
+#pragma warning(disable:4180) // qualifier applied to function type has no meaning
+#pragma warning(disable:4800) // Forcing result to true or false
+#endif
+
+namespace Catch {
+
+    struct ITransientExpression {
+        auto isBinaryExpression() const -> bool { return m_isBinaryExpression; }
+        auto getResult() const -> bool { return m_result; }
+        virtual void streamReconstructedExpression( std::ostream &os ) const = 0;
+
+        ITransientExpression( bool isBinaryExpression, bool result )
+        :   m_isBinaryExpression( isBinaryExpression ),
+            m_result( result )
+        {}
+
+        // We don't actually need a virtual destructor, but many static analysers
+        // complain if it's not here :-(
+        virtual ~ITransientExpression();
+
+        bool m_isBinaryExpression;
+        bool m_result;
+
+    };
+
+    void formatReconstructedExpression( std::ostream &os, std::string const& lhs, StringRef op, std::string const& rhs );
+
+    template<typename LhsT, typename RhsT>
+    class BinaryExpr  : public ITransientExpression {
+        LhsT m_lhs;
+        StringRef m_op;
+        RhsT m_rhs;
+
+        void streamReconstructedExpression( std::ostream &os ) const override {
+            formatReconstructedExpression
+                    ( os, Catch::Detail::stringify( m_lhs ), m_op, Catch::Detail::stringify( m_rhs ) );
+        }
+
+    public:
+        BinaryExpr( bool comparisonResult, LhsT lhs, StringRef op, RhsT rhs )
+        :   ITransientExpression{ true, comparisonResult },
+            m_lhs( lhs ),
+            m_op( op ),
+            m_rhs( rhs )
+        {}
+
+        template<typename T>
+        auto operator && ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {
+            static_assert(always_false<T>::value,
+            "chained comparisons are not supported inside assertions, "
+            "wrap the expression inside parentheses, or decompose it");
+        }
+
+        template<typename T>
+        auto operator || ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {
+            static_assert(always_false<T>::value,
+            "chained comparisons are not supported inside assertions, "
+            "wrap the expression inside parentheses, or decompose it");
+        }
+
+        template<typename T>
+        auto operator == ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {
+            static_assert(always_false<T>::value,
+            "chained comparisons are not supported inside assertions, "
+            "wrap the expression inside parentheses, or decompose it");
+        }
+
+        template<typename T>
+        auto operator != ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {
+            static_assert(always_false<T>::value,
+            "chained comparisons are not supported inside assertions, "
+            "wrap the expression inside parentheses, or decompose it");
+        }
+
+        template<typename T>
+        auto operator > ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {
+            static_assert(always_false<T>::value,
+            "chained comparisons are not supported inside assertions, "
+            "wrap the expression inside parentheses, or decompose it");
+        }
+
+        template<typename T>
+        auto operator < ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {
+            static_assert(always_false<T>::value,
+            "chained comparisons are not supported inside assertions, "
+            "wrap the expression inside parentheses, or decompose it");
+        }
+
+        template<typename T>
+        auto operator >= ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {
+            static_assert(always_false<T>::value,
+            "chained comparisons are not supported inside assertions, "
+            "wrap the expression inside parentheses, or decompose it");
+        }
+
+        template<typename T>
+        auto operator <= ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {
+            static_assert(always_false<T>::value,
+            "chained comparisons are not supported inside assertions, "
+            "wrap the expression inside parentheses, or decompose it");
+        }
+    };
+
+    template<typename LhsT>
+    class UnaryExpr : public ITransientExpression {
+        LhsT m_lhs;
+
+        void streamReconstructedExpression( std::ostream &os ) const override {
+            os << Catch::Detail::stringify( m_lhs );
+        }
+
+    public:
+        explicit UnaryExpr( LhsT lhs )
+        :   ITransientExpression{ false, static_cast<bool>(lhs) },
+            m_lhs( lhs )
+        {}
+    };
+
+    // Specialised comparison functions to handle equality comparisons between ints and pointers (NULL deduces as an int)
+    template<typename LhsT, typename RhsT>
+    auto compareEqual( LhsT const& lhs, RhsT const& rhs ) -> bool { return static_cast<bool>(lhs == rhs); }
+    template<typename T>
+    auto compareEqual( T* const& lhs, int rhs ) -> bool { return lhs == reinterpret_cast<void const*>( rhs ); }
+    template<typename T>
+    auto compareEqual( T* const& lhs, long rhs ) -> bool { return lhs == reinterpret_cast<void const*>( rhs ); }
+    template<typename T>
+    auto compareEqual( int lhs, T* const& rhs ) -> bool { return reinterpret_cast<void const*>( lhs ) == rhs; }
+    template<typename T>
+    auto compareEqual( long lhs, T* const& rhs ) -> bool { return reinterpret_cast<void const*>( lhs ) == rhs; }
+
+    template<typename LhsT, typename RhsT>
+    auto compareNotEqual( LhsT const& lhs, RhsT&& rhs ) -> bool { return static_cast<bool>(lhs != rhs); }
+    template<typename T>
+    auto compareNotEqual( T* const& lhs, int rhs ) -> bool { return lhs != reinterpret_cast<void const*>( rhs ); }
+    template<typename T>
+    auto compareNotEqual( T* const& lhs, long rhs ) -> bool { return lhs != reinterpret_cast<void const*>( rhs ); }
+    template<typename T>
+    auto compareNotEqual( int lhs, T* const& rhs ) -> bool { return reinterpret_cast<void const*>( lhs ) != rhs; }
+    template<typename T>
+    auto compareNotEqual( long lhs, T* const& rhs ) -> bool { return reinterpret_cast<void const*>( lhs ) != rhs; }
+
+    template<typename LhsT>
+    class ExprLhs {
+        LhsT m_lhs;
+    public:
+        explicit ExprLhs( LhsT lhs ) : m_lhs( lhs ) {}
+
+        template<typename RhsT>
+        auto operator == ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const {
+            return { compareEqual( m_lhs, rhs ), m_lhs, "==", rhs };
+        }
+        auto operator == ( bool rhs ) -> BinaryExpr<LhsT, bool> const {
+            return { m_lhs == rhs, m_lhs, "==", rhs };
+        }
+
+        template<typename RhsT>
+        auto operator != ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const {
+            return { compareNotEqual( m_lhs, rhs ), m_lhs, "!=", rhs };
+        }
+        auto operator != ( bool rhs ) -> BinaryExpr<LhsT, bool> const {
+            return { m_lhs != rhs, m_lhs, "!=", rhs };
+        }
+
+        template<typename RhsT>
+        auto operator > ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const {
+            return { static_cast<bool>(m_lhs > rhs), m_lhs, ">", rhs };
+        }
+        template<typename RhsT>
+        auto operator < ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const {
+            return { static_cast<bool>(m_lhs < rhs), m_lhs, "<", rhs };
+        }
+        template<typename RhsT>
+        auto operator >= ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const {
+            return { static_cast<bool>(m_lhs >= rhs), m_lhs, ">=", rhs };
+        }
+        template<typename RhsT>
+        auto operator <= ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const {
+            return { static_cast<bool>(m_lhs <= rhs), m_lhs, "<=", rhs };
+        }
+        template <typename RhsT>
+        auto operator | (RhsT const& rhs) -> BinaryExpr<LhsT, RhsT const&> const {
+            return { static_cast<bool>(m_lhs | rhs), m_lhs, "|", rhs };
+        }
+        template <typename RhsT>
+        auto operator & (RhsT const& rhs) -> BinaryExpr<LhsT, RhsT const&> const {
+            return { static_cast<bool>(m_lhs & rhs), m_lhs, "&", rhs };
+        }
+        template <typename RhsT>
+        auto operator ^ (RhsT const& rhs) -> BinaryExpr<LhsT, RhsT const&> const {
+            return { static_cast<bool>(m_lhs ^ rhs), m_lhs, "^", rhs };
+        }
+
+        template<typename RhsT>
+        auto operator && ( RhsT const& ) -> BinaryExpr<LhsT, RhsT const&> const {
+            static_assert(always_false<RhsT>::value,
+            "operator&& is not supported inside assertions, "
+            "wrap the expression inside parentheses, or decompose it");
+        }
+
+        template<typename RhsT>
+        auto operator || ( RhsT const& ) -> BinaryExpr<LhsT, RhsT const&> const {
+            static_assert(always_false<RhsT>::value,
+            "operator|| is not supported inside assertions, "
+            "wrap the expression inside parentheses, or decompose it");
+        }
+
+        auto makeUnaryExpr() const -> UnaryExpr<LhsT> {
+            return UnaryExpr<LhsT>{ m_lhs };
+        }
+    };
+
+    void handleExpression( ITransientExpression const& expr );
+
+    template<typename T>
+    void handleExpression( ExprLhs<T> const& expr ) {
+        handleExpression( expr.makeUnaryExpr() );
+    }
+
+    struct Decomposer {
+        template<typename T>
+        auto operator <= ( T const& lhs ) -> ExprLhs<T const&> {
+            return ExprLhs<T const&>{ lhs };
+        }
+
+        auto operator <=( bool value ) -> ExprLhs<bool> {
+            return ExprLhs<bool>{ value };
+        }
+    };
+
+} // end namespace Catch
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+// end catch_decomposer.h
+// start catch_interfaces_capture.h
+
+#include <string>
+#include <chrono>
+
+namespace Catch {
+
+    class AssertionResult;
+    struct AssertionInfo;
+    struct SectionInfo;
+    struct SectionEndInfo;
+    struct MessageInfo;
+    struct MessageBuilder;
+    struct Counts;
+    struct AssertionReaction;
+    struct SourceLineInfo;
+
+    struct ITransientExpression;
+    struct IGeneratorTracker;
+
+#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
+    struct BenchmarkInfo;
+    template <typename Duration = std::chrono::duration<double, std::nano>>
+    struct BenchmarkStats;
+#endif // CATCH_CONFIG_ENABLE_BENCHMARKING
+
+    struct IResultCapture {
+
+        virtual ~IResultCapture();
+
+        virtual bool sectionStarted(    SectionInfo const& sectionInfo,
+                                        Counts& assertions ) = 0;
+        virtual void sectionEnded( SectionEndInfo const& endInfo ) = 0;
+        virtual void sectionEndedEarly( SectionEndInfo const& endInfo ) = 0;
+
+        virtual auto acquireGeneratorTracker( StringRef generatorName, SourceLineInfo const& lineInfo ) -> IGeneratorTracker& = 0;
+
+#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
+        virtual void benchmarkPreparing( std::string const& name ) = 0;
+        virtual void benchmarkStarting( BenchmarkInfo const& info ) = 0;
+        virtual void benchmarkEnded( BenchmarkStats<> const& stats ) = 0;
+        virtual void benchmarkFailed( std::string const& error ) = 0;
+#endif // CATCH_CONFIG_ENABLE_BENCHMARKING
+
+        virtual void pushScopedMessage( MessageInfo const& message ) = 0;
+        virtual void popScopedMessage( MessageInfo const& message ) = 0;
+
+        virtual void emplaceUnscopedMessage( MessageBuilder const& builder ) = 0;
+
+        virtual void handleFatalErrorCondition( StringRef message ) = 0;
+
+        virtual void handleExpr
+                (   AssertionInfo const& info,
+                    ITransientExpression const& expr,
+                    AssertionReaction& reaction ) = 0;
+        virtual void handleMessage
+                (   AssertionInfo const& info,
+                    ResultWas::OfType resultType,
+                    StringRef const& message,
+                    AssertionReaction& reaction ) = 0;
+        virtual void handleUnexpectedExceptionNotThrown
+                (   AssertionInfo const& info,
+                    AssertionReaction& reaction ) = 0;
+        virtual void handleUnexpectedInflightException
+                (   AssertionInfo const& info,
+                    std::string const& message,
+                    AssertionReaction& reaction ) = 0;
+        virtual void handleIncomplete
+                (   AssertionInfo const& info ) = 0;
+        virtual void handleNonExpr
+                (   AssertionInfo const &info,
+                    ResultWas::OfType resultType,
+                    AssertionReaction &reaction ) = 0;
+
+        virtual bool lastAssertionPassed() = 0;
+        virtual void assertionPassed() = 0;
+
+        // Deprecated, do not use:
+        virtual std::string getCurrentTestName() const = 0;
+        virtual const AssertionResult* getLastResult() const = 0;
+        virtual void exceptionEarlyReported() = 0;
+    };
+
+    IResultCapture& getResultCapture();
+}
+
+// end catch_interfaces_capture.h
+namespace Catch {
+
+    struct TestFailureException{};
+    struct AssertionResultData;
+    struct IResultCapture;
+    class RunContext;
+
+    class LazyExpression {
+        friend class AssertionHandler;
+        friend struct AssertionStats;
+        friend class RunContext;
+
+        ITransientExpression const* m_transientExpression = nullptr;
+        bool m_isNegated;
+    public:
+        LazyExpression( bool isNegated );
+        LazyExpression( LazyExpression const& other );
+        LazyExpression& operator = ( LazyExpression const& ) = delete;
+
+        explicit operator bool() const;
+
+        friend auto operator << ( std::ostream& os, LazyExpression const& lazyExpr ) -> std::ostream&;
+    };
+
+    struct AssertionReaction {
+        bool shouldDebugBreak = false;
+        bool shouldThrow = false;
+    };
+
+    class AssertionHandler {
+        AssertionInfo m_assertionInfo;
+        AssertionReaction m_reaction;
+        bool m_completed = false;
+        IResultCapture& m_resultCapture;
+
+    public:
+        AssertionHandler
+            (   StringRef const& macroName,
+                SourceLineInfo const& lineInfo,
+                StringRef capturedExpression,
+                ResultDisposition::Flags resultDisposition );
+        ~AssertionHandler() {
+            if ( !m_completed ) {
+                m_resultCapture.handleIncomplete( m_assertionInfo );
+            }
+        }
+
+        template<typename T>
+        void handleExpr( ExprLhs<T> const& expr ) {
+            handleExpr( expr.makeUnaryExpr() );
+        }
+        void handleExpr( ITransientExpression const& expr );
+
+        void handleMessage(ResultWas::OfType resultType, StringRef const& message);
+
+        void handleExceptionThrownAsExpected();
+        void handleUnexpectedExceptionNotThrown();
+        void handleExceptionNotThrownAsExpected();
+        void handleThrowingCallSkipped();
+        void handleUnexpectedInflightException();
+
+        void complete();
+        void setCompleted();
+
+        // query
+        auto allowThrows() const -> bool;
+    };
+
+    void handleExceptionMatchExpr( AssertionHandler& handler, std::string const& str, StringRef const& matcherString );
+
+} // namespace Catch
+
+// end catch_assertionhandler.h
+// start catch_message.h
+
+#include <string>
+#include <vector>
+
+namespace Catch {
+
+    struct MessageInfo {
+        MessageInfo(    StringRef const& _macroName,
+                        SourceLineInfo const& _lineInfo,
+                        ResultWas::OfType _type );
+
+        StringRef macroName;
+        std::string message;
+        SourceLineInfo lineInfo;
+        ResultWas::OfType type;
+        unsigned int sequence;
+
+        bool operator == ( MessageInfo const& other ) const;
+        bool operator < ( MessageInfo const& other ) const;
+    private:
+        static unsigned int globalCount;
+    };
+
+    struct MessageStream {
+
+        template<typename T>
+        MessageStream& operator << ( T const& value ) {
+            m_stream << value;
+            return *this;
+        }
+
+        ReusableStringStream m_stream;
+    };
+
+    struct MessageBuilder : MessageStream {
+        MessageBuilder( StringRef const& macroName,
+                        SourceLineInfo const& lineInfo,
+                        ResultWas::OfType type );
+
+        template<typename T>
+        MessageBuilder& operator << ( T const& value ) {
+            m_stream << value;
+            return *this;
+        }
+
+        MessageInfo m_info;
+    };
+
+    class ScopedMessage {
+    public:
+        explicit ScopedMessage( MessageBuilder const& builder );
+        ScopedMessage( ScopedMessage& duplicate ) = delete;
+        ScopedMessage( ScopedMessage&& old );
+        ~ScopedMessage();
+
+        MessageInfo m_info;
+        bool m_moved;
+    };
+
+    class Capturer {
+        std::vector<MessageInfo> m_messages;
+        IResultCapture& m_resultCapture = getResultCapture();
+        size_t m_captured = 0;
+    public:
+        Capturer( StringRef macroName, SourceLineInfo const& lineInfo, ResultWas::OfType resultType, StringRef names );
+        ~Capturer();
+
+        void captureValue( size_t index, std::string const& value );
+
+        template<typename T>
+        void captureValues( size_t index, T const& value ) {
+            captureValue( index, Catch::Detail::stringify( value ) );
+        }
+
+        template<typename T, typename... Ts>
+        void captureValues( size_t index, T const& value, Ts const&... values ) {
+            captureValue( index, Catch::Detail::stringify(value) );
+            captureValues( index+1, values... );
+        }
+    };
+
+} // end namespace Catch
+
+// end catch_message.h
+#if !defined(CATCH_CONFIG_DISABLE)
+
+#if !defined(CATCH_CONFIG_DISABLE_STRINGIFICATION)
+  #define CATCH_INTERNAL_STRINGIFY(...) #__VA_ARGS__
+#else
+  #define CATCH_INTERNAL_STRINGIFY(...) "Disabled by CATCH_CONFIG_DISABLE_STRINGIFICATION"
+#endif
+
+#if defined(CATCH_CONFIG_FAST_COMPILE) || defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
+
+///////////////////////////////////////////////////////////////////////////////
+// Another way to speed-up compilation is to omit local try-catch for REQUIRE*
+// macros.
+#define INTERNAL_CATCH_TRY
+#define INTERNAL_CATCH_CATCH( capturer )
+
+#else // CATCH_CONFIG_FAST_COMPILE
+
+#define INTERNAL_CATCH_TRY try
+#define INTERNAL_CATCH_CATCH( handler ) catch(...) { handler.handleUnexpectedInflightException(); }
+
+#endif
+
+#define INTERNAL_CATCH_REACT( handler ) handler.complete();
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_TEST( macroName, resultDisposition, ... ) \
+    do { \
+        CATCH_INTERNAL_IGNORE_BUT_WARN(__VA_ARGS__); \
+        Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition ); \
+        INTERNAL_CATCH_TRY { \
+            CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
+            CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \
+            catchAssertionHandler.handleExpr( Catch::Decomposer() <= __VA_ARGS__ ); \
+            CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
+        } INTERNAL_CATCH_CATCH( catchAssertionHandler ) \
+        INTERNAL_CATCH_REACT( catchAssertionHandler ) \
+    } while( (void)0, (false) && static_cast<bool>( !!(__VA_ARGS__) ) )
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_IF( macroName, resultDisposition, ... ) \
+    INTERNAL_CATCH_TEST( macroName, resultDisposition, __VA_ARGS__ ); \
+    if( Catch::getResultCapture().lastAssertionPassed() )
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_ELSE( macroName, resultDisposition, ... ) \
+    INTERNAL_CATCH_TEST( macroName, resultDisposition, __VA_ARGS__ ); \
+    if( !Catch::getResultCapture().lastAssertionPassed() )
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_NO_THROW( macroName, resultDisposition, ... ) \
+    do { \
+        Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition ); \
+        try { \
+            static_cast<void>(__VA_ARGS__); \
+            catchAssertionHandler.handleExceptionNotThrownAsExpected(); \
+        } \
+        catch( ... ) { \
+            catchAssertionHandler.handleUnexpectedInflightException(); \
+        } \
+        INTERNAL_CATCH_REACT( catchAssertionHandler ) \
+    } while( false )
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_THROWS( macroName, resultDisposition, ... ) \
+    do { \
+        Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition); \
+        if( catchAssertionHandler.allowThrows() ) \
+            try { \
+                static_cast<void>(__VA_ARGS__); \
+                catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \
+            } \
+            catch( ... ) { \
+                catchAssertionHandler.handleExceptionThrownAsExpected(); \
+            } \
+        else \
+            catchAssertionHandler.handleThrowingCallSkipped(); \
+        INTERNAL_CATCH_REACT( catchAssertionHandler ) \
+    } while( false )
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_THROWS_AS( macroName, exceptionType, resultDisposition, expr ) \
+    do { \
+        Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(expr) ", " CATCH_INTERNAL_STRINGIFY(exceptionType), resultDisposition ); \
+        if( catchAssertionHandler.allowThrows() ) \
+            try { \
+                static_cast<void>(expr); \
+                catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \
+            } \
+            catch( exceptionType const& ) { \
+                catchAssertionHandler.handleExceptionThrownAsExpected(); \
+            } \
+            catch( ... ) { \
+                catchAssertionHandler.handleUnexpectedInflightException(); \
+            } \
+        else \
+            catchAssertionHandler.handleThrowingCallSkipped(); \
+        INTERNAL_CATCH_REACT( catchAssertionHandler ) \
+    } while( false )
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_MSG( macroName, messageType, resultDisposition, ... ) \
+    do { \
+        Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, Catch::StringRef(), resultDisposition ); \
+        catchAssertionHandler.handleMessage( messageType, ( Catch::MessageStream() << __VA_ARGS__ + ::Catch::StreamEndStop() ).m_stream.str() ); \
+        INTERNAL_CATCH_REACT( catchAssertionHandler ) \
+    } while( false )
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_CAPTURE( varName, macroName, ... ) \
+    auto varName = Catch::Capturer( macroName, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info, #__VA_ARGS__ ); \
+    varName.captureValues( 0, __VA_ARGS__ )
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_INFO( macroName, log ) \
+    Catch::ScopedMessage INTERNAL_CATCH_UNIQUE_NAME( scopedMessage )( Catch::MessageBuilder( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log );
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_UNSCOPED_INFO( macroName, log ) \
+    Catch::getResultCapture().emplaceUnscopedMessage( Catch::MessageBuilder( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log )
+
+///////////////////////////////////////////////////////////////////////////////
+// Although this is matcher-based, it can be used with just a string
+#define INTERNAL_CATCH_THROWS_STR_MATCHES( macroName, resultDisposition, matcher, ... ) \
+    do { \
+        Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \
+        if( catchAssertionHandler.allowThrows() ) \
+            try { \
+                static_cast<void>(__VA_ARGS__); \
+                catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \
+            } \
+            catch( ... ) { \
+                Catch::handleExceptionMatchExpr( catchAssertionHandler, matcher, #matcher##_catch_sr ); \
+            } \
+        else \
+            catchAssertionHandler.handleThrowingCallSkipped(); \
+        INTERNAL_CATCH_REACT( catchAssertionHandler ) \
+    } while( false )
+
+#endif // CATCH_CONFIG_DISABLE
+
+// end catch_capture.hpp
+// start catch_section.h
+
+// start catch_section_info.h
+
+// start catch_totals.h
+
+#include <cstddef>
+
+namespace Catch {
+
+    struct Counts {
+        Counts operator - ( Counts const& other ) const;
+        Counts& operator += ( Counts const& other );
+
+        std::size_t total() const;
+        bool allPassed() const;
+        bool allOk() const;
+
+        std::size_t passed = 0;
+        std::size_t failed = 0;
+        std::size_t failedButOk = 0;
+    };
+
+    struct Totals {
+
+        Totals operator - ( Totals const& other ) const;
+        Totals& operator += ( Totals const& other );
+
+        Totals delta( Totals const& prevTotals ) const;
+
+        int error = 0;
+        Counts assertions;
+        Counts testCases;
+    };
+}
+
+// end catch_totals.h
+#include <string>
+
+namespace Catch {
+
+    struct SectionInfo {
+        SectionInfo
+            (   SourceLineInfo const& _lineInfo,
+                std::string const& _name );
+
+        // Deprecated
+        SectionInfo
+            (   SourceLineInfo const& _lineInfo,
+                std::string const& _name,
+                std::string const& ) : SectionInfo( _lineInfo, _name ) {}
+
+        std::string name;
+        std::string description; // !Deprecated: this will always be empty
+        SourceLineInfo lineInfo;
+    };
+
+    struct SectionEndInfo {
+        SectionInfo sectionInfo;
+        Counts prevAssertions;
+        double durationInSeconds;
+    };
+
+} // end namespace Catch
+
+// end catch_section_info.h
+// start catch_timer.h
+
+#include <cstdint>
+
+namespace Catch {
+
+    auto getCurrentNanosecondsSinceEpoch() -> uint64_t;
+    auto getEstimatedClockResolution() -> uint64_t;
+
+    class Timer {
+        uint64_t m_nanoseconds = 0;
+    public:
+        void start();
+        auto getElapsedNanoseconds() const -> uint64_t;
+        auto getElapsedMicroseconds() const -> uint64_t;
+        auto getElapsedMilliseconds() const -> unsigned int;
+        auto getElapsedSeconds() const -> double;
+    };
+
+} // namespace Catch
+
+// end catch_timer.h
+#include <string>
+
+namespace Catch {
+
+    class Section : NonCopyable {
+    public:
+        Section( SectionInfo const& info );
+        ~Section();
+
+        // This indicates whether the section should be executed or not
+        explicit operator bool() const;
+
+    private:
+        SectionInfo m_info;
+
+        std::string m_name;
+        Counts m_assertions;
+        bool m_sectionIncluded;
+        Timer m_timer;
+    };
+
+} // end namespace Catch
+
+#define INTERNAL_CATCH_SECTION( ... ) \
+    CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
+    CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS \
+    if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, __VA_ARGS__ ) ) \
+    CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
+
+#define INTERNAL_CATCH_DYNAMIC_SECTION( ... ) \
+    CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
+    CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS \
+    if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, (Catch::ReusableStringStream() << __VA_ARGS__).str() ) ) \
+    CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
+
+// end catch_section.h
+// start catch_interfaces_exception.h
+
+// start catch_interfaces_registry_hub.h
+
+#include <string>
+#include <memory>
+
+namespace Catch {
+
+    class TestCase;
+    struct ITestCaseRegistry;
+    struct IExceptionTranslatorRegistry;
+    struct IExceptionTranslator;
+    struct IReporterRegistry;
+    struct IReporterFactory;
+    struct ITagAliasRegistry;
+    struct IMutableEnumValuesRegistry;
+
+    class StartupExceptionRegistry;
+
+    using IReporterFactoryPtr = std::shared_ptr<IReporterFactory>;
+
+    struct IRegistryHub {
+        virtual ~IRegistryHub();
+
+        virtual IReporterRegistry const& getReporterRegistry() const = 0;
+        virtual ITestCaseRegistry const& getTestCaseRegistry() const = 0;
+        virtual ITagAliasRegistry const& getTagAliasRegistry() const = 0;
+        virtual IExceptionTranslatorRegistry const& getExceptionTranslatorRegistry() const = 0;
+
+        virtual StartupExceptionRegistry const& getStartupExceptionRegistry() const = 0;
+    };
+
+    struct IMutableRegistryHub {
+        virtual ~IMutableRegistryHub();
+        virtual void registerReporter( std::string const& name, IReporterFactoryPtr const& factory ) = 0;
+        virtual void registerListener( IReporterFactoryPtr const& factory ) = 0;
+        virtual void registerTest( TestCase const& testInfo ) = 0;
+        virtual void registerTranslator( const IExceptionTranslator* translator ) = 0;
+        virtual void registerTagAlias( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) = 0;
+        virtual void registerStartupException() noexcept = 0;
+        virtual IMutableEnumValuesRegistry& getMutableEnumValuesRegistry() = 0;
+    };
+
+    IRegistryHub const& getRegistryHub();
+    IMutableRegistryHub& getMutableRegistryHub();
+    void cleanUp();
+    std::string translateActiveException();
+
+}
+
+// end catch_interfaces_registry_hub.h
+#if defined(CATCH_CONFIG_DISABLE)
+    #define INTERNAL_CATCH_TRANSLATE_EXCEPTION_NO_REG( translatorName, signature) \
+        static std::string translatorName( signature )
+#endif
+
+#include <exception>
+#include <string>
+#include <vector>
+
+namespace Catch {
+    using exceptionTranslateFunction = std::string(*)();
+
+    struct IExceptionTranslator;
+    using ExceptionTranslators = std::vector<std::unique_ptr<IExceptionTranslator const>>;
+
+    struct IExceptionTranslator {
+        virtual ~IExceptionTranslator();
+        virtual std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const = 0;
+    };
+
+    struct IExceptionTranslatorRegistry {
+        virtual ~IExceptionTranslatorRegistry();
+
+        virtual std::string translateActiveException() const = 0;
+    };
+
+    class ExceptionTranslatorRegistrar {
+        template<typename T>
+        class ExceptionTranslator : public IExceptionTranslator {
+        public:
+
+            ExceptionTranslator( std::string(*translateFunction)( T& ) )
+            : m_translateFunction( translateFunction )
+            {}
+
+            std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const override {
+#if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
+                return "";
+#else
+                try {
+                    if( it == itEnd )
+                        std::rethrow_exception(std::current_exception());
+                    else
+                        return (*it)->translate( it+1, itEnd );
+                }
+                catch( T& ex ) {
+                    return m_translateFunction( ex );
+                }
+#endif
+            }
+
+        protected:
+            std::string(*m_translateFunction)( T& );
+        };
+
+    public:
+        template<typename T>
+        ExceptionTranslatorRegistrar( std::string(*translateFunction)( T& ) ) {
+            getMutableRegistryHub().registerTranslator
+                ( new ExceptionTranslator<T>( translateFunction ) );
+        }
+    };
+}
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_TRANSLATE_EXCEPTION2( translatorName, signature ) \
+    static std::string translatorName( signature ); \
+    CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
+    CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
+    namespace{ Catch::ExceptionTranslatorRegistrar INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionRegistrar )( &translatorName ); } \
+    CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
+    static std::string translatorName( signature )
+
+#define INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION2( INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ), signature )
+
+// end catch_interfaces_exception.h
+// start catch_approx.h
+
+#include <type_traits>
+
+namespace Catch {
+namespace Detail {
+
+    class Approx {
+    private:
+        bool equalityComparisonImpl(double other) const;
+        // Validates the new margin (margin >= 0)
+        // out-of-line to avoid including stdexcept in the header
+        void setMargin(double margin);
+        // Validates the new epsilon (0 < epsilon < 1)
+        // out-of-line to avoid including stdexcept in the header
+        void setEpsilon(double epsilon);
+
+    public:
+        explicit Approx ( double value );
+
+        static Approx custom();
+
+        Approx operator-() const;
+
+        template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
+        Approx operator()( T const& value ) {
+            Approx approx( static_cast<double>(value) );
+            approx.m_epsilon = m_epsilon;
+            approx.m_margin = m_margin;
+            approx.m_scale = m_scale;
+            return approx;
+        }
+
+        template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
+        explicit Approx( T const& value ): Approx(static_cast<double>(value))
+        {}
+
+        template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
+        friend bool operator == ( const T& lhs, Approx const& rhs ) {
+            auto lhs_v = static_cast<double>(lhs);
+            return rhs.equalityComparisonImpl(lhs_v);
+        }
+
+        template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
+        friend bool operator == ( Approx const& lhs, const T& rhs ) {
+            return operator==( rhs, lhs );
+        }
+
+        template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
+        friend bool operator != ( T const& lhs, Approx const& rhs ) {
+            return !operator==( lhs, rhs );
+        }
+
+        template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
+        friend bool operator != ( Approx const& lhs, T const& rhs ) {
+            return !operator==( rhs, lhs );
+        }
+
+        template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
+        friend bool operator <= ( T const& lhs, Approx const& rhs ) {
+            return static_cast<double>(lhs) < rhs.m_value || lhs == rhs;
+        }
+
+        template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
+        friend bool operator <= ( Approx const& lhs, T const& rhs ) {
+            return lhs.m_value < static_cast<double>(rhs) || lhs == rhs;
+        }
+
+        template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
+        friend bool operator >= ( T const& lhs, Approx const& rhs ) {
+            return static_cast<double>(lhs) > rhs.m_value || lhs == rhs;
+        }
+
+        template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
+        friend bool operator >= ( Approx const& lhs, T const& rhs ) {
+            return lhs.m_value > static_cast<double>(rhs) || lhs == rhs;
+        }
+
+        template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
+        Approx& epsilon( T const& newEpsilon ) {
+            double epsilonAsDouble = static_cast<double>(newEpsilon);
+            setEpsilon(epsilonAsDouble);
+            return *this;
+        }
+
+        template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
+        Approx& margin( T const& newMargin ) {
+            double marginAsDouble = static_cast<double>(newMargin);
+            setMargin(marginAsDouble);
+            return *this;
+        }
+
+        template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
+        Approx& scale( T const& newScale ) {
+            m_scale = static_cast<double>(newScale);
+            return *this;
+        }
+
+        std::string toString() const;
+
+    private:
+        double m_epsilon;
+        double m_margin;
+        double m_scale;
+        double m_value;
+    };
+} // end namespace Detail
+
+namespace literals {
+    Detail::Approx operator "" _a(long double val);
+    Detail::Approx operator "" _a(unsigned long long val);
+} // end namespace literals
+
+template<>
+struct StringMaker<Catch::Detail::Approx> {
+    static std::string convert(Catch::Detail::Approx const& value);
+};
+
+} // end namespace Catch
+
+// end catch_approx.h
+// start catch_string_manip.h
+
+#include <string>
+#include <iosfwd>
+#include <vector>
+
+namespace Catch {
+
+    bool startsWith( std::string const& s, std::string const& prefix );
+    bool startsWith( std::string const& s, char prefix );
+    bool endsWith( std::string const& s, std::string const& suffix );
+    bool endsWith( std::string const& s, char suffix );
+    bool contains( std::string const& s, std::string const& infix );
+    void toLowerInPlace( std::string& s );
+    std::string toLower( std::string const& s );
+    //! Returns a new string without whitespace at the start/end
+    std::string trim( std::string const& str );
+    //! Returns a substring of the original ref without whitespace. Beware lifetimes!
+    StringRef trim(StringRef ref);
+
+    // !!! Be aware, returns refs into original string - make sure original string outlives them
+    std::vector<StringRef> splitStringRef( StringRef str, char delimiter );
+    bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis );
+
+    struct pluralise {
+        pluralise( std::size_t count, std::string const& label );
+
+        friend std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser );
+
+        std::size_t m_count;
+        std::string m_label;
+    };
+}
+
+// end catch_string_manip.h
+#ifndef CATCH_CONFIG_DISABLE_MATCHERS
+// start catch_capture_matchers.h
+
+// start catch_matchers.h
+
+#include <string>
+#include <vector>
+
+namespace Catch {
+namespace Matchers {
+    namespace Impl {
+
+        template<typename ArgT> struct MatchAllOf;
+        template<typename ArgT> struct MatchAnyOf;
+        template<typename ArgT> struct MatchNotOf;
+
+        class MatcherUntypedBase {
+        public:
+            MatcherUntypedBase() = default;
+            MatcherUntypedBase ( MatcherUntypedBase const& ) = default;
+            MatcherUntypedBase& operator = ( MatcherUntypedBase const& ) = delete;
+            std::string toString() const;
+
+        protected:
+            virtual ~MatcherUntypedBase();
+            virtual std::string describe() const = 0;
+            mutable std::string m_cachedToString;
+        };
+
+#ifdef __clang__
+#    pragma clang diagnostic push
+#    pragma clang diagnostic ignored "-Wnon-virtual-dtor"
+#endif
+
+        template<typename ObjectT>
+        struct MatcherMethod {
+            virtual bool match( ObjectT const& arg ) const = 0;
+        };
+
+#if defined(__OBJC__)
+        // Hack to fix Catch GH issue #1661. Could use id for generic Object support.
+        // use of const for Object pointers is very uncommon and under ARC it causes some kind of signature mismatch that breaks compilation
+        template<>
+        struct MatcherMethod<NSString*> {
+            virtual bool match( NSString* arg ) const = 0;
+        };
+#endif
+
+#ifdef __clang__
+#    pragma clang diagnostic pop
+#endif
+
+        template<typename T>
+        struct MatcherBase : MatcherUntypedBase, MatcherMethod<T> {
+
+            MatchAllOf<T> operator && ( MatcherBase const& other ) const;
+            MatchAnyOf<T> operator || ( MatcherBase const& other ) const;
+            MatchNotOf<T> operator ! () const;
+        };
+
+        template<typename ArgT>
+        struct MatchAllOf : MatcherBase<ArgT> {
+            bool match( ArgT const& arg ) const override {
+                for( auto matcher : m_matchers ) {
+                    if (!matcher->match(arg))
+                        return false;
+                }
+                return true;
+            }
+            std::string describe() const override {
+                std::string description;
+                description.reserve( 4 + m_matchers.size()*32 );
+                description += "( ";
+                bool first = true;
+                for( auto matcher : m_matchers ) {
+                    if( first )
+                        first = false;
+                    else
+                        description += " and ";
+                    description += matcher->toString();
+                }
+                description += " )";
+                return description;
+            }
+
+            MatchAllOf<ArgT> operator && ( MatcherBase<ArgT> const& other ) {
+                auto copy(*this);
+                copy.m_matchers.push_back( &other );
+                return copy;
+            }
+
+            std::vector<MatcherBase<ArgT> const*> m_matchers;
+        };
+        template<typename ArgT>
+        struct MatchAnyOf : MatcherBase<ArgT> {
+
+            bool match( ArgT const& arg ) const override {
+                for( auto matcher : m_matchers ) {
+                    if (matcher->match(arg))
+                        return true;
+                }
+                return false;
+            }
+            std::string describe() const override {
+                std::string description;
+                description.reserve( 4 + m_matchers.size()*32 );
+                description += "( ";
+                bool first = true;
+                for( auto matcher : m_matchers ) {
+                    if( first )
+                        first = false;
+                    else
+                        description += " or ";
+                    description += matcher->toString();
+                }
+                description += " )";
+                return description;
+            }
+
+            MatchAnyOf<ArgT> operator || ( MatcherBase<ArgT> const& other ) {
+                auto copy(*this);
+                copy.m_matchers.push_back( &other );
+                return copy;
+            }
+
+            std::vector<MatcherBase<ArgT> const*> m_matchers;
+        };
+
+        template<typename ArgT>
+        struct MatchNotOf : MatcherBase<ArgT> {
+
+            MatchNotOf( MatcherBase<ArgT> const& underlyingMatcher ) : m_underlyingMatcher( underlyingMatcher ) {}
+
+            bool match( ArgT const& arg ) const override {
+                return !m_underlyingMatcher.match( arg );
+            }
+
+            std::string describe() const override {
+                return "not " + m_underlyingMatcher.toString();
+            }
+            MatcherBase<ArgT> const& m_underlyingMatcher;
+        };
+
+        template<typename T>
+        MatchAllOf<T> MatcherBase<T>::operator && ( MatcherBase const& other ) const {
+            return MatchAllOf<T>() && *this && other;
+        }
+        template<typename T>
+        MatchAnyOf<T> MatcherBase<T>::operator || ( MatcherBase const& other ) const {
+            return MatchAnyOf<T>() || *this || other;
+        }
+        template<typename T>
+        MatchNotOf<T> MatcherBase<T>::operator ! () const {
+            return MatchNotOf<T>( *this );
+        }
+
+    } // namespace Impl
+
+} // namespace Matchers
+
+using namespace Matchers;
+using Matchers::Impl::MatcherBase;
+
+} // namespace Catch
+
+// end catch_matchers.h
+// start catch_matchers_exception.hpp
+
+namespace Catch {
+namespace Matchers {
+namespace Exception {
+
+class ExceptionMessageMatcher : public MatcherBase<std::exception> {
+    std::string m_message;
+public:
+
+    ExceptionMessageMatcher(std::string const& message):
+        m_message(message)
+    {}
+
+    bool match(std::exception const& ex) const override;
+
+    std::string describe() const override;
+};
+
+} // namespace Exception
+
+Exception::ExceptionMessageMatcher Message(std::string const& message);
+
+} // namespace Matchers
+} // namespace Catch
+
+// end catch_matchers_exception.hpp
+// start catch_matchers_floating.h
+
+namespace Catch {
+namespace Matchers {
+
+    namespace Floating {
+
+        enum class FloatingPointKind : uint8_t;
+
+        struct WithinAbsMatcher : MatcherBase<double> {
+            WithinAbsMatcher(double target, double margin);
+            bool match(double const& matchee) const override;
+            std::string describe() const override;
+        private:
+            double m_target;
+            double m_margin;
+        };
+
+        struct WithinUlpsMatcher : MatcherBase<double> {
+            WithinUlpsMatcher(double target, uint64_t ulps, FloatingPointKind baseType);
+            bool match(double const& matchee) const override;
+            std::string describe() const override;
+        private:
+            double m_target;
+            uint64_t m_ulps;
+            FloatingPointKind m_type;
+        };
+
+        // Given IEEE-754 format for floats and doubles, we can assume
+        // that float -> double promotion is lossless. Given this, we can
+        // assume that if we do the standard relative comparison of
+        // |lhs - rhs| <= epsilon * max(fabs(lhs), fabs(rhs)), then we get
+        // the same result if we do this for floats, as if we do this for
+        // doubles that were promoted from floats.
+        struct WithinRelMatcher : MatcherBase<double> {
+            WithinRelMatcher(double target, double epsilon);
+            bool match(double const& matchee) const override;
+            std::string describe() const override;
+        private:
+            double m_target;
+            double m_epsilon;
+        };
+
+    } // namespace Floating
+
+    // The following functions create the actual matcher objects.
+    // This allows the types to be inferred
+    Floating::WithinUlpsMatcher WithinULP(double target, uint64_t maxUlpDiff);
+    Floating::WithinUlpsMatcher WithinULP(float target, uint64_t maxUlpDiff);
+    Floating::WithinAbsMatcher WithinAbs(double target, double margin);
+    Floating::WithinRelMatcher WithinRel(double target, double eps);
+    // defaults epsilon to 100*numeric_limits<double>::epsilon()
+    Floating::WithinRelMatcher WithinRel(double target);
+    Floating::WithinRelMatcher WithinRel(float target, float eps);
+    // defaults epsilon to 100*numeric_limits<float>::epsilon()
+    Floating::WithinRelMatcher WithinRel(float target);
+
+} // namespace Matchers
+} // namespace Catch
+
+// end catch_matchers_floating.h
+// start catch_matchers_generic.hpp
+
+#include <functional>
+#include <string>
+
+namespace Catch {
+namespace Matchers {
+namespace Generic {
+
+namespace Detail {
+    std::string finalizeDescription(const std::string& desc);
+}
+
+template <typename T>
+class PredicateMatcher : public MatcherBase<T> {
+    std::function<bool(T const&)> m_predicate;
+    std::string m_description;
+public:
+
+    PredicateMatcher(std::function<bool(T const&)> const& elem, std::string const& descr)
+        :m_predicate(std::move(elem)),
+        m_description(Detail::finalizeDescription(descr))
+    {}
+
+    bool match( T const& item ) const override {
+        return m_predicate(item);
+    }
+
+    std::string describe() const override {
+        return m_description;
+    }
+};
+
+} // namespace Generic
+
+    // The following functions create the actual matcher objects.
+    // The user has to explicitly specify type to the function, because
+    // inferring std::function<bool(T const&)> is hard (but possible) and
+    // requires a lot of TMP.
+    template<typename T>
+    Generic::PredicateMatcher<T> Predicate(std::function<bool(T const&)> const& predicate, std::string const& description = "") {
+        return Generic::PredicateMatcher<T>(predicate, description);
+    }
+
+} // namespace Matchers
+} // namespace Catch
+
+// end catch_matchers_generic.hpp
+// start catch_matchers_string.h
+
+#include <string>
+
+namespace Catch {
+namespace Matchers {
+
+    namespace StdString {
+
+        struct CasedString
+        {
+            CasedString( std::string const& str, CaseSensitive::Choice caseSensitivity );
+            std::string adjustString( std::string const& str ) const;
+            std::string caseSensitivitySuffix() const;
+
+            CaseSensitive::Choice m_caseSensitivity;
+            std::string m_str;
+        };
+
+        struct StringMatcherBase : MatcherBase<std::string> {
+            StringMatcherBase( std::string const& operation, CasedString const& comparator );
+            std::string describe() const override;
+
+            CasedString m_comparator;
+            std::string m_operation;
+        };
+
+        struct EqualsMatcher : StringMatcherBase {
+            EqualsMatcher( CasedString const& comparator );
+            bool match( std::string const& source ) const override;
+        };
+        struct ContainsMatcher : StringMatcherBase {
+            ContainsMatcher( CasedString const& comparator );
+            bool match( std::string const& source ) const override;
+        };
+        struct StartsWithMatcher : StringMatcherBase {
+            StartsWithMatcher( CasedString const& comparator );
+            bool match( std::string const& source ) const override;
+        };
+        struct EndsWithMatcher : StringMatcherBase {
+            EndsWithMatcher( CasedString const& comparator );
+            bool match( std::string const& source ) const override;
+        };
+
+        struct RegexMatcher : MatcherBase<std::string> {
+            RegexMatcher( std::string regex, CaseSensitive::Choice caseSensitivity );
+            bool match( std::string const& matchee ) const override;
+            std::string describe() const override;
+
+        private:
+            std::string m_regex;
+            CaseSensitive::Choice m_caseSensitivity;
+        };
+
+    } // namespace StdString
+
+    // The following functions create the actual matcher objects.
+    // This allows the types to be inferred
+
+    StdString::EqualsMatcher Equals( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes );
+    StdString::ContainsMatcher Contains( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes );
+    StdString::EndsWithMatcher EndsWith( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes );
+    StdString::StartsWithMatcher StartsWith( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes );
+    StdString::RegexMatcher Matches( std::string const& regex, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes );
+
+} // namespace Matchers
+} // namespace Catch
+
+// end catch_matchers_string.h
+// start catch_matchers_vector.h
+
+#include <algorithm>
+
+namespace Catch {
+namespace Matchers {
+
+    namespace Vector {
+        template<typename T, typename Alloc>
+        struct ContainsElementMatcher : MatcherBase<std::vector<T, Alloc>> {
+
+            ContainsElementMatcher(T const &comparator) : m_comparator( comparator) {}
+
+            bool match(std::vector<T, Alloc> const &v) const override {
+                for (auto const& el : v) {
+                    if (el == m_comparator) {
+                        return true;
+                    }
+                }
+                return false;
+            }
+
+            std::string describe() const override {
+                return "Contains: " + ::Catch::Detail::stringify( m_comparator );
+            }
+
+            T const& m_comparator;
+        };
+
+        template<typename T, typename AllocComp, typename AllocMatch>
+        struct ContainsMatcher : MatcherBase<std::vector<T, AllocMatch>> {
+
+            ContainsMatcher(std::vector<T, AllocComp> const &comparator) : m_comparator( comparator ) {}
+
+            bool match(std::vector<T, AllocMatch> const &v) const override {
+                // !TBD: see note in EqualsMatcher
+                if (m_comparator.size() > v.size())
+                    return false;
+                for (auto const& comparator : m_comparator) {
+                    auto present = false;
+                    for (const auto& el : v) {
+                        if (el == comparator) {
+                            present = true;
+                            break;
+                        }
+                    }
+                    if (!present) {
+                        return false;
+                    }
+                }
+                return true;
+            }
+            std::string describe() const override {
+                return "Contains: " + ::Catch::Detail::stringify( m_comparator );
+            }
+
+            std::vector<T, AllocComp> const& m_comparator;
+        };
+
+        template<typename T, typename AllocComp, typename AllocMatch>
+        struct EqualsMatcher : MatcherBase<std::vector<T, AllocMatch>> {
+
+            EqualsMatcher(std::vector<T, AllocComp> const &comparator) : m_comparator( comparator ) {}
+
+            bool match(std::vector<T, AllocMatch> const &v) const override {
+                // !TBD: This currently works if all elements can be compared using !=
+                // - a more general approach would be via a compare template that defaults
+                // to using !=. but could be specialised for, e.g. std::vector<T, Alloc> etc
+                // - then just call that directly
+                if (m_comparator.size() != v.size())
+                    return false;
+                for (std::size_t i = 0; i < v.size(); ++i)
+                    if (m_comparator[i] != v[i])
+                        return false;
+                return true;
+            }
+            std::string describe() const override {
+                return "Equals: " + ::Catch::Detail::stringify( m_comparator );
+            }
+            std::vector<T, AllocComp> const& m_comparator;
+        };
+
+        template<typename T, typename AllocComp, typename AllocMatch>
+        struct ApproxMatcher : MatcherBase<std::vector<T, AllocMatch>> {
+
+            ApproxMatcher(std::vector<T, AllocComp> const& comparator) : m_comparator( comparator ) {}
+
+            bool match(std::vector<T, AllocMatch> const &v) const override {
+                if (m_comparator.size() != v.size())
+                    return false;
+                for (std::size_t i = 0; i < v.size(); ++i)
+                    if (m_comparator[i] != approx(v[i]))
+                        return false;
+                return true;
+            }
+            std::string describe() const override {
+                return "is approx: " + ::Catch::Detail::stringify( m_comparator );
+            }
+            template <typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
+            ApproxMatcher& epsilon( T const& newEpsilon ) {
+                approx.epsilon(newEpsilon);
+                return *this;
+            }
+            template <typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
+            ApproxMatcher& margin( T const& newMargin ) {
+                approx.margin(newMargin);
+                return *this;
+            }
+            template <typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
+            ApproxMatcher& scale( T const& newScale ) {
+                approx.scale(newScale);
+                return *this;
+            }
+
+            std::vector<T, AllocComp> const& m_comparator;
+            mutable Catch::Detail::Approx approx = Catch::Detail::Approx::custom();
+        };
+
+        template<typename T, typename AllocComp, typename AllocMatch>
+        struct UnorderedEqualsMatcher : MatcherBase<std::vector<T, AllocMatch>> {
+            UnorderedEqualsMatcher(std::vector<T, AllocComp> const& target) : m_target(target) {}
+            bool match(std::vector<T, AllocMatch> const& vec) const override {
+                if (m_target.size() != vec.size()) {
+                    return false;
+                }
+                return std::is_permutation(m_target.begin(), m_target.end(), vec.begin());
+            }
+
+            std::string describe() const override {
+                return "UnorderedEquals: " + ::Catch::Detail::stringify(m_target);
+            }
+        private:
+            std::vector<T, AllocComp> const& m_target;
+        };
+
+    } // namespace Vector
+
+    // The following functions create the actual matcher objects.
+    // This allows the types to be inferred
+
+    template<typename T, typename AllocComp = std::allocator<T>, typename AllocMatch = AllocComp>
+    Vector::ContainsMatcher<T, AllocComp, AllocMatch> Contains( std::vector<T, AllocComp> const& comparator ) {
+        return Vector::ContainsMatcher<T, AllocComp, AllocMatch>( comparator );
+    }
+
+    template<typename T, typename Alloc = std::allocator<T>>
+    Vector::ContainsElementMatcher<T, Alloc> VectorContains( T const& comparator ) {
+        return Vector::ContainsElementMatcher<T, Alloc>( comparator );
+    }
+
+    template<typename T, typename AllocComp = std::allocator<T>, typename AllocMatch = AllocComp>
+    Vector::EqualsMatcher<T, AllocComp, AllocMatch> Equals( std::vector<T, AllocComp> const& comparator ) {
+        return Vector::EqualsMatcher<T, AllocComp, AllocMatch>( comparator );
+    }
+
+    template<typename T, typename AllocComp = std::allocator<T>, typename AllocMatch = AllocComp>
+    Vector::ApproxMatcher<T, AllocComp, AllocMatch> Approx( std::vector<T, AllocComp> const& comparator ) {
+        return Vector::ApproxMatcher<T, AllocComp, AllocMatch>( comparator );
+    }
+
+    template<typename T, typename AllocComp = std::allocator<T>, typename AllocMatch = AllocComp>
+    Vector::UnorderedEqualsMatcher<T, AllocComp, AllocMatch> UnorderedEquals(std::vector<T, AllocComp> const& target) {
+        return Vector::UnorderedEqualsMatcher<T, AllocComp, AllocMatch>( target );
+    }
+
+} // namespace Matchers
+} // namespace Catch
+
+// end catch_matchers_vector.h
+namespace Catch {
+
+    template<typename ArgT, typename MatcherT>
+    class MatchExpr : public ITransientExpression {
+        ArgT const& m_arg;
+        MatcherT m_matcher;
+        StringRef m_matcherString;
+    public:
+        MatchExpr( ArgT const& arg, MatcherT const& matcher, StringRef const& matcherString )
+        :   ITransientExpression{ true, matcher.match( arg ) },
+            m_arg( arg ),
+            m_matcher( matcher ),
+            m_matcherString( matcherString )
+        {}
+
+        void streamReconstructedExpression( std::ostream &os ) const override {
+            auto matcherAsString = m_matcher.toString();
+            os << Catch::Detail::stringify( m_arg ) << ' ';
+            if( matcherAsString == Detail::unprintableString )
+                os << m_matcherString;
+            else
+                os << matcherAsString;
+        }
+    };
+
+    using StringMatcher = Matchers::Impl::MatcherBase<std::string>;
+
+    void handleExceptionMatchExpr( AssertionHandler& handler, StringMatcher const& matcher, StringRef const& matcherString  );
+
+    template<typename ArgT, typename MatcherT>
+    auto makeMatchExpr( ArgT const& arg, MatcherT const& matcher, StringRef const& matcherString  ) -> MatchExpr<ArgT, MatcherT> {
+        return MatchExpr<ArgT, MatcherT>( arg, matcher, matcherString );
+    }
+
+} // namespace Catch
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CHECK_THAT( macroName, matcher, resultDisposition, arg ) \
+    do { \
+        Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(arg) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \
+        INTERNAL_CATCH_TRY { \
+            catchAssertionHandler.handleExpr( Catch::makeMatchExpr( arg, matcher, #matcher##_catch_sr ) ); \
+        } INTERNAL_CATCH_CATCH( catchAssertionHandler ) \
+        INTERNAL_CATCH_REACT( catchAssertionHandler ) \
+    } while( false )
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_THROWS_MATCHES( macroName, exceptionType, resultDisposition, matcher, ... ) \
+    do { \
+        Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__) ", " CATCH_INTERNAL_STRINGIFY(exceptionType) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \
+        if( catchAssertionHandler.allowThrows() ) \
+            try { \
+                static_cast<void>(__VA_ARGS__ ); \
+                catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \
+            } \
+            catch( exceptionType const& ex ) { \
+                catchAssertionHandler.handleExpr( Catch::makeMatchExpr( ex, matcher, #matcher##_catch_sr ) ); \
+            } \
+            catch( ... ) { \
+                catchAssertionHandler.handleUnexpectedInflightException(); \
+            } \
+        else \
+            catchAssertionHandler.handleThrowingCallSkipped(); \
+        INTERNAL_CATCH_REACT( catchAssertionHandler ) \
+    } while( false )
+
+// end catch_capture_matchers.h
+#endif
+// start catch_generators.hpp
+
+// start catch_interfaces_generatortracker.h
+
+
+#include <memory>
+
+namespace Catch {
+
+    namespace Generators {
+        class GeneratorUntypedBase {
+        public:
+            GeneratorUntypedBase() = default;
+            virtual ~GeneratorUntypedBase();
+            // Attempts to move the generator to the next element
+             //
+             // Returns true iff the move succeeded (and a valid element
+             // can be retrieved).
+            virtual bool next() = 0;
+        };
+        using GeneratorBasePtr = std::unique_ptr<GeneratorUntypedBase>;
+
+    } // namespace Generators
+
+    struct IGeneratorTracker {
+        virtual ~IGeneratorTracker();
+        virtual auto hasGenerator() const -> bool = 0;
+        virtual auto getGenerator() const -> Generators::GeneratorBasePtr const& = 0;
+        virtual void setGenerator( Generators::GeneratorBasePtr&& generator ) = 0;
+    };
+
+} // namespace Catch
+
+// end catch_interfaces_generatortracker.h
+// start catch_enforce.h
+
+#include <exception>
+
+namespace Catch {
+#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
+    template <typename Ex>
+    [[noreturn]]
+    void throw_exception(Ex const& e) {
+        throw e;
+    }
+#else // ^^ Exceptions are enabled //  Exceptions are disabled vv
+    [[noreturn]]
+    void throw_exception(std::exception const& e);
+#endif
+
+    [[noreturn]]
+    void throw_logic_error(std::string const& msg);
+    [[noreturn]]
+    void throw_domain_error(std::string const& msg);
+    [[noreturn]]
+    void throw_runtime_error(std::string const& msg);
+
+} // namespace Catch;
+
+#define CATCH_MAKE_MSG(...) \
+    (Catch::ReusableStringStream() << __VA_ARGS__).str()
+
+#define CATCH_INTERNAL_ERROR(...) \
+    Catch::throw_logic_error(CATCH_MAKE_MSG( CATCH_INTERNAL_LINEINFO << ": Internal Catch2 error: " << __VA_ARGS__))
+
+#define CATCH_ERROR(...) \
+    Catch::throw_domain_error(CATCH_MAKE_MSG( __VA_ARGS__ ))
+
+#define CATCH_RUNTIME_ERROR(...) \
+    Catch::throw_runtime_error(CATCH_MAKE_MSG( __VA_ARGS__ ))
+
+#define CATCH_ENFORCE( condition, ... ) \
+    do{ if( !(condition) ) CATCH_ERROR( __VA_ARGS__ ); } while(false)
+
+// end catch_enforce.h
+#include <memory>
+#include <vector>
+#include <cassert>
+
+#include <utility>
+#include <exception>
+
+namespace Catch {
+
+class GeneratorException : public std::exception {
+    const char* const m_msg = "";
+
+public:
+    GeneratorException(const char* msg):
+        m_msg(msg)
+    {}
+
+    const char* what() const noexcept override final;
+};
+
+namespace Generators {
+
+    // !TBD move this into its own location?
+    namespace pf{
+        template<typename T, typename... Args>
+        std::unique_ptr<T> make_unique( Args&&... args ) {
+            return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
+        }
+    }
+
+    template<typename T>
+    struct IGenerator : GeneratorUntypedBase {
+        virtual ~IGenerator() = default;
+
+        // Returns the current element of the generator
+        //
+        // \Precondition The generator is either freshly constructed,
+        // or the last call to `next()` returned true
+        virtual T const& get() const = 0;
+        using type = T;
+    };
+
+    template<typename T>
+    class SingleValueGenerator final : public IGenerator<T> {
+        T m_value;
+    public:
+        SingleValueGenerator(T&& value) : m_value(std::move(value)) {}
+
+        T const& get() const override {
+            return m_value;
+        }
+        bool next() override {
+            return false;
+        }
+    };
+
+    template<typename T>
+    class FixedValuesGenerator final : public IGenerator<T> {
+        static_assert(!std::is_same<T, bool>::value,
+            "FixedValuesGenerator does not support bools because of std::vector<bool>"
+            "specialization, use SingleValue Generator instead.");
+        std::vector<T> m_values;
+        size_t m_idx = 0;
+    public:
+        FixedValuesGenerator( std::initializer_list<T> values ) : m_values( values ) {}
+
+        T const& get() const override {
+            return m_values[m_idx];
+        }
+        bool next() override {
+            ++m_idx;
+            return m_idx < m_values.size();
+        }
+    };
+
+    template <typename T>
+    class GeneratorWrapper final {
+        std::unique_ptr<IGenerator<T>> m_generator;
+    public:
+        GeneratorWrapper(std::unique_ptr<IGenerator<T>> generator):
+            m_generator(std::move(generator))
+        {}
+        T const& get() const {
+            return m_generator->get();
+        }
+        bool next() {
+            return m_generator->next();
+        }
+    };
+
+    template <typename T>
+    GeneratorWrapper<T> value(T&& value) {
+        return GeneratorWrapper<T>(pf::make_unique<SingleValueGenerator<T>>(std::forward<T>(value)));
+    }
+    template <typename T>
+    GeneratorWrapper<T> values(std::initializer_list<T> values) {
+        return GeneratorWrapper<T>(pf::make_unique<FixedValuesGenerator<T>>(values));
+    }
+
+    template<typename T>
+    class Generators : public IGenerator<T> {
+        std::vector<GeneratorWrapper<T>> m_generators;
+        size_t m_current = 0;
+
+        void populate(GeneratorWrapper<T>&& generator) {
+            m_generators.emplace_back(std::move(generator));
+        }
+        void populate(T&& val) {
+            m_generators.emplace_back(value(std::forward<T>(val)));
+        }
+        template<typename U>
+        void populate(U&& val) {
+            populate(T(std::forward<U>(val)));
+        }
+        template<typename U, typename... Gs>
+        void populate(U&& valueOrGenerator, Gs &&... moreGenerators) {
+            populate(std::forward<U>(valueOrGenerator));
+            populate(std::forward<Gs>(moreGenerators)...);
+        }
+
+    public:
+        template <typename... Gs>
+        Generators(Gs &&... moreGenerators) {
+            m_generators.reserve(sizeof...(Gs));
+            populate(std::forward<Gs>(moreGenerators)...);
+        }
+
+        T const& get() const override {
+            return m_generators[m_current].get();
+        }
+
+        bool next() override {
+            if (m_current >= m_generators.size()) {
+                return false;
+            }
+            const bool current_status = m_generators[m_current].next();
+            if (!current_status) {
+                ++m_current;
+            }
+            return m_current < m_generators.size();
+        }
+    };
+
+    template<typename... Ts>
+    GeneratorWrapper<std::tuple<Ts...>> table( std::initializer_list<std::tuple<typename std::decay<Ts>::type...>> tuples ) {
+        return values<std::tuple<Ts...>>( tuples );
+    }
+
+    // Tag type to signal that a generator sequence should convert arguments to a specific type
+    template <typename T>
+    struct as {};
+
+    template<typename T, typename... Gs>
+    auto makeGenerators( GeneratorWrapper<T>&& generator, Gs &&... moreGenerators ) -> Generators<T> {
+        return Generators<T>(std::move(generator), std::forward<Gs>(moreGenerators)...);
+    }
+    template<typename T>
+    auto makeGenerators( GeneratorWrapper<T>&& generator ) -> Generators<T> {
+        return Generators<T>(std::move(generator));
+    }
+    template<typename T, typename... Gs>
+    auto makeGenerators( T&& val, Gs &&... moreGenerators ) -> Generators<T> {
+        return makeGenerators( value( std::forward<T>( val ) ), std::forward<Gs>( moreGenerators )... );
+    }
+    template<typename T, typename U, typename... Gs>
+    auto makeGenerators( as<T>, U&& val, Gs &&... moreGenerators ) -> Generators<T> {
+        return makeGenerators( value( T( std::forward<U>( val ) ) ), std::forward<Gs>( moreGenerators )... );
+    }
+
+    auto acquireGeneratorTracker( StringRef generatorName, SourceLineInfo const& lineInfo ) -> IGeneratorTracker&;
+
+    template<typename L>
+    // Note: The type after -> is weird, because VS2015 cannot parse
+    //       the expression used in the typedef inside, when it is in
+    //       return type. Yeah.
+    auto generate( StringRef generatorName, SourceLineInfo const& lineInfo, L const& generatorExpression ) -> decltype(std::declval<decltype(generatorExpression())>().get()) {
+        using UnderlyingType = typename decltype(generatorExpression())::type;
+
+        IGeneratorTracker& tracker = acquireGeneratorTracker( generatorName, lineInfo );
+        if (!tracker.hasGenerator()) {
+            tracker.setGenerator(pf::make_unique<Generators<UnderlyingType>>(generatorExpression()));
+        }
+
+        auto const& generator = static_cast<IGenerator<UnderlyingType> const&>( *tracker.getGenerator() );
+        return generator.get();
+    }
+
+} // namespace Generators
+} // namespace Catch
+
+#define GENERATE( ... ) \
+    Catch::Generators::generate( INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_UNIQUE_NAME(generator)), \
+                                 CATCH_INTERNAL_LINEINFO, \
+                                 [ ]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace)
+#define GENERATE_COPY( ... ) \
+    Catch::Generators::generate( INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_UNIQUE_NAME(generator)), \
+                                 CATCH_INTERNAL_LINEINFO, \
+                                 [=]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace)
+#define GENERATE_REF( ... ) \
+    Catch::Generators::generate( INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_UNIQUE_NAME(generator)), \
+                                 CATCH_INTERNAL_LINEINFO, \
+                                 [&]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace)
+
+// end catch_generators.hpp
+// start catch_generators_generic.hpp
+
+namespace Catch {
+namespace Generators {
+
+    template <typename T>
+    class TakeGenerator : public IGenerator<T> {
+        GeneratorWrapper<T> m_generator;
+        size_t m_returned = 0;
+        size_t m_target;
+    public:
+        TakeGenerator(size_t target, GeneratorWrapper<T>&& generator):
+            m_generator(std::move(generator)),
+            m_target(target)
+        {
+            assert(target != 0 && "Empty generators are not allowed");
+        }
+        T const& get() const override {
+            return m_generator.get();
+        }
+        bool next() override {
+            ++m_returned;
+            if (m_returned >= m_target) {
+                return false;
+            }
+
+            const auto success = m_generator.next();
+            // If the underlying generator does not contain enough values
+            // then we cut short as well
+            if (!success) {
+                m_returned = m_target;
+            }
+            return success;
+        }
+    };
+
+    template <typename T>
+    GeneratorWrapper<T> take(size_t target, GeneratorWrapper<T>&& generator) {
+        return GeneratorWrapper<T>(pf::make_unique<TakeGenerator<T>>(target, std::move(generator)));
+    }
+
+    template <typename T, typename Predicate>
+    class FilterGenerator : public IGenerator<T> {
+        GeneratorWrapper<T> m_generator;
+        Predicate m_predicate;
+    public:
+        template <typename P = Predicate>
+        FilterGenerator(P&& pred, GeneratorWrapper<T>&& generator):
+            m_generator(std::move(generator)),
+            m_predicate(std::forward<P>(pred))
+        {
+            if (!m_predicate(m_generator.get())) {
+                // It might happen that there are no values that pass the
+                // filter. In that case we throw an exception.
+                auto has_initial_value = next();
+                if (!has_initial_value) {
+                    Catch::throw_exception(GeneratorException("No valid value found in filtered generator"));
+                }
+            }
+        }
+
+        T const& get() const override {
+            return m_generator.get();
+        }
+
+        bool next() override {
+            bool success = m_generator.next();
+            if (!success) {
+                return false;
+            }
+            while (!m_predicate(m_generator.get()) && (success = m_generator.next()) == true);
+            return success;
+        }
+    };
+
+    template <typename T, typename Predicate>
+    GeneratorWrapper<T> filter(Predicate&& pred, GeneratorWrapper<T>&& generator) {
+        return GeneratorWrapper<T>(std::unique_ptr<IGenerator<T>>(pf::make_unique<FilterGenerator<T, Predicate>>(std::forward<Predicate>(pred), std::move(generator))));
+    }
+
+    template <typename T>
+    class RepeatGenerator : public IGenerator<T> {
+        static_assert(!std::is_same<T, bool>::value,
+            "RepeatGenerator currently does not support bools"
+            "because of std::vector<bool> specialization");
+        GeneratorWrapper<T> m_generator;
+        mutable std::vector<T> m_returned;
+        size_t m_target_repeats;
+        size_t m_current_repeat = 0;
+        size_t m_repeat_index = 0;
+    public:
+        RepeatGenerator(size_t repeats, GeneratorWrapper<T>&& generator):
+            m_generator(std::move(generator)),
+            m_target_repeats(repeats)
+        {
+            assert(m_target_repeats > 0 && "Repeat generator must repeat at least once");
+        }
+
+        T const& get() const override {
+            if (m_current_repeat == 0) {
+                m_returned.push_back(m_generator.get());
+                return m_returned.back();
+            }
+            return m_returned[m_repeat_index];
+        }
+
+        bool next() override {
+            // There are 2 basic cases:
+            // 1) We are still reading the generator
+            // 2) We are reading our own cache
+
+            // In the first case, we need to poke the underlying generator.
+            // If it happily moves, we are left in that state, otherwise it is time to start reading from our cache
+            if (m_current_repeat == 0) {
+                const auto success = m_generator.next();
+                if (!success) {
+                    ++m_current_repeat;
+                }
+                return m_current_repeat < m_target_repeats;
+            }
+
+            // In the second case, we need to move indices forward and check that we haven't run up against the end
+            ++m_repeat_index;
+            if (m_repeat_index == m_returned.size()) {
+                m_repeat_index = 0;
+                ++m_current_repeat;
+            }
+            return m_current_repeat < m_target_repeats;
+        }
+    };
+
+    template <typename T>
+    GeneratorWrapper<T> repeat(size_t repeats, GeneratorWrapper<T>&& generator) {
+        return GeneratorWrapper<T>(pf::make_unique<RepeatGenerator<T>>(repeats, std::move(generator)));
+    }
+
+    template <typename T, typename U, typename Func>
+    class MapGenerator : public IGenerator<T> {
+        // TBD: provide static assert for mapping function, for friendly error message
+        GeneratorWrapper<U> m_generator;
+        Func m_function;
+        // To avoid returning dangling reference, we have to save the values
+        T m_cache;
+    public:
+        template <typename F2 = Func>
+        MapGenerator(F2&& function, GeneratorWrapper<U>&& generator) :
+            m_generator(std::move(generator)),
+            m_function(std::forward<F2>(function)),
+            m_cache(m_function(m_generator.get()))
+        {}
+
+        T const& get() const override {
+            return m_cache;
+        }
+        bool next() override {
+            const auto success = m_generator.next();
+            if (success) {
+                m_cache = m_function(m_generator.get());
+            }
+            return success;
+        }
+    };
+
+    template <typename Func, typename U, typename T = FunctionReturnType<Func, U>>
+    GeneratorWrapper<T> map(Func&& function, GeneratorWrapper<U>&& generator) {
+        return GeneratorWrapper<T>(
+            pf::make_unique<MapGenerator<T, U, Func>>(std::forward<Func>(function), std::move(generator))
+        );
+    }
+
+    template <typename T, typename U, typename Func>
+    GeneratorWrapper<T> map(Func&& function, GeneratorWrapper<U>&& generator) {
+        return GeneratorWrapper<T>(
+            pf::make_unique<MapGenerator<T, U, Func>>(std::forward<Func>(function), std::move(generator))
+        );
+    }
+
+    template <typename T>
+    class ChunkGenerator final : public IGenerator<std::vector<T>> {
+        std::vector<T> m_chunk;
+        size_t m_chunk_size;
+        GeneratorWrapper<T> m_generator;
+        bool m_used_up = false;
+    public:
+        ChunkGenerator(size_t size, GeneratorWrapper<T> generator) :
+            m_chunk_size(size), m_generator(std::move(generator))
+        {
+            m_chunk.reserve(m_chunk_size);
+            if (m_chunk_size != 0) {
+                m_chunk.push_back(m_generator.get());
+                for (size_t i = 1; i < m_chunk_size; ++i) {
+                    if (!m_generator.next()) {
+                        Catch::throw_exception(GeneratorException("Not enough values to initialize the first chunk"));
+                    }
+                    m_chunk.push_back(m_generator.get());
+                }
+            }
+        }
+        std::vector<T> const& get() const override {
+            return m_chunk;
+        }
+        bool next() override {
+            m_chunk.clear();
+            for (size_t idx = 0; idx < m_chunk_size; ++idx) {
+                if (!m_generator.next()) {
+                    return false;
+                }
+                m_chunk.push_back(m_generator.get());
+            }
+            return true;
+        }
+    };
+
+    template <typename T>
+    GeneratorWrapper<std::vector<T>> chunk(size_t size, GeneratorWrapper<T>&& generator) {
+        return GeneratorWrapper<std::vector<T>>(
+            pf::make_unique<ChunkGenerator<T>>(size, std::move(generator))
+        );
+    }
+
+} // namespace Generators
+} // namespace Catch
+
+// end catch_generators_generic.hpp
+// start catch_generators_specific.hpp
+
+// start catch_context.h
+
+#include <memory>
+
+namespace Catch {
+
+    struct IResultCapture;
+    struct IRunner;
+    struct IConfig;
+    struct IMutableContext;
+
+    using IConfigPtr = std::shared_ptr<IConfig const>;
+
+    struct IContext
+    {
+        virtual ~IContext();
+
+        virtual IResultCapture* getResultCapture() = 0;
+        virtual IRunner* getRunner() = 0;
+        virtual IConfigPtr const& getConfig() const = 0;
+    };
+
+    struct IMutableContext : IContext
+    {
+        virtual ~IMutableContext();
+        virtual void setResultCapture( IResultCapture* resultCapture ) = 0;
+        virtual void setRunner( IRunner* runner ) = 0;
+        virtual void setConfig( IConfigPtr const& config ) = 0;
+
+    private:
+        static IMutableContext *currentContext;
+        friend IMutableContext& getCurrentMutableContext();
+        friend void cleanUpContext();
+        static void createContext();
+    };
+
+    inline IMutableContext& getCurrentMutableContext()
+    {
+        if( !IMutableContext::currentContext )
+            IMutableContext::createContext();
+        // NOLINTNEXTLINE(clang-analyzer-core.uninitialized.UndefReturn)
+        return *IMutableContext::currentContext;
+    }
+
+    inline IContext& getCurrentContext()
+    {
+        return getCurrentMutableContext();
+    }
+
+    void cleanUpContext();
+
+    class SimplePcg32;
+    SimplePcg32& rng();
+}
+
+// end catch_context.h
+// start catch_interfaces_config.h
+
+// start catch_option.hpp
+
+namespace Catch {
+
+    // An optional type
+    template<typename T>
+    class Option {
+    public:
+        Option() : nullableValue( nullptr ) {}
+        Option( T const& _value )
+        : nullableValue( new( storage ) T( _value ) )
+        {}
+        Option( Option const& _other )
+        : nullableValue( _other ? new( storage ) T( *_other ) : nullptr )
+        {}
+
+        ~Option() {
+            reset();
+        }
+
+        Option& operator= ( Option const& _other ) {
+            if( &_other != this ) {
+                reset();
+                if( _other )
+                    nullableValue = new( storage ) T( *_other );
+            }
+            return *this;
+        }
+        Option& operator = ( T const& _value ) {
+            reset();
+            nullableValue = new( storage ) T( _value );
+            return *this;
+        }
+
+        void reset() {
+            if( nullableValue )
+                nullableValue->~T();
+            nullableValue = nullptr;
+        }
+
+        T& operator*() { return *nullableValue; }
+        T const& operator*() const { return *nullableValue; }
+        T* operator->() { return nullableValue; }
+        const T* operator->() const { return nullableValue; }
+
+        T valueOr( T const& defaultValue ) const {
+            return nullableValue ? *nullableValue : defaultValue;
+        }
+
+        bool some() const { return nullableValue != nullptr; }
+        bool none() const { return nullableValue == nullptr; }
+
+        bool operator !() const { return nullableValue == nullptr; }
+        explicit operator bool() const {
+            return some();
+        }
+
+    private:
+        T *nullableValue;
+        alignas(alignof(T)) char storage[sizeof(T)];
+    };
+
+} // end namespace Catch
+
+// end catch_option.hpp
+#include <chrono>
+#include <iosfwd>
+#include <string>
+#include <vector>
+#include <memory>
+
+namespace Catch {
+
+    enum class Verbosity {
+        Quiet = 0,
+        Normal,
+        High
+    };
+
+    struct WarnAbout { enum What {
+        Nothing = 0x00,
+        NoAssertions = 0x01,
+        NoTests = 0x02
+    }; };
+
+    struct ShowDurations { enum OrNot {
+        DefaultForReporter,
+        Always,
+        Never
+    }; };
+    struct RunTests { enum InWhatOrder {
+        InDeclarationOrder,
+        InLexicographicalOrder,
+        InRandomOrder
+    }; };
+    struct UseColour { enum YesOrNo {
+        Auto,
+        Yes,
+        No
+    }; };
+    struct WaitForKeypress { enum When {
+        Never,
+        BeforeStart = 1,
+        BeforeExit = 2,
+        BeforeStartAndExit = BeforeStart | BeforeExit
+    }; };
+
+    class TestSpec;
+
+    struct IConfig : NonCopyable {
+
+        virtual ~IConfig();
+
+        virtual bool allowThrows() const = 0;
+        virtual std::ostream& stream() const = 0;
+        virtual std::string name() const = 0;
+        virtual bool includeSuccessfulResults() const = 0;
+        virtual bool shouldDebugBreak() const = 0;
+        virtual bool warnAboutMissingAssertions() const = 0;
+        virtual bool warnAboutNoTests() const = 0;
+        virtual int abortAfter() const = 0;
+        virtual bool showInvisibles() const = 0;
+        virtual ShowDurations::OrNot showDurations() const = 0;
+        virtual double minDuration() const = 0;
+        virtual TestSpec const& testSpec() const = 0;
+        virtual bool hasTestFilters() const = 0;
+        virtual std::vector<std::string> const& getTestsOrTags() const = 0;
+        virtual RunTests::InWhatOrder runOrder() const = 0;
+        virtual unsigned int rngSeed() const = 0;
+        virtual UseColour::YesOrNo useColour() const = 0;
+        virtual std::vector<std::string> const& getSectionsToRun() const = 0;
+        virtual Verbosity verbosity() const = 0;
+
+        virtual bool benchmarkNoAnalysis() const = 0;
+        virtual int benchmarkSamples() const = 0;
+        virtual double benchmarkConfidenceInterval() const = 0;
+        virtual unsigned int benchmarkResamples() const = 0;
+        virtual std::chrono::milliseconds benchmarkWarmupTime() const = 0;
+    };
+
+    using IConfigPtr = std::shared_ptr<IConfig const>;
+}
+
+// end catch_interfaces_config.h
+// start catch_random_number_generator.h
+
+#include <cstdint>
+
+namespace Catch {
+
+    // This is a simple implementation of C++11 Uniform Random Number
+    // Generator. It does not provide all operators, because Catch2
+    // does not use it, but it should behave as expected inside stdlib's
+    // distributions.
+    // The implementation is based on the PCG family (http://pcg-random.org)
+    class SimplePcg32 {
+        using state_type = std::uint64_t;
+    public:
+        using result_type = std::uint32_t;
+        static constexpr result_type (min)() {
+            return 0;
+        }
+        static constexpr result_type (max)() {
+            return static_cast<result_type>(-1);
+        }
+
+        // Provide some default initial state for the default constructor
+        SimplePcg32():SimplePcg32(0xed743cc4U) {}
+
+        explicit SimplePcg32(result_type seed_);
+
+        void seed(result_type seed_);
+        void discard(uint64_t skip);
+
+        result_type operator()();
+
+    private:
+        friend bool operator==(SimplePcg32 const& lhs, SimplePcg32 const& rhs);
+        friend bool operator!=(SimplePcg32 const& lhs, SimplePcg32 const& rhs);
+
+        // In theory we also need operator<< and operator>>
+        // In practice we do not use them, so we will skip them for now
+
+        std::uint64_t m_state;
+        // This part of the state determines which "stream" of the numbers
+        // is chosen -- we take it as a constant for Catch2, so we only
+        // need to deal with seeding the main state.
+        // Picked by reading 8 bytes from `/dev/random` :-)
+        static const std::uint64_t s_inc = (0x13ed0cc53f939476ULL << 1ULL) | 1ULL;
+    };
+
+} // end namespace Catch
+
+// end catch_random_number_generator.h
+#include <random>
+
+namespace Catch {
+namespace Generators {
+
+template <typename Float>
+class RandomFloatingGenerator final : public IGenerator<Float> {
+    Catch::SimplePcg32& m_rng;
+    std::uniform_real_distribution<Float> m_dist;
+    Float m_current_number;
+public:
+
+    RandomFloatingGenerator(Float a, Float b):
+        m_rng(rng()),
+        m_dist(a, b) {
+        static_cast<void>(next());
+    }
+
+    Float const& get() const override {
+        return m_current_number;
+    }
+    bool next() override {
+        m_current_number = m_dist(m_rng);
+        return true;
+    }
+};
+
+template <typename Integer>
+class RandomIntegerGenerator final : public IGenerator<Integer> {
+    Catch::SimplePcg32& m_rng;
+    std::uniform_int_distribution<Integer> m_dist;
+    Integer m_current_number;
+public:
+
+    RandomIntegerGenerator(Integer a, Integer b):
+        m_rng(rng()),
+        m_dist(a, b) {
+        static_cast<void>(next());
+    }
+
+    Integer const& get() const override {
+        return m_current_number;
+    }
+    bool next() override {
+        m_current_number = m_dist(m_rng);
+        return true;
+    }
+};
+
+// TODO: Ideally this would be also constrained against the various char types,
+//       but I don't expect users to run into that in practice.
+template <typename T>
+typename std::enable_if<std::is_integral<T>::value && !std::is_same<T, bool>::value,
+GeneratorWrapper<T>>::type
+random(T a, T b) {
+    return GeneratorWrapper<T>(
+        pf::make_unique<RandomIntegerGenerator<T>>(a, b)
+    );
+}
+
+template <typename T>
+typename std::enable_if<std::is_floating_point<T>::value,
+GeneratorWrapper<T>>::type
+random(T a, T b) {
+    return GeneratorWrapper<T>(
+        pf::make_unique<RandomFloatingGenerator<T>>(a, b)
+    );
+}
+
+template <typename T>
+class RangeGenerator final : public IGenerator<T> {
+    T m_current;
+    T m_end;
+    T m_step;
+    bool m_positive;
+
+public:
+    RangeGenerator(T const& start, T const& end, T const& step):
+        m_current(start),
+        m_end(end),
+        m_step(step),
+        m_positive(m_step > T(0))
+    {
+        assert(m_current != m_end && "Range start and end cannot be equal");
+        assert(m_step != T(0) && "Step size cannot be zero");
+        assert(((m_positive && m_current <= m_end) || (!m_positive && m_current >= m_end)) && "Step moves away from end");
+    }
+
+    RangeGenerator(T const& start, T const& end):
+        RangeGenerator(start, end, (start < end) ? T(1) : T(-1))
+    {}
+
+    T const& get() const override {
+        return m_current;
+    }
+
+    bool next() override {
+        m_current += m_step;
+        return (m_positive) ? (m_current < m_end) : (m_current > m_end);
+    }
+};
+
+template <typename T>
+GeneratorWrapper<T> range(T const& start, T const& end, T const& step) {
+    static_assert(std::is_arithmetic<T>::value && !std::is_same<T, bool>::value, "Type must be numeric");
+    return GeneratorWrapper<T>(pf::make_unique<RangeGenerator<T>>(start, end, step));
+}
+
+template <typename T>
+GeneratorWrapper<T> range(T const& start, T const& end) {
+    static_assert(std::is_integral<T>::value && !std::is_same<T, bool>::value, "Type must be an integer");
+    return GeneratorWrapper<T>(pf::make_unique<RangeGenerator<T>>(start, end));
+}
+
+template <typename T>
+class IteratorGenerator final : public IGenerator<T> {
+    static_assert(!std::is_same<T, bool>::value,
+        "IteratorGenerator currently does not support bools"
+        "because of std::vector<bool> specialization");
+
+    std::vector<T> m_elems;
+    size_t m_current = 0;
+public:
+    template <typename InputIterator, typename InputSentinel>
+    IteratorGenerator(InputIterator first, InputSentinel last):m_elems(first, last) {
+        if (m_elems.empty()) {
+            Catch::throw_exception(GeneratorException("IteratorGenerator received no valid values"));
+        }
+    }
+
+    T const& get() const override {
+        return m_elems[m_current];
+    }
+
+    bool next() override {
+        ++m_current;
+        return m_current != m_elems.size();
+    }
+};
+
+template <typename InputIterator,
+          typename InputSentinel,
+          typename ResultType = typename std::iterator_traits<InputIterator>::value_type>
+GeneratorWrapper<ResultType> from_range(InputIterator from, InputSentinel to) {
+    return GeneratorWrapper<ResultType>(pf::make_unique<IteratorGenerator<ResultType>>(from, to));
+}
+
+template <typename Container,
+          typename ResultType = typename Container::value_type>
+GeneratorWrapper<ResultType> from_range(Container const& cnt) {
+    return GeneratorWrapper<ResultType>(pf::make_unique<IteratorGenerator<ResultType>>(cnt.begin(), cnt.end()));
+}
+
+} // namespace Generators
+} // namespace Catch
+
+// end catch_generators_specific.hpp
+
+// These files are included here so the single_include script doesn't put them
+// in the conditionally compiled sections
+// start catch_test_case_info.h
+
+#include <string>
+#include <vector>
+#include <memory>
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wpadded"
+#endif
+
+namespace Catch {
+
+    struct ITestInvoker;
+
+    struct TestCaseInfo {
+        enum SpecialProperties{
+            None = 0,
+            IsHidden = 1 << 1,
+            ShouldFail = 1 << 2,
+            MayFail = 1 << 3,
+            Throws = 1 << 4,
+            NonPortable = 1 << 5,
+            Benchmark = 1 << 6
+        };
+
+        TestCaseInfo(   std::string const& _name,
+                        std::string const& _className,
+                        std::string const& _description,
+                        std::vector<std::string> const& _tags,
+                        SourceLineInfo const& _lineInfo );
+
+        friend void setTags( TestCaseInfo& testCaseInfo, std::vector<std::string> tags );
+
+        bool isHidden() const;
+        bool throws() const;
+        bool okToFail() const;
+        bool expectedToFail() const;
+
+        std::string tagsAsString() const;
+
+        std::string name;
+        std::string className;
+        std::string description;
+        std::vector<std::string> tags;
+        std::vector<std::string> lcaseTags;
+        SourceLineInfo lineInfo;
+        SpecialProperties properties;
+    };
+
+    class TestCase : public TestCaseInfo {
+    public:
+
+        TestCase( ITestInvoker* testCase, TestCaseInfo&& info );
+
+        TestCase withName( std::string const& _newName ) const;
+
+        void invoke() const;
+
+        TestCaseInfo const& getTestCaseInfo() const;
+
+        bool operator == ( TestCase const& other ) const;
+        bool operator < ( TestCase const& other ) const;
+
+    private:
+        std::shared_ptr<ITestInvoker> test;
+    };
+
+    TestCase makeTestCase(  ITestInvoker* testCase,
+                            std::string const& className,
+                            NameAndTags const& nameAndTags,
+                            SourceLineInfo const& lineInfo );
+}
+
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+
+// end catch_test_case_info.h
+// start catch_interfaces_runner.h
+
+namespace Catch {
+
+    struct IRunner {
+        virtual ~IRunner();
+        virtual bool aborting() const = 0;
+    };
+}
+
+// end catch_interfaces_runner.h
+
+#ifdef __OBJC__
+// start catch_objc.hpp
+
+#import <objc/runtime.h>
+
+#include <string>
+
+// NB. Any general catch headers included here must be included
+// in catch.hpp first to make sure they are included by the single
+// header for non obj-usage
+
+///////////////////////////////////////////////////////////////////////////////
+// This protocol is really only here for (self) documenting purposes, since
+// all its methods are optional.
+@protocol OcFixture
+
+@optional
+
+-(void) setUp;
+-(void) tearDown;
+
+@end
+
+namespace Catch {
+
+    class OcMethod : public ITestInvoker {
+
+    public:
+        OcMethod( Class cls, SEL sel ) : m_cls( cls ), m_sel( sel ) {}
+
+        virtual void invoke() const {
+            id obj = [[m_cls alloc] init];
+
+            performOptionalSelector( obj, @selector(setUp)  );
+            performOptionalSelector( obj, m_sel );
+            performOptionalSelector( obj, @selector(tearDown)  );
+
+            arcSafeRelease( obj );
+        }
+    private:
+        virtual ~OcMethod() {}
+
+        Class m_cls;
+        SEL m_sel;
+    };
+
+    namespace Detail{
+
+        inline std::string getAnnotation(   Class cls,
+                                            std::string const& annotationName,
+                                            std::string const& testCaseName ) {
+            NSString* selStr = [[NSString alloc] initWithFormat:@"Catch_%s_%s", annotationName.c_str(), testCaseName.c_str()];
+            SEL sel = NSSelectorFromString( selStr );
+            arcSafeRelease( selStr );
+            id value = performOptionalSelector( cls, sel );
+            if( value )
+                return [(NSString*)value UTF8String];
+            return "";
+        }
+    }
+
+    inline std::size_t registerTestMethods() {
+        std::size_t noTestMethods = 0;
+        int noClasses = objc_getClassList( nullptr, 0 );
+
+        Class* classes = (CATCH_UNSAFE_UNRETAINED Class *)malloc( sizeof(Class) * noClasses);
+        objc_getClassList( classes, noClasses );
+
+        for( int c = 0; c < noClasses; c++ ) {
+            Class cls = classes[c];
+            {
+                u_int count;
+                Method* methods = class_copyMethodList( cls, &count );
+                for( u_int m = 0; m < count ; m++ ) {
+                    SEL selector = method_getName(methods[m]);
+                    std::string methodName = sel_getName(selector);
+                    if( startsWith( methodName, "Catch_TestCase_" ) ) {
+                        std::string testCaseName = methodName.substr( 15 );
+                        std::string name = Detail::getAnnotation( cls, "Name", testCaseName );
+                        std::string desc = Detail::getAnnotation( cls, "Description", testCaseName );
+                        const char* className = class_getName( cls );
+
+                        getMutableRegistryHub().registerTest( makeTestCase( new OcMethod( cls, selector ), className, NameAndTags( name.c_str(), desc.c_str() ), SourceLineInfo("",0) ) );
+                        noTestMethods++;
+                    }
+                }
+                free(methods);
+            }
+        }
+        return noTestMethods;
+    }
+
+#if !defined(CATCH_CONFIG_DISABLE_MATCHERS)
+
+    namespace Matchers {
+        namespace Impl {
+        namespace NSStringMatchers {
+
+            struct StringHolder : MatcherBase<NSString*>{
+                StringHolder( NSString* substr ) : m_substr( [substr copy] ){}
+                StringHolder( StringHolder const& other ) : m_substr( [other.m_substr copy] ){}
+                StringHolder() {
+                    arcSafeRelease( m_substr );
+                }
+
+                bool match( NSString* str ) const override {
+                    return false;
+                }
+
+                NSString* CATCH_ARC_STRONG m_substr;
+            };
+
+            struct Equals : StringHolder {
+                Equals( NSString* substr ) : StringHolder( substr ){}
+
+                bool match( NSString* str ) const override {
+                    return  (str != nil || m_substr == nil ) &&
+                            [str isEqualToString:m_substr];
+                }
+
+                std::string describe() const override {
+                    return "equals string: " + Catch::Detail::stringify( m_substr );
+                }
+            };
+
+            struct Contains : StringHolder {
+                Contains( NSString* substr ) : StringHolder( substr ){}
+
+                bool match( NSString* str ) const override {
+                    return  (str != nil || m_substr == nil ) &&
+                            [str rangeOfString:m_substr].location != NSNotFound;
+                }
+
+                std::string describe() const override {
+                    return "contains string: " + Catch::Detail::stringify( m_substr );
+                }
+            };
+
+            struct StartsWith : StringHolder {
+                StartsWith( NSString* substr ) : StringHolder( substr ){}
+
+                bool match( NSString* str ) const override {
+                    return  (str != nil || m_substr == nil ) &&
+                            [str rangeOfString:m_substr].location == 0;
+                }
+
+                std::string describe() const override {
+                    return "starts with: " + Catch::Detail::stringify( m_substr );
+                }
+            };
+            struct EndsWith : StringHolder {
+                EndsWith( NSString* substr ) : StringHolder( substr ){}
+
+                bool match( NSString* str ) const override {
+                    return  (str != nil || m_substr == nil ) &&
+                            [str rangeOfString:m_substr].location == [str length] - [m_substr length];
+                }
+
+                std::string describe() const override {
+                    return "ends with: " + Catch::Detail::stringify( m_substr );
+                }
+            };
+
+        } // namespace NSStringMatchers
+        } // namespace Impl
+
+        inline Impl::NSStringMatchers::Equals
+            Equals( NSString* substr ){ return Impl::NSStringMatchers::Equals( substr ); }
+
+        inline Impl::NSStringMatchers::Contains
+            Contains( NSString* substr ){ return Impl::NSStringMatchers::Contains( substr ); }
+
+        inline Impl::NSStringMatchers::StartsWith
+            StartsWith( NSString* substr ){ return Impl::NSStringMatchers::StartsWith( substr ); }
+
+        inline Impl::NSStringMatchers::EndsWith
+            EndsWith( NSString* substr ){ return Impl::NSStringMatchers::EndsWith( substr ); }
+
+    } // namespace Matchers
+
+    using namespace Matchers;
+
+#endif // CATCH_CONFIG_DISABLE_MATCHERS
+
+} // namespace Catch
+
+///////////////////////////////////////////////////////////////////////////////
+#define OC_MAKE_UNIQUE_NAME( root, uniqueSuffix ) root##uniqueSuffix
+#define OC_TEST_CASE2( name, desc, uniqueSuffix ) \
++(NSString*) OC_MAKE_UNIQUE_NAME( Catch_Name_test_, uniqueSuffix ) \
+{ \
+return @ name; \
+} \
++(NSString*) OC_MAKE_UNIQUE_NAME( Catch_Description_test_, uniqueSuffix ) \
+{ \
+return @ desc; \
+} \
+-(void) OC_MAKE_UNIQUE_NAME( Catch_TestCase_test_, uniqueSuffix )
+
+#define OC_TEST_CASE( name, desc ) OC_TEST_CASE2( name, desc, __LINE__ )
+
+// end catch_objc.hpp
+#endif
+
+// Benchmarking needs the externally-facing parts of reporters to work
+#if defined(CATCH_CONFIG_EXTERNAL_INTERFACES) || defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
+// start catch_external_interfaces.h
+
+// start catch_reporter_bases.hpp
+
+// start catch_interfaces_reporter.h
+
+// start catch_config.hpp
+
+// start catch_test_spec_parser.h
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wpadded"
+#endif
+
+// start catch_test_spec.h
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wpadded"
+#endif
+
+// start catch_wildcard_pattern.h
+
+namespace Catch
+{
+    class WildcardPattern {
+        enum WildcardPosition {
+            NoWildcard = 0,
+            WildcardAtStart = 1,
+            WildcardAtEnd = 2,
+            WildcardAtBothEnds = WildcardAtStart | WildcardAtEnd
+        };
+
+    public:
+
+        WildcardPattern( std::string const& pattern, CaseSensitive::Choice caseSensitivity );
+        virtual ~WildcardPattern() = default;
+        virtual bool matches( std::string const& str ) const;
+
+    private:
+        std::string normaliseString( std::string const& str ) const;
+        CaseSensitive::Choice m_caseSensitivity;
+        WildcardPosition m_wildcard = NoWildcard;
+        std::string m_pattern;
+    };
+}
+
+// end catch_wildcard_pattern.h
+#include <string>
+#include <vector>
+#include <memory>
+
+namespace Catch {
+
+    struct IConfig;
+
+    class TestSpec {
+        class Pattern {
+        public:
+            explicit Pattern( std::string const& name );
+            virtual ~Pattern();
+            virtual bool matches( TestCaseInfo const& testCase ) const = 0;
+            std::string const& name() const;
+        private:
+            std::string const m_name;
+        };
+        using PatternPtr = std::shared_ptr<Pattern>;
+
+        class NamePattern : public Pattern {
+        public:
+            explicit NamePattern( std::string const& name, std::string const& filterString );
+            bool matches( TestCaseInfo const& testCase ) const override;
+        private:
+            WildcardPattern m_wildcardPattern;
+        };
+
+        class TagPattern : public Pattern {
+        public:
+            explicit TagPattern( std::string const& tag, std::string const& filterString );
+            bool matches( TestCaseInfo const& testCase ) const override;
+        private:
+            std::string m_tag;
+        };
+
+        class ExcludedPattern : public Pattern {
+        public:
+            explicit ExcludedPattern( PatternPtr const& underlyingPattern );
+            bool matches( TestCaseInfo const& testCase ) const override;
+        private:
+            PatternPtr m_underlyingPattern;
+        };
+
+        struct Filter {
+            std::vector<PatternPtr> m_patterns;
+
+            bool matches( TestCaseInfo const& testCase ) const;
+            std::string name() const;
+        };
+
+    public:
+        struct FilterMatch {
+            std::string name;
+            std::vector<TestCase const*> tests;
+        };
+        using Matches = std::vector<FilterMatch>;
+        using vectorStrings = std::vector<std::string>;
+
+        bool hasFilters() const;
+        bool matches( TestCaseInfo const& testCase ) const;
+        Matches matchesByFilter( std::vector<TestCase> const& testCases, IConfig const& config ) const;
+        const vectorStrings & getInvalidArgs() const;
+
+    private:
+        std::vector<Filter> m_filters;
+        std::vector<std::string> m_invalidArgs;
+        friend class TestSpecParser;
+    };
+}
+
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+
+// end catch_test_spec.h
+// start catch_interfaces_tag_alias_registry.h
+
+#include <string>
+
+namespace Catch {
+
+    struct TagAlias;
+
+    struct ITagAliasRegistry {
+        virtual ~ITagAliasRegistry();
+        // Nullptr if not present
+        virtual TagAlias const* find( std::string const& alias ) const = 0;
+        virtual std::string expandAliases( std::string const& unexpandedTestSpec ) const = 0;
+
+        static ITagAliasRegistry const& get();
+    };
+
+} // end namespace Catch
+
+// end catch_interfaces_tag_alias_registry.h
+namespace Catch {
+
+    class TestSpecParser {
+        enum Mode{ None, Name, QuotedName, Tag, EscapedName };
+        Mode m_mode = None;
+        Mode lastMode = None;
+        bool m_exclusion = false;
+        std::size_t m_pos = 0;
+        std::size_t m_realPatternPos = 0;
+        std::string m_arg;
+        std::string m_substring;
+        std::string m_patternName;
+        std::vector<std::size_t> m_escapeChars;
+        TestSpec::Filter m_currentFilter;
+        TestSpec m_testSpec;
+        ITagAliasRegistry const* m_tagAliases = nullptr;
+
+    public:
+        TestSpecParser( ITagAliasRegistry const& tagAliases );
+
+        TestSpecParser& parse( std::string const& arg );
+        TestSpec testSpec();
+
+    private:
+        bool visitChar( char c );
+        void startNewMode( Mode mode );
+        bool processNoneChar( char c );
+        void processNameChar( char c );
+        bool processOtherChar( char c );
+        void endMode();
+        void escape();
+        bool isControlChar( char c ) const;
+        void saveLastMode();
+        void revertBackToLastMode();
+        void addFilter();
+        bool separate();
+
+        // Handles common preprocessing of the pattern for name/tag patterns
+        std::string preprocessPattern();
+        // Adds the current pattern as a test name
+        void addNamePattern();
+        // Adds the current pattern as a tag
+        void addTagPattern();
+
+        inline void addCharToPattern(char c) {
+            m_substring += c;
+            m_patternName += c;
+            m_realPatternPos++;
+        }
+
+    };
+    TestSpec parseTestSpec( std::string const& arg );
+
+} // namespace Catch
+
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+
+// end catch_test_spec_parser.h
+// Libstdc++ doesn't like incomplete classes for unique_ptr
+
+#include <memory>
+#include <vector>
+#include <string>
+
+#ifndef CATCH_CONFIG_CONSOLE_WIDTH
+#define CATCH_CONFIG_CONSOLE_WIDTH 80
+#endif
+
+namespace Catch {
+
+    struct IStream;
+
+    struct ConfigData {
+        bool listTests = false;
+        bool listTags = false;
+        bool listReporters = false;
+        bool listTestNamesOnly = false;
+
+        bool showSuccessfulTests = false;
+        bool shouldDebugBreak = false;
+        bool noThrow = false;
+        bool showHelp = false;
+        bool showInvisibles = false;
+        bool filenamesAsTags = false;
+        bool libIdentify = false;
+
+        int abortAfter = -1;
+        unsigned int rngSeed = 0;
+
+        bool benchmarkNoAnalysis = false;
+        unsigned int benchmarkSamples = 100;
+        double benchmarkConfidenceInterval = 0.95;
+        unsigned int benchmarkResamples = 100000;
+        std::chrono::milliseconds::rep benchmarkWarmupTime = 100;
+
+        Verbosity verbosity = Verbosity::Normal;
+        WarnAbout::What warnings = WarnAbout::Nothing;
+        ShowDurations::OrNot showDurations = ShowDurations::DefaultForReporter;
+        double minDuration = -1;
+        RunTests::InWhatOrder runOrder = RunTests::InDeclarationOrder;
+        UseColour::YesOrNo useColour = UseColour::Auto;
+        WaitForKeypress::When waitForKeypress = WaitForKeypress::Never;
+
+        std::string outputFilename;
+        std::string name;
+        std::string processName;
+#ifndef CATCH_CONFIG_DEFAULT_REPORTER
+#define CATCH_CONFIG_DEFAULT_REPORTER "console"
+#endif
+        std::string reporterName = CATCH_CONFIG_DEFAULT_REPORTER;
+#undef CATCH_CONFIG_DEFAULT_REPORTER
+
+        std::vector<std::string> testsOrTags;
+        std::vector<std::string> sectionsToRun;
+    };
+
+    class Config : public IConfig {
+    public:
+
+        Config() = default;
+        Config( ConfigData const& data );
+        virtual ~Config() = default;
+
+        std::string const& getFilename() const;
+
+        bool listTests() const;
+        bool listTestNamesOnly() const;
+        bool listTags() const;
+        bool listReporters() const;
+
+        std::string getProcessName() const;
+        std::string const& getReporterName() const;
+
+        std::vector<std::string> const& getTestsOrTags() const override;
+        std::vector<std::string> const& getSectionsToRun() const override;
+
+        TestSpec const& testSpec() const override;
+        bool hasTestFilters() const override;
+
+        bool showHelp() const;
+
+        // IConfig interface
+        bool allowThrows() const override;
+        std::ostream& stream() const override;
+        std::string name() const override;
+        bool includeSuccessfulResults() const override;
+        bool warnAboutMissingAssertions() const override;
+        bool warnAboutNoTests() const override;
+        ShowDurations::OrNot showDurations() const override;
+        double minDuration() const override;
+        RunTests::InWhatOrder runOrder() const override;
+        unsigned int rngSeed() const override;
+        UseColour::YesOrNo useColour() const override;
+        bool shouldDebugBreak() const override;
+        int abortAfter() const override;
+        bool showInvisibles() const override;
+        Verbosity verbosity() const override;
+        bool benchmarkNoAnalysis() const override;
+        int benchmarkSamples() const override;
+        double benchmarkConfidenceInterval() const override;
+        unsigned int benchmarkResamples() const override;
+        std::chrono::milliseconds benchmarkWarmupTime() const override;
+
+    private:
+
+        IStream const* openStream();
+        ConfigData m_data;
+
+        std::unique_ptr<IStream const> m_stream;
+        TestSpec m_testSpec;
+        bool m_hasTestFilters = false;
+    };
+
+} // end namespace Catch
+
+// end catch_config.hpp
+// start catch_assertionresult.h
+
+#include <string>
+
+namespace Catch {
+
+    struct AssertionResultData
+    {
+        AssertionResultData() = delete;
+
+        AssertionResultData( ResultWas::OfType _resultType, LazyExpression const& _lazyExpression );
+
+        std::string message;
+        mutable std::string reconstructedExpression;
+        LazyExpression lazyExpression;
+        ResultWas::OfType resultType;
+
+        std::string reconstructExpression() const;
+    };
+
+    class AssertionResult {
+    public:
+        AssertionResult() = delete;
+        AssertionResult( AssertionInfo const& info, AssertionResultData const& data );
+
+        bool isOk() const;
+        bool succeeded() const;
+        ResultWas::OfType getResultType() const;
+        bool hasExpression() const;
+        bool hasMessage() const;
+        std::string getExpression() const;
+        std::string getExpressionInMacro() const;
+        bool hasExpandedExpression() const;
+        std::string getExpandedExpression() const;
+        std::string getMessage() const;
+        SourceLineInfo getSourceInfo() const;
+        StringRef getTestMacroName() const;
+
+    //protected:
+        AssertionInfo m_info;
+        AssertionResultData m_resultData;
+    };
+
+} // end namespace Catch
+
+// end catch_assertionresult.h
+#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
+// start catch_estimate.hpp
+
+ // Statistics estimates
+
+
+namespace Catch {
+    namespace Benchmark {
+        template <typename Duration>
+        struct Estimate {
+            Duration point;
+            Duration lower_bound;
+            Duration upper_bound;
+            double confidence_interval;
+
+            template <typename Duration2>
+            operator Estimate<Duration2>() const {
+                return { point, lower_bound, upper_bound, confidence_interval };
+            }
+        };
+    } // namespace Benchmark
+} // namespace Catch
+
+// end catch_estimate.hpp
+// start catch_outlier_classification.hpp
+
+// Outlier information
+
+namespace Catch {
+    namespace Benchmark {
+        struct OutlierClassification {
+            int samples_seen = 0;
+            int low_severe = 0;     // more than 3 times IQR below Q1
+            int low_mild = 0;       // 1.5 to 3 times IQR below Q1
+            int high_mild = 0;      // 1.5 to 3 times IQR above Q3
+            int high_severe = 0;    // more than 3 times IQR above Q3
+
+            int total() const {
+                return low_severe + low_mild + high_mild + high_severe;
+            }
+        };
+    } // namespace Benchmark
+} // namespace Catch
+
+// end catch_outlier_classification.hpp
+
+#include <iterator>
+#endif // CATCH_CONFIG_ENABLE_BENCHMARKING
+
+#include <string>
+#include <iosfwd>
+#include <map>
+#include <set>
+#include <memory>
+#include <algorithm>
+
+namespace Catch {
+
+    struct ReporterConfig {
+        explicit ReporterConfig( IConfigPtr const& _fullConfig );
+
+        ReporterConfig( IConfigPtr const& _fullConfig, std::ostream& _stream );
+
+        std::ostream& stream() const;
+        IConfigPtr fullConfig() const;
+
+    private:
+        std::ostream* m_stream;
+        IConfigPtr m_fullConfig;
+    };
+
+    struct ReporterPreferences {
+        bool shouldRedirectStdOut = false;
+        bool shouldReportAllAssertions = false;
+    };
+
+    template<typename T>
+    struct LazyStat : Option<T> {
+        LazyStat& operator=( T const& _value ) {
+            Option<T>::operator=( _value );
+            used = false;
+            return *this;
+        }
+        void reset() {
+            Option<T>::reset();
+            used = false;
+        }
+        bool used = false;
+    };
+
+    struct TestRunInfo {
+        TestRunInfo( std::string const& _name );
+        std::string name;
+    };
+    struct GroupInfo {
+        GroupInfo(  std::string const& _name,
+                    std::size_t _groupIndex,
+                    std::size_t _groupsCount );
+
+        std::string name;
+        std::size_t groupIndex;
+        std::size_t groupsCounts;
+    };
+
+    struct AssertionStats {
+        AssertionStats( AssertionResult const& _assertionResult,
+                        std::vector<MessageInfo> const& _infoMessages,
+                        Totals const& _totals );
+
+        AssertionStats( AssertionStats const& )              = default;
+        AssertionStats( AssertionStats && )                  = default;
+        AssertionStats& operator = ( AssertionStats const& ) = delete;
+        AssertionStats& operator = ( AssertionStats && )     = delete;
+        virtual ~AssertionStats();
+
+        AssertionResult assertionResult;
+        std::vector<MessageInfo> infoMessages;
+        Totals totals;
+    };
+
+    struct SectionStats {
+        SectionStats(   SectionInfo const& _sectionInfo,
+                        Counts const& _assertions,
+                        double _durationInSeconds,
+                        bool _missingAssertions );
+        SectionStats( SectionStats const& )              = default;
+        SectionStats( SectionStats && )                  = default;
+        SectionStats& operator = ( SectionStats const& ) = default;
+        SectionStats& operator = ( SectionStats && )     = default;
+        virtual ~SectionStats();
+
+        SectionInfo sectionInfo;
+        Counts assertions;
+        double durationInSeconds;
+        bool missingAssertions;
+    };
+
+    struct TestCaseStats {
+        TestCaseStats(  TestCaseInfo const& _testInfo,
+                        Totals const& _totals,
+                        std::string const& _stdOut,
+                        std::string const& _stdErr,
+                        bool _aborting );
+
+        TestCaseStats( TestCaseStats const& )              = default;
+        TestCaseStats( TestCaseStats && )                  = default;
+        TestCaseStats& operator = ( TestCaseStats const& ) = default;
+        TestCaseStats& operator = ( TestCaseStats && )     = default;
+        virtual ~TestCaseStats();
+
+        TestCaseInfo testInfo;
+        Totals totals;
+        std::string stdOut;
+        std::string stdErr;
+        bool aborting;
+    };
+
+    struct TestGroupStats {
+        TestGroupStats( GroupInfo const& _groupInfo,
+                        Totals const& _totals,
+                        bool _aborting );
+        TestGroupStats( GroupInfo const& _groupInfo );
+
+        TestGroupStats( TestGroupStats const& )              = default;
+        TestGroupStats( TestGroupStats && )                  = default;
+        TestGroupStats& operator = ( TestGroupStats const& ) = default;
+        TestGroupStats& operator = ( TestGroupStats && )     = default;
+        virtual ~TestGroupStats();
+
+        GroupInfo groupInfo;
+        Totals totals;
+        bool aborting;
+    };
+
+    struct TestRunStats {
+        TestRunStats(   TestRunInfo const& _runInfo,
+                        Totals const& _totals,
+                        bool _aborting );
+
+        TestRunStats( TestRunStats const& )              = default;
+        TestRunStats( TestRunStats && )                  = default;
+        TestRunStats& operator = ( TestRunStats const& ) = default;
+        TestRunStats& operator = ( TestRunStats && )     = default;
+        virtual ~TestRunStats();
+
+        TestRunInfo runInfo;
+        Totals totals;
+        bool aborting;
+    };
+
+#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
+    struct BenchmarkInfo {
+        std::string name;
+        double estimatedDuration;
+        int iterations;
+        int samples;
+        unsigned int resamples;
+        double clockResolution;
+        double clockCost;
+    };
+
+    template <class Duration>
+    struct BenchmarkStats {
+        BenchmarkInfo info;
+
+        std::vector<Duration> samples;
+        Benchmark::Estimate<Duration> mean;
+        Benchmark::Estimate<Duration> standardDeviation;
+        Benchmark::OutlierClassification outliers;
+        double outlierVariance;
+
+        template <typename Duration2>
+        operator BenchmarkStats<Duration2>() const {
+            std::vector<Duration2> samples2;
+            samples2.reserve(samples.size());
+            std::transform(samples.begin(), samples.end(), std::back_inserter(samples2), [](Duration d) { return Duration2(d); });
+            return {
+                info,
+                std::move(samples2),
+                mean,
+                standardDeviation,
+                outliers,
+                outlierVariance,
+            };
+        }
+    };
+#endif // CATCH_CONFIG_ENABLE_BENCHMARKING
+
+    struct IStreamingReporter {
+        virtual ~IStreamingReporter() = default;
+
+        // Implementing class must also provide the following static methods:
+        // static std::string getDescription();
+        // static std::set<Verbosity> getSupportedVerbosities()
+
+        virtual ReporterPreferences getPreferences() const = 0;
+
+        virtual void noMatchingTestCases( std::string const& spec ) = 0;
+
+        virtual void reportInvalidArguments(std::string const&) {}
+
+        virtual void testRunStarting( TestRunInfo const& testRunInfo ) = 0;
+        virtual void testGroupStarting( GroupInfo const& groupInfo ) = 0;
+
+        virtual void testCaseStarting( TestCaseInfo const& testInfo ) = 0;
+        virtual void sectionStarting( SectionInfo const& sectionInfo ) = 0;
+
+#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
+        virtual void benchmarkPreparing( std::string const& ) {}
+        virtual void benchmarkStarting( BenchmarkInfo const& ) {}
+        virtual void benchmarkEnded( BenchmarkStats<> const& ) {}
+        virtual void benchmarkFailed( std::string const& ) {}
+#endif // CATCH_CONFIG_ENABLE_BENCHMARKING
+
+        virtual void assertionStarting( AssertionInfo const& assertionInfo ) = 0;
+
+        // The return value indicates if the messages buffer should be cleared:
+        virtual bool assertionEnded( AssertionStats const& assertionStats ) = 0;
+
+        virtual void sectionEnded( SectionStats const& sectionStats ) = 0;
+        virtual void testCaseEnded( TestCaseStats const& testCaseStats ) = 0;
+        virtual void testGroupEnded( TestGroupStats const& testGroupStats ) = 0;
+        virtual void testRunEnded( TestRunStats const& testRunStats ) = 0;
+
+        virtual void skipTest( TestCaseInfo const& testInfo ) = 0;
+
+        // Default empty implementation provided
+        virtual void fatalErrorEncountered( StringRef name );
+
+        virtual bool isMulti() const;
+    };
+    using IStreamingReporterPtr = std::unique_ptr<IStreamingReporter>;
+
+    struct IReporterFactory {
+        virtual ~IReporterFactory();
+        virtual IStreamingReporterPtr create( ReporterConfig const& config ) const = 0;
+        virtual std::string getDescription() const = 0;
+    };
+    using IReporterFactoryPtr = std::shared_ptr<IReporterFactory>;
+
+    struct IReporterRegistry {
+        using FactoryMap = std::map<std::string, IReporterFactoryPtr>;
+        using Listeners = std::vector<IReporterFactoryPtr>;
+
+        virtual ~IReporterRegistry();
+        virtual IStreamingReporterPtr create( std::string const& name, IConfigPtr const& config ) const = 0;
+        virtual FactoryMap const& getFactories() const = 0;
+        virtual Listeners const& getListeners() const = 0;
+    };
+
+} // end namespace Catch
+
+// end catch_interfaces_reporter.h
+#include <algorithm>
+#include <cstring>
+#include <cfloat>
+#include <cstdio>
+#include <cassert>
+#include <memory>
+#include <ostream>
+
+namespace Catch {
+    void prepareExpandedExpression(AssertionResult& result);
+
+    // Returns double formatted as %.3f (format expected on output)
+    std::string getFormattedDuration( double duration );
+
+    //! Should the reporter show
+    bool shouldShowDuration( IConfig const& config, double duration );
+
+    std::string serializeFilters( std::vector<std::string> const& container );
+
+    template<typename DerivedT>
+    struct StreamingReporterBase : IStreamingReporter {
+
+        StreamingReporterBase( ReporterConfig const& _config )
+        :   m_config( _config.fullConfig() ),
+            stream( _config.stream() )
+        {
+            m_reporterPrefs.shouldRedirectStdOut = false;
+            if( !DerivedT::getSupportedVerbosities().count( m_config->verbosity() ) )
+                CATCH_ERROR( "Verbosity level not supported by this reporter" );
+        }
+
+        ReporterPreferences getPreferences() const override {
+            return m_reporterPrefs;
+        }
+
+        static std::set<Verbosity> getSupportedVerbosities() {
+            return { Verbosity::Normal };
+        }
+
+        ~StreamingReporterBase() override = default;
+
+        void noMatchingTestCases(std::string const&) override {}
+
+        void reportInvalidArguments(std::string const&) override {}
+
+        void testRunStarting(TestRunInfo const& _testRunInfo) override {
+            currentTestRunInfo = _testRunInfo;
+        }
+
+        void testGroupStarting(GroupInfo const& _groupInfo) override {
+            currentGroupInfo = _groupInfo;
+        }
+
+        void testCaseStarting(TestCaseInfo const& _testInfo) override  {
+            currentTestCaseInfo = _testInfo;
+        }
+        void sectionStarting(SectionInfo const& _sectionInfo) override {
+            m_sectionStack.push_back(_sectionInfo);
+        }
+
+        void sectionEnded(SectionStats const& /* _sectionStats */) override {
+            m_sectionStack.pop_back();
+        }
+        void testCaseEnded(TestCaseStats const& /* _testCaseStats */) override {
+            currentTestCaseInfo.reset();
+        }
+        void testGroupEnded(TestGroupStats const& /* _testGroupStats */) override {
+            currentGroupInfo.reset();
+        }
+        void testRunEnded(TestRunStats const& /* _testRunStats */) override {
+            currentTestCaseInfo.reset();
+            currentGroupInfo.reset();
+            currentTestRunInfo.reset();
+        }
+
+        void skipTest(TestCaseInfo const&) override {
+            // Don't do anything with this by default.
+            // It can optionally be overridden in the derived class.
+        }
+
+        IConfigPtr m_config;
+        std::ostream& stream;
+
+        LazyStat<TestRunInfo> currentTestRunInfo;
+        LazyStat<GroupInfo> currentGroupInfo;
+        LazyStat<TestCaseInfo> currentTestCaseInfo;
+
+        std::vector<SectionInfo> m_sectionStack;
+        ReporterPreferences m_reporterPrefs;
+    };
+
+    template<typename DerivedT>
+    struct CumulativeReporterBase : IStreamingReporter {
+        template<typename T, typename ChildNodeT>
+        struct Node {
+            explicit Node( T const& _value ) : value( _value ) {}
+            virtual ~Node() {}
+
+            using ChildNodes = std::vector<std::shared_ptr<ChildNodeT>>;
+            T value;
+            ChildNodes children;
+        };
+        struct SectionNode {
+            explicit SectionNode(SectionStats const& _stats) : stats(_stats) {}
+            virtual ~SectionNode() = default;
+
+            bool operator == (SectionNode const& other) const {
+                return stats.sectionInfo.lineInfo == other.stats.sectionInfo.lineInfo;
+            }
+            bool operator == (std::shared_ptr<SectionNode> const& other) const {
+                return operator==(*other);
+            }
+
+            SectionStats stats;
+            using ChildSections = std::vector<std::shared_ptr<SectionNode>>;
+            using Assertions = std::vector<AssertionStats>;
+            ChildSections childSections;
+            Assertions assertions;
+            std::string stdOut;
+            std::string stdErr;
+        };
+
+        struct BySectionInfo {
+            BySectionInfo( SectionInfo const& other ) : m_other( other ) {}
+            BySectionInfo( BySectionInfo const& other ) : m_other( other.m_other ) {}
+            bool operator() (std::shared_ptr<SectionNode> const& node) const {
+                return ((node->stats.sectionInfo.name == m_other.name) &&
+                        (node->stats.sectionInfo.lineInfo == m_other.lineInfo));
+            }
+            void operator=(BySectionInfo const&) = delete;
+
+        private:
+            SectionInfo const& m_other;
+        };
+
+        using TestCaseNode = Node<TestCaseStats, SectionNode>;
+        using TestGroupNode = Node<TestGroupStats, TestCaseNode>;
+        using TestRunNode = Node<TestRunStats, TestGroupNode>;
+
+        CumulativeReporterBase( ReporterConfig const& _config )
+        :   m_config( _config.fullConfig() ),
+            stream( _config.stream() )
+        {
+            m_reporterPrefs.shouldRedirectStdOut = false;
+            if( !DerivedT::getSupportedVerbosities().count( m_config->verbosity() ) )
+                CATCH_ERROR( "Verbosity level not supported by this reporter" );
+        }
+        ~CumulativeReporterBase() override = default;
+
+        ReporterPreferences getPreferences() const override {
+            return m_reporterPrefs;
+        }
+
+        static std::set<Verbosity> getSupportedVerbosities() {
+            return { Verbosity::Normal };
+        }
+
+        void testRunStarting( TestRunInfo const& ) override {}
+        void testGroupStarting( GroupInfo const& ) override {}
+
+        void testCaseStarting( TestCaseInfo const& ) override {}
+
+        void sectionStarting( SectionInfo const& sectionInfo ) override {
+            SectionStats incompleteStats( sectionInfo, Counts(), 0, false );
+            std::shared_ptr<SectionNode> node;
+            if( m_sectionStack.empty() ) {
+                if( !m_rootSection )
+                    m_rootSection = std::make_shared<SectionNode>( incompleteStats );
+                node = m_rootSection;
+            }
+            else {
+                SectionNode& parentNode = *m_sectionStack.back();
+                auto it =
+                    std::find_if(   parentNode.childSections.begin(),
+                                    parentNode.childSections.end(),
+                                    BySectionInfo( sectionInfo ) );
+                if( it == parentNode.childSections.end() ) {
+                    node = std::make_shared<SectionNode>( incompleteStats );
+                    parentNode.childSections.push_back( node );
+                }
+                else
+                    node = *it;
+            }
+            m_sectionStack.push_back( node );
+            m_deepestSection = std::move(node);
+        }
+
+        void assertionStarting(AssertionInfo const&) override {}
+
+        bool assertionEnded(AssertionStats const& assertionStats) override {
+            assert(!m_sectionStack.empty());
+            // AssertionResult holds a pointer to a temporary DecomposedExpression,
+            // which getExpandedExpression() calls to build the expression string.
+            // Our section stack copy of the assertionResult will likely outlive the
+            // temporary, so it must be expanded or discarded now to avoid calling
+            // a destroyed object later.
+            prepareExpandedExpression(const_cast<AssertionResult&>( assertionStats.assertionResult ) );
+            SectionNode& sectionNode = *m_sectionStack.back();
+            sectionNode.assertions.push_back(assertionStats);
+            return true;
+        }
+        void sectionEnded(SectionStats const& sectionStats) override {
+            assert(!m_sectionStack.empty());
+            SectionNode& node = *m_sectionStack.back();
+            node.stats = sectionStats;
+            m_sectionStack.pop_back();
+        }
+        void testCaseEnded(TestCaseStats const& testCaseStats) override {
+            auto node = std::make_shared<TestCaseNode>(testCaseStats);
+            assert(m_sectionStack.size() == 0);
+            node->children.push_back(m_rootSection);
+            m_testCases.push_back(node);
+            m_rootSection.reset();
+
+            assert(m_deepestSection);
+            m_deepestSection->stdOut = testCaseStats.stdOut;
+            m_deepestSection->stdErr = testCaseStats.stdErr;
+        }
+        void testGroupEnded(TestGroupStats const& testGroupStats) override {
+            auto node = std::make_shared<TestGroupNode>(testGroupStats);
+            node->children.swap(m_testCases);
+            m_testGroups.push_back(node);
+        }
+        void testRunEnded(TestRunStats const& testRunStats) override {
+            auto node = std::make_shared<TestRunNode>(testRunStats);
+            node->children.swap(m_testGroups);
+            m_testRuns.push_back(node);
+            testRunEndedCumulative();
+        }
+        virtual void testRunEndedCumulative() = 0;
+
+        void skipTest(TestCaseInfo const&) override {}
+
+        IConfigPtr m_config;
+        std::ostream& stream;
+        std::vector<AssertionStats> m_assertions;
+        std::vector<std::vector<std::shared_ptr<SectionNode>>> m_sections;
+        std::vector<std::shared_ptr<TestCaseNode>> m_testCases;
+        std::vector<std::shared_ptr<TestGroupNode>> m_testGroups;
+
+        std::vector<std::shared_ptr<TestRunNode>> m_testRuns;
+
+        std::shared_ptr<SectionNode> m_rootSection;
+        std::shared_ptr<SectionNode> m_deepestSection;
+        std::vector<std::shared_ptr<SectionNode>> m_sectionStack;
+        ReporterPreferences m_reporterPrefs;
+    };
+
+    template<char C>
+    char const* getLineOfChars() {
+        static char line[CATCH_CONFIG_CONSOLE_WIDTH] = {0};
+        if( !*line ) {
+            std::memset( line, C, CATCH_CONFIG_CONSOLE_WIDTH-1 );
+            line[CATCH_CONFIG_CONSOLE_WIDTH-1] = 0;
+        }
+        return line;
+    }
+
+    struct TestEventListenerBase : StreamingReporterBase<TestEventListenerBase> {
+        TestEventListenerBase( ReporterConfig const& _config );
+
+        static std::set<Verbosity> getSupportedVerbosities();
+
+        void assertionStarting(AssertionInfo const&) override;
+        bool assertionEnded(AssertionStats const&) override;
+    };
+
+} // end namespace Catch
+
+// end catch_reporter_bases.hpp
+// start catch_console_colour.h
+
+namespace Catch {
+
+    struct Colour {
+        enum Code {
+            None = 0,
+
+            White,
+            Red,
+            Green,
+            Blue,
+            Cyan,
+            Yellow,
+            Grey,
+
+            Bright = 0x10,
+
+            BrightRed = Bright | Red,
+            BrightGreen = Bright | Green,
+            LightGrey = Bright | Grey,
+            BrightWhite = Bright | White,
+            BrightYellow = Bright | Yellow,
+
+            // By intention
+            FileName = LightGrey,
+            Warning = BrightYellow,
+            ResultError = BrightRed,
+            ResultSuccess = BrightGreen,
+            ResultExpectedFailure = Warning,
+
+            Error = BrightRed,
+            Success = Green,
+
+            OriginalExpression = Cyan,
+            ReconstructedExpression = BrightYellow,
+
+            SecondaryText = LightGrey,
+            Headers = White
+        };
+
+        // Use constructed object for RAII guard
+        Colour( Code _colourCode );
+        Colour( Colour&& other ) noexcept;
+        Colour& operator=( Colour&& other ) noexcept;
+        ~Colour();
+
+        // Use static method for one-shot changes
+        static void use( Code _colourCode );
+
+    private:
+        bool m_moved = false;
+    };
+
+    std::ostream& operator << ( std::ostream& os, Colour const& );
+
+} // end namespace Catch
+
+// end catch_console_colour.h
+// start catch_reporter_registrars.hpp
+
+
+namespace Catch {
+
+    template<typename T>
+    class ReporterRegistrar {
+
+        class ReporterFactory : public IReporterFactory {
+
+            IStreamingReporterPtr create( ReporterConfig const& config ) const override {
+                return std::unique_ptr<T>( new T( config ) );
+            }
+
+            std::string getDescription() const override {
+                return T::getDescription();
+            }
+        };
+
+    public:
+
+        explicit ReporterRegistrar( std::string const& name ) {
+            getMutableRegistryHub().registerReporter( name, std::make_shared<ReporterFactory>() );
+        }
+    };
+
+    template<typename T>
+    class ListenerRegistrar {
+
+        class ListenerFactory : public IReporterFactory {
+
+            IStreamingReporterPtr create( ReporterConfig const& config ) const override {
+                return std::unique_ptr<T>( new T( config ) );
+            }
+            std::string getDescription() const override {
+                return std::string();
+            }
+        };
+
+    public:
+
+        ListenerRegistrar() {
+            getMutableRegistryHub().registerListener( std::make_shared<ListenerFactory>() );
+        }
+    };
+}
+
+#if !defined(CATCH_CONFIG_DISABLE)
+
+#define CATCH_REGISTER_REPORTER( name, reporterType ) \
+    CATCH_INTERNAL_START_WARNINGS_SUPPRESSION         \
+    CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS          \
+    namespace{ Catch::ReporterRegistrar<reporterType> catch_internal_RegistrarFor##reporterType( name ); } \
+    CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
+
+#define CATCH_REGISTER_LISTENER( listenerType ) \
+    CATCH_INTERNAL_START_WARNINGS_SUPPRESSION   \
+    CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS    \
+    namespace{ Catch::ListenerRegistrar<listenerType> catch_internal_RegistrarFor##listenerType; } \
+    CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
+#else // CATCH_CONFIG_DISABLE
+
+#define CATCH_REGISTER_REPORTER(name, reporterType)
+#define CATCH_REGISTER_LISTENER(listenerType)
+
+#endif // CATCH_CONFIG_DISABLE
+
+// end catch_reporter_registrars.hpp
+// Allow users to base their work off existing reporters
+// start catch_reporter_compact.h
+
+namespace Catch {
+
+    struct CompactReporter : StreamingReporterBase<CompactReporter> {
+
+        using StreamingReporterBase::StreamingReporterBase;
+
+        ~CompactReporter() override;
+
+        static std::string getDescription();
+
+        void noMatchingTestCases(std::string const& spec) override;
+
+        void assertionStarting(AssertionInfo const&) override;
+
+        bool assertionEnded(AssertionStats const& _assertionStats) override;
+
+        void sectionEnded(SectionStats const& _sectionStats) override;
+
+        void testRunEnded(TestRunStats const& _testRunStats) override;
+
+    };
+
+} // end namespace Catch
+
+// end catch_reporter_compact.h
+// start catch_reporter_console.h
+
+#if defined(_MSC_VER)
+#pragma warning(push)
+#pragma warning(disable:4061) // Not all labels are EXPLICITLY handled in switch
+                              // Note that 4062 (not all labels are handled
+                              // and default is missing) is enabled
+#endif
+
+namespace Catch {
+    // Fwd decls
+    struct SummaryColumn;
+    class TablePrinter;
+
+    struct ConsoleReporter : StreamingReporterBase<ConsoleReporter> {
+        std::unique_ptr<TablePrinter> m_tablePrinter;
+
+        ConsoleReporter(ReporterConfig const& config);
+        ~ConsoleReporter() override;
+        static std::string getDescription();
+
+        void noMatchingTestCases(std::string const& spec) override;
+
+        void reportInvalidArguments(std::string const&arg) override;
+
+        void assertionStarting(AssertionInfo const&) override;
+
+        bool assertionEnded(AssertionStats const& _assertionStats) override;
+
+        void sectionStarting(SectionInfo const& _sectionInfo) override;
+        void sectionEnded(SectionStats const& _sectionStats) override;
+
+#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
+        void benchmarkPreparing(std::string const& name) override;
+        void benchmarkStarting(BenchmarkInfo const& info) override;
+        void benchmarkEnded(BenchmarkStats<> const& stats) override;
+        void benchmarkFailed(std::string const& error) override;
+#endif // CATCH_CONFIG_ENABLE_BENCHMARKING
+
+        void testCaseEnded(TestCaseStats const& _testCaseStats) override;
+        void testGroupEnded(TestGroupStats const& _testGroupStats) override;
+        void testRunEnded(TestRunStats const& _testRunStats) override;
+        void testRunStarting(TestRunInfo const& _testRunInfo) override;
+    private:
+
+        void lazyPrint();
+
+        void lazyPrintWithoutClosingBenchmarkTable();
+        void lazyPrintRunInfo();
+        void lazyPrintGroupInfo();
+        void printTestCaseAndSectionHeader();
+
+        void printClosedHeader(std::string const& _name);
+        void printOpenHeader(std::string const& _name);
+
+        // if string has a : in first line will set indent to follow it on
+        // subsequent lines
+        void printHeaderString(std::string const& _string, std::size_t indent = 0);
+
+        void printTotals(Totals const& totals);
+        void printSummaryRow(std::string const& label, std::vector<SummaryColumn> const& cols, std::size_t row);
+
+        void printTotalsDivider(Totals const& totals);
+        void printSummaryDivider();
+        void printTestFilters();
+
+    private:
+        bool m_headerPrinted = false;
+    };
+
+} // end namespace Catch
+
+#if defined(_MSC_VER)
+#pragma warning(pop)
+#endif
+
+// end catch_reporter_console.h
+// start catch_reporter_junit.h
+
+// start catch_xmlwriter.h
+
+#include <vector>
+
+namespace Catch {
+    enum class XmlFormatting {
+        None = 0x00,
+        Indent = 0x01,
+        Newline = 0x02,
+    };
+
+    XmlFormatting operator | (XmlFormatting lhs, XmlFormatting rhs);
+    XmlFormatting operator & (XmlFormatting lhs, XmlFormatting rhs);
+
+    class XmlEncode {
+    public:
+        enum ForWhat { ForTextNodes, ForAttributes };
+
+        XmlEncode( std::string const& str, ForWhat forWhat = ForTextNodes );
+
+        void encodeTo( std::ostream& os ) const;
+
+        friend std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode );
+
+    private:
+        std::string m_str;
+        ForWhat m_forWhat;
+    };
+
+    class XmlWriter {
+    public:
+
+        class ScopedElement {
+        public:
+            ScopedElement( XmlWriter* writer, XmlFormatting fmt );
+
+            ScopedElement( ScopedElement&& other ) noexcept;
+            ScopedElement& operator=( ScopedElement&& other ) noexcept;
+
+            ~ScopedElement();
+
+            ScopedElement& writeText( std::string const& text, XmlFormatting fmt = XmlFormatting::Newline | XmlFormatting::Indent );
+
+            template<typename T>
+            ScopedElement& writeAttribute( std::string const& name, T const& attribute ) {
+                m_writer->writeAttribute( name, attribute );
+                return *this;
+            }
+
+        private:
+            mutable XmlWriter* m_writer = nullptr;
+            XmlFormatting m_fmt;
+        };
+
+        XmlWriter( std::ostream& os = Catch::cout() );
+        ~XmlWriter();
+
+        XmlWriter( XmlWriter const& ) = delete;
+        XmlWriter& operator=( XmlWriter const& ) = delete;
+
+        XmlWriter& startElement( std::string const& name, XmlFormatting fmt = XmlFormatting::Newline | XmlFormatting::Indent);
+
+        ScopedElement scopedElement( std::string const& name, XmlFormatting fmt = XmlFormatting::Newline | XmlFormatting::Indent);
+
+        XmlWriter& endElement(XmlFormatting fmt = XmlFormatting::Newline | XmlFormatting::Indent);
+
+        XmlWriter& writeAttribute( std::string const& name, std::string const& attribute );
+
+        XmlWriter& writeAttribute( std::string const& name, bool attribute );
+
+        template<typename T>
+        XmlWriter& writeAttribute( std::string const& name, T const& attribute ) {
+            ReusableStringStream rss;
+            rss << attribute;
+            return writeAttribute( name, rss.str() );
+        }
+
+        XmlWriter& writeText( std::string const& text, XmlFormatting fmt = XmlFormatting::Newline | XmlFormatting::Indent);
+
+        XmlWriter& writeComment(std::string const& text, XmlFormatting fmt = XmlFormatting::Newline | XmlFormatting::Indent);
+
+        void writeStylesheetRef( std::string const& url );
+
+        XmlWriter& writeBlankLine();
+
+        void ensureTagClosed();
+
+    private:
+
+        void applyFormatting(XmlFormatting fmt);
+
+        void writeDeclaration();
+
+        void newlineIfNecessary();
+
+        bool m_tagIsOpen = false;
+        bool m_needsNewline = false;
+        std::vector<std::string> m_tags;
+        std::string m_indent;
+        std::ostream& m_os;
+    };
+
+}
+
+// end catch_xmlwriter.h
+namespace Catch {
+
+    class JunitReporter : public CumulativeReporterBase<JunitReporter> {
+    public:
+        JunitReporter(ReporterConfig const& _config);
+
+        ~JunitReporter() override;
+
+        static std::string getDescription();
+
+        void noMatchingTestCases(std::string const& /*spec*/) override;
+
+        void testRunStarting(TestRunInfo const& runInfo) override;
+
+        void testGroupStarting(GroupInfo const& groupInfo) override;
+
+        void testCaseStarting(TestCaseInfo const& testCaseInfo) override;
+        bool assertionEnded(AssertionStats const& assertionStats) override;
+
+        void testCaseEnded(TestCaseStats const& testCaseStats) override;
+
+        void testGroupEnded(TestGroupStats const& testGroupStats) override;
+
+        void testRunEndedCumulative() override;
+
+        void writeGroup(TestGroupNode const& groupNode, double suiteTime);
+
+        void writeTestCase(TestCaseNode const& testCaseNode);
+
+        void writeSection( std::string const& className,
+                           std::string const& rootName,
+                           SectionNode const& sectionNode,
+                           bool testOkToFail );
+
+        void writeAssertions(SectionNode const& sectionNode);
+        void writeAssertion(AssertionStats const& stats);
+
+        XmlWriter xml;
+        Timer suiteTimer;
+        std::string stdOutForSuite;
+        std::string stdErrForSuite;
+        unsigned int unexpectedExceptions = 0;
+        bool m_okToFail = false;
+    };
+
+} // end namespace Catch
+
+// end catch_reporter_junit.h
+// start catch_reporter_xml.h
+
+namespace Catch {
+    class XmlReporter : public StreamingReporterBase<XmlReporter> {
+    public:
+        XmlReporter(ReporterConfig const& _config);
+
+        ~XmlReporter() override;
+
+        static std::string getDescription();
+
+        virtual std::string getStylesheetRef() const;
+
+        void writeSourceInfo(SourceLineInfo const& sourceInfo);
+
+    public: // StreamingReporterBase
+
+        void noMatchingTestCases(std::string const& s) override;
+
+        void testRunStarting(TestRunInfo const& testInfo) override;
+
+        void testGroupStarting(GroupInfo const& groupInfo) override;
+
+        void testCaseStarting(TestCaseInfo const& testInfo) override;
+
+        void sectionStarting(SectionInfo const& sectionInfo) override;
+
+        void assertionStarting(AssertionInfo const&) override;
+
+        bool assertionEnded(AssertionStats const& assertionStats) override;
+
+        void sectionEnded(SectionStats const& sectionStats) override;
+
+        void testCaseEnded(TestCaseStats const& testCaseStats) override;
+
+        void testGroupEnded(TestGroupStats const& testGroupStats) override;
+
+        void testRunEnded(TestRunStats const& testRunStats) override;
+
+#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
+        void benchmarkPreparing(std::string const& name) override;
+        void benchmarkStarting(BenchmarkInfo const&) override;
+        void benchmarkEnded(BenchmarkStats<> const&) override;
+        void benchmarkFailed(std::string const&) override;
+#endif // CATCH_CONFIG_ENABLE_BENCHMARKING
+
+    private:
+        Timer m_testCaseTimer;
+        XmlWriter m_xml;
+        int m_sectionDepth = 0;
+    };
+
+} // end namespace Catch
+
+// end catch_reporter_xml.h
+
+// end catch_external_interfaces.h
+#endif
+
+#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
+// start catch_benchmarking_all.hpp
+
+// A proxy header that includes all of the benchmarking headers to allow
+// concise include of the benchmarking features. You should prefer the
+// individual includes in standard use.
+
+// start catch_benchmark.hpp
+
+ // Benchmark
+
+// start catch_chronometer.hpp
+
+// User-facing chronometer
+
+
+// start catch_clock.hpp
+
+// Clocks
+
+
+#include <chrono>
+#include <ratio>
+
+namespace Catch {
+    namespace Benchmark {
+        template <typename Clock>
+        using ClockDuration = typename Clock::duration;
+        template <typename Clock>
+        using FloatDuration = std::chrono::duration<double, typename Clock::period>;
+
+        template <typename Clock>
+        using TimePoint = typename Clock::time_point;
+
+        using default_clock = std::chrono::steady_clock;
+
+        template <typename Clock>
+        struct now {
+            TimePoint<Clock> operator()() const {
+                return Clock::now();
+            }
+        };
+
+        using fp_seconds = std::chrono::duration<double, std::ratio<1>>;
+    } // namespace Benchmark
+} // namespace Catch
+
+// end catch_clock.hpp
+// start catch_optimizer.hpp
+
+ // Hinting the optimizer
+
+
+#if defined(_MSC_VER)
+#   include <atomic> // atomic_thread_fence
+#endif
+
+namespace Catch {
+    namespace Benchmark {
+#if defined(__GNUC__) || defined(__clang__)
+        template <typename T>
+        inline void keep_memory(T* p) {
+            asm volatile("" : : "g"(p) : "memory");
+        }
+        inline void keep_memory() {
+            asm volatile("" : : : "memory");
+        }
+
+        namespace Detail {
+            inline void optimizer_barrier() { keep_memory(); }
+        } // namespace Detail
+#elif defined(_MSC_VER)
+
+#pragma optimize("", off)
+        template <typename T>
+        inline void keep_memory(T* p) {
+            // thanks @milleniumbug
+            *reinterpret_cast<char volatile*>(p) = *reinterpret_cast<char const volatile*>(p);
+        }
+        // TODO equivalent keep_memory()
+#pragma optimize("", on)
+
+        namespace Detail {
+            inline void optimizer_barrier() {
+                std::atomic_thread_fence(std::memory_order_seq_cst);
+            }
+        } // namespace Detail
+
+#endif
+
+        template <typename T>
+        inline void deoptimize_value(T&& x) {
+            keep_memory(&x);
+        }
+
+        template <typename Fn, typename... Args>
+        inline auto invoke_deoptimized(Fn&& fn, Args&&... args) -> typename std::enable_if<!std::is_same<void, decltype(fn(args...))>::value>::type {
+            deoptimize_value(std::forward<Fn>(fn) (std::forward<Args...>(args...)));
+        }
+
+        template <typename Fn, typename... Args>
+        inline auto invoke_deoptimized(Fn&& fn, Args&&... args) -> typename std::enable_if<std::is_same<void, decltype(fn(args...))>::value>::type {
+            std::forward<Fn>(fn) (std::forward<Args...>(args...));
+        }
+    } // namespace Benchmark
+} // namespace Catch
+
+// end catch_optimizer.hpp
+// start catch_complete_invoke.hpp
+
+// Invoke with a special case for void
+
+
+#include <type_traits>
+#include <utility>
+
+namespace Catch {
+    namespace Benchmark {
+        namespace Detail {
+            template <typename T>
+            struct CompleteType { using type = T; };
+            template <>
+            struct CompleteType<void> { struct type {}; };
+
+            template <typename T>
+            using CompleteType_t = typename CompleteType<T>::type;
+
+            template <typename Result>
+            struct CompleteInvoker {
+                template <typename Fun, typename... Args>
+                static Result invoke(Fun&& fun, Args&&... args) {
+                    return std::forward<Fun>(fun)(std::forward<Args>(args)...);
+                }
+            };
+            template <>
+            struct CompleteInvoker<void> {
+                template <typename Fun, typename... Args>
+                static CompleteType_t<void> invoke(Fun&& fun, Args&&... args) {
+                    std::forward<Fun>(fun)(std::forward<Args>(args)...);
+                    return {};
+                }
+            };
+
+            // invoke and not return void :(
+            template <typename Fun, typename... Args>
+            CompleteType_t<FunctionReturnType<Fun, Args...>> complete_invoke(Fun&& fun, Args&&... args) {
+                return CompleteInvoker<FunctionReturnType<Fun, Args...>>::invoke(std::forward<Fun>(fun), std::forward<Args>(args)...);
+            }
+
+            const std::string benchmarkErrorMsg = "a benchmark failed to run successfully";
+        } // namespace Detail
+
+        template <typename Fun>
+        Detail::CompleteType_t<FunctionReturnType<Fun>> user_code(Fun&& fun) {
+            CATCH_TRY{
+                return Detail::complete_invoke(std::forward<Fun>(fun));
+            } CATCH_CATCH_ALL{
+                getResultCapture().benchmarkFailed(translateActiveException());
+                CATCH_RUNTIME_ERROR(Detail::benchmarkErrorMsg);
+            }
+        }
+    } // namespace Benchmark
+} // namespace Catch
+
+// end catch_complete_invoke.hpp
+namespace Catch {
+    namespace Benchmark {
+        namespace Detail {
+            struct ChronometerConcept {
+                virtual void start() = 0;
+                virtual void finish() = 0;
+                virtual ~ChronometerConcept() = default;
+            };
+            template <typename Clock>
+            struct ChronometerModel final : public ChronometerConcept {
+                void start() override { started = Clock::now(); }
+                void finish() override { finished = Clock::now(); }
+
+                ClockDuration<Clock> elapsed() const { return finished - started; }
+
+                TimePoint<Clock> started;
+                TimePoint<Clock> finished;
+            };
+        } // namespace Detail
+
+        struct Chronometer {
+        public:
+            template <typename Fun>
+            void measure(Fun&& fun) { measure(std::forward<Fun>(fun), is_callable<Fun(int)>()); }
+
+            int runs() const { return k; }
+
+            Chronometer(Detail::ChronometerConcept& meter, int k)
+                : impl(&meter)
+                , k(k) {}
+
+        private:
+            template <typename Fun>
+            void measure(Fun&& fun, std::false_type) {
+                measure([&fun](int) { return fun(); }, std::true_type());
+            }
+
+            template <typename Fun>
+            void measure(Fun&& fun, std::true_type) {
+                Detail::optimizer_barrier();
+                impl->start();
+                for (int i = 0; i < k; ++i) invoke_deoptimized(fun, i);
+                impl->finish();
+                Detail::optimizer_barrier();
+            }
+
+            Detail::ChronometerConcept* impl;
+            int k;
+        };
+    } // namespace Benchmark
+} // namespace Catch
+
+// end catch_chronometer.hpp
+// start catch_environment.hpp
+
+// Environment information
+
+
+namespace Catch {
+    namespace Benchmark {
+        template <typename Duration>
+        struct EnvironmentEstimate {
+            Duration mean;
+            OutlierClassification outliers;
+
+            template <typename Duration2>
+            operator EnvironmentEstimate<Duration2>() const {
+                return { mean, outliers };
+            }
+        };
+        template <typename Clock>
+        struct Environment {
+            using clock_type = Clock;
+            EnvironmentEstimate<FloatDuration<Clock>> clock_resolution;
+            EnvironmentEstimate<FloatDuration<Clock>> clock_cost;
+        };
+    } // namespace Benchmark
+} // namespace Catch
+
+// end catch_environment.hpp
+// start catch_execution_plan.hpp
+
+ // Execution plan
+
+
+// start catch_benchmark_function.hpp
+
+ // Dumb std::function implementation for consistent call overhead
+
+
+#include <cassert>
+#include <type_traits>
+#include <utility>
+#include <memory>
+
+namespace Catch {
+    namespace Benchmark {
+        namespace Detail {
+            template <typename T>
+            using Decay = typename std::decay<T>::type;
+            template <typename T, typename U>
+            struct is_related
+                : std::is_same<Decay<T>, Decay<U>> {};
+
+            /// We need to reinvent std::function because every piece of code that might add overhead
+            /// in a measurement context needs to have consistent performance characteristics so that we
+            /// can account for it in the measurement.
+            /// Implementations of std::function with optimizations that aren't always applicable, like
+            /// small buffer optimizations, are not uncommon.
+            /// This is effectively an implementation of std::function without any such optimizations;
+            /// it may be slow, but it is consistently slow.
+            struct BenchmarkFunction {
+            private:
+                struct callable {
+                    virtual void call(Chronometer meter) const = 0;
+                    virtual callable* clone() const = 0;
+                    virtual ~callable() = default;
+                };
+                template <typename Fun>
+                struct model : public callable {
+                    model(Fun&& fun) : fun(std::move(fun)) {}
+                    model(Fun const& fun) : fun(fun) {}
+
+                    model<Fun>* clone() const override { return new model<Fun>(*this); }
+
+                    void call(Chronometer meter) const override {
+                        call(meter, is_callable<Fun(Chronometer)>());
+                    }
+                    void call(Chronometer meter, std::true_type) const {
+                        fun(meter);
+                    }
+                    void call(Chronometer meter, std::false_type) const {
+                        meter.measure(fun);
+                    }
+
+                    Fun fun;
+                };
+
+                struct do_nothing { void operator()() const {} };
+
+                template <typename T>
+                BenchmarkFunction(model<T>* c) : f(c) {}
+
+            public:
+                BenchmarkFunction()
+                    : f(new model<do_nothing>{ {} }) {}
+
+                template <typename Fun,
+                    typename std::enable_if<!is_related<Fun, BenchmarkFunction>::value, int>::type = 0>
+                    BenchmarkFunction(Fun&& fun)
+                    : f(new model<typename std::decay<Fun>::type>(std::forward<Fun>(fun))) {}
+
+                BenchmarkFunction(BenchmarkFunction&& that)
+                    : f(std::move(that.f)) {}
+
+                BenchmarkFunction(BenchmarkFunction const& that)
+                    : f(that.f->clone()) {}
+
+                BenchmarkFunction& operator=(BenchmarkFunction&& that) {
+                    f = std::move(that.f);
+                    return *this;
+                }
+
+                BenchmarkFunction& operator=(BenchmarkFunction const& that) {
+                    f.reset(that.f->clone());
+                    return *this;
+                }
+
+                void operator()(Chronometer meter) const { f->call(meter); }
+
+            private:
+                std::unique_ptr<callable> f;
+            };
+        } // namespace Detail
+    } // namespace Benchmark
+} // namespace Catch
+
+// end catch_benchmark_function.hpp
+// start catch_repeat.hpp
+
+// repeat algorithm
+
+
+#include <type_traits>
+#include <utility>
+
+namespace Catch {
+    namespace Benchmark {
+        namespace Detail {
+            template <typename Fun>
+            struct repeater {
+                void operator()(int k) const {
+                    for (int i = 0; i < k; ++i) {
+                        fun();
+                    }
+                }
+                Fun fun;
+            };
+            template <typename Fun>
+            repeater<typename std::decay<Fun>::type> repeat(Fun&& fun) {
+                return { std::forward<Fun>(fun) };
+            }
+        } // namespace Detail
+    } // namespace Benchmark
+} // namespace Catch
+
+// end catch_repeat.hpp
+// start catch_run_for_at_least.hpp
+
+// Run a function for a minimum amount of time
+
+
+// start catch_measure.hpp
+
+// Measure
+
+
+// start catch_timing.hpp
+
+// Timing
+
+
+#include <tuple>
+#include <type_traits>
+
+namespace Catch {
+    namespace Benchmark {
+        template <typename Duration, typename Result>
+        struct Timing {
+            Duration elapsed;
+            Result result;
+            int iterations;
+        };
+        template <typename Clock, typename Func, typename... Args>
+        using TimingOf = Timing<ClockDuration<Clock>, Detail::CompleteType_t<FunctionReturnType<Func, Args...>>>;
+    } // namespace Benchmark
+} // namespace Catch
+
+// end catch_timing.hpp
+#include <utility>
+
+namespace Catch {
+    namespace Benchmark {
+        namespace Detail {
+            template <typename Clock, typename Fun, typename... Args>
+            TimingOf<Clock, Fun, Args...> measure(Fun&& fun, Args&&... args) {
+                auto start = Clock::now();
+                auto&& r = Detail::complete_invoke(fun, std::forward<Args>(args)...);
+                auto end = Clock::now();
+                auto delta = end - start;
+                return { delta, std::forward<decltype(r)>(r), 1 };
+            }
+        } // namespace Detail
+    } // namespace Benchmark
+} // namespace Catch
+
+// end catch_measure.hpp
+#include <utility>
+#include <type_traits>
+
+namespace Catch {
+    namespace Benchmark {
+        namespace Detail {
+            template <typename Clock, typename Fun>
+            TimingOf<Clock, Fun, int> measure_one(Fun&& fun, int iters, std::false_type) {
+                return Detail::measure<Clock>(fun, iters);
+            }
+            template <typename Clock, typename Fun>
+            TimingOf<Clock, Fun, Chronometer> measure_one(Fun&& fun, int iters, std::true_type) {
+                Detail::ChronometerModel<Clock> meter;
+                auto&& result = Detail::complete_invoke(fun, Chronometer(meter, iters));
+
+                return { meter.elapsed(), std::move(result), iters };
+            }
+
+            template <typename Clock, typename Fun>
+            using run_for_at_least_argument_t = typename std::conditional<is_callable<Fun(Chronometer)>::value, Chronometer, int>::type;
+
+            struct optimized_away_error : std::exception {
+                const char* what() const noexcept override {
+                    return "could not measure benchmark, maybe it was optimized away";
+                }
+            };
+
+            template <typename Clock, typename Fun>
+            TimingOf<Clock, Fun, run_for_at_least_argument_t<Clock, Fun>> run_for_at_least(ClockDuration<Clock> how_long, int seed, Fun&& fun) {
+                auto iters = seed;
+                while (iters < (1 << 30)) {
+                    auto&& Timing = measure_one<Clock>(fun, iters, is_callable<Fun(Chronometer)>());
+
+                    if (Timing.elapsed >= how_long) {
+                        return { Timing.elapsed, std::move(Timing.result), iters };
+                    }
+                    iters *= 2;
+                }
+                Catch::throw_exception(optimized_away_error{});
+            }
+        } // namespace Detail
+    } // namespace Benchmark
+} // namespace Catch
+
+// end catch_run_for_at_least.hpp
+#include <algorithm>
+#include <iterator>
+
+namespace Catch {
+    namespace Benchmark {
+        template <typename Duration>
+        struct ExecutionPlan {
+            int iterations_per_sample;
+            Duration estimated_duration;
+            Detail::BenchmarkFunction benchmark;
+            Duration warmup_time;
+            int warmup_iterations;
+
+            template <typename Duration2>
+            operator ExecutionPlan<Duration2>() const {
+                return { iterations_per_sample, estimated_duration, benchmark, warmup_time, warmup_iterations };
+            }
+
+            template <typename Clock>
+            std::vector<FloatDuration<Clock>> run(const IConfig &cfg, Environment<FloatDuration<Clock>> env) const {
+                // warmup a bit
+                Detail::run_for_at_least<Clock>(std::chrono::duration_cast<ClockDuration<Clock>>(warmup_time), warmup_iterations, Detail::repeat(now<Clock>{}));
+
+                std::vector<FloatDuration<Clock>> times;
+                times.reserve(cfg.benchmarkSamples());
+                std::generate_n(std::back_inserter(times), cfg.benchmarkSamples(), [this, env] {
+                    Detail::ChronometerModel<Clock> model;
+                    this->benchmark(Chronometer(model, iterations_per_sample));
+                    auto sample_time = model.elapsed() - env.clock_cost.mean;
+                    if (sample_time < FloatDuration<Clock>::zero()) sample_time = FloatDuration<Clock>::zero();
+                    return sample_time / iterations_per_sample;
+                });
+                return times;
+            }
+        };
+    } // namespace Benchmark
+} // namespace Catch
+
+// end catch_execution_plan.hpp
+// start catch_estimate_clock.hpp
+
+ // Environment measurement
+
+
+// start catch_stats.hpp
+
+// Statistical analysis tools
+
+
+#include <algorithm>
+#include <functional>
+#include <vector>
+#include <iterator>
+#include <numeric>
+#include <tuple>
+#include <cmath>
+#include <utility>
+#include <cstddef>
+#include <random>
+
+namespace Catch {
+    namespace Benchmark {
+        namespace Detail {
+            using sample = std::vector<double>;
+
+            double weighted_average_quantile(int k, int q, std::vector<double>::iterator first, std::vector<double>::iterator last);
+
+            template <typename Iterator>
+            OutlierClassification classify_outliers(Iterator first, Iterator last) {
+                std::vector<double> copy(first, last);
+
+                auto q1 = weighted_average_quantile(1, 4, copy.begin(), copy.end());
+                auto q3 = weighted_average_quantile(3, 4, copy.begin(), copy.end());
+                auto iqr = q3 - q1;
+                auto los = q1 - (iqr * 3.);
+                auto lom = q1 - (iqr * 1.5);
+                auto him = q3 + (iqr * 1.5);
+                auto his = q3 + (iqr * 3.);
+
+                OutlierClassification o;
+                for (; first != last; ++first) {
+                    auto&& t = *first;
+                    if (t < los) ++o.low_severe;
+                    else if (t < lom) ++o.low_mild;
+                    else if (t > his) ++o.high_severe;
+                    else if (t > him) ++o.high_mild;
+                    ++o.samples_seen;
+                }
+                return o;
+            }
+
+            template <typename Iterator>
+            double mean(Iterator first, Iterator last) {
+                auto count = last - first;
+                double sum = std::accumulate(first, last, 0.);
+                return sum / count;
+            }
+
+            template <typename URng, typename Iterator, typename Estimator>
+            sample resample(URng& rng, int resamples, Iterator first, Iterator last, Estimator& estimator) {
+                auto n = last - first;
+                std::uniform_int_distribution<decltype(n)> dist(0, n - 1);
+
+                sample out;
+                out.reserve(resamples);
+                std::generate_n(std::back_inserter(out), resamples, [n, first, &estimator, &dist, &rng] {
+                    std::vector<double> resampled;
+                    resampled.reserve(n);
+                    std::generate_n(std::back_inserter(resampled), n, [first, &dist, &rng] { return first[dist(rng)]; });
+                    return estimator(resampled.begin(), resampled.end());
+                });
+                std::sort(out.begin(), out.end());
+                return out;
+            }
+
+            template <typename Estimator, typename Iterator>
+            sample jackknife(Estimator&& estimator, Iterator first, Iterator last) {
+                auto n = last - first;
+                auto second = std::next(first);
+                sample results;
+                results.reserve(n);
+
+                for (auto it = first; it != last; ++it) {
+                    std::iter_swap(it, first);
+                    results.push_back(estimator(second, last));
+                }
+
+                return results;
+            }
+
+            inline double normal_cdf(double x) {
+                return std::erfc(-x / std::sqrt(2.0)) / 2.0;
+            }
+
+            double erfc_inv(double x);
+
+            double normal_quantile(double p);
+
+            template <typename Iterator, typename Estimator>
+            Estimate<double> bootstrap(double confidence_level, Iterator first, Iterator last, sample const& resample, Estimator&& estimator) {
+                auto n_samples = last - first;
+
+                double point = estimator(first, last);
+                // Degenerate case with a single sample
+                if (n_samples == 1) return { point, point, point, confidence_level };
+
+                sample jack = jackknife(estimator, first, last);
+                double jack_mean = mean(jack.begin(), jack.end());
+                double sum_squares, sum_cubes;
+                std::tie(sum_squares, sum_cubes) = std::accumulate(jack.begin(), jack.end(), std::make_pair(0., 0.), [jack_mean](std::pair<double, double> sqcb, double x) -> std::pair<double, double> {
+                    auto d = jack_mean - x;
+                    auto d2 = d * d;
+                    auto d3 = d2 * d;
+                    return { sqcb.first + d2, sqcb.second + d3 };
+                });
+
+                double accel = sum_cubes / (6 * std::pow(sum_squares, 1.5));
+                int n = static_cast<int>(resample.size());
+                double prob_n = std::count_if(resample.begin(), resample.end(), [point](double x) { return x < point; }) / (double)n;
+                // degenerate case with uniform samples
+                if (prob_n == 0) return { point, point, point, confidence_level };
+
+                double bias = normal_quantile(prob_n);
+                double z1 = normal_quantile((1. - confidence_level) / 2.);
+
+                auto cumn = [n](double x) -> int {
+                    return std::lround(normal_cdf(x) * n); };
+                auto a = [bias, accel](double b) { return bias + b / (1. - accel * b); };
+                double b1 = bias + z1;
+                double b2 = bias - z1;
+                double a1 = a(b1);
+                double a2 = a(b2);
+                auto lo = (std::max)(cumn(a1), 0);
+                auto hi = (std::min)(cumn(a2), n - 1);
+
+                return { point, resample[lo], resample[hi], confidence_level };
+            }
+
+            double outlier_variance(Estimate<double> mean, Estimate<double> stddev, int n);
+
+            struct bootstrap_analysis {
+                Estimate<double> mean;
+                Estimate<double> standard_deviation;
+                double outlier_variance;
+            };
+
+            bootstrap_analysis analyse_samples(double confidence_level, int n_resamples, std::vector<double>::iterator first, std::vector<double>::iterator last);
+        } // namespace Detail
+    } // namespace Benchmark
+} // namespace Catch
+
+// end catch_stats.hpp
+#include <algorithm>
+#include <iterator>
+#include <tuple>
+#include <vector>
+#include <cmath>
+
+namespace Catch {
+    namespace Benchmark {
+        namespace Detail {
+            template <typename Clock>
+            std::vector<double> resolution(int k) {
+                std::vector<TimePoint<Clock>> times;
+                times.reserve(k + 1);
+                std::generate_n(std::back_inserter(times), k + 1, now<Clock>{});
+
+                std::vector<double> deltas;
+                deltas.reserve(k);
+                std::transform(std::next(times.begin()), times.end(), times.begin(),
+                    std::back_inserter(deltas),
+                    [](TimePoint<Clock> a, TimePoint<Clock> b) { return static_cast<double>((a - b).count()); });
+
+                return deltas;
+            }
+
+            const auto warmup_iterations = 10000;
+            const auto warmup_time = std::chrono::milliseconds(100);
+            const auto minimum_ticks = 1000;
+            const auto warmup_seed = 10000;
+            const auto clock_resolution_estimation_time = std::chrono::milliseconds(500);
+            const auto clock_cost_estimation_time_limit = std::chrono::seconds(1);
+            const auto clock_cost_estimation_tick_limit = 100000;
+            const auto clock_cost_estimation_time = std::chrono::milliseconds(10);
+            const auto clock_cost_estimation_iterations = 10000;
+
+            template <typename Clock>
+            int warmup() {
+                return run_for_at_least<Clock>(std::chrono::duration_cast<ClockDuration<Clock>>(warmup_time), warmup_seed, &resolution<Clock>)
+                    .iterations;
+            }
+            template <typename Clock>
+            EnvironmentEstimate<FloatDuration<Clock>> estimate_clock_resolution(int iterations) {
+                auto r = run_for_at_least<Clock>(std::chrono::duration_cast<ClockDuration<Clock>>(clock_resolution_estimation_time), iterations, &resolution<Clock>)
+                    .result;
+                return {
+                    FloatDuration<Clock>(mean(r.begin(), r.end())),
+                    classify_outliers(r.begin(), r.end()),
+                };
+            }
+            template <typename Clock>
+            EnvironmentEstimate<FloatDuration<Clock>> estimate_clock_cost(FloatDuration<Clock> resolution) {
+                auto time_limit = (std::min)(
+                    resolution * clock_cost_estimation_tick_limit,
+                    FloatDuration<Clock>(clock_cost_estimation_time_limit));
+                auto time_clock = [](int k) {
+                    return Detail::measure<Clock>([k] {
+                        for (int i = 0; i < k; ++i) {
+                            volatile auto ignored = Clock::now();
+                            (void)ignored;
+                        }
+                    }).elapsed;
+                };
+                time_clock(1);
+                int iters = clock_cost_estimation_iterations;
+                auto&& r = run_for_at_least<Clock>(std::chrono::duration_cast<ClockDuration<Clock>>(clock_cost_estimation_time), iters, time_clock);
+                std::vector<double> times;
+                int nsamples = static_cast<int>(std::ceil(time_limit / r.elapsed));
+                times.reserve(nsamples);
+                std::generate_n(std::back_inserter(times), nsamples, [time_clock, &r] {
+                    return static_cast<double>((time_clock(r.iterations) / r.iterations).count());
+                });
+                return {
+                    FloatDuration<Clock>(mean(times.begin(), times.end())),
+                    classify_outliers(times.begin(), times.end()),
+                };
+            }
+
+            template <typename Clock>
+            Environment<FloatDuration<Clock>> measure_environment() {
+                static Environment<FloatDuration<Clock>>* env = nullptr;
+                if (env) {
+                    return *env;
+                }
+
+                auto iters = Detail::warmup<Clock>();
+                auto resolution = Detail::estimate_clock_resolution<Clock>(iters);
+                auto cost = Detail::estimate_clock_cost<Clock>(resolution.mean);
+
+                env = new Environment<FloatDuration<Clock>>{ resolution, cost };
+                return *env;
+            }
+        } // namespace Detail
+    } // namespace Benchmark
+} // namespace Catch
+
+// end catch_estimate_clock.hpp
+// start catch_analyse.hpp
+
+ // Run and analyse one benchmark
+
+
+// start catch_sample_analysis.hpp
+
+// Benchmark results
+
+
+#include <algorithm>
+#include <vector>
+#include <string>
+#include <iterator>
+
+namespace Catch {
+    namespace Benchmark {
+        template <typename Duration>
+        struct SampleAnalysis {
+            std::vector<Duration> samples;
+            Estimate<Duration> mean;
+            Estimate<Duration> standard_deviation;
+            OutlierClassification outliers;
+            double outlier_variance;
+
+            template <typename Duration2>
+            operator SampleAnalysis<Duration2>() const {
+                std::vector<Duration2> samples2;
+                samples2.reserve(samples.size());
+                std::transform(samples.begin(), samples.end(), std::back_inserter(samples2), [](Duration d) { return Duration2(d); });
+                return {
+                    std::move(samples2),
+                    mean,
+                    standard_deviation,
+                    outliers,
+                    outlier_variance,
+                };
+            }
+        };
+    } // namespace Benchmark
+} // namespace Catch
+
+// end catch_sample_analysis.hpp
+#include <algorithm>
+#include <iterator>
+#include <vector>
+
+namespace Catch {
+    namespace Benchmark {
+        namespace Detail {
+            template <typename Duration, typename Iterator>
+            SampleAnalysis<Duration> analyse(const IConfig &cfg, Environment<Duration>, Iterator first, Iterator last) {
+                if (!cfg.benchmarkNoAnalysis()) {
+                    std::vector<double> samples;
+                    samples.reserve(last - first);
+                    std::transform(first, last, std::back_inserter(samples), [](Duration d) { return d.count(); });
+
+                    auto analysis = Catch::Benchmark::Detail::analyse_samples(cfg.benchmarkConfidenceInterval(), cfg.benchmarkResamples(), samples.begin(), samples.end());
+                    auto outliers = Catch::Benchmark::Detail::classify_outliers(samples.begin(), samples.end());
+
+                    auto wrap_estimate = [](Estimate<double> e) {
+                        return Estimate<Duration> {
+                            Duration(e.point),
+                                Duration(e.lower_bound),
+                                Duration(e.upper_bound),
+                                e.confidence_interval,
+                        };
+                    };
+                    std::vector<Duration> samples2;
+                    samples2.reserve(samples.size());
+                    std::transform(samples.begin(), samples.end(), std::back_inserter(samples2), [](double d) { return Duration(d); });
+                    return {
+                        std::move(samples2),
+                        wrap_estimate(analysis.mean),
+                        wrap_estimate(analysis.standard_deviation),
+                        outliers,
+                        analysis.outlier_variance,
+                    };
+                } else {
+                    std::vector<Duration> samples;
+                    samples.reserve(last - first);
+
+                    Duration mean = Duration(0);
+                    int i = 0;
+                    for (auto it = first; it < last; ++it, ++i) {
+                        samples.push_back(Duration(*it));
+                        mean += Duration(*it);
+                    }
+                    mean /= i;
+
+                    return {
+                        std::move(samples),
+                        Estimate<Duration>{mean, mean, mean, 0.0},
+                        Estimate<Duration>{Duration(0), Duration(0), Duration(0), 0.0},
+                        OutlierClassification{},
+                        0.0
+                    };
+                }
+            }
+        } // namespace Detail
+    } // namespace Benchmark
+} // namespace Catch
+
+// end catch_analyse.hpp
+#include <algorithm>
+#include <functional>
+#include <string>
+#include <vector>
+#include <cmath>
+
+namespace Catch {
+    namespace Benchmark {
+        struct Benchmark {
+            Benchmark(std::string &&name)
+                : name(std::move(name)) {}
+
+            template <class FUN>
+            Benchmark(std::string &&name, FUN &&func)
+                : fun(std::move(func)), name(std::move(name)) {}
+
+            template <typename Clock>
+            ExecutionPlan<FloatDuration<Clock>> prepare(const IConfig &cfg, Environment<FloatDuration<Clock>> env) const {
+                auto min_time = env.clock_resolution.mean * Detail::minimum_ticks;
+                auto run_time = std::max(min_time, std::chrono::duration_cast<decltype(min_time)>(cfg.benchmarkWarmupTime()));
+                auto&& test = Detail::run_for_at_least<Clock>(std::chrono::duration_cast<ClockDuration<Clock>>(run_time), 1, fun);
+                int new_iters = static_cast<int>(std::ceil(min_time * test.iterations / test.elapsed));
+                return { new_iters, test.elapsed / test.iterations * new_iters * cfg.benchmarkSamples(), fun, std::chrono::duration_cast<FloatDuration<Clock>>(cfg.benchmarkWarmupTime()), Detail::warmup_iterations };
+            }
+
+            template <typename Clock = default_clock>
+            void run() {
+                IConfigPtr cfg = getCurrentContext().getConfig();
+
+                auto env = Detail::measure_environment<Clock>();
+
+                getResultCapture().benchmarkPreparing(name);
+                CATCH_TRY{
+                    auto plan = user_code([&] {
+                        return prepare<Clock>(*cfg, env);
+                    });
+
+                    BenchmarkInfo info {
+                        name,
+                        plan.estimated_duration.count(),
+                        plan.iterations_per_sample,
+                        cfg->benchmarkSamples(),
+                        cfg->benchmarkResamples(),
+                        env.clock_resolution.mean.count(),
+                        env.clock_cost.mean.count()
+                    };
+
+                    getResultCapture().benchmarkStarting(info);
+
+                    auto samples = user_code([&] {
+                        return plan.template run<Clock>(*cfg, env);
+                    });
+
+                    auto analysis = Detail::analyse(*cfg, env, samples.begin(), samples.end());
+                    BenchmarkStats<FloatDuration<Clock>> stats{ info, analysis.samples, analysis.mean, analysis.standard_deviation, analysis.outliers, analysis.outlier_variance };
+                    getResultCapture().benchmarkEnded(stats);
+
+                } CATCH_CATCH_ALL{
+                    if (translateActiveException() != Detail::benchmarkErrorMsg) // benchmark errors have been reported, otherwise rethrow.
+                        std::rethrow_exception(std::current_exception());
+                }
+            }
+
+            // sets lambda to be used in fun *and* executes benchmark!
+            template <typename Fun,
+                typename std::enable_if<!Detail::is_related<Fun, Benchmark>::value, int>::type = 0>
+                Benchmark & operator=(Fun func) {
+                fun = Detail::BenchmarkFunction(func);
+                run();
+                return *this;
+            }
+
+            explicit operator bool() {
+                return true;
+            }
+
+        private:
+            Detail::BenchmarkFunction fun;
+            std::string name;
+        };
+    }
+} // namespace Catch
+
+#define INTERNAL_CATCH_GET_1_ARG(arg1, arg2, ...) arg1
+#define INTERNAL_CATCH_GET_2_ARG(arg1, arg2, ...) arg2
+
+#define INTERNAL_CATCH_BENCHMARK(BenchmarkName, name, benchmarkIndex)\
+    if( Catch::Benchmark::Benchmark BenchmarkName{name} ) \
+        BenchmarkName = [&](int benchmarkIndex)
+
+#define INTERNAL_CATCH_BENCHMARK_ADVANCED(BenchmarkName, name)\
+    if( Catch::Benchmark::Benchmark BenchmarkName{name} ) \
+        BenchmarkName = [&]
+
+// end catch_benchmark.hpp
+// start catch_constructor.hpp
+
+// Constructor and destructor helpers
+
+
+#include <type_traits>
+
+namespace Catch {
+    namespace Benchmark {
+        namespace Detail {
+            template <typename T, bool Destruct>
+            struct ObjectStorage
+            {
+                using TStorage = typename std::aligned_storage<sizeof(T), std::alignment_of<T>::value>::type;
+
+                ObjectStorage() : data() {}
+
+                ObjectStorage(const ObjectStorage& other)
+                {
+                    new(&data) T(other.stored_object());
+                }
+
+                ObjectStorage(ObjectStorage&& other)
+                {
+                    new(&data) T(std::move(other.stored_object()));
+                }
+
+                ~ObjectStorage() { destruct_on_exit<T>(); }
+
+                template <typename... Args>
+                void construct(Args&&... args)
+                {
+                    new (&data) T(std::forward<Args>(args)...);
+                }
+
+                template <bool AllowManualDestruction = !Destruct>
+                typename std::enable_if<AllowManualDestruction>::type destruct()
+                {
+                    stored_object().~T();
+                }
+
+            private:
+                // If this is a constructor benchmark, destruct the underlying object
+                template <typename U>
+                void destruct_on_exit(typename std::enable_if<Destruct, U>::type* = 0) { destruct<true>(); }
+                // Otherwise, don't
+                template <typename U>
+                void destruct_on_exit(typename std::enable_if<!Destruct, U>::type* = 0) { }
+
+                T& stored_object() {
+                    return *static_cast<T*>(static_cast<void*>(&data));
+                }
+
+                T const& stored_object() const {
+                    return *static_cast<T*>(static_cast<void*>(&data));
+                }
+
+                TStorage data;
+            };
+        }
+
+        template <typename T>
+        using storage_for = Detail::ObjectStorage<T, true>;
+
+        template <typename T>
+        using destructable_object = Detail::ObjectStorage<T, false>;
+    }
+}
+
+// end catch_constructor.hpp
+// end catch_benchmarking_all.hpp
+#endif
+
+#endif // ! CATCH_CONFIG_IMPL_ONLY
+
+#ifdef CATCH_IMPL
+// start catch_impl.hpp
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wweak-vtables"
+#endif
+
+// Keep these here for external reporters
+// start catch_test_case_tracker.h
+
+#include <string>
+#include <vector>
+#include <memory>
+
+namespace Catch {
+namespace TestCaseTracking {
+
+    struct NameAndLocation {
+        std::string name;
+        SourceLineInfo location;
+
+        NameAndLocation( std::string const& _name, SourceLineInfo const& _location );
+        friend bool operator==(NameAndLocation const& lhs, NameAndLocation const& rhs) {
+            return lhs.name == rhs.name
+                && lhs.location == rhs.location;
+        }
+    };
+
+    class ITracker;
+
+    using ITrackerPtr = std::shared_ptr<ITracker>;
+
+    class  ITracker {
+        NameAndLocation m_nameAndLocation;
+
+    public:
+        ITracker(NameAndLocation const& nameAndLoc) :
+            m_nameAndLocation(nameAndLoc)
+        {}
+
+        // static queries
+        NameAndLocation const& nameAndLocation() const {
+            return m_nameAndLocation;
+        }
+
+        virtual ~ITracker();
+
+        // dynamic queries
+        virtual bool isComplete() const = 0; // Successfully completed or failed
+        virtual bool isSuccessfullyCompleted() const = 0;
+        virtual bool isOpen() const = 0; // Started but not complete
+        virtual bool hasChildren() const = 0;
+        virtual bool hasStarted() const = 0;
+
+        virtual ITracker& parent() = 0;
+
+        // actions
+        virtual void close() = 0; // Successfully complete
+        virtual void fail() = 0;
+        virtual void markAsNeedingAnotherRun() = 0;
+
+        virtual void addChild( ITrackerPtr const& child ) = 0;
+        virtual ITrackerPtr findChild( NameAndLocation const& nameAndLocation ) = 0;
+        virtual void openChild() = 0;
+
+        // Debug/ checking
+        virtual bool isSectionTracker() const = 0;
+        virtual bool isGeneratorTracker() const = 0;
+    };
+
+    class TrackerContext {
+
+        enum RunState {
+            NotStarted,
+            Executing,
+            CompletedCycle
+        };
+
+        ITrackerPtr m_rootTracker;
+        ITracker* m_currentTracker = nullptr;
+        RunState m_runState = NotStarted;
+
+    public:
+
+        ITracker& startRun();
+        void endRun();
+
+        void startCycle();
+        void completeCycle();
+
+        bool completedCycle() const;
+        ITracker& currentTracker();
+        void setCurrentTracker( ITracker* tracker );
+    };
+
+    class TrackerBase : public ITracker {
+    protected:
+        enum CycleState {
+            NotStarted,
+            Executing,
+            ExecutingChildren,
+            NeedsAnotherRun,
+            CompletedSuccessfully,
+            Failed
+        };
+
+        using Children = std::vector<ITrackerPtr>;
+        TrackerContext& m_ctx;
+        ITracker* m_parent;
+        Children m_children;
+        CycleState m_runState = NotStarted;
+
+    public:
+        TrackerBase( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent );
+
+        bool isComplete() const override;
+        bool isSuccessfullyCompleted() const override;
+        bool isOpen() const override;
+        bool hasChildren() const override;
+        bool hasStarted() const override {
+            return m_runState != NotStarted;
+        }
+
+        void addChild( ITrackerPtr const& child ) override;
+
+        ITrackerPtr findChild( NameAndLocation const& nameAndLocation ) override;
+        ITracker& parent() override;
+
+        void openChild() override;
+
+        bool isSectionTracker() const override;
+        bool isGeneratorTracker() const override;
+
+        void open();
+
+        void close() override;
+        void fail() override;
+        void markAsNeedingAnotherRun() override;
+
+    private:
+        void moveToParent();
+        void moveToThis();
+    };
+
+    class SectionTracker : public TrackerBase {
+        std::vector<std::string> m_filters;
+        std::string m_trimmed_name;
+    public:
+        SectionTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent );
+
+        bool isSectionTracker() const override;
+
+        bool isComplete() const override;
+
+        static SectionTracker& acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation );
+
+        void tryOpen();
+
+        void addInitialFilters( std::vector<std::string> const& filters );
+        void addNextFilters( std::vector<std::string> const& filters );
+        //! Returns filters active in this tracker
+        std::vector<std::string> const& getFilters() const;
+        //! Returns whitespace-trimmed name of the tracked section
+        std::string const& trimmedName() const;
+    };
+
+} // namespace TestCaseTracking
+
+using TestCaseTracking::ITracker;
+using TestCaseTracking::TrackerContext;
+using TestCaseTracking::SectionTracker;
+
+} // namespace Catch
+
+// end catch_test_case_tracker.h
+
+// start catch_leak_detector.h
+
+namespace Catch {
+
+    struct LeakDetector {
+        LeakDetector();
+        ~LeakDetector();
+    };
+
+}
+// end catch_leak_detector.h
+// Cpp files will be included in the single-header file here
+// start catch_stats.cpp
+
+// Statistical analysis tools
+
+#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
+
+#include <cassert>
+#include <random>
+
+#if defined(CATCH_CONFIG_USE_ASYNC)
+#include <future>
+#endif
+
+namespace {
+    double erf_inv(double x) {
+        // Code accompanying the article "Approximating the erfinv function" in GPU Computing Gems, Volume 2
+        double w, p;
+
+        w = -log((1.0 - x) * (1.0 + x));
+
+        if (w < 6.250000) {
+            w = w - 3.125000;
+            p = -3.6444120640178196996e-21;
+            p = -1.685059138182016589e-19 + p * w;
+            p = 1.2858480715256400167e-18 + p * w;
+            p = 1.115787767802518096e-17 + p * w;
+            p = -1.333171662854620906e-16 + p * w;
+            p = 2.0972767875968561637e-17 + p * w;
+            p = 6.6376381343583238325e-15 + p * w;
+            p = -4.0545662729752068639e-14 + p * w;
+            p = -8.1519341976054721522e-14 + p * w;
+            p = 2.6335093153082322977e-12 + p * w;
+            p = -1.2975133253453532498e-11 + p * w;
+            p = -5.4154120542946279317e-11 + p * w;
+            p = 1.051212273321532285e-09 + p * w;
+            p = -4.1126339803469836976e-09 + p * w;
+            p = -2.9070369957882005086e-08 + p * w;
+            p = 4.2347877827932403518e-07 + p * w;
+            p = -1.3654692000834678645e-06 + p * w;
+            p = -1.3882523362786468719e-05 + p * w;
+            p = 0.0001867342080340571352 + p * w;
+            p = -0.00074070253416626697512 + p * w;
+            p = -0.0060336708714301490533 + p * w;
+            p = 0.24015818242558961693 + p * w;
+            p = 1.6536545626831027356 + p * w;
+        } else if (w < 16.000000) {
+            w = sqrt(w) - 3.250000;
+            p = 2.2137376921775787049e-09;
+            p = 9.0756561938885390979e-08 + p * w;
+            p = -2.7517406297064545428e-07 + p * w;
+            p = 1.8239629214389227755e-08 + p * w;
+            p = 1.5027403968909827627e-06 + p * w;
+            p = -4.013867526981545969e-06 + p * w;
+            p = 2.9234449089955446044e-06 + p * w;
+            p = 1.2475304481671778723e-05 + p * w;
+            p = -4.7318229009055733981e-05 + p * w;
+            p = 6.8284851459573175448e-05 + p * w;
+            p = 2.4031110387097893999e-05 + p * w;
+            p = -0.0003550375203628474796 + p * w;
+            p = 0.00095328937973738049703 + p * w;
+            p = -0.0016882755560235047313 + p * w;
+            p = 0.0024914420961078508066 + p * w;
+            p = -0.0037512085075692412107 + p * w;
+            p = 0.005370914553590063617 + p * w;
+            p = 1.0052589676941592334 + p * w;
+            p = 3.0838856104922207635 + p * w;
+        } else {
+            w = sqrt(w) - 5.000000;
+            p = -2.7109920616438573243e-11;
+            p = -2.5556418169965252055e-10 + p * w;
+            p = 1.5076572693500548083e-09 + p * w;
+            p = -3.7894654401267369937e-09 + p * w;
+            p = 7.6157012080783393804e-09 + p * w;
+            p = -1.4960026627149240478e-08 + p * w;
+            p = 2.9147953450901080826e-08 + p * w;
+            p = -6.7711997758452339498e-08 + p * w;
+            p = 2.2900482228026654717e-07 + p * w;
+            p = -9.9298272942317002539e-07 + p * w;
+            p = 4.5260625972231537039e-06 + p * w;
+            p = -1.9681778105531670567e-05 + p * w;
+            p = 7.5995277030017761139e-05 + p * w;
+            p = -0.00021503011930044477347 + p * w;
+            p = -0.00013871931833623122026 + p * w;
+            p = 1.0103004648645343977 + p * w;
+            p = 4.8499064014085844221 + p * w;
+        }
+        return p * x;
+    }
+
+    double standard_deviation(std::vector<double>::iterator first, std::vector<double>::iterator last) {
+        auto m = Catch::Benchmark::Detail::mean(first, last);
+        double variance = std::accumulate(first, last, 0., [m](double a, double b) {
+            double diff = b - m;
+            return a + diff * diff;
+            }) / (last - first);
+            return std::sqrt(variance);
+    }
+
+}
+
+namespace Catch {
+    namespace Benchmark {
+        namespace Detail {
+
+            double weighted_average_quantile(int k, int q, std::vector<double>::iterator first, std::vector<double>::iterator last) {
+                auto count = last - first;
+                double idx = (count - 1) * k / static_cast<double>(q);
+                int j = static_cast<int>(idx);
+                double g = idx - j;
+                std::nth_element(first, first + j, last);
+                auto xj = first[j];
+                if (g == 0) return xj;
+
+                auto xj1 = *std::min_element(first + (j + 1), last);
+                return xj + g * (xj1 - xj);
+            }
+
+            double erfc_inv(double x) {
+                return erf_inv(1.0 - x);
+            }
+
+            double normal_quantile(double p) {
+                static const double ROOT_TWO = std::sqrt(2.0);
+
+                double result = 0.0;
+                assert(p >= 0 && p <= 1);
+                if (p < 0 || p > 1) {
+                    return result;
+                }
+
+                result = -erfc_inv(2.0 * p);
+                // result *= normal distribution standard deviation (1.0) * sqrt(2)
+                result *= /*sd * */ ROOT_TWO;
+                // result += normal disttribution mean (0)
+                return result;
+            }
+
+            double outlier_variance(Estimate<double> mean, Estimate<double> stddev, int n) {
+                double sb = stddev.point;
+                double mn = mean.point / n;
+                double mg_min = mn / 2.;
+                double sg = (std::min)(mg_min / 4., sb / std::sqrt(n));
+                double sg2 = sg * sg;
+                double sb2 = sb * sb;
+
+                auto c_max = [n, mn, sb2, sg2](double x) -> double {
+                    double k = mn - x;
+                    double d = k * k;
+                    double nd = n * d;
+                    double k0 = -n * nd;
+                    double k1 = sb2 - n * sg2 + nd;
+                    double det = k1 * k1 - 4 * sg2 * k0;
+                    return (int)(-2. * k0 / (k1 + std::sqrt(det)));
+                };
+
+                auto var_out = [n, sb2, sg2](double c) {
+                    double nc = n - c;
+                    return (nc / n) * (sb2 - nc * sg2);
+                };
+
+                return (std::min)(var_out(1), var_out((std::min)(c_max(0.), c_max(mg_min)))) / sb2;
+            }
+
+            bootstrap_analysis analyse_samples(double confidence_level, int n_resamples, std::vector<double>::iterator first, std::vector<double>::iterator last) {
+                CATCH_INTERNAL_START_WARNINGS_SUPPRESSION
+                CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS
+                static std::random_device entropy;
+                CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
+
+                auto n = static_cast<int>(last - first); // seriously, one can't use integral types without hell in C++
+
+                auto mean = &Detail::mean<std::vector<double>::iterator>;
+                auto stddev = &standard_deviation;
+
+#if defined(CATCH_CONFIG_USE_ASYNC)
+                auto Estimate = [=](double(*f)(std::vector<double>::iterator, std::vector<double>::iterator)) {
+                    auto seed = entropy();
+                    return std::async(std::launch::async, [=] {
+                        std::mt19937 rng(seed);
+                        auto resampled = resample(rng, n_resamples, first, last, f);
+                        return bootstrap(confidence_level, first, last, resampled, f);
+                    });
+                };
+
+                auto mean_future = Estimate(mean);
+                auto stddev_future = Estimate(stddev);
+
+                auto mean_estimate = mean_future.get();
+                auto stddev_estimate = stddev_future.get();
+#else
+                auto Estimate = [=](double(*f)(std::vector<double>::iterator, std::vector<double>::iterator)) {
+                    auto seed = entropy();
+                    std::mt19937 rng(seed);
+                    auto resampled = resample(rng, n_resamples, first, last, f);
+                    return bootstrap(confidence_level, first, last, resampled, f);
+                };
+
+                auto mean_estimate = Estimate(mean);
+                auto stddev_estimate = Estimate(stddev);
+#endif // CATCH_USE_ASYNC
+
+                double outlier_variance = Detail::outlier_variance(mean_estimate, stddev_estimate, n);
+
+                return { mean_estimate, stddev_estimate, outlier_variance };
+            }
+        } // namespace Detail
+    } // namespace Benchmark
+} // namespace Catch
+
+#endif // CATCH_CONFIG_ENABLE_BENCHMARKING
+// end catch_stats.cpp
+// start catch_approx.cpp
+
+#include <cmath>
+#include <limits>
+
+namespace {
+
+// Performs equivalent check of std::fabs(lhs - rhs) <= margin
+// But without the subtraction to allow for INFINITY in comparison
+bool marginComparison(double lhs, double rhs, double margin) {
+    return (lhs + margin >= rhs) && (rhs + margin >= lhs);
+}
+
+}
+
+namespace Catch {
+namespace Detail {
+
+    Approx::Approx ( double value )
+    :   m_epsilon( std::numeric_limits<float>::epsilon()*100 ),
+        m_margin( 0.0 ),
+        m_scale( 0.0 ),
+        m_value( value )
+    {}
+
+    Approx Approx::custom() {
+        return Approx( 0 );
+    }
+
+    Approx Approx::operator-() const {
+        auto temp(*this);
+        temp.m_value = -temp.m_value;
+        return temp;
+    }
+
+    std::string Approx::toString() const {
+        ReusableStringStream rss;
+        rss << "Approx( " << ::Catch::Detail::stringify( m_value ) << " )";
+        return rss.str();
+    }
+
+    bool Approx::equalityComparisonImpl(const double other) const {
+        // First try with fixed margin, then compute margin based on epsilon, scale and Approx's value
+        // Thanks to Richard Harris for his help refining the scaled margin value
+        return marginComparison(m_value, other, m_margin)
+            || marginComparison(m_value, other, m_epsilon * (m_scale + std::fabs(std::isinf(m_value)? 0 : m_value)));
+    }
+
+    void Approx::setMargin(double newMargin) {
+        CATCH_ENFORCE(newMargin >= 0,
+            "Invalid Approx::margin: " << newMargin << '.'
+            << " Approx::Margin has to be non-negative.");
+        m_margin = newMargin;
+    }
+
+    void Approx::setEpsilon(double newEpsilon) {
+        CATCH_ENFORCE(newEpsilon >= 0 && newEpsilon <= 1.0,
+            "Invalid Approx::epsilon: " << newEpsilon << '.'
+            << " Approx::epsilon has to be in [0, 1]");
+        m_epsilon = newEpsilon;
+    }
+
+} // end namespace Detail
+
+namespace literals {
+    Detail::Approx operator "" _a(long double val) {
+        return Detail::Approx(val);
+    }
+    Detail::Approx operator "" _a(unsigned long long val) {
+        return Detail::Approx(val);
+    }
+} // end namespace literals
+
+std::string StringMaker<Catch::Detail::Approx>::convert(Catch::Detail::Approx const& value) {
+    return value.toString();
+}
+
+} // end namespace Catch
+// end catch_approx.cpp
+// start catch_assertionhandler.cpp
+
+// start catch_debugger.h
+
+namespace Catch {
+    bool isDebuggerActive();
+}
+
+#ifdef CATCH_PLATFORM_MAC
+
+    #if defined(__i386__) || defined(__x86_64__)
+        #define CATCH_TRAP() __asm__("int $3\n" : : ) /* NOLINT */
+    #elif defined(__aarch64__)
+        #define CATCH_TRAP()  __asm__(".inst 0xd4200000")
+    #endif
+
+#elif defined(CATCH_PLATFORM_IPHONE)
+
+    // use inline assembler
+    #if defined(__i386__) || defined(__x86_64__)
+        #define CATCH_TRAP()  __asm__("int $3")
+    #elif defined(__aarch64__)
+        #define CATCH_TRAP()  __asm__(".inst 0xd4200000")
+    #elif defined(__arm__) && !defined(__thumb__)
+        #define CATCH_TRAP()  __asm__(".inst 0xe7f001f0")
+    #elif defined(__arm__) &&  defined(__thumb__)
+        #define CATCH_TRAP()  __asm__(".inst 0xde01")
+    #endif
+
+#elif defined(CATCH_PLATFORM_LINUX)
+    // If we can use inline assembler, do it because this allows us to break
+    // directly at the location of the failing check instead of breaking inside
+    // raise() called from it, i.e. one stack frame below.
+    #if defined(__GNUC__) && (defined(__i386) || defined(__x86_64))
+        #define CATCH_TRAP() asm volatile ("int $3") /* NOLINT */
+    #else // Fall back to the generic way.
+        #include <signal.h>
+
+        #define CATCH_TRAP() raise(SIGTRAP)
+    #endif
+#elif defined(_MSC_VER)
+    #define CATCH_TRAP() __debugbreak()
+#elif defined(__MINGW32__)
+    extern "C" __declspec(dllimport) void __stdcall DebugBreak();
+    #define CATCH_TRAP() DebugBreak()
+#endif
+
+#ifndef CATCH_BREAK_INTO_DEBUGGER
+    #ifdef CATCH_TRAP
+        #define CATCH_BREAK_INTO_DEBUGGER() []{ if( Catch::isDebuggerActive() ) { CATCH_TRAP(); } }()
+    #else
+        #define CATCH_BREAK_INTO_DEBUGGER() []{}()
+    #endif
+#endif
+
+// end catch_debugger.h
+// start catch_run_context.h
+
+// start catch_fatal_condition.h
+
+#include <cassert>
+
+namespace Catch {
+
+    // Wrapper for platform-specific fatal error (signals/SEH) handlers
+    //
+    // Tries to be cooperative with other handlers, and not step over
+    // other handlers. This means that unknown structured exceptions
+    // are passed on, previous signal handlers are called, and so on.
+    //
+    // Can only be instantiated once, and assumes that once a signal
+    // is caught, the binary will end up terminating. Thus, there
+    class FatalConditionHandler {
+        bool m_started = false;
+
+        // Install/disengage implementation for specific platform.
+        // Should be if-defed to work on current platform, can assume
+        // engage-disengage 1:1 pairing.
+        void engage_platform();
+        void disengage_platform();
+    public:
+        // Should also have platform-specific implementations as needed
+        FatalConditionHandler();
+        ~FatalConditionHandler();
+
+        void engage() {
+            assert(!m_started && "Handler cannot be installed twice.");
+            m_started = true;
+            engage_platform();
+        }
+
+        void disengage() {
+            assert(m_started && "Handler cannot be uninstalled without being installed first");
+            m_started = false;
+            disengage_platform();
+        }
+    };
+
+    //! Simple RAII guard for (dis)engaging the FatalConditionHandler
+    class FatalConditionHandlerGuard {
+        FatalConditionHandler* m_handler;
+    public:
+        FatalConditionHandlerGuard(FatalConditionHandler* handler):
+            m_handler(handler) {
+            m_handler->engage();
+        }
+        ~FatalConditionHandlerGuard() {
+            m_handler->disengage();
+        }
+    };
+
+} // end namespace Catch
+
+// end catch_fatal_condition.h
+#include <string>
+
+namespace Catch {
+
+    struct IMutableContext;
+
+    ///////////////////////////////////////////////////////////////////////////
+
+    class RunContext : public IResultCapture, public IRunner {
+
+    public:
+        RunContext( RunContext const& ) = delete;
+        RunContext& operator =( RunContext const& ) = delete;
+
+        explicit RunContext( IConfigPtr const& _config, IStreamingReporterPtr&& reporter );
+
+        ~RunContext() override;
+
+        void testGroupStarting( std::string const& testSpec, std::size_t groupIndex, std::size_t groupsCount );
+        void testGroupEnded( std::string const& testSpec, Totals const& totals, std::size_t groupIndex, std::size_t groupsCount );
+
+        Totals runTest(TestCase const& testCase);
+
+        IConfigPtr config() const;
+        IStreamingReporter& reporter() const;
+
+    public: // IResultCapture
+
+        // Assertion handlers
+        void handleExpr
+                (   AssertionInfo const& info,
+                    ITransientExpression const& expr,
+                    AssertionReaction& reaction ) override;
+        void handleMessage
+                (   AssertionInfo const& info,
+                    ResultWas::OfType resultType,
+                    StringRef const& message,
+                    AssertionReaction& reaction ) override;
+        void handleUnexpectedExceptionNotThrown
+                (   AssertionInfo const& info,
+                    AssertionReaction& reaction ) override;
+        void handleUnexpectedInflightException
+                (   AssertionInfo const& info,
+                    std::string const& message,
+                    AssertionReaction& reaction ) override;
+        void handleIncomplete
+                (   AssertionInfo const& info ) override;
+        void handleNonExpr
+                (   AssertionInfo const &info,
+                    ResultWas::OfType resultType,
+                    AssertionReaction &reaction ) override;
+
+        bool sectionStarted( SectionInfo const& sectionInfo, Counts& assertions ) override;
+
+        void sectionEnded( SectionEndInfo const& endInfo ) override;
+        void sectionEndedEarly( SectionEndInfo const& endInfo ) override;
+
+        auto acquireGeneratorTracker( StringRef generatorName, SourceLineInfo const& lineInfo ) -> IGeneratorTracker& override;
+
+#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
+        void benchmarkPreparing( std::string const& name ) override;
+        void benchmarkStarting( BenchmarkInfo const& info ) override;
+        void benchmarkEnded( BenchmarkStats<> const& stats ) override;
+        void benchmarkFailed( std::string const& error ) override;
+#endif // CATCH_CONFIG_ENABLE_BENCHMARKING
+
+        void pushScopedMessage( MessageInfo const& message ) override;
+        void popScopedMessage( MessageInfo const& message ) override;
+
+        void emplaceUnscopedMessage( MessageBuilder const& builder ) override;
+
+        std::string getCurrentTestName() const override;
+
+        const AssertionResult* getLastResult() const override;
+
+        void exceptionEarlyReported() override;
+
+        void handleFatalErrorCondition( StringRef message ) override;
+
+        bool lastAssertionPassed() override;
+
+        void assertionPassed() override;
+
+    public:
+        // !TBD We need to do this another way!
+        bool aborting() const final;
+
+    private:
+
+        void runCurrentTest( std::string& redirectedCout, std::string& redirectedCerr );
+        void invokeActiveTestCase();
+
+        void resetAssertionInfo();
+        bool testForMissingAssertions( Counts& assertions );
+
+        void assertionEnded( AssertionResult const& result );
+        void reportExpr
+                (   AssertionInfo const &info,
+                    ResultWas::OfType resultType,
+                    ITransientExpression const *expr,
+                    bool negated );
+
+        void populateReaction( AssertionReaction& reaction );
+
+    private:
+
+        void handleUnfinishedSections();
+
+        TestRunInfo m_runInfo;
+        IMutableContext& m_context;
+        TestCase const* m_activeTestCase = nullptr;
+        ITracker* m_testCaseTracker = nullptr;
+        Option<AssertionResult> m_lastResult;
+
+        IConfigPtr m_config;
+        Totals m_totals;
+        IStreamingReporterPtr m_reporter;
+        std::vector<MessageInfo> m_messages;
+        std::vector<ScopedMessage> m_messageScopes; /* Keeps owners of so-called unscoped messages. */
+        AssertionInfo m_lastAssertionInfo;
+        std::vector<SectionEndInfo> m_unfinishedSections;
+        std::vector<ITracker*> m_activeSections;
+        TrackerContext m_trackerContext;
+        FatalConditionHandler m_fatalConditionhandler;
+        bool m_lastAssertionPassed = false;
+        bool m_shouldReportUnexpected = true;
+        bool m_includeSuccessfulResults;
+    };
+
+    void seedRng(IConfig const& config);
+    unsigned int rngSeed();
+} // end namespace Catch
+
+// end catch_run_context.h
+namespace Catch {
+
+    namespace {
+        auto operator <<( std::ostream& os, ITransientExpression const& expr ) -> std::ostream& {
+            expr.streamReconstructedExpression( os );
+            return os;
+        }
+    }
+
+    LazyExpression::LazyExpression( bool isNegated )
+    :   m_isNegated( isNegated )
+    {}
+
+    LazyExpression::LazyExpression( LazyExpression const& other ) : m_isNegated( other.m_isNegated ) {}
+
+    LazyExpression::operator bool() const {
+        return m_transientExpression != nullptr;
+    }
+
+    auto operator << ( std::ostream& os, LazyExpression const& lazyExpr ) -> std::ostream& {
+        if( lazyExpr.m_isNegated )
+            os << "!";
+
+        if( lazyExpr ) {
+            if( lazyExpr.m_isNegated && lazyExpr.m_transientExpression->isBinaryExpression() )
+                os << "(" << *lazyExpr.m_transientExpression << ")";
+            else
+                os << *lazyExpr.m_transientExpression;
+        }
+        else {
+            os << "{** error - unchecked empty expression requested **}";
+        }
+        return os;
+    }
+
+    AssertionHandler::AssertionHandler
+        (   StringRef const& macroName,
+            SourceLineInfo const& lineInfo,
+            StringRef capturedExpression,
+            ResultDisposition::Flags resultDisposition )
+    :   m_assertionInfo{ macroName, lineInfo, capturedExpression, resultDisposition },
+        m_resultCapture( getResultCapture() )
+    {}
+
+    void AssertionHandler::handleExpr( ITransientExpression const& expr ) {
+        m_resultCapture.handleExpr( m_assertionInfo, expr, m_reaction );
+    }
+    void AssertionHandler::handleMessage(ResultWas::OfType resultType, StringRef const& message) {
+        m_resultCapture.handleMessage( m_assertionInfo, resultType, message, m_reaction );
+    }
+
+    auto AssertionHandler::allowThrows() const -> bool {
+        return getCurrentContext().getConfig()->allowThrows();
+    }
+
+    void AssertionHandler::complete() {
+        setCompleted();
+        if( m_reaction.shouldDebugBreak ) {
+
+            // If you find your debugger stopping you here then go one level up on the
+            // call-stack for the code that caused it (typically a failed assertion)
+
+            // (To go back to the test and change execution, jump over the throw, next)
+            CATCH_BREAK_INTO_DEBUGGER();
+        }
+        if (m_reaction.shouldThrow) {
+#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
+            throw Catch::TestFailureException();
+#else
+            CATCH_ERROR( "Test failure requires aborting test!" );
+#endif
+        }
+    }
+    void AssertionHandler::setCompleted() {
+        m_completed = true;
+    }
+
+    void AssertionHandler::handleUnexpectedInflightException() {
+        m_resultCapture.handleUnexpectedInflightException( m_assertionInfo, Catch::translateActiveException(), m_reaction );
+    }
+
+    void AssertionHandler::handleExceptionThrownAsExpected() {
+        m_resultCapture.handleNonExpr(m_assertionInfo, ResultWas::Ok, m_reaction);
+    }
+    void AssertionHandler::handleExceptionNotThrownAsExpected() {
+        m_resultCapture.handleNonExpr(m_assertionInfo, ResultWas::Ok, m_reaction);
+    }
+
+    void AssertionHandler::handleUnexpectedExceptionNotThrown() {
+        m_resultCapture.handleUnexpectedExceptionNotThrown( m_assertionInfo, m_reaction );
+    }
+
+    void AssertionHandler::handleThrowingCallSkipped() {
+        m_resultCapture.handleNonExpr(m_assertionInfo, ResultWas::Ok, m_reaction);
+    }
+
+    // This is the overload that takes a string and infers the Equals matcher from it
+    // The more general overload, that takes any string matcher, is in catch_capture_matchers.cpp
+    void handleExceptionMatchExpr( AssertionHandler& handler, std::string const& str, StringRef const& matcherString  ) {
+        handleExceptionMatchExpr( handler, Matchers::Equals( str ), matcherString );
+    }
+
+} // namespace Catch
+// end catch_assertionhandler.cpp
+// start catch_assertionresult.cpp
+
+namespace Catch {
+    AssertionResultData::AssertionResultData(ResultWas::OfType _resultType, LazyExpression const & _lazyExpression):
+        lazyExpression(_lazyExpression),
+        resultType(_resultType) {}
+
+    std::string AssertionResultData::reconstructExpression() const {
+
+        if( reconstructedExpression.empty() ) {
+            if( lazyExpression ) {
+                ReusableStringStream rss;
+                rss << lazyExpression;
+                reconstructedExpression = rss.str();
+            }
+        }
+        return reconstructedExpression;
+    }
+
+    AssertionResult::AssertionResult( AssertionInfo const& info, AssertionResultData const& data )
+    :   m_info( info ),
+        m_resultData( data )
+    {}
+
+    // Result was a success
+    bool AssertionResult::succeeded() const {
+        return Catch::isOk( m_resultData.resultType );
+    }
+
+    // Result was a success, or failure is suppressed
+    bool AssertionResult::isOk() const {
+        return Catch::isOk( m_resultData.resultType ) || shouldSuppressFailure( m_info.resultDisposition );
+    }
+
+    ResultWas::OfType AssertionResult::getResultType() const {
+        return m_resultData.resultType;
+    }
+
+    bool AssertionResult::hasExpression() const {
+        return !m_info.capturedExpression.empty();
+    }
+
+    bool AssertionResult::hasMessage() const {
+        return !m_resultData.message.empty();
+    }
+
+    std::string AssertionResult::getExpression() const {
+        // Possibly overallocating by 3 characters should be basically free
+        std::string expr; expr.reserve(m_info.capturedExpression.size() + 3);
+        if (isFalseTest(m_info.resultDisposition)) {
+            expr += "!(";
+        }
+        expr += m_info.capturedExpression;
+        if (isFalseTest(m_info.resultDisposition)) {
+            expr += ')';
+        }
+        return expr;
+    }
+
+    std::string AssertionResult::getExpressionInMacro() const {
+        std::string expr;
+        if( m_info.macroName.empty() )
+            expr = static_cast<std::string>(m_info.capturedExpression);
+        else {
+            expr.reserve( m_info.macroName.size() + m_info.capturedExpression.size() + 4 );
+            expr += m_info.macroName;
+            expr += "( ";
+            expr += m_info.capturedExpression;
+            expr += " )";
+        }
+        return expr;
+    }
+
+    bool AssertionResult::hasExpandedExpression() const {
+        return hasExpression() && getExpandedExpression() != getExpression();
+    }
+
+    std::string AssertionResult::getExpandedExpression() const {
+        std::string expr = m_resultData.reconstructExpression();
+        return expr.empty()
+                ? getExpression()
+                : expr;
+    }
+
+    std::string AssertionResult::getMessage() const {
+        return m_resultData.message;
+    }
+    SourceLineInfo AssertionResult::getSourceInfo() const {
+        return m_info.lineInfo;
+    }
+
+    StringRef AssertionResult::getTestMacroName() const {
+        return m_info.macroName;
+    }
+
+} // end namespace Catch
+// end catch_assertionresult.cpp
+// start catch_capture_matchers.cpp
+
+namespace Catch {
+
+    using StringMatcher = Matchers::Impl::MatcherBase<std::string>;
+
+    // This is the general overload that takes a any string matcher
+    // There is another overload, in catch_assertionhandler.h/.cpp, that only takes a string and infers
+    // the Equals matcher (so the header does not mention matchers)
+    void handleExceptionMatchExpr( AssertionHandler& handler, StringMatcher const& matcher, StringRef const& matcherString  ) {
+        std::string exceptionMessage = Catch::translateActiveException();
+        MatchExpr<std::string, StringMatcher const&> expr( exceptionMessage, matcher, matcherString );
+        handler.handleExpr( expr );
+    }
+
+} // namespace Catch
+// end catch_capture_matchers.cpp
+// start catch_commandline.cpp
+
+// start catch_commandline.h
+
+// start catch_clara.h
+
+// Use Catch's value for console width (store Clara's off to the side, if present)
+#ifdef CLARA_CONFIG_CONSOLE_WIDTH
+#define CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH
+#undef CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH
+#endif
+#define CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH CATCH_CONFIG_CONSOLE_WIDTH-1
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wweak-vtables"
+#pragma clang diagnostic ignored "-Wexit-time-destructors"
+#pragma clang diagnostic ignored "-Wshadow"
+#endif
+
+// start clara.hpp
+// Copyright 2017 Two Blue Cubes Ltd. All rights reserved.
+//
+// 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)
+//
+// See https://github.com/philsquared/Clara for more details
+
+// Clara v1.1.5
+
+
+#ifndef CATCH_CLARA_CONFIG_CONSOLE_WIDTH
+#define CATCH_CLARA_CONFIG_CONSOLE_WIDTH 80
+#endif
+
+#ifndef CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH
+#define CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH CATCH_CLARA_CONFIG_CONSOLE_WIDTH
+#endif
+
+#ifndef CLARA_CONFIG_OPTIONAL_TYPE
+#ifdef __has_include
+#if __has_include(<optional>) && __cplusplus >= 201703L
+#include <optional>
+#define CLARA_CONFIG_OPTIONAL_TYPE std::optional
+#endif
+#endif
+#endif
+
+// ----------- #included from clara_textflow.hpp -----------
+
+// TextFlowCpp
+//
+// A single-header library for wrapping and laying out basic text, by Phil Nash
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+// This project is hosted at https://github.com/philsquared/textflowcpp
+
+
+#include <cassert>
+#include <ostream>
+#include <sstream>
+#include <vector>
+
+#ifndef CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH
+#define CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH 80
+#endif
+
+namespace Catch {
+namespace clara {
+namespace TextFlow {
+
+inline auto isWhitespace(char c) -> bool {
+	static std::string chars = " \t\n\r";
+	return chars.find(c) != std::string::npos;
+}
+inline auto isBreakableBefore(char c) -> bool {
+	static std::string chars = "[({<|";
+	return chars.find(c) != std::string::npos;
+}
+inline auto isBreakableAfter(char c) -> bool {
+	static std::string chars = "])}>.,:;*+-=&/\\";
+	return chars.find(c) != std::string::npos;
+}
+
+class Columns;
+
+class Column {
+	std::vector<std::string> m_strings;
+	size_t m_width = CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH;
+	size_t m_indent = 0;
+	size_t m_initialIndent = std::string::npos;
+
+public:
+	class iterator {
+		friend Column;
+
+		Column const& m_column;
+		size_t m_stringIndex = 0;
+		size_t m_pos = 0;
+
+		size_t m_len = 0;
+		size_t m_end = 0;
+		bool m_suffix = false;
+
+		iterator(Column const& column, size_t stringIndex)
+			: m_column(column),
+			m_stringIndex(stringIndex) {}
+
+		auto line() const -> std::string const& { return m_column.m_strings[m_stringIndex]; }
+
+		auto isBoundary(size_t at) const -> bool {
+			assert(at > 0);
+			assert(at <= line().size());
+
+			return at == line().size() ||
+				(isWhitespace(line()[at]) && !isWhitespace(line()[at - 1])) ||
+				isBreakableBefore(line()[at]) ||
+				isBreakableAfter(line()[at - 1]);
+		}
+
+		void calcLength() {
+			assert(m_stringIndex < m_column.m_strings.size());
+
+			m_suffix = false;
+			auto width = m_column.m_width - indent();
+			m_end = m_pos;
+			if (line()[m_pos] == '\n') {
+				++m_end;
+			}
+			while (m_end < line().size() && line()[m_end] != '\n')
+				++m_end;
+
+			if (m_end < m_pos + width) {
+				m_len = m_end - m_pos;
+			} else {
+				size_t len = width;
+				while (len > 0 && !isBoundary(m_pos + len))
+					--len;
+				while (len > 0 && isWhitespace(line()[m_pos + len - 1]))
+					--len;
+
+				if (len > 0) {
+					m_len = len;
+				} else {
+					m_suffix = true;
+					m_len = width - 1;
+				}
+			}
+		}
+
+		auto indent() const -> size_t {
+			auto initial = m_pos == 0 && m_stringIndex == 0 ? m_column.m_initialIndent : std::string::npos;
+			return initial == std::string::npos ? m_column.m_indent : initial;
+		}
+
+		auto addIndentAndSuffix(std::string const &plain) const -> std::string {
+			return std::string(indent(), ' ') + (m_suffix ? plain + "-" : plain);
+		}
+
+	public:
+		using difference_type = std::ptrdiff_t;
+		using value_type = std::string;
+		using pointer = value_type * ;
+		using reference = value_type & ;
+		using iterator_category = std::forward_iterator_tag;
+
+		explicit iterator(Column const& column) : m_column(column) {
+			assert(m_column.m_width > m_column.m_indent);
+			assert(m_column.m_initialIndent == std::string::npos || m_column.m_width > m_column.m_initialIndent);
+			calcLength();
+			if (m_len == 0)
+				m_stringIndex++; // Empty string
+		}
+
+		auto operator *() const -> std::string {
+			assert(m_stringIndex < m_column.m_strings.size());
+			assert(m_pos <= m_end);
+			return addIndentAndSuffix(line().substr(m_pos, m_len));
+		}
+
+		auto operator ++() -> iterator& {
+			m_pos += m_len;
+			if (m_pos < line().size() && line()[m_pos] == '\n')
+				m_pos += 1;
+			else
+				while (m_pos < line().size() && isWhitespace(line()[m_pos]))
+					++m_pos;
+
+			if (m_pos == line().size()) {
+				m_pos = 0;
+				++m_stringIndex;
+			}
+			if (m_stringIndex < m_column.m_strings.size())
+				calcLength();
+			return *this;
+		}
+		auto operator ++(int) -> iterator {
+			iterator prev(*this);
+			operator++();
+			return prev;
+		}
+
+		auto operator ==(iterator const& other) const -> bool {
+			return
+				m_pos == other.m_pos &&
+				m_stringIndex == other.m_stringIndex &&
+				&m_column == &other.m_column;
+		}
+		auto operator !=(iterator const& other) const -> bool {
+			return !operator==(other);
+		}
+	};
+	using const_iterator = iterator;
+
+	explicit Column(std::string const& text) { m_strings.push_back(text); }
+
+	auto width(size_t newWidth) -> Column& {
+		assert(newWidth > 0);
+		m_width = newWidth;
+		return *this;
+	}
+	auto indent(size_t newIndent) -> Column& {
+		m_indent = newIndent;
+		return *this;
+	}
+	auto initialIndent(size_t newIndent) -> Column& {
+		m_initialIndent = newIndent;
+		return *this;
+	}
+
+	auto width() const -> size_t { return m_width; }
+	auto begin() const -> iterator { return iterator(*this); }
+	auto end() const -> iterator { return { *this, m_strings.size() }; }
+
+	inline friend std::ostream& operator << (std::ostream& os, Column const& col) {
+		bool first = true;
+		for (auto line : col) {
+			if (first)
+				first = false;
+			else
+				os << "\n";
+			os << line;
+		}
+		return os;
+	}
+
+	auto operator + (Column const& other)->Columns;
+
+	auto toString() const -> std::string {
+		std::ostringstream oss;
+		oss << *this;
+		return oss.str();
+	}
+};
+
+class Spacer : public Column {
+
+public:
+	explicit Spacer(size_t spaceWidth) : Column("") {
+		width(spaceWidth);
+	}
+};
+
+class Columns {
+	std::vector<Column> m_columns;
+
+public:
+
+	class iterator {
+		friend Columns;
+		struct EndTag {};
+
+		std::vector<Column> const& m_columns;
+		std::vector<Column::iterator> m_iterators;
+		size_t m_activeIterators;
+
+		iterator(Columns const& columns, EndTag)
+			: m_columns(columns.m_columns),
+			m_activeIterators(0) {
+			m_iterators.reserve(m_columns.size());
+
+			for (auto const& col : m_columns)
+				m_iterators.push_back(col.end());
+		}
+
+	public:
+		using difference_type = std::ptrdiff_t;
+		using value_type = std::string;
+		using pointer = value_type * ;
+		using reference = value_type & ;
+		using iterator_category = std::forward_iterator_tag;
+
+		explicit iterator(Columns const& columns)
+			: m_columns(columns.m_columns),
+			m_activeIterators(m_columns.size()) {
+			m_iterators.reserve(m_columns.size());
+
+			for (auto const& col : m_columns)
+				m_iterators.push_back(col.begin());
+		}
+
+		auto operator ==(iterator const& other) const -> bool {
+			return m_iterators == other.m_iterators;
+		}
+		auto operator !=(iterator const& other) const -> bool {
+			return m_iterators != other.m_iterators;
+		}
+		auto operator *() const -> std::string {
+			std::string row, padding;
+
+			for (size_t i = 0; i < m_columns.size(); ++i) {
+				auto width = m_columns[i].width();
+				if (m_iterators[i] != m_columns[i].end()) {
+					std::string col = *m_iterators[i];
+					row += padding + col;
+					if (col.size() < width)
+						padding = std::string(width - col.size(), ' ');
+					else
+						padding = "";
+				} else {
+					padding += std::string(width, ' ');
+				}
+			}
+			return row;
+		}
+		auto operator ++() -> iterator& {
+			for (size_t i = 0; i < m_columns.size(); ++i) {
+				if (m_iterators[i] != m_columns[i].end())
+					++m_iterators[i];
+			}
+			return *this;
+		}
+		auto operator ++(int) -> iterator {
+			iterator prev(*this);
+			operator++();
+			return prev;
+		}
+	};
+	using const_iterator = iterator;
+
+	auto begin() const -> iterator { return iterator(*this); }
+	auto end() const -> iterator { return { *this, iterator::EndTag() }; }
+
+	auto operator += (Column const& col) -> Columns& {
+		m_columns.push_back(col);
+		return *this;
+	}
+	auto operator + (Column const& col) -> Columns {
+		Columns combined = *this;
+		combined += col;
+		return combined;
+	}
+
+	inline friend std::ostream& operator << (std::ostream& os, Columns const& cols) {
+
+		bool first = true;
+		for (auto line : cols) {
+			if (first)
+				first = false;
+			else
+				os << "\n";
+			os << line;
+		}
+		return os;
+	}
+
+	auto toString() const -> std::string {
+		std::ostringstream oss;
+		oss << *this;
+		return oss.str();
+	}
+};
+
+inline auto Column::operator + (Column const& other) -> Columns {
+	Columns cols;
+	cols += *this;
+	cols += other;
+	return cols;
+}
+}
+
+}
+}
+
+// ----------- end of #include from clara_textflow.hpp -----------
+// ........... back in clara.hpp
+
+#include <cctype>
+#include <string>
+#include <memory>
+#include <set>
+#include <algorithm>
+
+#if !defined(CATCH_PLATFORM_WINDOWS) && ( defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) )
+#define CATCH_PLATFORM_WINDOWS
+#endif
+
+namespace Catch { namespace clara {
+namespace detail {
+
+    // Traits for extracting arg and return type of lambdas (for single argument lambdas)
+    template<typename L>
+    struct UnaryLambdaTraits : UnaryLambdaTraits<decltype( &L::operator() )> {};
+
+    template<typename ClassT, typename ReturnT, typename... Args>
+    struct UnaryLambdaTraits<ReturnT( ClassT::* )( Args... ) const> {
+        static const bool isValid = false;
+    };
+
+    template<typename ClassT, typename ReturnT, typename ArgT>
+    struct UnaryLambdaTraits<ReturnT( ClassT::* )( ArgT ) const> {
+        static const bool isValid = true;
+        using ArgType = typename std::remove_const<typename std::remove_reference<ArgT>::type>::type;
+        using ReturnType = ReturnT;
+    };
+
+    class TokenStream;
+
+    // Transport for raw args (copied from main args, or supplied via init list for testing)
+    class Args {
+        friend TokenStream;
+        std::string m_exeName;
+        std::vector<std::string> m_args;
+
+    public:
+        Args( int argc, char const* const* argv )
+            : m_exeName(argv[0]),
+              m_args(argv + 1, argv + argc) {}
+
+        Args( std::initializer_list<std::string> args )
+        :   m_exeName( *args.begin() ),
+            m_args( args.begin()+1, args.end() )
+        {}
+
+        auto exeName() const -> std::string {
+            return m_exeName;
+        }
+    };
+
+    // Wraps a token coming from a token stream. These may not directly correspond to strings as a single string
+    // may encode an option + its argument if the : or = form is used
+    enum class TokenType {
+        Option, Argument
+    };
+    struct Token {
+        TokenType type;
+        std::string token;
+    };
+
+    inline auto isOptPrefix( char c ) -> bool {
+        return c == '-'
+#ifdef CATCH_PLATFORM_WINDOWS
+            || c == '/'
+#endif
+        ;
+    }
+
+    // Abstracts iterators into args as a stream of tokens, with option arguments uniformly handled
+    class TokenStream {
+        using Iterator = std::vector<std::string>::const_iterator;
+        Iterator it;
+        Iterator itEnd;
+        std::vector<Token> m_tokenBuffer;
+
+        void loadBuffer() {
+            m_tokenBuffer.resize( 0 );
+
+            // Skip any empty strings
+            while( it != itEnd && it->empty() )
+                ++it;
+
+            if( it != itEnd ) {
+                auto const &next = *it;
+                if( isOptPrefix( next[0] ) ) {
+                    auto delimiterPos = next.find_first_of( " :=" );
+                    if( delimiterPos != std::string::npos ) {
+                        m_tokenBuffer.push_back( { TokenType::Option, next.substr( 0, delimiterPos ) } );
+                        m_tokenBuffer.push_back( { TokenType::Argument, next.substr( delimiterPos + 1 ) } );
+                    } else {
+                        if( next[1] != '-' && next.size() > 2 ) {
+                            std::string opt = "- ";
+                            for( size_t i = 1; i < next.size(); ++i ) {
+                                opt[1] = next[i];
+                                m_tokenBuffer.push_back( { TokenType::Option, opt } );
+                            }
+                        } else {
+                            m_tokenBuffer.push_back( { TokenType::Option, next } );
+                        }
+                    }
+                } else {
+                    m_tokenBuffer.push_back( { TokenType::Argument, next } );
+                }
+            }
+        }
+
+    public:
+        explicit TokenStream( Args const &args ) : TokenStream( args.m_args.begin(), args.m_args.end() ) {}
+
+        TokenStream( Iterator it, Iterator itEnd ) : it( it ), itEnd( itEnd ) {
+            loadBuffer();
+        }
+
+        explicit operator bool() const {
+            return !m_tokenBuffer.empty() || it != itEnd;
+        }
+
+        auto count() const -> size_t { return m_tokenBuffer.size() + (itEnd - it); }
+
+        auto operator*() const -> Token {
+            assert( !m_tokenBuffer.empty() );
+            return m_tokenBuffer.front();
+        }
+
+        auto operator->() const -> Token const * {
+            assert( !m_tokenBuffer.empty() );
+            return &m_tokenBuffer.front();
+        }
+
+        auto operator++() -> TokenStream & {
+            if( m_tokenBuffer.size() >= 2 ) {
+                m_tokenBuffer.erase( m_tokenBuffer.begin() );
+            } else {
+                if( it != itEnd )
+                    ++it;
+                loadBuffer();
+            }
+            return *this;
+        }
+    };
+
+    class ResultBase {
+    public:
+        enum Type {
+            Ok, LogicError, RuntimeError
+        };
+
+    protected:
+        ResultBase( Type type ) : m_type( type ) {}
+        virtual ~ResultBase() = default;
+
+        virtual void enforceOk() const = 0;
+
+        Type m_type;
+    };
+
+    template<typename T>
+    class ResultValueBase : public ResultBase {
+    public:
+        auto value() const -> T const & {
+            enforceOk();
+            return m_value;
+        }
+
+    protected:
+        ResultValueBase( Type type ) : ResultBase( type ) {}
+
+        ResultValueBase( ResultValueBase const &other ) : ResultBase( other ) {
+            if( m_type == ResultBase::Ok )
+                new( &m_value ) T( other.m_value );
+        }
+
+        ResultValueBase( Type, T const &value ) : ResultBase( Ok ) {
+            new( &m_value ) T( value );
+        }
+
+        auto operator=( ResultValueBase const &other ) -> ResultValueBase & {
+            if( m_type == ResultBase::Ok )
+                m_value.~T();
+            ResultBase::operator=(other);
+            if( m_type == ResultBase::Ok )
+                new( &m_value ) T( other.m_value );
+            return *this;
+        }
+
+        ~ResultValueBase() override {
+            if( m_type == Ok )
+                m_value.~T();
+        }
+
+        union {
+            T m_value;
+        };
+    };
+
+    template<>
+    class ResultValueBase<void> : public ResultBase {
+    protected:
+        using ResultBase::ResultBase;
+    };
+
+    template<typename T = void>
+    class BasicResult : public ResultValueBase<T> {
+    public:
+        template<typename U>
+        explicit BasicResult( BasicResult<U> const &other )
+        :   ResultValueBase<T>( other.type() ),
+            m_errorMessage( other.errorMessage() )
+        {
+            assert( type() != ResultBase::Ok );
+        }
+
+        template<typename U>
+        static auto ok( U const &value ) -> BasicResult { return { ResultBase::Ok, value }; }
+        static auto ok() -> BasicResult { return { ResultBase::Ok }; }
+        static auto logicError( std::string const &message ) -> BasicResult { return { ResultBase::LogicError, message }; }
+        static auto runtimeError( std::string const &message ) -> BasicResult { return { ResultBase::RuntimeError, message }; }
+
+        explicit operator bool() const { return m_type == ResultBase::Ok; }
+        auto type() const -> ResultBase::Type { return m_type; }
+        auto errorMessage() const -> std::string { return m_errorMessage; }
+
+    protected:
+        void enforceOk() const override {
+
+            // Errors shouldn't reach this point, but if they do
+            // the actual error message will be in m_errorMessage
+            assert( m_type != ResultBase::LogicError );
+            assert( m_type != ResultBase::RuntimeError );
+            if( m_type != ResultBase::Ok )
+                std::abort();
+        }
+
+        std::string m_errorMessage; // Only populated if resultType is an error
+
+        BasicResult( ResultBase::Type type, std::string const &message )
+        :   ResultValueBase<T>(type),
+            m_errorMessage(message)
+        {
+            assert( m_type != ResultBase::Ok );
+        }
+
+        using ResultValueBase<T>::ResultValueBase;
+        using ResultBase::m_type;
+    };
+
+    enum class ParseResultType {
+        Matched, NoMatch, ShortCircuitAll, ShortCircuitSame
+    };
+
+    class ParseState {
+    public:
+
+        ParseState( ParseResultType type, TokenStream const &remainingTokens )
+        : m_type(type),
+          m_remainingTokens( remainingTokens )
+        {}
+
+        auto type() const -> ParseResultType { return m_type; }
+        auto remainingTokens() const -> TokenStream { return m_remainingTokens; }
+
+    private:
+        ParseResultType m_type;
+        TokenStream m_remainingTokens;
+    };
+
+    using Result = BasicResult<void>;
+    using ParserResult = BasicResult<ParseResultType>;
+    using InternalParseResult = BasicResult<ParseState>;
+
+    struct HelpColumns {
+        std::string left;
+        std::string right;
+    };
+
+    template<typename T>
+    inline auto convertInto( std::string const &source, T& target ) -> ParserResult {
+        std::stringstream ss;
+        ss << source;
+        ss >> target;
+        if( ss.fail() )
+            return ParserResult::runtimeError( "Unable to convert '" + source + "' to destination type" );
+        else
+            return ParserResult::ok( ParseResultType::Matched );
+    }
+    inline auto convertInto( std::string const &source, std::string& target ) -> ParserResult {
+        target = source;
+        return ParserResult::ok( ParseResultType::Matched );
+    }
+    inline auto convertInto( std::string const &source, bool &target ) -> ParserResult {
+        std::string srcLC = source;
+        std::transform( srcLC.begin(), srcLC.end(), srcLC.begin(), []( unsigned char c ) { return static_cast<char>( std::tolower(c) ); } );
+        if (srcLC == "y" || srcLC == "1" || srcLC == "true" || srcLC == "yes" || srcLC == "on")
+            target = true;
+        else if (srcLC == "n" || srcLC == "0" || srcLC == "false" || srcLC == "no" || srcLC == "off")
+            target = false;
+        else
+            return ParserResult::runtimeError( "Expected a boolean value but did not recognise: '" + source + "'" );
+        return ParserResult::ok( ParseResultType::Matched );
+    }
+#ifdef CLARA_CONFIG_OPTIONAL_TYPE
+    template<typename T>
+    inline auto convertInto( std::string const &source, CLARA_CONFIG_OPTIONAL_TYPE<T>& target ) -> ParserResult {
+        T temp;
+        auto result = convertInto( source, temp );
+        if( result )
+            target = std::move(temp);
+        return result;
+    }
+#endif // CLARA_CONFIG_OPTIONAL_TYPE
+
+    struct NonCopyable {
+        NonCopyable() = default;
+        NonCopyable( NonCopyable const & ) = delete;
+        NonCopyable( NonCopyable && ) = delete;
+        NonCopyable &operator=( NonCopyable const & ) = delete;
+        NonCopyable &operator=( NonCopyable && ) = delete;
+    };
+
+    struct BoundRef : NonCopyable {
+        virtual ~BoundRef() = default;
+        virtual auto isContainer() const -> bool { return false; }
+        virtual auto isFlag() const -> bool { return false; }
+    };
+    struct BoundValueRefBase : BoundRef {
+        virtual auto setValue( std::string const &arg ) -> ParserResult = 0;
+    };
+    struct BoundFlagRefBase : BoundRef {
+        virtual auto setFlag( bool flag ) -> ParserResult = 0;
+        virtual auto isFlag() const -> bool { return true; }
+    };
+
+    template<typename T>
+    struct BoundValueRef : BoundValueRefBase {
+        T &m_ref;
+
+        explicit BoundValueRef( T &ref ) : m_ref( ref ) {}
+
+        auto setValue( std::string const &arg ) -> ParserResult override {
+            return convertInto( arg, m_ref );
+        }
+    };
+
+    template<typename T>
+    struct BoundValueRef<std::vector<T>> : BoundValueRefBase {
+        std::vector<T> &m_ref;
+
+        explicit BoundValueRef( std::vector<T> &ref ) : m_ref( ref ) {}
+
+        auto isContainer() const -> bool override { return true; }
+
+        auto setValue( std::string const &arg ) -> ParserResult override {
+            T temp;
+            auto result = convertInto( arg, temp );
+            if( result )
+                m_ref.push_back( temp );
+            return result;
+        }
+    };
+
+    struct BoundFlagRef : BoundFlagRefBase {
+        bool &m_ref;
+
+        explicit BoundFlagRef( bool &ref ) : m_ref( ref ) {}
+
+        auto setFlag( bool flag ) -> ParserResult override {
+            m_ref = flag;
+            return ParserResult::ok( ParseResultType::Matched );
+        }
+    };
+
+    template<typename ReturnType>
+    struct LambdaInvoker {
+        static_assert( std::is_same<ReturnType, ParserResult>::value, "Lambda must return void or clara::ParserResult" );
+
+        template<typename L, typename ArgType>
+        static auto invoke( L const &lambda, ArgType const &arg ) -> ParserResult {
+            return lambda( arg );
+        }
+    };
+
+    template<>
+    struct LambdaInvoker<void> {
+        template<typename L, typename ArgType>
+        static auto invoke( L const &lambda, ArgType const &arg ) -> ParserResult {
+            lambda( arg );
+            return ParserResult::ok( ParseResultType::Matched );
+        }
+    };
+
+    template<typename ArgType, typename L>
+    inline auto invokeLambda( L const &lambda, std::string const &arg ) -> ParserResult {
+        ArgType temp{};
+        auto result = convertInto( arg, temp );
+        return !result
+           ? result
+           : LambdaInvoker<typename UnaryLambdaTraits<L>::ReturnType>::invoke( lambda, temp );
+    }
+
+    template<typename L>
+    struct BoundLambda : BoundValueRefBase {
+        L m_lambda;
+
+        static_assert( UnaryLambdaTraits<L>::isValid, "Supplied lambda must take exactly one argument" );
+        explicit BoundLambda( L const &lambda ) : m_lambda( lambda ) {}
+
+        auto setValue( std::string const &arg ) -> ParserResult override {
+            return invokeLambda<typename UnaryLambdaTraits<L>::ArgType>( m_lambda, arg );
+        }
+    };
+
+    template<typename L>
+    struct BoundFlagLambda : BoundFlagRefBase {
+        L m_lambda;
+
+        static_assert( UnaryLambdaTraits<L>::isValid, "Supplied lambda must take exactly one argument" );
+        static_assert( std::is_same<typename UnaryLambdaTraits<L>::ArgType, bool>::value, "flags must be boolean" );
+
+        explicit BoundFlagLambda( L const &lambda ) : m_lambda( lambda ) {}
+
+        auto setFlag( bool flag ) -> ParserResult override {
+            return LambdaInvoker<typename UnaryLambdaTraits<L>::ReturnType>::invoke( m_lambda, flag );
+        }
+    };
+
+    enum class Optionality { Optional, Required };
+
+    struct Parser;
+
+    class ParserBase {
+    public:
+        virtual ~ParserBase() = default;
+        virtual auto validate() const -> Result { return Result::ok(); }
+        virtual auto parse( std::string const& exeName, TokenStream const &tokens) const -> InternalParseResult  = 0;
+        virtual auto cardinality() const -> size_t { return 1; }
+
+        auto parse( Args const &args ) const -> InternalParseResult {
+            return parse( args.exeName(), TokenStream( args ) );
+        }
+    };
+
+    template<typename DerivedT>
+    class ComposableParserImpl : public ParserBase {
+    public:
+        template<typename T>
+        auto operator|( T const &other ) const -> Parser;
+
+		template<typename T>
+        auto operator+( T const &other ) const -> Parser;
+    };
+
+    // Common code and state for Args and Opts
+    template<typename DerivedT>
+    class ParserRefImpl : public ComposableParserImpl<DerivedT> {
+    protected:
+        Optionality m_optionality = Optionality::Optional;
+        std::shared_ptr<BoundRef> m_ref;
+        std::string m_hint;
+        std::string m_description;
+
+        explicit ParserRefImpl( std::shared_ptr<BoundRef> const &ref ) : m_ref( ref ) {}
+
+    public:
+        template<typename T>
+        ParserRefImpl( T &ref, std::string const &hint )
+        :   m_ref( std::make_shared<BoundValueRef<T>>( ref ) ),
+            m_hint( hint )
+        {}
+
+        template<typename LambdaT>
+        ParserRefImpl( LambdaT const &ref, std::string const &hint )
+        :   m_ref( std::make_shared<BoundLambda<LambdaT>>( ref ) ),
+            m_hint(hint)
+        {}
+
+        auto operator()( std::string const &description ) -> DerivedT & {
+            m_description = description;
+            return static_cast<DerivedT &>( *this );
+        }
+
+        auto optional() -> DerivedT & {
+            m_optionality = Optionality::Optional;
+            return static_cast<DerivedT &>( *this );
+        };
+
+        auto required() -> DerivedT & {
+            m_optionality = Optionality::Required;
+            return static_cast<DerivedT &>( *this );
+        };
+
+        auto isOptional() const -> bool {
+            return m_optionality == Optionality::Optional;
+        }
+
+        auto cardinality() const -> size_t override {
+            if( m_ref->isContainer() )
+                return 0;
+            else
+                return 1;
+        }
+
+        auto hint() const -> std::string { return m_hint; }
+    };
+
+    class ExeName : public ComposableParserImpl<ExeName> {
+        std::shared_ptr<std::string> m_name;
+        std::shared_ptr<BoundValueRefBase> m_ref;
+
+        template<typename LambdaT>
+        static auto makeRef(LambdaT const &lambda) -> std::shared_ptr<BoundValueRefBase> {
+            return std::make_shared<BoundLambda<LambdaT>>( lambda) ;
+        }
+
+    public:
+        ExeName() : m_name( std::make_shared<std::string>( "<executable>" ) ) {}
+
+        explicit ExeName( std::string &ref ) : ExeName() {
+            m_ref = std::make_shared<BoundValueRef<std::string>>( ref );
+        }
+
+        template<typename LambdaT>
+        explicit ExeName( LambdaT const& lambda ) : ExeName() {
+            m_ref = std::make_shared<BoundLambda<LambdaT>>( lambda );
+        }
+
+        // The exe name is not parsed out of the normal tokens, but is handled specially
+        auto parse( std::string const&, TokenStream const &tokens ) const -> InternalParseResult override {
+            return InternalParseResult::ok( ParseState( ParseResultType::NoMatch, tokens ) );
+        }
+
+        auto name() const -> std::string { return *m_name; }
+        auto set( std::string const& newName ) -> ParserResult {
+
+            auto lastSlash = newName.find_last_of( "\\/" );
+            auto filename = ( lastSlash == std::string::npos )
+                    ? newName
+                    : newName.substr( lastSlash+1 );
+
+            *m_name = filename;
+            if( m_ref )
+                return m_ref->setValue( filename );
+            else
+                return ParserResult::ok( ParseResultType::Matched );
+        }
+    };
+
+    class Arg : public ParserRefImpl<Arg> {
+    public:
+        using ParserRefImpl::ParserRefImpl;
+
+        auto parse( std::string const &, TokenStream const &tokens ) const -> InternalParseResult override {
+            auto validationResult = validate();
+            if( !validationResult )
+                return InternalParseResult( validationResult );
+
+            auto remainingTokens = tokens;
+            auto const &token = *remainingTokens;
+            if( token.type != TokenType::Argument )
+                return InternalParseResult::ok( ParseState( ParseResultType::NoMatch, remainingTokens ) );
+
+            assert( !m_ref->isFlag() );
+            auto valueRef = static_cast<detail::BoundValueRefBase*>( m_ref.get() );
+
+            auto result = valueRef->setValue( remainingTokens->token );
+            if( !result )
+                return InternalParseResult( result );
+            else
+                return InternalParseResult::ok( ParseState( ParseResultType::Matched, ++remainingTokens ) );
+        }
+    };
+
+    inline auto normaliseOpt( std::string const &optName ) -> std::string {
+#ifdef CATCH_PLATFORM_WINDOWS
+        if( optName[0] == '/' )
+            return "-" + optName.substr( 1 );
+        else
+#endif
+            return optName;
+    }
+
+    class Opt : public ParserRefImpl<Opt> {
+    protected:
+        std::vector<std::string> m_optNames;
+
+    public:
+        template<typename LambdaT>
+        explicit Opt( LambdaT const &ref ) : ParserRefImpl( std::make_shared<BoundFlagLambda<LambdaT>>( ref ) ) {}
+
+        explicit Opt( bool &ref ) : ParserRefImpl( std::make_shared<BoundFlagRef>( ref ) ) {}
+
+        template<typename LambdaT>
+        Opt( LambdaT const &ref, std::string const &hint ) : ParserRefImpl( ref, hint ) {}
+
+        template<typename T>
+        Opt( T &ref, std::string const &hint ) : ParserRefImpl( ref, hint ) {}
+
+        auto operator[]( std::string const &optName ) -> Opt & {
+            m_optNames.push_back( optName );
+            return *this;
+        }
+
+        auto getHelpColumns() const -> std::vector<HelpColumns> {
+            std::ostringstream oss;
+            bool first = true;
+            for( auto const &opt : m_optNames ) {
+                if (first)
+                    first = false;
+                else
+                    oss << ", ";
+                oss << opt;
+            }
+            if( !m_hint.empty() )
+                oss << " <" << m_hint << ">";
+            return { { oss.str(), m_description } };
+        }
+
+        auto isMatch( std::string const &optToken ) const -> bool {
+            auto normalisedToken = normaliseOpt( optToken );
+            for( auto const &name : m_optNames ) {
+                if( normaliseOpt( name ) == normalisedToken )
+                    return true;
+            }
+            return false;
+        }
+
+        using ParserBase::parse;
+
+        auto parse( std::string const&, TokenStream const &tokens ) const -> InternalParseResult override {
+            auto validationResult = validate();
+            if( !validationResult )
+                return InternalParseResult( validationResult );
+
+            auto remainingTokens = tokens;
+            if( remainingTokens && remainingTokens->type == TokenType::Option ) {
+                auto const &token = *remainingTokens;
+                if( isMatch(token.token ) ) {
+                    if( m_ref->isFlag() ) {
+                        auto flagRef = static_cast<detail::BoundFlagRefBase*>( m_ref.get() );
+                        auto result = flagRef->setFlag( true );
+                        if( !result )
+                            return InternalParseResult( result );
+                        if( result.value() == ParseResultType::ShortCircuitAll )
+                            return InternalParseResult::ok( ParseState( result.value(), remainingTokens ) );
+                    } else {
+                        auto valueRef = static_cast<detail::BoundValueRefBase*>( m_ref.get() );
+                        ++remainingTokens;
+                        if( !remainingTokens )
+                            return InternalParseResult::runtimeError( "Expected argument following " + token.token );
+                        auto const &argToken = *remainingTokens;
+                        if( argToken.type != TokenType::Argument )
+                            return InternalParseResult::runtimeError( "Expected argument following " + token.token );
+                        auto result = valueRef->setValue( argToken.token );
+                        if( !result )
+                            return InternalParseResult( result );
+                        if( result.value() == ParseResultType::ShortCircuitAll )
+                            return InternalParseResult::ok( ParseState( result.value(), remainingTokens ) );
+                    }
+                    return InternalParseResult::ok( ParseState( ParseResultType::Matched, ++remainingTokens ) );
+                }
+            }
+            return InternalParseResult::ok( ParseState( ParseResultType::NoMatch, remainingTokens ) );
+        }
+
+        auto validate() const -> Result override {
+            if( m_optNames.empty() )
+                return Result::logicError( "No options supplied to Opt" );
+            for( auto const &name : m_optNames ) {
+                if( name.empty() )
+                    return Result::logicError( "Option name cannot be empty" );
+#ifdef CATCH_PLATFORM_WINDOWS
+                if( name[0] != '-' && name[0] != '/' )
+                    return Result::logicError( "Option name must begin with '-' or '/'" );
+#else
+                if( name[0] != '-' )
+                    return Result::logicError( "Option name must begin with '-'" );
+#endif
+            }
+            return ParserRefImpl::validate();
+        }
+    };
+
+    struct Help : Opt {
+        Help( bool &showHelpFlag )
+        :   Opt([&]( bool flag ) {
+                showHelpFlag = flag;
+                return ParserResult::ok( ParseResultType::ShortCircuitAll );
+            })
+        {
+            static_cast<Opt &>( *this )
+                    ("display usage information")
+                    ["-?"]["-h"]["--help"]
+                    .optional();
+        }
+    };
+
+    struct Parser : ParserBase {
+
+        mutable ExeName m_exeName;
+        std::vector<Opt> m_options;
+        std::vector<Arg> m_args;
+
+        auto operator|=( ExeName const &exeName ) -> Parser & {
+            m_exeName = exeName;
+            return *this;
+        }
+
+        auto operator|=( Arg const &arg ) -> Parser & {
+            m_args.push_back(arg);
+            return *this;
+        }
+
+        auto operator|=( Opt const &opt ) -> Parser & {
+            m_options.push_back(opt);
+            return *this;
+        }
+
+        auto operator|=( Parser const &other ) -> Parser & {
+            m_options.insert(m_options.end(), other.m_options.begin(), other.m_options.end());
+            m_args.insert(m_args.end(), other.m_args.begin(), other.m_args.end());
+            return *this;
+        }
+
+        template<typename T>
+        auto operator|( T const &other ) const -> Parser {
+            return Parser( *this ) |= other;
+        }
+
+        // Forward deprecated interface with '+' instead of '|'
+        template<typename T>
+        auto operator+=( T const &other ) -> Parser & { return operator|=( other ); }
+        template<typename T>
+        auto operator+( T const &other ) const -> Parser { return operator|( other ); }
+
+        auto getHelpColumns() const -> std::vector<HelpColumns> {
+            std::vector<HelpColumns> cols;
+            for (auto const &o : m_options) {
+                auto childCols = o.getHelpColumns();
+                cols.insert( cols.end(), childCols.begin(), childCols.end() );
+            }
+            return cols;
+        }
+
+        void writeToStream( std::ostream &os ) const {
+            if (!m_exeName.name().empty()) {
+                os << "usage:\n" << "  " << m_exeName.name() << " ";
+                bool required = true, first = true;
+                for( auto const &arg : m_args ) {
+                    if (first)
+                        first = false;
+                    else
+                        os << " ";
+                    if( arg.isOptional() && required ) {
+                        os << "[";
+                        required = false;
+                    }
+                    os << "<" << arg.hint() << ">";
+                    if( arg.cardinality() == 0 )
+                        os << " ... ";
+                }
+                if( !required )
+                    os << "]";
+                if( !m_options.empty() )
+                    os << " options";
+                os << "\n\nwhere options are:" << std::endl;
+            }
+
+            auto rows = getHelpColumns();
+            size_t consoleWidth = CATCH_CLARA_CONFIG_CONSOLE_WIDTH;
+            size_t optWidth = 0;
+            for( auto const &cols : rows )
+                optWidth = (std::max)(optWidth, cols.left.size() + 2);
+
+            optWidth = (std::min)(optWidth, consoleWidth/2);
+
+            for( auto const &cols : rows ) {
+                auto row =
+                        TextFlow::Column( cols.left ).width( optWidth ).indent( 2 ) +
+                        TextFlow::Spacer(4) +
+                        TextFlow::Column( cols.right ).width( consoleWidth - 7 - optWidth );
+                os << row << std::endl;
+            }
+        }
+
+        friend auto operator<<( std::ostream &os, Parser const &parser ) -> std::ostream& {
+            parser.writeToStream( os );
+            return os;
+        }
+
+        auto validate() const -> Result override {
+            for( auto const &opt : m_options ) {
+                auto result = opt.validate();
+                if( !result )
+                    return result;
+            }
+            for( auto const &arg : m_args ) {
+                auto result = arg.validate();
+                if( !result )
+                    return result;
+            }
+            return Result::ok();
+        }
+
+        using ParserBase::parse;
+
+        auto parse( std::string const& exeName, TokenStream const &tokens ) const -> InternalParseResult override {
+
+            struct ParserInfo {
+                ParserBase const* parser = nullptr;
+                size_t count = 0;
+            };
+            const size_t totalParsers = m_options.size() + m_args.size();
+            assert( totalParsers < 512 );
+            // ParserInfo parseInfos[totalParsers]; // <-- this is what we really want to do
+            ParserInfo parseInfos[512];
+
+            {
+                size_t i = 0;
+                for (auto const &opt : m_options) parseInfos[i++].parser = &opt;
+                for (auto const &arg : m_args) parseInfos[i++].parser = &arg;
+            }
+
+            m_exeName.set( exeName );
+
+            auto result = InternalParseResult::ok( ParseState( ParseResultType::NoMatch, tokens ) );
+            while( result.value().remainingTokens() ) {
+                bool tokenParsed = false;
+
+                for( size_t i = 0; i < totalParsers; ++i ) {
+                    auto&  parseInfo = parseInfos[i];
+                    if( parseInfo.parser->cardinality() == 0 || parseInfo.count < parseInfo.parser->cardinality() ) {
+                        result = parseInfo.parser->parse(exeName, result.value().remainingTokens());
+                        if (!result)
+                            return result;
+                        if (result.value().type() != ParseResultType::NoMatch) {
+                            tokenParsed = true;
+                            ++parseInfo.count;
+                            break;
+                        }
+                    }
+                }
+
+                if( result.value().type() == ParseResultType::ShortCircuitAll )
+                    return result;
+                if( !tokenParsed )
+                    return InternalParseResult::runtimeError( "Unrecognised token: " + result.value().remainingTokens()->token );
+            }
+            // !TBD Check missing required options
+            return result;
+        }
+    };
+
+    template<typename DerivedT>
+    template<typename T>
+    auto ComposableParserImpl<DerivedT>::operator|( T const &other ) const -> Parser {
+        return Parser() | static_cast<DerivedT const &>( *this ) | other;
+    }
+} // namespace detail
+
+// A Combined parser
+using detail::Parser;
+
+// A parser for options
+using detail::Opt;
+
+// A parser for arguments
+using detail::Arg;
+
+// Wrapper for argc, argv from main()
+using detail::Args;
+
+// Specifies the name of the executable
+using detail::ExeName;
+
+// Convenience wrapper for option parser that specifies the help option
+using detail::Help;
+
+// enum of result types from a parse
+using detail::ParseResultType;
+
+// Result type for parser operation
+using detail::ParserResult;
+
+}} // namespace Catch::clara
+
+// end clara.hpp
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+
+// Restore Clara's value for console width, if present
+#ifdef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH
+#define CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH
+#undef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH
+#endif
+
+// end catch_clara.h
+namespace Catch {
+
+    clara::Parser makeCommandLineParser( ConfigData& config );
+
+} // end namespace Catch
+
+// end catch_commandline.h
+#include <fstream>
+#include <ctime>
+
+namespace Catch {
+
+    clara::Parser makeCommandLineParser( ConfigData& config ) {
+
+        using namespace clara;
+
+        auto const setWarning = [&]( std::string const& warning ) {
+                auto warningSet = [&]() {
+                    if( warning == "NoAssertions" )
+                        return WarnAbout::NoAssertions;
+
+                    if ( warning == "NoTests" )
+                        return WarnAbout::NoTests;
+
+                    return WarnAbout::Nothing;
+                }();
+
+                if (warningSet == WarnAbout::Nothing)
+                    return ParserResult::runtimeError( "Unrecognised warning: '" + warning + "'" );
+                config.warnings = static_cast<WarnAbout::What>( config.warnings | warningSet );
+                return ParserResult::ok( ParseResultType::Matched );
+            };
+        auto const loadTestNamesFromFile = [&]( std::string const& filename ) {
+                std::ifstream f( filename.c_str() );
+                if( !f.is_open() )
+                    return ParserResult::runtimeError( "Unable to load input file: '" + filename + "'" );
+
+                std::string line;
+                while( std::getline( f, line ) ) {
+                    line = trim(line);
+                    if( !line.empty() && !startsWith( line, '#' ) ) {
+                        if( !startsWith( line, '"' ) )
+                            line = '"' + line + '"';
+                        config.testsOrTags.push_back( line );
+                        config.testsOrTags.emplace_back( "," );
+                    }
+                }
+                //Remove comma in the end
+                if(!config.testsOrTags.empty())
+                    config.testsOrTags.erase( config.testsOrTags.end()-1 );
+
+                return ParserResult::ok( ParseResultType::Matched );
+            };
+        auto const setTestOrder = [&]( std::string const& order ) {
+                if( startsWith( "declared", order ) )
+                    config.runOrder = RunTests::InDeclarationOrder;
+                else if( startsWith( "lexical", order ) )
+                    config.runOrder = RunTests::InLexicographicalOrder;
+                else if( startsWith( "random", order ) )
+                    config.runOrder = RunTests::InRandomOrder;
+                else
+                    return clara::ParserResult::runtimeError( "Unrecognised ordering: '" + order + "'" );
+                return ParserResult::ok( ParseResultType::Matched );
+            };
+        auto const setRngSeed = [&]( std::string const& seed ) {
+                if( seed != "time" )
+                    return clara::detail::convertInto( seed, config.rngSeed );
+                config.rngSeed = static_cast<unsigned int>( std::time(nullptr) );
+                return ParserResult::ok( ParseResultType::Matched );
+            };
+        auto const setColourUsage = [&]( std::string const& useColour ) {
+                    auto mode = toLower( useColour );
+
+                    if( mode == "yes" )
+                        config.useColour = UseColour::Yes;
+                    else if( mode == "no" )
+                        config.useColour = UseColour::No;
+                    else if( mode == "auto" )
+                        config.useColour = UseColour::Auto;
+                    else
+                        return ParserResult::runtimeError( "colour mode must be one of: auto, yes or no. '" + useColour + "' not recognised" );
+                return ParserResult::ok( ParseResultType::Matched );
+            };
+        auto const setWaitForKeypress = [&]( std::string const& keypress ) {
+                auto keypressLc = toLower( keypress );
+                if (keypressLc == "never")
+                    config.waitForKeypress = WaitForKeypress::Never;
+                else if( keypressLc == "start" )
+                    config.waitForKeypress = WaitForKeypress::BeforeStart;
+                else if( keypressLc == "exit" )
+                    config.waitForKeypress = WaitForKeypress::BeforeExit;
+                else if( keypressLc == "both" )
+                    config.waitForKeypress = WaitForKeypress::BeforeStartAndExit;
+                else
+                    return ParserResult::runtimeError( "keypress argument must be one of: never, start, exit or both. '" + keypress + "' not recognised" );
+            return ParserResult::ok( ParseResultType::Matched );
+            };
+        auto const setVerbosity = [&]( std::string const& verbosity ) {
+            auto lcVerbosity = toLower( verbosity );
+            if( lcVerbosity == "quiet" )
+                config.verbosity = Verbosity::Quiet;
+            else if( lcVerbosity == "normal" )
+                config.verbosity = Verbosity::Normal;
+            else if( lcVerbosity == "high" )
+                config.verbosity = Verbosity::High;
+            else
+                return ParserResult::runtimeError( "Unrecognised verbosity, '" + verbosity + "'" );
+            return ParserResult::ok( ParseResultType::Matched );
+        };
+        auto const setReporter = [&]( std::string const& reporter ) {
+            IReporterRegistry::FactoryMap const& factories = getRegistryHub().getReporterRegistry().getFactories();
+
+            auto lcReporter = toLower( reporter );
+            auto result = factories.find( lcReporter );
+
+            if( factories.end() != result )
+                config.reporterName = lcReporter;
+            else
+                return ParserResult::runtimeError( "Unrecognized reporter, '" + reporter + "'. Check available with --list-reporters" );
+            return ParserResult::ok( ParseResultType::Matched );
+        };
+
+        auto cli
+            = ExeName( config.processName )
+            | Help( config.showHelp )
+            | Opt( config.listTests )
+                ["-l"]["--list-tests"]
+                ( "list all/matching test cases" )
+            | Opt( config.listTags )
+                ["-t"]["--list-tags"]
+                ( "list all/matching tags" )
+            | Opt( config.showSuccessfulTests )
+                ["-s"]["--success"]
+                ( "include successful tests in output" )
+            | Opt( config.shouldDebugBreak )
+                ["-b"]["--break"]
+                ( "break into debugger on failure" )
+            | Opt( config.noThrow )
+                ["-e"]["--nothrow"]
+                ( "skip exception tests" )
+            | Opt( config.showInvisibles )
+                ["-i"]["--invisibles"]
+                ( "show invisibles (tabs, newlines)" )
+            | Opt( config.outputFilename, "filename" )
+                ["-o"]["--out"]
+                ( "output filename" )
+            | Opt( setReporter, "name" )
+                ["-r"]["--reporter"]
+                ( "reporter to use (defaults to console)" )
+            | Opt( config.name, "name" )
+                ["-n"]["--name"]
+                ( "suite name" )
+            | Opt( [&]( bool ){ config.abortAfter = 1; } )
+                ["-a"]["--abort"]
+                ( "abort at first failure" )
+            | Opt( [&]( int x ){ config.abortAfter = x; }, "no. failures" )
+                ["-x"]["--abortx"]
+                ( "abort after x failures" )
+            | Opt( setWarning, "warning name" )
+                ["-w"]["--warn"]
+                ( "enable warnings" )
+            | Opt( [&]( bool flag ) { config.showDurations = flag ? ShowDurations::Always : ShowDurations::Never; }, "yes|no" )
+                ["-d"]["--durations"]
+                ( "show test durations" )
+            | Opt( config.minDuration, "seconds" )
+                ["-D"]["--min-duration"]
+                ( "show test durations for tests taking at least the given number of seconds" )
+            | Opt( loadTestNamesFromFile, "filename" )
+                ["-f"]["--input-file"]
+                ( "load test names to run from a file" )
+            | Opt( config.filenamesAsTags )
+                ["-#"]["--filenames-as-tags"]
+                ( "adds a tag for the filename" )
+            | Opt( config.sectionsToRun, "section name" )
+                ["-c"]["--section"]
+                ( "specify section to run" )
+            | Opt( setVerbosity, "quiet|normal|high" )
+                ["-v"]["--verbosity"]
+                ( "set output verbosity" )
+            | Opt( config.listTestNamesOnly )
+                ["--list-test-names-only"]
+                ( "list all/matching test cases names only" )
+            | Opt( config.listReporters )
+                ["--list-reporters"]
+                ( "list all reporters" )
+            | Opt( setTestOrder, "decl|lex|rand" )
+                ["--order"]
+                ( "test case order (defaults to decl)" )
+            | Opt( setRngSeed, "'time'|number" )
+                ["--rng-seed"]
+                ( "set a specific seed for random numbers" )
+            | Opt( setColourUsage, "yes|no" )
+                ["--use-colour"]
+                ( "should output be colourised" )
+            | Opt( config.libIdentify )
+                ["--libidentify"]
+                ( "report name and version according to libidentify standard" )
+            | Opt( setWaitForKeypress, "never|start|exit|both" )
+                ["--wait-for-keypress"]
+                ( "waits for a keypress before exiting" )
+            | Opt( config.benchmarkSamples, "samples" )
+                ["--benchmark-samples"]
+                ( "number of samples to collect (default: 100)" )
+            | Opt( config.benchmarkResamples, "resamples" )
+                ["--benchmark-resamples"]
+                ( "number of resamples for the bootstrap (default: 100000)" )
+            | Opt( config.benchmarkConfidenceInterval, "confidence interval" )
+                ["--benchmark-confidence-interval"]
+                ( "confidence interval for the bootstrap (between 0 and 1, default: 0.95)" )
+            | Opt( config.benchmarkNoAnalysis )
+                ["--benchmark-no-analysis"]
+                ( "perform only measurements; do not perform any analysis" )
+            | Opt( config.benchmarkWarmupTime, "benchmarkWarmupTime" )
+                ["--benchmark-warmup-time"]
+                ( "amount of time in milliseconds spent on warming up each test (default: 100)" )
+            | Arg( config.testsOrTags, "test name|pattern|tags" )
+                ( "which test or tests to use" );
+
+        return cli;
+    }
+
+} // end namespace Catch
+// end catch_commandline.cpp
+// start catch_common.cpp
+
+#include <cstring>
+#include <ostream>
+
+namespace Catch {
+
+    bool SourceLineInfo::operator == ( SourceLineInfo const& other ) const noexcept {
+        return line == other.line && (file == other.file || std::strcmp(file, other.file) == 0);
+    }
+    bool SourceLineInfo::operator < ( SourceLineInfo const& other ) const noexcept {
+        // We can assume that the same file will usually have the same pointer.
+        // Thus, if the pointers are the same, there is no point in calling the strcmp
+        return line < other.line || ( line == other.line && file != other.file && (std::strcmp(file, other.file) < 0));
+    }
+
+    std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ) {
+#ifndef __GNUG__
+        os << info.file << '(' << info.line << ')';
+#else
+        os << info.file << ':' << info.line;
+#endif
+        return os;
+    }
+
+    std::string StreamEndStop::operator+() const {
+        return std::string();
+    }
+
+    NonCopyable::NonCopyable() = default;
+    NonCopyable::~NonCopyable() = default;
+
+}
+// end catch_common.cpp
+// start catch_config.cpp
+
+namespace Catch {
+
+    Config::Config( ConfigData const& data )
+    :   m_data( data ),
+        m_stream( openStream() )
+    {
+        // We need to trim filter specs to avoid trouble with superfluous
+        // whitespace (esp. important for bdd macros, as those are manually
+        // aligned with whitespace).
+
+        for (auto& elem : m_data.testsOrTags) {
+            elem = trim(elem);
+        }
+        for (auto& elem : m_data.sectionsToRun) {
+            elem = trim(elem);
+        }
+
+        TestSpecParser parser(ITagAliasRegistry::get());
+        if (!m_data.testsOrTags.empty()) {
+            m_hasTestFilters = true;
+            for (auto const& testOrTags : m_data.testsOrTags) {
+                parser.parse(testOrTags);
+            }
+        }
+        m_testSpec = parser.testSpec();
+    }
+
+    std::string const& Config::getFilename() const {
+        return m_data.outputFilename ;
+    }
+
+    bool Config::listTests() const          { return m_data.listTests; }
+    bool Config::listTestNamesOnly() const  { return m_data.listTestNamesOnly; }
+    bool Config::listTags() const           { return m_data.listTags; }
+    bool Config::listReporters() const      { return m_data.listReporters; }
+
+    std::string Config::getProcessName() const { return m_data.processName; }
+    std::string const& Config::getReporterName() const { return m_data.reporterName; }
+
+    std::vector<std::string> const& Config::getTestsOrTags() const { return m_data.testsOrTags; }
+    std::vector<std::string> const& Config::getSectionsToRun() const { return m_data.sectionsToRun; }
+
+    TestSpec const& Config::testSpec() const { return m_testSpec; }
+    bool Config::hasTestFilters() const { return m_hasTestFilters; }
+
+    bool Config::showHelp() const { return m_data.showHelp; }
+
+    // IConfig interface
+    bool Config::allowThrows() const                   { return !m_data.noThrow; }
+    std::ostream& Config::stream() const               { return m_stream->stream(); }
+    std::string Config::name() const                   { return m_data.name.empty() ? m_data.processName : m_data.name; }
+    bool Config::includeSuccessfulResults() const      { return m_data.showSuccessfulTests; }
+    bool Config::warnAboutMissingAssertions() const    { return !!(m_data.warnings & WarnAbout::NoAssertions); }
+    bool Config::warnAboutNoTests() const              { return !!(m_data.warnings & WarnAbout::NoTests); }
+    ShowDurations::OrNot Config::showDurations() const { return m_data.showDurations; }
+    double Config::minDuration() const                 { return m_data.minDuration; }
+    RunTests::InWhatOrder Config::runOrder() const     { return m_data.runOrder; }
+    unsigned int Config::rngSeed() const               { return m_data.rngSeed; }
+    UseColour::YesOrNo Config::useColour() const       { return m_data.useColour; }
+    bool Config::shouldDebugBreak() const              { return m_data.shouldDebugBreak; }
+    int Config::abortAfter() const                     { return m_data.abortAfter; }
+    bool Config::showInvisibles() const                { return m_data.showInvisibles; }
+    Verbosity Config::verbosity() const                { return m_data.verbosity; }
+
+    bool Config::benchmarkNoAnalysis() const                      { return m_data.benchmarkNoAnalysis; }
+    int Config::benchmarkSamples() const                          { return m_data.benchmarkSamples; }
+    double Config::benchmarkConfidenceInterval() const            { return m_data.benchmarkConfidenceInterval; }
+    unsigned int Config::benchmarkResamples() const               { return m_data.benchmarkResamples; }
+    std::chrono::milliseconds Config::benchmarkWarmupTime() const { return std::chrono::milliseconds(m_data.benchmarkWarmupTime); }
+
+    IStream const* Config::openStream() {
+        return Catch::makeStream(m_data.outputFilename);
+    }
+
+} // end namespace Catch
+// end catch_config.cpp
+// start catch_console_colour.cpp
+
+#if defined(__clang__)
+#    pragma clang diagnostic push
+#    pragma clang diagnostic ignored "-Wexit-time-destructors"
+#endif
+
+// start catch_errno_guard.h
+
+namespace Catch {
+
+    class ErrnoGuard {
+    public:
+        ErrnoGuard();
+        ~ErrnoGuard();
+    private:
+        int m_oldErrno;
+    };
+
+}
+
+// end catch_errno_guard.h
+// start catch_windows_h_proxy.h
+
+
+#if defined(CATCH_PLATFORM_WINDOWS)
+
+#if !defined(NOMINMAX) && !defined(CATCH_CONFIG_NO_NOMINMAX)
+#  define CATCH_DEFINED_NOMINMAX
+#  define NOMINMAX
+#endif
+#if !defined(WIN32_LEAN_AND_MEAN) && !defined(CATCH_CONFIG_NO_WIN32_LEAN_AND_MEAN)
+#  define CATCH_DEFINED_WIN32_LEAN_AND_MEAN
+#  define WIN32_LEAN_AND_MEAN
+#endif
+
+#ifdef __AFXDLL
+#include <AfxWin.h>
+#else
+#include <windows.h>
+#endif
+
+#ifdef CATCH_DEFINED_NOMINMAX
+#  undef NOMINMAX
+#endif
+#ifdef CATCH_DEFINED_WIN32_LEAN_AND_MEAN
+#  undef WIN32_LEAN_AND_MEAN
+#endif
+
+#endif // defined(CATCH_PLATFORM_WINDOWS)
+
+// end catch_windows_h_proxy.h
+#include <sstream>
+
+namespace Catch {
+    namespace {
+
+        struct IColourImpl {
+            virtual ~IColourImpl() = default;
+            virtual void use( Colour::Code _colourCode ) = 0;
+        };
+
+        struct NoColourImpl : IColourImpl {
+            void use( Colour::Code ) override {}
+
+            static IColourImpl* instance() {
+                static NoColourImpl s_instance;
+                return &s_instance;
+            }
+        };
+
+    } // anon namespace
+} // namespace Catch
+
+#if !defined( CATCH_CONFIG_COLOUR_NONE ) && !defined( CATCH_CONFIG_COLOUR_WINDOWS ) && !defined( CATCH_CONFIG_COLOUR_ANSI )
+#   ifdef CATCH_PLATFORM_WINDOWS
+#       define CATCH_CONFIG_COLOUR_WINDOWS
+#   else
+#       define CATCH_CONFIG_COLOUR_ANSI
+#   endif
+#endif
+
+#if defined ( CATCH_CONFIG_COLOUR_WINDOWS ) /////////////////////////////////////////
+
+namespace Catch {
+namespace {
+
+    class Win32ColourImpl : public IColourImpl {
+    public:
+        Win32ColourImpl() : stdoutHandle( GetStdHandle(STD_OUTPUT_HANDLE) )
+        {
+            CONSOLE_SCREEN_BUFFER_INFO csbiInfo;
+            GetConsoleScreenBufferInfo( stdoutHandle, &csbiInfo );
+            originalForegroundAttributes = csbiInfo.wAttributes & ~( BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_BLUE | BACKGROUND_INTENSITY );
+            originalBackgroundAttributes = csbiInfo.wAttributes & ~( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY );
+        }
+
+        void use( Colour::Code _colourCode ) override {
+            switch( _colourCode ) {
+                case Colour::None:      return setTextAttribute( originalForegroundAttributes );
+                case Colour::White:     return setTextAttribute( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE );
+                case Colour::Red:       return setTextAttribute( FOREGROUND_RED );
+                case Colour::Green:     return setTextAttribute( FOREGROUND_GREEN );
+                case Colour::Blue:      return setTextAttribute( FOREGROUND_BLUE );
+                case Colour::Cyan:      return setTextAttribute( FOREGROUND_BLUE | FOREGROUND_GREEN );
+                case Colour::Yellow:    return setTextAttribute( FOREGROUND_RED | FOREGROUND_GREEN );
+                case Colour::Grey:      return setTextAttribute( 0 );
+
+                case Colour::LightGrey:     return setTextAttribute( FOREGROUND_INTENSITY );
+                case Colour::BrightRed:     return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_RED );
+                case Colour::BrightGreen:   return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN );
+                case Colour::BrightWhite:   return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE );
+                case Colour::BrightYellow:  return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN );
+
+                case Colour::Bright: CATCH_INTERNAL_ERROR( "not a colour" );
+
+                default:
+                    CATCH_ERROR( "Unknown colour requested" );
+            }
+        }
+
+    private:
+        void setTextAttribute( WORD _textAttribute ) {
+            SetConsoleTextAttribute( stdoutHandle, _textAttribute | originalBackgroundAttributes );
+        }
+        HANDLE stdoutHandle;
+        WORD originalForegroundAttributes;
+        WORD originalBackgroundAttributes;
+    };
+
+    IColourImpl* platformColourInstance() {
+        static Win32ColourImpl s_instance;
+
+        IConfigPtr config = getCurrentContext().getConfig();
+        UseColour::YesOrNo colourMode = config
+            ? config->useColour()
+            : UseColour::Auto;
+        if( colourMode == UseColour::Auto )
+            colourMode = UseColour::Yes;
+        return colourMode == UseColour::Yes
+            ? &s_instance
+            : NoColourImpl::instance();
+    }
+
+} // end anon namespace
+} // end namespace Catch
+
+#elif defined( CATCH_CONFIG_COLOUR_ANSI ) //////////////////////////////////////
+
+#include <unistd.h>
+
+namespace Catch {
+namespace {
+
+    // use POSIX/ ANSI console terminal codes
+    // Thanks to Adam Strzelecki for original contribution
+    // (http://github.com/nanoant)
+    // https://github.com/philsquared/Catch/pull/131
+    class PosixColourImpl : public IColourImpl {
+    public:
+        void use( Colour::Code _colourCode ) override {
+            switch( _colourCode ) {
+                case Colour::None:
+                case Colour::White:     return setColour( "[0m" );
+                case Colour::Red:       return setColour( "[0;31m" );
+                case Colour::Green:     return setColour( "[0;32m" );
+                case Colour::Blue:      return setColour( "[0;34m" );
+                case Colour::Cyan:      return setColour( "[0;36m" );
+                case Colour::Yellow:    return setColour( "[0;33m" );
+                case Colour::Grey:      return setColour( "[1;30m" );
+
+                case Colour::LightGrey:     return setColour( "[0;37m" );
+                case Colour::BrightRed:     return setColour( "[1;31m" );
+                case Colour::BrightGreen:   return setColour( "[1;32m" );
+                case Colour::BrightWhite:   return setColour( "[1;37m" );
+                case Colour::BrightYellow:  return setColour( "[1;33m" );
+
+                case Colour::Bright: CATCH_INTERNAL_ERROR( "not a colour" );
+                default: CATCH_INTERNAL_ERROR( "Unknown colour requested" );
+            }
+        }
+        static IColourImpl* instance() {
+            static PosixColourImpl s_instance;
+            return &s_instance;
+        }
+
+    private:
+        void setColour( const char* _escapeCode ) {
+            getCurrentContext().getConfig()->stream()
+                << '\033' << _escapeCode;
+        }
+    };
+
+    bool useColourOnPlatform() {
+        return
+#if defined(CATCH_PLATFORM_MAC) || defined(CATCH_PLATFORM_IPHONE)
+            !isDebuggerActive() &&
+#endif
+#if !(defined(__DJGPP__) && defined(__STRICT_ANSI__))
+            isatty(STDOUT_FILENO)
+#else
+            false
+#endif
+            ;
+    }
+    IColourImpl* platformColourInstance() {
+        ErrnoGuard guard;
+        IConfigPtr config = getCurrentContext().getConfig();
+        UseColour::YesOrNo colourMode = config
+            ? config->useColour()
+            : UseColour::Auto;
+        if( colourMode == UseColour::Auto )
+            colourMode = useColourOnPlatform()
+                ? UseColour::Yes
+                : UseColour::No;
+        return colourMode == UseColour::Yes
+            ? PosixColourImpl::instance()
+            : NoColourImpl::instance();
+    }
+
+} // end anon namespace
+} // end namespace Catch
+
+#else  // not Windows or ANSI ///////////////////////////////////////////////
+
+namespace Catch {
+
+    static IColourImpl* platformColourInstance() { return NoColourImpl::instance(); }
+
+} // end namespace Catch
+
+#endif // Windows/ ANSI/ None
+
+namespace Catch {
+
+    Colour::Colour( Code _colourCode ) { use( _colourCode ); }
+    Colour::Colour( Colour&& other ) noexcept {
+        m_moved = other.m_moved;
+        other.m_moved = true;
+    }
+    Colour& Colour::operator=( Colour&& other ) noexcept {
+        m_moved = other.m_moved;
+        other.m_moved  = true;
+        return *this;
+    }
+
+    Colour::~Colour(){ if( !m_moved ) use( None ); }
+
+    void Colour::use( Code _colourCode ) {
+        static IColourImpl* impl = platformColourInstance();
+        // Strictly speaking, this cannot possibly happen.
+        // However, under some conditions it does happen (see #1626),
+        // and this change is small enough that we can let practicality
+        // triumph over purity in this case.
+        if (impl != nullptr) {
+            impl->use( _colourCode );
+        }
+    }
+
+    std::ostream& operator << ( std::ostream& os, Colour const& ) {
+        return os;
+    }
+
+} // end namespace Catch
+
+#if defined(__clang__)
+#    pragma clang diagnostic pop
+#endif
+
+// end catch_console_colour.cpp
+// start catch_context.cpp
+
+namespace Catch {
+
+    class Context : public IMutableContext, NonCopyable {
+
+    public: // IContext
+        IResultCapture* getResultCapture() override {
+            return m_resultCapture;
+        }
+        IRunner* getRunner() override {
+            return m_runner;
+        }
+
+        IConfigPtr const& getConfig() const override {
+            return m_config;
+        }
+
+        ~Context() override;
+
+    public: // IMutableContext
+        void setResultCapture( IResultCapture* resultCapture ) override {
+            m_resultCapture = resultCapture;
+        }
+        void setRunner( IRunner* runner ) override {
+            m_runner = runner;
+        }
+        void setConfig( IConfigPtr const& config ) override {
+            m_config = config;
+        }
+
+        friend IMutableContext& getCurrentMutableContext();
+
+    private:
+        IConfigPtr m_config;
+        IRunner* m_runner = nullptr;
+        IResultCapture* m_resultCapture = nullptr;
+    };
+
+    IMutableContext *IMutableContext::currentContext = nullptr;
+
+    void IMutableContext::createContext()
+    {
+        currentContext = new Context();
+    }
+
+    void cleanUpContext() {
+        delete IMutableContext::currentContext;
+        IMutableContext::currentContext = nullptr;
+    }
+    IContext::~IContext() = default;
+    IMutableContext::~IMutableContext() = default;
+    Context::~Context() = default;
+
+    SimplePcg32& rng() {
+        static SimplePcg32 s_rng;
+        return s_rng;
+    }
+
+}
+// end catch_context.cpp
+// start catch_debug_console.cpp
+
+// start catch_debug_console.h
+
+#include <string>
+
+namespace Catch {
+    void writeToDebugConsole( std::string const& text );
+}
+
+// end catch_debug_console.h
+#if defined(CATCH_CONFIG_ANDROID_LOGWRITE)
+#include <android/log.h>
+
+    namespace Catch {
+        void writeToDebugConsole( std::string const& text ) {
+            __android_log_write( ANDROID_LOG_DEBUG, "Catch", text.c_str() );
+        }
+    }
+
+#elif defined(CATCH_PLATFORM_WINDOWS)
+
+    namespace Catch {
+        void writeToDebugConsole( std::string const& text ) {
+            ::OutputDebugStringA( text.c_str() );
+        }
+    }
+
+#else
+
+    namespace Catch {
+        void writeToDebugConsole( std::string const& text ) {
+            // !TBD: Need a version for Mac/ XCode and other IDEs
+            Catch::cout() << text;
+        }
+    }
+
+#endif // Platform
+// end catch_debug_console.cpp
+// start catch_debugger.cpp
+
+#if defined(CATCH_PLATFORM_MAC) || defined(CATCH_PLATFORM_IPHONE)
+
+#  include <cassert>
+#  include <sys/types.h>
+#  include <unistd.h>
+#  include <cstddef>
+#  include <ostream>
+
+#ifdef __apple_build_version__
+    // These headers will only compile with AppleClang (XCode)
+    // For other compilers (Clang, GCC, ... ) we need to exclude them
+#  include <sys/sysctl.h>
+#endif
+
+    namespace Catch {
+        #ifdef __apple_build_version__
+        // The following function is taken directly from the following technical note:
+        // https://developer.apple.com/library/archive/qa/qa1361/_index.html
+
+        // Returns true if the current process is being debugged (either
+        // running under the debugger or has a debugger attached post facto).
+        bool isDebuggerActive(){
+            int                 mib[4];
+            struct kinfo_proc   info;
+            std::size_t         size;
+
+            // Initialize the flags so that, if sysctl fails for some bizarre
+            // reason, we get a predictable result.
+
+            info.kp_proc.p_flag = 0;
+
+            // Initialize mib, which tells sysctl the info we want, in this case
+            // we're looking for information about a specific process ID.
+
+            mib[0] = CTL_KERN;
+            mib[1] = KERN_PROC;
+            mib[2] = KERN_PROC_PID;
+            mib[3] = getpid();
+
+            // Call sysctl.
+
+            size = sizeof(info);
+            if( sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, nullptr, 0) != 0 ) {
+                Catch::cerr() << "\n** Call to sysctl failed - unable to determine if debugger is active **\n" << std::endl;
+                return false;
+            }
+
+            // We're being debugged if the P_TRACED flag is set.
+
+            return ( (info.kp_proc.p_flag & P_TRACED) != 0 );
+        }
+        #else
+        bool isDebuggerActive() {
+            // We need to find another way to determine this for non-appleclang compilers on macOS
+            return false;
+        }
+        #endif
+    } // namespace Catch
+
+#elif defined(CATCH_PLATFORM_LINUX)
+    #include <fstream>
+    #include <string>
+
+    namespace Catch{
+        // The standard POSIX way of detecting a debugger is to attempt to
+        // ptrace() the process, but this needs to be done from a child and not
+        // this process itself to still allow attaching to this process later
+        // if wanted, so is rather heavy. Under Linux we have the PID of the
+        // "debugger" (which doesn't need to be gdb, of course, it could also
+        // be strace, for example) in /proc/$PID/status, so just get it from
+        // there instead.
+        bool isDebuggerActive(){
+            // Libstdc++ has a bug, where std::ifstream sets errno to 0
+            // This way our users can properly assert over errno values
+            ErrnoGuard guard;
+            std::ifstream in("/proc/self/status");
+            for( std::string line; std::getline(in, line); ) {
+                static const int PREFIX_LEN = 11;
+                if( line.compare(0, PREFIX_LEN, "TracerPid:\t") == 0 ) {
+                    // We're traced if the PID is not 0 and no other PID starts
+                    // with 0 digit, so it's enough to check for just a single
+                    // character.
+                    return line.length() > PREFIX_LEN && line[PREFIX_LEN] != '0';
+                }
+            }
+
+            return false;
+        }
+    } // namespace Catch
+#elif defined(_MSC_VER)
+    extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent();
+    namespace Catch {
+        bool isDebuggerActive() {
+            return IsDebuggerPresent() != 0;
+        }
+    }
+#elif defined(__MINGW32__)
+    extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent();
+    namespace Catch {
+        bool isDebuggerActive() {
+            return IsDebuggerPresent() != 0;
+        }
+    }
+#else
+    namespace Catch {
+       bool isDebuggerActive() { return false; }
+    }
+#endif // Platform
+// end catch_debugger.cpp
+// start catch_decomposer.cpp
+
+namespace Catch {
+
+    ITransientExpression::~ITransientExpression() = default;
+
+    void formatReconstructedExpression( std::ostream &os, std::string const& lhs, StringRef op, std::string const& rhs ) {
+        if( lhs.size() + rhs.size() < 40 &&
+                lhs.find('\n') == std::string::npos &&
+                rhs.find('\n') == std::string::npos )
+            os << lhs << " " << op << " " << rhs;
+        else
+            os << lhs << "\n" << op << "\n" << rhs;
+    }
+}
+// end catch_decomposer.cpp
+// start catch_enforce.cpp
+
+#include <stdexcept>
+
+namespace Catch {
+#if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) && !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS_CUSTOM_HANDLER)
+    [[noreturn]]
+    void throw_exception(std::exception const& e) {
+        Catch::cerr() << "Catch will terminate because it needed to throw an exception.\n"
+                      << "The message was: " << e.what() << '\n';
+        std::terminate();
+    }
+#endif
+
+    [[noreturn]]
+    void throw_logic_error(std::string const& msg) {
+        throw_exception(std::logic_error(msg));
+    }
+
+    [[noreturn]]
+    void throw_domain_error(std::string const& msg) {
+        throw_exception(std::domain_error(msg));
+    }
+
+    [[noreturn]]
+    void throw_runtime_error(std::string const& msg) {
+        throw_exception(std::runtime_error(msg));
+    }
+
+} // namespace Catch;
+// end catch_enforce.cpp
+// start catch_enum_values_registry.cpp
+// start catch_enum_values_registry.h
+
+#include <vector>
+#include <memory>
+
+namespace Catch {
+
+    namespace Detail {
+
+        std::unique_ptr<EnumInfo> makeEnumInfo( StringRef enumName, StringRef allValueNames, std::vector<int> const& values );
+
+        class EnumValuesRegistry : public IMutableEnumValuesRegistry {
+
+            std::vector<std::unique_ptr<EnumInfo>> m_enumInfos;
+
+            EnumInfo const& registerEnum( StringRef enumName, StringRef allEnums, std::vector<int> const& values) override;
+        };
+
+        std::vector<StringRef> parseEnums( StringRef enums );
+
+    } // Detail
+
+} // Catch
+
+// end catch_enum_values_registry.h
+
+#include <map>
+#include <cassert>
+
+namespace Catch {
+
+    IMutableEnumValuesRegistry::~IMutableEnumValuesRegistry() {}
+
+    namespace Detail {
+
+        namespace {
+            // Extracts the actual name part of an enum instance
+            // In other words, it returns the Blue part of Bikeshed::Colour::Blue
+            StringRef extractInstanceName(StringRef enumInstance) {
+                // Find last occurrence of ":"
+                size_t name_start = enumInstance.size();
+                while (name_start > 0 && enumInstance[name_start - 1] != ':') {
+                    --name_start;
+                }
+                return enumInstance.substr(name_start, enumInstance.size() - name_start);
+            }
+        }
+
+        std::vector<StringRef> parseEnums( StringRef enums ) {
+            auto enumValues = splitStringRef( enums, ',' );
+            std::vector<StringRef> parsed;
+            parsed.reserve( enumValues.size() );
+            for( auto const& enumValue : enumValues ) {
+                parsed.push_back(trim(extractInstanceName(enumValue)));
+            }
+            return parsed;
+        }
+
+        EnumInfo::~EnumInfo() {}
+
+        StringRef EnumInfo::lookup( int value ) const {
+            for( auto const& valueToName : m_values ) {
+                if( valueToName.first == value )
+                    return valueToName.second;
+            }
+            return "{** unexpected enum value **}"_sr;
+        }
+
+        std::unique_ptr<EnumInfo> makeEnumInfo( StringRef enumName, StringRef allValueNames, std::vector<int> const& values ) {
+            std::unique_ptr<EnumInfo> enumInfo( new EnumInfo );
+            enumInfo->m_name = enumName;
+            enumInfo->m_values.reserve( values.size() );
+
+            const auto valueNames = Catch::Detail::parseEnums( allValueNames );
+            assert( valueNames.size() == values.size() );
+            std::size_t i = 0;
+            for( auto value : values )
+                enumInfo->m_values.emplace_back(value, valueNames[i++]);
+
+            return enumInfo;
+        }
+
+        EnumInfo const& EnumValuesRegistry::registerEnum( StringRef enumName, StringRef allValueNames, std::vector<int> const& values ) {
+            m_enumInfos.push_back(makeEnumInfo(enumName, allValueNames, values));
+            return *m_enumInfos.back();
+        }
+
+    } // Detail
+} // Catch
+
+// end catch_enum_values_registry.cpp
+// start catch_errno_guard.cpp
+
+#include <cerrno>
+
+namespace Catch {
+        ErrnoGuard::ErrnoGuard():m_oldErrno(errno){}
+        ErrnoGuard::~ErrnoGuard() { errno = m_oldErrno; }
+}
+// end catch_errno_guard.cpp
+// start catch_exception_translator_registry.cpp
+
+// start catch_exception_translator_registry.h
+
+#include <vector>
+#include <string>
+#include <memory>
+
+namespace Catch {
+
+    class ExceptionTranslatorRegistry : public IExceptionTranslatorRegistry {
+    public:
+        ~ExceptionTranslatorRegistry();
+        virtual void registerTranslator( const IExceptionTranslator* translator );
+        std::string translateActiveException() const override;
+        std::string tryTranslators() const;
+
+    private:
+        std::vector<std::unique_ptr<IExceptionTranslator const>> m_translators;
+    };
+}
+
+// end catch_exception_translator_registry.h
+#ifdef __OBJC__
+#import "Foundation/Foundation.h"
+#endif
+
+namespace Catch {
+
+    ExceptionTranslatorRegistry::~ExceptionTranslatorRegistry() {
+    }
+
+    void ExceptionTranslatorRegistry::registerTranslator( const IExceptionTranslator* translator ) {
+        m_translators.push_back( std::unique_ptr<const IExceptionTranslator>( translator ) );
+    }
+
+#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
+    std::string ExceptionTranslatorRegistry::translateActiveException() const {
+        try {
+#ifdef __OBJC__
+            // In Objective-C try objective-c exceptions first
+            @try {
+                return tryTranslators();
+            }
+            @catch (NSException *exception) {
+                return Catch::Detail::stringify( [exception description] );
+            }
+#else
+            // Compiling a mixed mode project with MSVC means that CLR
+            // exceptions will be caught in (...) as well. However, these
+            // do not fill-in std::current_exception and thus lead to crash
+            // when attempting rethrow.
+            // /EHa switch also causes structured exceptions to be caught
+            // here, but they fill-in current_exception properly, so
+            // at worst the output should be a little weird, instead of
+            // causing a crash.
+            if (std::current_exception() == nullptr) {
+                return "Non C++ exception. Possibly a CLR exception.";
+            }
+            return tryTranslators();
+#endif
+        }
+        catch( TestFailureException& ) {
+            std::rethrow_exception(std::current_exception());
+        }
+        catch( std::exception& ex ) {
+            return ex.what();
+        }
+        catch( std::string& msg ) {
+            return msg;
+        }
+        catch( const char* msg ) {
+            return msg;
+        }
+        catch(...) {
+            return "Unknown exception";
+        }
+    }
+
+    std::string ExceptionTranslatorRegistry::tryTranslators() const {
+        if (m_translators.empty()) {
+            std::rethrow_exception(std::current_exception());
+        } else {
+            return m_translators[0]->translate(m_translators.begin() + 1, m_translators.end());
+        }
+    }
+
+#else // ^^ Exceptions are enabled // Exceptions are disabled vv
+    std::string ExceptionTranslatorRegistry::translateActiveException() const {
+        CATCH_INTERNAL_ERROR("Attempted to translate active exception under CATCH_CONFIG_DISABLE_EXCEPTIONS!");
+    }
+
+    std::string ExceptionTranslatorRegistry::tryTranslators() const {
+        CATCH_INTERNAL_ERROR("Attempted to use exception translators under CATCH_CONFIG_DISABLE_EXCEPTIONS!");
+    }
+#endif
+
+}
+// end catch_exception_translator_registry.cpp
+// start catch_fatal_condition.cpp
+
+#include <algorithm>
+
+#if !defined( CATCH_CONFIG_WINDOWS_SEH ) && !defined( CATCH_CONFIG_POSIX_SIGNALS )
+
+namespace Catch {
+
+    // If neither SEH nor signal handling is required, the handler impls
+    // do not have to do anything, and can be empty.
+    void FatalConditionHandler::engage_platform() {}
+    void FatalConditionHandler::disengage_platform() {}
+    FatalConditionHandler::FatalConditionHandler() = default;
+    FatalConditionHandler::~FatalConditionHandler() = default;
+
+} // end namespace Catch
+
+#endif // !CATCH_CONFIG_WINDOWS_SEH && !CATCH_CONFIG_POSIX_SIGNALS
+
+#if defined( CATCH_CONFIG_WINDOWS_SEH ) && defined( CATCH_CONFIG_POSIX_SIGNALS )
+#error "Inconsistent configuration: Windows' SEH handling and POSIX signals cannot be enabled at the same time"
+#endif // CATCH_CONFIG_WINDOWS_SEH && CATCH_CONFIG_POSIX_SIGNALS
+
+#if defined( CATCH_CONFIG_WINDOWS_SEH ) || defined( CATCH_CONFIG_POSIX_SIGNALS )
+
+namespace {
+    //! Signals fatal error message to the run context
+    void reportFatal( char const * const message ) {
+        Catch::getCurrentContext().getResultCapture()->handleFatalErrorCondition( message );
+    }
+
+    //! Minimal size Catch2 needs for its own fatal error handling.
+    //! Picked anecdotally, so it might not be sufficient on all
+    //! platforms, and for all configurations.
+    constexpr std::size_t minStackSizeForErrors = 32 * 1024;
+} // end unnamed namespace
+
+#endif // CATCH_CONFIG_WINDOWS_SEH || CATCH_CONFIG_POSIX_SIGNALS
+
+#if defined( CATCH_CONFIG_WINDOWS_SEH )
+
+namespace Catch {
+
+    struct SignalDefs { DWORD id; const char* name; };
+
+    // There is no 1-1 mapping between signals and windows exceptions.
+    // Windows can easily distinguish between SO and SigSegV,
+    // but SigInt, SigTerm, etc are handled differently.
+    static SignalDefs signalDefs[] = {
+        { static_cast<DWORD>(EXCEPTION_ILLEGAL_INSTRUCTION),  "SIGILL - Illegal instruction signal" },
+        { static_cast<DWORD>(EXCEPTION_STACK_OVERFLOW), "SIGSEGV - Stack overflow" },
+        { static_cast<DWORD>(EXCEPTION_ACCESS_VIOLATION), "SIGSEGV - Segmentation violation signal" },
+        { static_cast<DWORD>(EXCEPTION_INT_DIVIDE_BY_ZERO), "Divide by zero error" },
+    };
+
+    static LONG CALLBACK handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo) {
+        for (auto const& def : signalDefs) {
+            if (ExceptionInfo->ExceptionRecord->ExceptionCode == def.id) {
+                reportFatal(def.name);
+            }
+        }
+        // If its not an exception we care about, pass it along.
+        // This stops us from eating debugger breaks etc.
+        return EXCEPTION_CONTINUE_SEARCH;
+    }
+
+    // Since we do not support multiple instantiations, we put these
+    // into global variables and rely on cleaning them up in outlined
+    // constructors/destructors
+    static PVOID exceptionHandlerHandle = nullptr;
+
+    // For MSVC, we reserve part of the stack memory for handling
+    // memory overflow structured exception.
+    FatalConditionHandler::FatalConditionHandler() {
+        ULONG guaranteeSize = static_cast<ULONG>(minStackSizeForErrors);
+        if (!SetThreadStackGuarantee(&guaranteeSize)) {
+            // We do not want to fully error out, because needing
+            // the stack reserve should be rare enough anyway.
+            Catch::cerr()
+                << "Failed to reserve piece of stack."
+                << " Stack overflows will not be reported successfully.";
+        }
+    }
+
+    // We do not attempt to unset the stack guarantee, because
+    // Windows does not support lowering the stack size guarantee.
+    FatalConditionHandler::~FatalConditionHandler() = default;
+
+    void FatalConditionHandler::engage_platform() {
+        // Register as first handler in current chain
+        exceptionHandlerHandle = AddVectoredExceptionHandler(1, handleVectoredException);
+        if (!exceptionHandlerHandle) {
+            CATCH_RUNTIME_ERROR("Could not register vectored exception handler");
+        }
+    }
+
+    void FatalConditionHandler::disengage_platform() {
+        if (!RemoveVectoredExceptionHandler(exceptionHandlerHandle)) {
+            CATCH_RUNTIME_ERROR("Could not unregister vectored exception handler");
+        }
+        exceptionHandlerHandle = nullptr;
+    }
+
+} // end namespace Catch
+
+#endif // CATCH_CONFIG_WINDOWS_SEH
+
+#if defined( CATCH_CONFIG_POSIX_SIGNALS )
+
+#include <signal.h>
+
+namespace Catch {
+
+    struct SignalDefs {
+        int id;
+        const char* name;
+    };
+
+    static SignalDefs signalDefs[] = {
+        { SIGINT,  "SIGINT - Terminal interrupt signal" },
+        { SIGILL,  "SIGILL - Illegal instruction signal" },
+        { SIGFPE,  "SIGFPE - Floating point error signal" },
+        { SIGSEGV, "SIGSEGV - Segmentation violation signal" },
+        { SIGTERM, "SIGTERM - Termination request signal" },
+        { SIGABRT, "SIGABRT - Abort (abnormal termination) signal" }
+    };
+
+// Older GCCs trigger -Wmissing-field-initializers for T foo = {}
+// which is zero initialization, but not explicit. We want to avoid
+// that.
+#if defined(__GNUC__)
+#    pragma GCC diagnostic push
+#    pragma GCC diagnostic ignored "-Wmissing-field-initializers"
+#endif
+
+    static char* altStackMem = nullptr;
+    static std::size_t altStackSize = 0;
+    static stack_t oldSigStack{};
+    static struct sigaction oldSigActions[sizeof(signalDefs) / sizeof(SignalDefs)]{};
+
+    static void restorePreviousSignalHandlers() {
+        // We set signal handlers back to the previous ones. Hopefully
+        // nobody overwrote them in the meantime, and doesn't expect
+        // their signal handlers to live past ours given that they
+        // installed them after ours..
+        for (std::size_t i = 0; i < sizeof(signalDefs) / sizeof(SignalDefs); ++i) {
+            sigaction(signalDefs[i].id, &oldSigActions[i], nullptr);
+        }
+        // Return the old stack
+        sigaltstack(&oldSigStack, nullptr);
+    }
+
+    static void handleSignal( int sig ) {
+        char const * name = "<unknown signal>";
+        for (auto const& def : signalDefs) {
+            if (sig == def.id) {
+                name = def.name;
+                break;
+            }
+        }
+        // We need to restore previous signal handlers and let them do
+        // their thing, so that the users can have the debugger break
+        // when a signal is raised, and so on.
+        restorePreviousSignalHandlers();
+        reportFatal( name );
+        raise( sig );
+    }
+
+    FatalConditionHandler::FatalConditionHandler() {
+        assert(!altStackMem && "Cannot initialize POSIX signal handler when one already exists");
+        if (altStackSize == 0) {
+            altStackSize = std::max(static_cast<size_t>(SIGSTKSZ), minStackSizeForErrors);
+        }
+        altStackMem = new char[altStackSize]();
+    }
+
+    FatalConditionHandler::~FatalConditionHandler() {
+        delete[] altStackMem;
+        // We signal that another instance can be constructed by zeroing
+        // out the pointer.
+        altStackMem = nullptr;
+    }
+
+    void FatalConditionHandler::engage_platform() {
+        stack_t sigStack;
+        sigStack.ss_sp = altStackMem;
+        sigStack.ss_size = altStackSize;
+        sigStack.ss_flags = 0;
+        sigaltstack(&sigStack, &oldSigStack);
+        struct sigaction sa = { };
+
+        sa.sa_handler = handleSignal;
+        sa.sa_flags = SA_ONSTACK;
+        for (std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i) {
+            sigaction(signalDefs[i].id, &sa, &oldSigActions[i]);
+        }
+    }
+
+#if defined(__GNUC__)
+#    pragma GCC diagnostic pop
+#endif
+
+    void FatalConditionHandler::disengage_platform() {
+        restorePreviousSignalHandlers();
+    }
+
+} // end namespace Catch
+
+#endif // CATCH_CONFIG_POSIX_SIGNALS
+// end catch_fatal_condition.cpp
+// start catch_generators.cpp
+
+#include <limits>
+#include <set>
+
+namespace Catch {
+
+IGeneratorTracker::~IGeneratorTracker() {}
+
+const char* GeneratorException::what() const noexcept {
+    return m_msg;
+}
+
+namespace Generators {
+
+    GeneratorUntypedBase::~GeneratorUntypedBase() {}
+
+    auto acquireGeneratorTracker( StringRef generatorName, SourceLineInfo const& lineInfo ) -> IGeneratorTracker& {
+        return getResultCapture().acquireGeneratorTracker( generatorName, lineInfo );
+    }
+
+} // namespace Generators
+} // namespace Catch
+// end catch_generators.cpp
+// start catch_interfaces_capture.cpp
+
+namespace Catch {
+    IResultCapture::~IResultCapture() = default;
+}
+// end catch_interfaces_capture.cpp
+// start catch_interfaces_config.cpp
+
+namespace Catch {
+    IConfig::~IConfig() = default;
+}
+// end catch_interfaces_config.cpp
+// start catch_interfaces_exception.cpp
+
+namespace Catch {
+    IExceptionTranslator::~IExceptionTranslator() = default;
+    IExceptionTranslatorRegistry::~IExceptionTranslatorRegistry() = default;
+}
+// end catch_interfaces_exception.cpp
+// start catch_interfaces_registry_hub.cpp
+
+namespace Catch {
+    IRegistryHub::~IRegistryHub() = default;
+    IMutableRegistryHub::~IMutableRegistryHub() = default;
+}
+// end catch_interfaces_registry_hub.cpp
+// start catch_interfaces_reporter.cpp
+
+// start catch_reporter_listening.h
+
+namespace Catch {
+
+    class ListeningReporter : public IStreamingReporter {
+        using Reporters = std::vector<IStreamingReporterPtr>;
+        Reporters m_listeners;
+        IStreamingReporterPtr m_reporter = nullptr;
+        ReporterPreferences m_preferences;
+
+    public:
+        ListeningReporter();
+
+        void addListener( IStreamingReporterPtr&& listener );
+        void addReporter( IStreamingReporterPtr&& reporter );
+
+    public: // IStreamingReporter
+
+        ReporterPreferences getPreferences() const override;
+
+        void noMatchingTestCases( std::string const& spec ) override;
+
+        void reportInvalidArguments(std::string const&arg) override;
+
+        static std::set<Verbosity> getSupportedVerbosities();
+
+#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
+        void benchmarkPreparing(std::string const& name) override;
+        void benchmarkStarting( BenchmarkInfo const& benchmarkInfo ) override;
+        void benchmarkEnded( BenchmarkStats<> const& benchmarkStats ) override;
+        void benchmarkFailed(std::string const&) override;
+#endif // CATCH_CONFIG_ENABLE_BENCHMARKING
+
+        void testRunStarting( TestRunInfo const& testRunInfo ) override;
+        void testGroupStarting( GroupInfo const& groupInfo ) override;
+        void testCaseStarting( TestCaseInfo const& testInfo ) override;
+        void sectionStarting( SectionInfo const& sectionInfo ) override;
+        void assertionStarting( AssertionInfo const& assertionInfo ) override;
+
+        // The return value indicates if the messages buffer should be cleared:
+        bool assertionEnded( AssertionStats const& assertionStats ) override;
+        void sectionEnded( SectionStats const& sectionStats ) override;
+        void testCaseEnded( TestCaseStats const& testCaseStats ) override;
+        void testGroupEnded( TestGroupStats const& testGroupStats ) override;
+        void testRunEnded( TestRunStats const& testRunStats ) override;
+
+        void skipTest( TestCaseInfo const& testInfo ) override;
+        bool isMulti() const override;
+
+    };
+
+} // end namespace Catch
+
+// end catch_reporter_listening.h
+namespace Catch {
+
+    ReporterConfig::ReporterConfig( IConfigPtr const& _fullConfig )
+    :   m_stream( &_fullConfig->stream() ), m_fullConfig( _fullConfig ) {}
+
+    ReporterConfig::ReporterConfig( IConfigPtr const& _fullConfig, std::ostream& _stream )
+    :   m_stream( &_stream ), m_fullConfig( _fullConfig ) {}
+
+    std::ostream& ReporterConfig::stream() const { return *m_stream; }
+    IConfigPtr ReporterConfig::fullConfig() const { return m_fullConfig; }
+
+    TestRunInfo::TestRunInfo( std::string const& _name ) : name( _name ) {}
+
+    GroupInfo::GroupInfo(  std::string const& _name,
+                           std::size_t _groupIndex,
+                           std::size_t _groupsCount )
+    :   name( _name ),
+        groupIndex( _groupIndex ),
+        groupsCounts( _groupsCount )
+    {}
+
+     AssertionStats::AssertionStats( AssertionResult const& _assertionResult,
+                                     std::vector<MessageInfo> const& _infoMessages,
+                                     Totals const& _totals )
+    :   assertionResult( _assertionResult ),
+        infoMessages( _infoMessages ),
+        totals( _totals )
+    {
+        assertionResult.m_resultData.lazyExpression.m_transientExpression = _assertionResult.m_resultData.lazyExpression.m_transientExpression;
+
+        if( assertionResult.hasMessage() ) {
+            // Copy message into messages list.
+            // !TBD This should have been done earlier, somewhere
+            MessageBuilder builder( assertionResult.getTestMacroName(), assertionResult.getSourceInfo(), assertionResult.getResultType() );
+            builder << assertionResult.getMessage();
+            builder.m_info.message = builder.m_stream.str();
+
+            infoMessages.push_back( builder.m_info );
+        }
+    }
+
+     AssertionStats::~AssertionStats() = default;
+
+    SectionStats::SectionStats(  SectionInfo const& _sectionInfo,
+                                 Counts const& _assertions,
+                                 double _durationInSeconds,
+                                 bool _missingAssertions )
+    :   sectionInfo( _sectionInfo ),
+        assertions( _assertions ),
+        durationInSeconds( _durationInSeconds ),
+        missingAssertions( _missingAssertions )
+    {}
+
+    SectionStats::~SectionStats() = default;
+
+    TestCaseStats::TestCaseStats(  TestCaseInfo const& _testInfo,
+                                   Totals const& _totals,
+                                   std::string const& _stdOut,
+                                   std::string const& _stdErr,
+                                   bool _aborting )
+    : testInfo( _testInfo ),
+        totals( _totals ),
+        stdOut( _stdOut ),
+        stdErr( _stdErr ),
+        aborting( _aborting )
+    {}
+
+    TestCaseStats::~TestCaseStats() = default;
+
+    TestGroupStats::TestGroupStats( GroupInfo const& _groupInfo,
+                                    Totals const& _totals,
+                                    bool _aborting )
+    :   groupInfo( _groupInfo ),
+        totals( _totals ),
+        aborting( _aborting )
+    {}
+
+    TestGroupStats::TestGroupStats( GroupInfo const& _groupInfo )
+    :   groupInfo( _groupInfo ),
+        aborting( false )
+    {}
+
+    TestGroupStats::~TestGroupStats() = default;
+
+    TestRunStats::TestRunStats(   TestRunInfo const& _runInfo,
+                    Totals const& _totals,
+                    bool _aborting )
+    :   runInfo( _runInfo ),
+        totals( _totals ),
+        aborting( _aborting )
+    {}
+
+    TestRunStats::~TestRunStats() = default;
+
+    void IStreamingReporter::fatalErrorEncountered( StringRef ) {}
+    bool IStreamingReporter::isMulti() const { return false; }
+
+    IReporterFactory::~IReporterFactory() = default;
+    IReporterRegistry::~IReporterRegistry() = default;
+
+} // end namespace Catch
+// end catch_interfaces_reporter.cpp
+// start catch_interfaces_runner.cpp
+
+namespace Catch {
+    IRunner::~IRunner() = default;
+}
+// end catch_interfaces_runner.cpp
+// start catch_interfaces_testcase.cpp
+
+namespace Catch {
+    ITestInvoker::~ITestInvoker() = default;
+    ITestCaseRegistry::~ITestCaseRegistry() = default;
+}
+// end catch_interfaces_testcase.cpp
+// start catch_leak_detector.cpp
+
+#ifdef CATCH_CONFIG_WINDOWS_CRTDBG
+#include <crtdbg.h>
+
+namespace Catch {
+
+    LeakDetector::LeakDetector() {
+        int flag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);
+        flag |= _CRTDBG_LEAK_CHECK_DF;
+        flag |= _CRTDBG_ALLOC_MEM_DF;
+        _CrtSetDbgFlag(flag);
+        _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
+        _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
+        // Change this to leaking allocation's number to break there
+        _CrtSetBreakAlloc(-1);
+    }
+}
+
+#else
+
+    Catch::LeakDetector::LeakDetector() {}
+
+#endif
+
+Catch::LeakDetector::~LeakDetector() {
+    Catch::cleanUp();
+}
+// end catch_leak_detector.cpp
+// start catch_list.cpp
+
+// start catch_list.h
+
+#include <set>
+
+namespace Catch {
+
+    std::size_t listTests( Config const& config );
+
+    std::size_t listTestsNamesOnly( Config const& config );
+
+    struct TagInfo {
+        void add( std::string const& spelling );
+        std::string all() const;
+
+        std::set<std::string> spellings;
+        std::size_t count = 0;
+    };
+
+    std::size_t listTags( Config const& config );
+
+    std::size_t listReporters();
+
+    Option<std::size_t> list( std::shared_ptr<Config> const& config );
+
+} // end namespace Catch
+
+// end catch_list.h
+// start catch_text.h
+
+namespace Catch {
+    using namespace clara::TextFlow;
+}
+
+// end catch_text.h
+#include <limits>
+#include <algorithm>
+#include <iomanip>
+
+namespace Catch {
+
+    std::size_t listTests( Config const& config ) {
+        TestSpec const& testSpec = config.testSpec();
+        if( config.hasTestFilters() )
+            Catch::cout() << "Matching test cases:\n";
+        else {
+            Catch::cout() << "All available test cases:\n";
+        }
+
+        auto matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config );
+        for( auto const& testCaseInfo : matchedTestCases ) {
+            Colour::Code colour = testCaseInfo.isHidden()
+                ? Colour::SecondaryText
+                : Colour::None;
+            Colour colourGuard( colour );
+
+            Catch::cout() << Column( testCaseInfo.name ).initialIndent( 2 ).indent( 4 ) << "\n";
+            if( config.verbosity() >= Verbosity::High ) {
+                Catch::cout() << Column( Catch::Detail::stringify( testCaseInfo.lineInfo ) ).indent(4) << std::endl;
+                std::string description = testCaseInfo.description;
+                if( description.empty() )
+                    description = "(NO DESCRIPTION)";
+                Catch::cout() << Column( description ).indent(4) << std::endl;
+            }
+            if( !testCaseInfo.tags.empty() )
+                Catch::cout() << Column( testCaseInfo.tagsAsString() ).indent( 6 ) << "\n";
+        }
+
+        if( !config.hasTestFilters() )
+            Catch::cout() << pluralise( matchedTestCases.size(), "test case" ) << '\n' << std::endl;
+        else
+            Catch::cout() << pluralise( matchedTestCases.size(), "matching test case" ) << '\n' << std::endl;
+        return matchedTestCases.size();
+    }
+
+    std::size_t listTestsNamesOnly( Config const& config ) {
+        TestSpec const& testSpec = config.testSpec();
+        std::size_t matchedTests = 0;
+        std::vector<TestCase> matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config );
+        for( auto const& testCaseInfo : matchedTestCases ) {
+            matchedTests++;
+            if( startsWith( testCaseInfo.name, '#' ) )
+               Catch::cout() << '"' << testCaseInfo.name << '"';
+            else
+               Catch::cout() << testCaseInfo.name;
+            if ( config.verbosity() >= Verbosity::High )
+                Catch::cout() << "\t@" << testCaseInfo.lineInfo;
+            Catch::cout() << std::endl;
+        }
+        return matchedTests;
+    }
+
+    void TagInfo::add( std::string const& spelling ) {
+        ++count;
+        spellings.insert( spelling );
+    }
+
+    std::string TagInfo::all() const {
+        size_t size = 0;
+        for (auto const& spelling : spellings) {
+            // Add 2 for the brackes
+            size += spelling.size() + 2;
+        }
+
+        std::string out; out.reserve(size);
+        for (auto const& spelling : spellings) {
+            out += '[';
+            out += spelling;
+            out += ']';
+        }
+        return out;
+    }
+
+    std::size_t listTags( Config const& config ) {
+        TestSpec const& testSpec = config.testSpec();
+        if( config.hasTestFilters() )
+            Catch::cout() << "Tags for matching test cases:\n";
+        else {
+            Catch::cout() << "All available tags:\n";
+        }
+
+        std::map<std::string, TagInfo> tagCounts;
+
+        std::vector<TestCase> matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config );
+        for( auto const& testCase : matchedTestCases ) {
+            for( auto const& tagName : testCase.getTestCaseInfo().tags ) {
+                std::string lcaseTagName = toLower( tagName );
+                auto countIt = tagCounts.find( lcaseTagName );
+                if( countIt == tagCounts.end() )
+                    countIt = tagCounts.insert( std::make_pair( lcaseTagName, TagInfo() ) ).first;
+                countIt->second.add( tagName );
+            }
+        }
+
+        for( auto const& tagCount : tagCounts ) {
+            ReusableStringStream rss;
+            rss << "  " << std::setw(2) << tagCount.second.count << "  ";
+            auto str = rss.str();
+            auto wrapper = Column( tagCount.second.all() )
+                                                    .initialIndent( 0 )
+                                                    .indent( str.size() )
+                                                    .width( CATCH_CONFIG_CONSOLE_WIDTH-10 );
+            Catch::cout() << str << wrapper << '\n';
+        }
+        Catch::cout() << pluralise( tagCounts.size(), "tag" ) << '\n' << std::endl;
+        return tagCounts.size();
+    }
+
+    std::size_t listReporters() {
+        Catch::cout() << "Available reporters:\n";
+        IReporterRegistry::FactoryMap const& factories = getRegistryHub().getReporterRegistry().getFactories();
+        std::size_t maxNameLen = 0;
+        for( auto const& factoryKvp : factories )
+            maxNameLen = (std::max)( maxNameLen, factoryKvp.first.size() );
+
+        for( auto const& factoryKvp : factories ) {
+            Catch::cout()
+                    << Column( factoryKvp.first + ":" )
+                            .indent(2)
+                            .width( 5+maxNameLen )
+                    +  Column( factoryKvp.second->getDescription() )
+                            .initialIndent(0)
+                            .indent(2)
+                            .width( CATCH_CONFIG_CONSOLE_WIDTH - maxNameLen-8 )
+                    << "\n";
+        }
+        Catch::cout() << std::endl;
+        return factories.size();
+    }
+
+    Option<std::size_t> list( std::shared_ptr<Config> const& config ) {
+        Option<std::size_t> listedCount;
+        getCurrentMutableContext().setConfig( config );
+        if( config->listTests() )
+            listedCount = listedCount.valueOr(0) + listTests( *config );
+        if( config->listTestNamesOnly() )
+            listedCount = listedCount.valueOr(0) + listTestsNamesOnly( *config );
+        if( config->listTags() )
+            listedCount = listedCount.valueOr(0) + listTags( *config );
+        if( config->listReporters() )
+            listedCount = listedCount.valueOr(0) + listReporters();
+        return listedCount;
+    }
+
+} // end namespace Catch
+// end catch_list.cpp
+// start catch_matchers.cpp
+
+namespace Catch {
+namespace Matchers {
+    namespace Impl {
+
+        std::string MatcherUntypedBase::toString() const {
+            if( m_cachedToString.empty() )
+                m_cachedToString = describe();
+            return m_cachedToString;
+        }
+
+        MatcherUntypedBase::~MatcherUntypedBase() = default;
+
+    } // namespace Impl
+} // namespace Matchers
+
+using namespace Matchers;
+using Matchers::Impl::MatcherBase;
+
+} // namespace Catch
+// end catch_matchers.cpp
+// start catch_matchers_exception.cpp
+
+namespace Catch {
+namespace Matchers {
+namespace Exception {
+
+bool ExceptionMessageMatcher::match(std::exception const& ex) const {
+    return ex.what() == m_message;
+}
+
+std::string ExceptionMessageMatcher::describe() const {
+    return "exception message matches \"" + m_message + "\"";
+}
+
+}
+Exception::ExceptionMessageMatcher Message(std::string const& message) {
+    return Exception::ExceptionMessageMatcher(message);
+}
+
+// namespace Exception
+} // namespace Matchers
+} // namespace Catch
+// end catch_matchers_exception.cpp
+// start catch_matchers_floating.cpp
+
+// start catch_polyfills.hpp
+
+namespace Catch {
+    bool isnan(float f);
+    bool isnan(double d);
+}
+
+// end catch_polyfills.hpp
+// start catch_to_string.hpp
+
+#include <string>
+
+namespace Catch {
+    template <typename T>
+    std::string to_string(T const& t) {
+#if defined(CATCH_CONFIG_CPP11_TO_STRING)
+        return std::to_string(t);
+#else
+        ReusableStringStream rss;
+        rss << t;
+        return rss.str();
+#endif
+    }
+} // end namespace Catch
+
+// end catch_to_string.hpp
+#include <algorithm>
+#include <cmath>
+#include <cstdlib>
+#include <cstdint>
+#include <cstring>
+#include <sstream>
+#include <type_traits>
+#include <iomanip>
+#include <limits>
+
+namespace Catch {
+namespace {
+
+    int32_t convert(float f) {
+        static_assert(sizeof(float) == sizeof(int32_t), "Important ULP matcher assumption violated");
+        int32_t i;
+        std::memcpy(&i, &f, sizeof(f));
+        return i;
+    }
+
+    int64_t convert(double d) {
+        static_assert(sizeof(double) == sizeof(int64_t), "Important ULP matcher assumption violated");
+        int64_t i;
+        std::memcpy(&i, &d, sizeof(d));
+        return i;
+    }
+
+    template <typename FP>
+    bool almostEqualUlps(FP lhs, FP rhs, uint64_t maxUlpDiff) {
+        // Comparison with NaN should always be false.
+        // This way we can rule it out before getting into the ugly details
+        if (Catch::isnan(lhs) || Catch::isnan(rhs)) {
+            return false;
+        }
+
+        auto lc = convert(lhs);
+        auto rc = convert(rhs);
+
+        if ((lc < 0) != (rc < 0)) {
+            // Potentially we can have +0 and -0
+            return lhs == rhs;
+        }
+
+        // static cast as a workaround for IBM XLC
+        auto ulpDiff = std::abs(static_cast<FP>(lc - rc));
+        return static_cast<uint64_t>(ulpDiff) <= maxUlpDiff;
+    }
+
+#if defined(CATCH_CONFIG_GLOBAL_NEXTAFTER)
+
+    float nextafter(float x, float y) {
+        return ::nextafterf(x, y);
+    }
+
+    double nextafter(double x, double y) {
+        return ::nextafter(x, y);
+    }
+
+#endif // ^^^ CATCH_CONFIG_GLOBAL_NEXTAFTER ^^^
+
+template <typename FP>
+FP step(FP start, FP direction, uint64_t steps) {
+    for (uint64_t i = 0; i < steps; ++i) {
+#if defined(CATCH_CONFIG_GLOBAL_NEXTAFTER)
+        start = Catch::nextafter(start, direction);
+#else
+        start = std::nextafter(start, direction);
+#endif
+    }
+    return start;
+}
+
+// Performs equivalent check of std::fabs(lhs - rhs) <= margin
+// But without the subtraction to allow for INFINITY in comparison
+bool marginComparison(double lhs, double rhs, double margin) {
+    return (lhs + margin >= rhs) && (rhs + margin >= lhs);
+}
+
+template <typename FloatingPoint>
+void write(std::ostream& out, FloatingPoint num) {
+    out << std::scientific
+        << std::setprecision(std::numeric_limits<FloatingPoint>::max_digits10 - 1)
+        << num;
+}
+
+} // end anonymous namespace
+
+namespace Matchers {
+namespace Floating {
+
+    enum class FloatingPointKind : uint8_t {
+        Float,
+        Double
+    };
+
+    WithinAbsMatcher::WithinAbsMatcher(double target, double margin)
+        :m_target{ target }, m_margin{ margin } {
+        CATCH_ENFORCE(margin >= 0, "Invalid margin: " << margin << '.'
+            << " Margin has to be non-negative.");
+    }
+
+    // Performs equivalent check of std::fabs(lhs - rhs) <= margin
+    // But without the subtraction to allow for INFINITY in comparison
+    bool WithinAbsMatcher::match(double const& matchee) const {
+        return (matchee + m_margin >= m_target) && (m_target + m_margin >= matchee);
+    }
+
+    std::string WithinAbsMatcher::describe() const {
+        return "is within " + ::Catch::Detail::stringify(m_margin) + " of " + ::Catch::Detail::stringify(m_target);
+    }
+
+    WithinUlpsMatcher::WithinUlpsMatcher(double target, uint64_t ulps, FloatingPointKind baseType)
+        :m_target{ target }, m_ulps{ ulps }, m_type{ baseType } {
+        CATCH_ENFORCE(m_type == FloatingPointKind::Double
+                   || m_ulps < (std::numeric_limits<uint32_t>::max)(),
+            "Provided ULP is impossibly large for a float comparison.");
+    }
+
+#if defined(__clang__)
+#pragma clang diagnostic push
+// Clang <3.5 reports on the default branch in the switch below
+#pragma clang diagnostic ignored "-Wunreachable-code"
+#endif
+
+    bool WithinUlpsMatcher::match(double const& matchee) const {
+        switch (m_type) {
+        case FloatingPointKind::Float:
+            return almostEqualUlps<float>(static_cast<float>(matchee), static_cast<float>(m_target), m_ulps);
+        case FloatingPointKind::Double:
+            return almostEqualUlps<double>(matchee, m_target, m_ulps);
+        default:
+            CATCH_INTERNAL_ERROR( "Unknown FloatingPointKind value" );
+        }
+    }
+
+#if defined(__clang__)
+#pragma clang diagnostic pop
+#endif
+
+    std::string WithinUlpsMatcher::describe() const {
+        std::stringstream ret;
+
+        ret << "is within " << m_ulps << " ULPs of ";
+
+        if (m_type == FloatingPointKind::Float) {
+            write(ret, static_cast<float>(m_target));
+            ret << 'f';
+        } else {
+            write(ret, m_target);
+        }
+
+        ret << " ([";
+        if (m_type == FloatingPointKind::Double) {
+            write(ret, step(m_target, static_cast<double>(-INFINITY), m_ulps));
+            ret << ", ";
+            write(ret, step(m_target, static_cast<double>( INFINITY), m_ulps));
+        } else {
+            // We have to cast INFINITY to float because of MinGW, see #1782
+            write(ret, step(static_cast<float>(m_target), static_cast<float>(-INFINITY), m_ulps));
+            ret << ", ";
+            write(ret, step(static_cast<float>(m_target), static_cast<float>( INFINITY), m_ulps));
+        }
+        ret << "])";
+
+        return ret.str();
+    }
+
+    WithinRelMatcher::WithinRelMatcher(double target, double epsilon):
+        m_target(target),
+        m_epsilon(epsilon){
+        CATCH_ENFORCE(m_epsilon >= 0., "Relative comparison with epsilon <  0 does not make sense.");
+        CATCH_ENFORCE(m_epsilon  < 1., "Relative comparison with epsilon >= 1 does not make sense.");
+    }
+
+    bool WithinRelMatcher::match(double const& matchee) const {
+        const auto relMargin = m_epsilon * (std::max)(std::fabs(matchee), std::fabs(m_target));
+        return marginComparison(matchee, m_target,
+                                std::isinf(relMargin)? 0 : relMargin);
+    }
+
+    std::string WithinRelMatcher::describe() const {
+        Catch::ReusableStringStream sstr;
+        sstr << "and " << m_target << " are within " << m_epsilon * 100. << "% of each other";
+        return sstr.str();
+    }
+
+}// namespace Floating
+
+Floating::WithinUlpsMatcher WithinULP(double target, uint64_t maxUlpDiff) {
+    return Floating::WithinUlpsMatcher(target, maxUlpDiff, Floating::FloatingPointKind::Double);
+}
+
+Floating::WithinUlpsMatcher WithinULP(float target, uint64_t maxUlpDiff) {
+    return Floating::WithinUlpsMatcher(target, maxUlpDiff, Floating::FloatingPointKind::Float);
+}
+
+Floating::WithinAbsMatcher WithinAbs(double target, double margin) {
+    return Floating::WithinAbsMatcher(target, margin);
+}
+
+Floating::WithinRelMatcher WithinRel(double target, double eps) {
+    return Floating::WithinRelMatcher(target, eps);
+}
+
+Floating::WithinRelMatcher WithinRel(double target) {
+    return Floating::WithinRelMatcher(target, std::numeric_limits<double>::epsilon() * 100);
+}
+
+Floating::WithinRelMatcher WithinRel(float target, float eps) {
+    return Floating::WithinRelMatcher(target, eps);
+}
+
+Floating::WithinRelMatcher WithinRel(float target) {
+    return Floating::WithinRelMatcher(target, std::numeric_limits<float>::epsilon() * 100);
+}
+
+} // namespace Matchers
+} // namespace Catch
+// end catch_matchers_floating.cpp
+// start catch_matchers_generic.cpp
+
+std::string Catch::Matchers::Generic::Detail::finalizeDescription(const std::string& desc) {
+    if (desc.empty()) {
+        return "matches undescribed predicate";
+    } else {
+        return "matches predicate: \"" + desc + '"';
+    }
+}
+// end catch_matchers_generic.cpp
+// start catch_matchers_string.cpp
+
+#include <regex>
+
+namespace Catch {
+namespace Matchers {
+
+    namespace StdString {
+
+        CasedString::CasedString( std::string const& str, CaseSensitive::Choice caseSensitivity )
+        :   m_caseSensitivity( caseSensitivity ),
+            m_str( adjustString( str ) )
+        {}
+        std::string CasedString::adjustString( std::string const& str ) const {
+            return m_caseSensitivity == CaseSensitive::No
+                   ? toLower( str )
+                   : str;
+        }
+        std::string CasedString::caseSensitivitySuffix() const {
+            return m_caseSensitivity == CaseSensitive::No
+                   ? " (case insensitive)"
+                   : std::string();
+        }
+
+        StringMatcherBase::StringMatcherBase( std::string const& operation, CasedString const& comparator )
+        : m_comparator( comparator ),
+          m_operation( operation ) {
+        }
+
+        std::string StringMatcherBase::describe() const {
+            std::string description;
+            description.reserve(5 + m_operation.size() + m_comparator.m_str.size() +
+                                        m_comparator.caseSensitivitySuffix().size());
+            description += m_operation;
+            description += ": \"";
+            description += m_comparator.m_str;
+            description += "\"";
+            description += m_comparator.caseSensitivitySuffix();
+            return description;
+        }
+
+        EqualsMatcher::EqualsMatcher( CasedString const& comparator ) : StringMatcherBase( "equals", comparator ) {}
+
+        bool EqualsMatcher::match( std::string const& source ) const {
+            return m_comparator.adjustString( source ) == m_comparator.m_str;
+        }
+
+        ContainsMatcher::ContainsMatcher( CasedString const& comparator ) : StringMatcherBase( "contains", comparator ) {}
+
+        bool ContainsMatcher::match( std::string const& source ) const {
+            return contains( m_comparator.adjustString( source ), m_comparator.m_str );
+        }
+
+        StartsWithMatcher::StartsWithMatcher( CasedString const& comparator ) : StringMatcherBase( "starts with", comparator ) {}
+
+        bool StartsWithMatcher::match( std::string const& source ) const {
+            return startsWith( m_comparator.adjustString( source ), m_comparator.m_str );
+        }
+
+        EndsWithMatcher::EndsWithMatcher( CasedString const& comparator ) : StringMatcherBase( "ends with", comparator ) {}
+
+        bool EndsWithMatcher::match( std::string const& source ) const {
+            return endsWith( m_comparator.adjustString( source ), m_comparator.m_str );
+        }
+
+        RegexMatcher::RegexMatcher(std::string regex, CaseSensitive::Choice caseSensitivity): m_regex(std::move(regex)), m_caseSensitivity(caseSensitivity) {}
+
+        bool RegexMatcher::match(std::string const& matchee) const {
+            auto flags = std::regex::ECMAScript; // ECMAScript is the default syntax option anyway
+            if (m_caseSensitivity == CaseSensitive::Choice::No) {
+                flags |= std::regex::icase;
+            }
+            auto reg = std::regex(m_regex, flags);
+            return std::regex_match(matchee, reg);
+        }
+
+        std::string RegexMatcher::describe() const {
+            return "matches " + ::Catch::Detail::stringify(m_regex) + ((m_caseSensitivity == CaseSensitive::Choice::Yes)? " case sensitively" : " case insensitively");
+        }
+
+    } // namespace StdString
+
+    StdString::EqualsMatcher Equals( std::string const& str, CaseSensitive::Choice caseSensitivity ) {
+        return StdString::EqualsMatcher( StdString::CasedString( str, caseSensitivity) );
+    }
+    StdString::ContainsMatcher Contains( std::string const& str, CaseSensitive::Choice caseSensitivity ) {
+        return StdString::ContainsMatcher( StdString::CasedString( str, caseSensitivity) );
+    }
+    StdString::EndsWithMatcher EndsWith( std::string const& str, CaseSensitive::Choice caseSensitivity ) {
+        return StdString::EndsWithMatcher( StdString::CasedString( str, caseSensitivity) );
+    }
+    StdString::StartsWithMatcher StartsWith( std::string const& str, CaseSensitive::Choice caseSensitivity ) {
+        return StdString::StartsWithMatcher( StdString::CasedString( str, caseSensitivity) );
+    }
+
+    StdString::RegexMatcher Matches(std::string const& regex, CaseSensitive::Choice caseSensitivity) {
+        return StdString::RegexMatcher(regex, caseSensitivity);
+    }
+
+} // namespace Matchers
+} // namespace Catch
+// end catch_matchers_string.cpp
+// start catch_message.cpp
+
+// start catch_uncaught_exceptions.h
+
+namespace Catch {
+    bool uncaught_exceptions();
+} // end namespace Catch
+
+// end catch_uncaught_exceptions.h
+#include <cassert>
+#include <stack>
+
+namespace Catch {
+
+    MessageInfo::MessageInfo(   StringRef const& _macroName,
+                                SourceLineInfo const& _lineInfo,
+                                ResultWas::OfType _type )
+    :   macroName( _macroName ),
+        lineInfo( _lineInfo ),
+        type( _type ),
+        sequence( ++globalCount )
+    {}
+
+    bool MessageInfo::operator==( MessageInfo const& other ) const {
+        return sequence == other.sequence;
+    }
+
+    bool MessageInfo::operator<( MessageInfo const& other ) const {
+        return sequence < other.sequence;
+    }
+
+    // This may need protecting if threading support is added
+    unsigned int MessageInfo::globalCount = 0;
+
+    ////////////////////////////////////////////////////////////////////////////
+
+    Catch::MessageBuilder::MessageBuilder( StringRef const& macroName,
+                                           SourceLineInfo const& lineInfo,
+                                           ResultWas::OfType type )
+        :m_info(macroName, lineInfo, type) {}
+
+    ////////////////////////////////////////////////////////////////////////////
+
+    ScopedMessage::ScopedMessage( MessageBuilder const& builder )
+    : m_info( builder.m_info ), m_moved()
+    {
+        m_info.message = builder.m_stream.str();
+        getResultCapture().pushScopedMessage( m_info );
+    }
+
+    ScopedMessage::ScopedMessage( ScopedMessage&& old )
+    : m_info( old.m_info ), m_moved()
+    {
+        old.m_moved = true;
+    }
+
+    ScopedMessage::~ScopedMessage() {
+        if ( !uncaught_exceptions() && !m_moved ){
+            getResultCapture().popScopedMessage(m_info);
+        }
+    }
+
+    Capturer::Capturer( StringRef macroName, SourceLineInfo const& lineInfo, ResultWas::OfType resultType, StringRef names ) {
+        auto trimmed = [&] (size_t start, size_t end) {
+            while (names[start] == ',' || isspace(static_cast<unsigned char>(names[start]))) {
+                ++start;
+            }
+            while (names[end] == ',' || isspace(static_cast<unsigned char>(names[end]))) {
+                --end;
+            }
+            return names.substr(start, end - start + 1);
+        };
+        auto skipq = [&] (size_t start, char quote) {
+            for (auto i = start + 1; i < names.size() ; ++i) {
+                if (names[i] == quote)
+                    return i;
+                if (names[i] == '\\')
+                    ++i;
+            }
+            CATCH_INTERNAL_ERROR("CAPTURE parsing encountered unmatched quote");
+        };
+
+        size_t start = 0;
+        std::stack<char> openings;
+        for (size_t pos = 0; pos < names.size(); ++pos) {
+            char c = names[pos];
+            switch (c) {
+            case '[':
+            case '{':
+            case '(':
+            // It is basically impossible to disambiguate between
+            // comparison and start of template args in this context
+//            case '<':
+                openings.push(c);
+                break;
+            case ']':
+            case '}':
+            case ')':
+//           case '>':
+                openings.pop();
+                break;
+            case '"':
+            case '\'':
+                pos = skipq(pos, c);
+                break;
+            case ',':
+                if (start != pos && openings.empty()) {
+                    m_messages.emplace_back(macroName, lineInfo, resultType);
+                    m_messages.back().message = static_cast<std::string>(trimmed(start, pos));
+                    m_messages.back().message += " := ";
+                    start = pos;
+                }
+            }
+        }
+        assert(openings.empty() && "Mismatched openings");
+        m_messages.emplace_back(macroName, lineInfo, resultType);
+        m_messages.back().message = static_cast<std::string>(trimmed(start, names.size() - 1));
+        m_messages.back().message += " := ";
+    }
+    Capturer::~Capturer() {
+        if ( !uncaught_exceptions() ){
+            assert( m_captured == m_messages.size() );
+            for( size_t i = 0; i < m_captured; ++i  )
+                m_resultCapture.popScopedMessage( m_messages[i] );
+        }
+    }
+
+    void Capturer::captureValue( size_t index, std::string const& value ) {
+        assert( index < m_messages.size() );
+        m_messages[index].message += value;
+        m_resultCapture.pushScopedMessage( m_messages[index] );
+        m_captured++;
+    }
+
+} // end namespace Catch
+// end catch_message.cpp
+// start catch_output_redirect.cpp
+
+// start catch_output_redirect.h
+#ifndef TWOBLUECUBES_CATCH_OUTPUT_REDIRECT_H
+#define TWOBLUECUBES_CATCH_OUTPUT_REDIRECT_H
+
+#include <cstdio>
+#include <iosfwd>
+#include <string>
+
+namespace Catch {
+
+    class RedirectedStream {
+        std::ostream& m_originalStream;
+        std::ostream& m_redirectionStream;
+        std::streambuf* m_prevBuf;
+
+    public:
+        RedirectedStream( std::ostream& originalStream, std::ostream& redirectionStream );
+        ~RedirectedStream();
+    };
+
+    class RedirectedStdOut {
+        ReusableStringStream m_rss;
+        RedirectedStream m_cout;
+    public:
+        RedirectedStdOut();
+        auto str() const -> std::string;
+    };
+
+    // StdErr has two constituent streams in C++, std::cerr and std::clog
+    // This means that we need to redirect 2 streams into 1 to keep proper
+    // order of writes
+    class RedirectedStdErr {
+        ReusableStringStream m_rss;
+        RedirectedStream m_cerr;
+        RedirectedStream m_clog;
+    public:
+        RedirectedStdErr();
+        auto str() const -> std::string;
+    };
+
+    class RedirectedStreams {
+    public:
+        RedirectedStreams(RedirectedStreams const&) = delete;
+        RedirectedStreams& operator=(RedirectedStreams const&) = delete;
+        RedirectedStreams(RedirectedStreams&&) = delete;
+        RedirectedStreams& operator=(RedirectedStreams&&) = delete;
+
+        RedirectedStreams(std::string& redirectedCout, std::string& redirectedCerr);
+        ~RedirectedStreams();
+    private:
+        std::string& m_redirectedCout;
+        std::string& m_redirectedCerr;
+        RedirectedStdOut m_redirectedStdOut;
+        RedirectedStdErr m_redirectedStdErr;
+    };
+
+#if defined(CATCH_CONFIG_NEW_CAPTURE)
+
+    // Windows's implementation of std::tmpfile is terrible (it tries
+    // to create a file inside system folder, thus requiring elevated
+    // privileges for the binary), so we have to use tmpnam(_s) and
+    // create the file ourselves there.
+    class TempFile {
+    public:
+        TempFile(TempFile const&) = delete;
+        TempFile& operator=(TempFile const&) = delete;
+        TempFile(TempFile&&) = delete;
+        TempFile& operator=(TempFile&&) = delete;
+
+        TempFile();
+        ~TempFile();
+
+        std::FILE* getFile();
+        std::string getContents();
+
+    private:
+        std::FILE* m_file = nullptr;
+    #if defined(_MSC_VER)
+        char m_buffer[L_tmpnam] = { 0 };
+    #endif
+    };
+
+    class OutputRedirect {
+    public:
+        OutputRedirect(OutputRedirect const&) = delete;
+        OutputRedirect& operator=(OutputRedirect const&) = delete;
+        OutputRedirect(OutputRedirect&&) = delete;
+        OutputRedirect& operator=(OutputRedirect&&) = delete;
+
+        OutputRedirect(std::string& stdout_dest, std::string& stderr_dest);
+        ~OutputRedirect();
+
+    private:
+        int m_originalStdout = -1;
+        int m_originalStderr = -1;
+        TempFile m_stdoutFile;
+        TempFile m_stderrFile;
+        std::string& m_stdoutDest;
+        std::string& m_stderrDest;
+    };
+
+#endif
+
+} // end namespace Catch
+
+#endif // TWOBLUECUBES_CATCH_OUTPUT_REDIRECT_H
+// end catch_output_redirect.h
+#include <cstdio>
+#include <cstring>
+#include <fstream>
+#include <sstream>
+#include <stdexcept>
+
+#if defined(CATCH_CONFIG_NEW_CAPTURE)
+    #if defined(_MSC_VER)
+    #include <io.h>      //_dup and _dup2
+    #define dup _dup
+    #define dup2 _dup2
+    #define fileno _fileno
+    #else
+    #include <unistd.h>  // dup and dup2
+    #endif
+#endif
+
+namespace Catch {
+
+    RedirectedStream::RedirectedStream( std::ostream& originalStream, std::ostream& redirectionStream )
+    :   m_originalStream( originalStream ),
+        m_redirectionStream( redirectionStream ),
+        m_prevBuf( m_originalStream.rdbuf() )
+    {
+        m_originalStream.rdbuf( m_redirectionStream.rdbuf() );
+    }
+
+    RedirectedStream::~RedirectedStream() {
+        m_originalStream.rdbuf( m_prevBuf );
+    }
+
+    RedirectedStdOut::RedirectedStdOut() : m_cout( Catch::cout(), m_rss.get() ) {}
+    auto RedirectedStdOut::str() const -> std::string { return m_rss.str(); }
+
+    RedirectedStdErr::RedirectedStdErr()
+    :   m_cerr( Catch::cerr(), m_rss.get() ),
+        m_clog( Catch::clog(), m_rss.get() )
+    {}
+    auto RedirectedStdErr::str() const -> std::string { return m_rss.str(); }
+
+    RedirectedStreams::RedirectedStreams(std::string& redirectedCout, std::string& redirectedCerr)
+    :   m_redirectedCout(redirectedCout),
+        m_redirectedCerr(redirectedCerr)
+    {}
+
+    RedirectedStreams::~RedirectedStreams() {
+        m_redirectedCout += m_redirectedStdOut.str();
+        m_redirectedCerr += m_redirectedStdErr.str();
+    }
+
+#if defined(CATCH_CONFIG_NEW_CAPTURE)
+
+#if defined(_MSC_VER)
+    TempFile::TempFile() {
+        if (tmpnam_s(m_buffer)) {
+            CATCH_RUNTIME_ERROR("Could not get a temp filename");
+        }
+        if (fopen_s(&m_file, m_buffer, "w+")) {
+            char buffer[100];
+            if (strerror_s(buffer, errno)) {
+                CATCH_RUNTIME_ERROR("Could not translate errno to a string");
+            }
+            CATCH_RUNTIME_ERROR("Could not open the temp file: '" << m_buffer << "' because: " << buffer);
+        }
+    }
+#else
+    TempFile::TempFile() {
+        m_file = std::tmpfile();
+        if (!m_file) {
+            CATCH_RUNTIME_ERROR("Could not create a temp file.");
+        }
+    }
+
+#endif
+
+    TempFile::~TempFile() {
+         // TBD: What to do about errors here?
+         std::fclose(m_file);
+         // We manually create the file on Windows only, on Linux
+         // it will be autodeleted
+#if defined(_MSC_VER)
+         std::remove(m_buffer);
+#endif
+    }
+
+    FILE* TempFile::getFile() {
+        return m_file;
+    }
+
+    std::string TempFile::getContents() {
+        std::stringstream sstr;
+        char buffer[100] = {};
+        std::rewind(m_file);
+        while (std::fgets(buffer, sizeof(buffer), m_file)) {
+            sstr << buffer;
+        }
+        return sstr.str();
+    }
+
+    OutputRedirect::OutputRedirect(std::string& stdout_dest, std::string& stderr_dest) :
+        m_originalStdout(dup(1)),
+        m_originalStderr(dup(2)),
+        m_stdoutDest(stdout_dest),
+        m_stderrDest(stderr_dest) {
+        dup2(fileno(m_stdoutFile.getFile()), 1);
+        dup2(fileno(m_stderrFile.getFile()), 2);
+    }
+
+    OutputRedirect::~OutputRedirect() {
+        Catch::cout() << std::flush;
+        fflush(stdout);
+        // Since we support overriding these streams, we flush cerr
+        // even though std::cerr is unbuffered
+        Catch::cerr() << std::flush;
+        Catch::clog() << std::flush;
+        fflush(stderr);
+
+        dup2(m_originalStdout, 1);
+        dup2(m_originalStderr, 2);
+
+        m_stdoutDest += m_stdoutFile.getContents();
+        m_stderrDest += m_stderrFile.getContents();
+    }
+
+#endif // CATCH_CONFIG_NEW_CAPTURE
+
+} // namespace Catch
+
+#if defined(CATCH_CONFIG_NEW_CAPTURE)
+    #if defined(_MSC_VER)
+    #undef dup
+    #undef dup2
+    #undef fileno
+    #endif
+#endif
+// end catch_output_redirect.cpp
+// start catch_polyfills.cpp
+
+#include <cmath>
+
+namespace Catch {
+
+#if !defined(CATCH_CONFIG_POLYFILL_ISNAN)
+    bool isnan(float f) {
+        return std::isnan(f);
+    }
+    bool isnan(double d) {
+        return std::isnan(d);
+    }
+#else
+    // For now we only use this for embarcadero
+    bool isnan(float f) {
+        return std::_isnan(f);
+    }
+    bool isnan(double d) {
+        return std::_isnan(d);
+    }
+#endif
+
+} // end namespace Catch
+// end catch_polyfills.cpp
+// start catch_random_number_generator.cpp
+
+namespace Catch {
+
+namespace {
+
+#if defined(_MSC_VER)
+#pragma warning(push)
+#pragma warning(disable:4146) // we negate uint32 during the rotate
+#endif
+        // Safe rotr implementation thanks to John Regehr
+        uint32_t rotate_right(uint32_t val, uint32_t count) {
+            const uint32_t mask = 31;
+            count &= mask;
+            return (val >> count) | (val << (-count & mask));
+        }
+
+#if defined(_MSC_VER)
+#pragma warning(pop)
+#endif
+
+}
+
+    SimplePcg32::SimplePcg32(result_type seed_) {
+        seed(seed_);
+    }
+
+    void SimplePcg32::seed(result_type seed_) {
+        m_state = 0;
+        (*this)();
+        m_state += seed_;
+        (*this)();
+    }
+
+    void SimplePcg32::discard(uint64_t skip) {
+        // We could implement this to run in O(log n) steps, but this
+        // should suffice for our use case.
+        for (uint64_t s = 0; s < skip; ++s) {
+            static_cast<void>((*this)());
+        }
+    }
+
+    SimplePcg32::result_type SimplePcg32::operator()() {
+        // prepare the output value
+        const uint32_t xorshifted = static_cast<uint32_t>(((m_state >> 18u) ^ m_state) >> 27u);
+        const auto output = rotate_right(xorshifted, m_state >> 59u);
+
+        // advance state
+        m_state = m_state * 6364136223846793005ULL + s_inc;
+
+        return output;
+    }
+
+    bool operator==(SimplePcg32 const& lhs, SimplePcg32 const& rhs) {
+        return lhs.m_state == rhs.m_state;
+    }
+
+    bool operator!=(SimplePcg32 const& lhs, SimplePcg32 const& rhs) {
+        return lhs.m_state != rhs.m_state;
+    }
+}
+// end catch_random_number_generator.cpp
+// start catch_registry_hub.cpp
+
+// start catch_test_case_registry_impl.h
+
+#include <vector>
+#include <set>
+#include <algorithm>
+#include <ios>
+
+namespace Catch {
+
+    class TestCase;
+    struct IConfig;
+
+    std::vector<TestCase> sortTests( IConfig const& config, std::vector<TestCase> const& unsortedTestCases );
+
+    bool isThrowSafe( TestCase const& testCase, IConfig const& config );
+    bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config );
+
+    void enforceNoDuplicateTestCases( std::vector<TestCase> const& functions );
+
+    std::vector<TestCase> filterTests( std::vector<TestCase> const& testCases, TestSpec const& testSpec, IConfig const& config );
+    std::vector<TestCase> const& getAllTestCasesSorted( IConfig const& config );
+
+    class TestRegistry : public ITestCaseRegistry {
+    public:
+        virtual ~TestRegistry() = default;
+
+        virtual void registerTest( TestCase const& testCase );
+
+        std::vector<TestCase> const& getAllTests() const override;
+        std::vector<TestCase> const& getAllTestsSorted( IConfig const& config ) const override;
+
+    private:
+        std::vector<TestCase> m_functions;
+        mutable RunTests::InWhatOrder m_currentSortOrder = RunTests::InDeclarationOrder;
+        mutable std::vector<TestCase> m_sortedFunctions;
+        std::size_t m_unnamedCount = 0;
+        std::ios_base::Init m_ostreamInit; // Forces cout/ cerr to be initialised
+    };
+
+    ///////////////////////////////////////////////////////////////////////////
+
+    class TestInvokerAsFunction : public ITestInvoker {
+        void(*m_testAsFunction)();
+    public:
+        TestInvokerAsFunction( void(*testAsFunction)() ) noexcept;
+
+        void invoke() const override;
+    };
+
+    std::string extractClassName( StringRef const& classOrQualifiedMethodName );
+
+    ///////////////////////////////////////////////////////////////////////////
+
+} // end namespace Catch
+
+// end catch_test_case_registry_impl.h
+// start catch_reporter_registry.h
+
+#include <map>
+
+namespace Catch {
+
+    class ReporterRegistry : public IReporterRegistry {
+
+    public:
+
+        ~ReporterRegistry() override;
+
+        IStreamingReporterPtr create( std::string const& name, IConfigPtr const& config ) const override;
+
+        void registerReporter( std::string const& name, IReporterFactoryPtr const& factory );
+        void registerListener( IReporterFactoryPtr const& factory );
+
+        FactoryMap const& getFactories() const override;
+        Listeners const& getListeners() const override;
+
+    private:
+        FactoryMap m_factories;
+        Listeners m_listeners;
+    };
+}
+
+// end catch_reporter_registry.h
+// start catch_tag_alias_registry.h
+
+// start catch_tag_alias.h
+
+#include <string>
+
+namespace Catch {
+
+    struct TagAlias {
+        TagAlias(std::string const& _tag, SourceLineInfo _lineInfo);
+
+        std::string tag;
+        SourceLineInfo lineInfo;
+    };
+
+} // end namespace Catch
+
+// end catch_tag_alias.h
+#include <map>
+
+namespace Catch {
+
+    class TagAliasRegistry : public ITagAliasRegistry {
+    public:
+        ~TagAliasRegistry() override;
+        TagAlias const* find( std::string const& alias ) const override;
+        std::string expandAliases( std::string const& unexpandedTestSpec ) const override;
+        void add( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo );
+
+    private:
+        std::map<std::string, TagAlias> m_registry;
+    };
+
+} // end namespace Catch
+
+// end catch_tag_alias_registry.h
+// start catch_startup_exception_registry.h
+
+#include <vector>
+#include <exception>
+
+namespace Catch {
+
+    class StartupExceptionRegistry {
+#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
+    public:
+        void add(std::exception_ptr const& exception) noexcept;
+        std::vector<std::exception_ptr> const& getExceptions() const noexcept;
+    private:
+        std::vector<std::exception_ptr> m_exceptions;
+#endif
+    };
+
+} // end namespace Catch
+
+// end catch_startup_exception_registry.h
+// start catch_singletons.hpp
+
+namespace Catch {
+
+    struct ISingleton {
+        virtual ~ISingleton();
+    };
+
+    void addSingleton( ISingleton* singleton );
+    void cleanupSingletons();
+
+    template<typename SingletonImplT, typename InterfaceT = SingletonImplT, typename MutableInterfaceT = InterfaceT>
+    class Singleton : SingletonImplT, public ISingleton {
+
+        static auto getInternal() -> Singleton* {
+            static Singleton* s_instance = nullptr;
+            if( !s_instance ) {
+                s_instance = new Singleton;
+                addSingleton( s_instance );
+            }
+            return s_instance;
+        }
+
+    public:
+        static auto get() -> InterfaceT const& {
+            return *getInternal();
+        }
+        static auto getMutable() -> MutableInterfaceT& {
+            return *getInternal();
+        }
+    };
+
+} // namespace Catch
+
+// end catch_singletons.hpp
+namespace Catch {
+
+    namespace {
+
+        class RegistryHub : public IRegistryHub, public IMutableRegistryHub,
+                            private NonCopyable {
+
+        public: // IRegistryHub
+            RegistryHub() = default;
+            IReporterRegistry const& getReporterRegistry() const override {
+                return m_reporterRegistry;
+            }
+            ITestCaseRegistry const& getTestCaseRegistry() const override {
+                return m_testCaseRegistry;
+            }
+            IExceptionTranslatorRegistry const& getExceptionTranslatorRegistry() const override {
+                return m_exceptionTranslatorRegistry;
+            }
+            ITagAliasRegistry const& getTagAliasRegistry() const override {
+                return m_tagAliasRegistry;
+            }
+            StartupExceptionRegistry const& getStartupExceptionRegistry() const override {
+                return m_exceptionRegistry;
+            }
+
+        public: // IMutableRegistryHub
+            void registerReporter( std::string const& name, IReporterFactoryPtr const& factory ) override {
+                m_reporterRegistry.registerReporter( name, factory );
+            }
+            void registerListener( IReporterFactoryPtr const& factory ) override {
+                m_reporterRegistry.registerListener( factory );
+            }
+            void registerTest( TestCase const& testInfo ) override {
+                m_testCaseRegistry.registerTest( testInfo );
+            }
+            void registerTranslator( const IExceptionTranslator* translator ) override {
+                m_exceptionTranslatorRegistry.registerTranslator( translator );
+            }
+            void registerTagAlias( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) override {
+                m_tagAliasRegistry.add( alias, tag, lineInfo );
+            }
+            void registerStartupException() noexcept override {
+#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
+                m_exceptionRegistry.add(std::current_exception());
+#else
+                CATCH_INTERNAL_ERROR("Attempted to register active exception under CATCH_CONFIG_DISABLE_EXCEPTIONS!");
+#endif
+            }
+            IMutableEnumValuesRegistry& getMutableEnumValuesRegistry() override {
+                return m_enumValuesRegistry;
+            }
+
+        private:
+            TestRegistry m_testCaseRegistry;
+            ReporterRegistry m_reporterRegistry;
+            ExceptionTranslatorRegistry m_exceptionTranslatorRegistry;
+            TagAliasRegistry m_tagAliasRegistry;
+            StartupExceptionRegistry m_exceptionRegistry;
+            Detail::EnumValuesRegistry m_enumValuesRegistry;
+        };
+    }
+
+    using RegistryHubSingleton = Singleton<RegistryHub, IRegistryHub, IMutableRegistryHub>;
+
+    IRegistryHub const& getRegistryHub() {
+        return RegistryHubSingleton::get();
+    }
+    IMutableRegistryHub& getMutableRegistryHub() {
+        return RegistryHubSingleton::getMutable();
+    }
+    void cleanUp() {
+        cleanupSingletons();
+        cleanUpContext();
+    }
+    std::string translateActiveException() {
+        return getRegistryHub().getExceptionTranslatorRegistry().translateActiveException();
+    }
+
+} // end namespace Catch
+// end catch_registry_hub.cpp
+// start catch_reporter_registry.cpp
+
+namespace Catch {
+
+    ReporterRegistry::~ReporterRegistry() = default;
+
+    IStreamingReporterPtr ReporterRegistry::create( std::string const& name, IConfigPtr const& config ) const {
+        auto it =  m_factories.find( name );
+        if( it == m_factories.end() )
+            return nullptr;
+        return it->second->create( ReporterConfig( config ) );
+    }
+
+    void ReporterRegistry::registerReporter( std::string const& name, IReporterFactoryPtr const& factory ) {
+        m_factories.emplace(name, factory);
+    }
+    void ReporterRegistry::registerListener( IReporterFactoryPtr const& factory ) {
+        m_listeners.push_back( factory );
+    }
+
+    IReporterRegistry::FactoryMap const& ReporterRegistry::getFactories() const {
+        return m_factories;
+    }
+    IReporterRegistry::Listeners const& ReporterRegistry::getListeners() const {
+        return m_listeners;
+    }
+
+}
+// end catch_reporter_registry.cpp
+// start catch_result_type.cpp
+
+namespace Catch {
+
+    bool isOk( ResultWas::OfType resultType ) {
+        return ( resultType & ResultWas::FailureBit ) == 0;
+    }
+    bool isJustInfo( int flags ) {
+        return flags == ResultWas::Info;
+    }
+
+    ResultDisposition::Flags operator | ( ResultDisposition::Flags lhs, ResultDisposition::Flags rhs ) {
+        return static_cast<ResultDisposition::Flags>( static_cast<int>( lhs ) | static_cast<int>( rhs ) );
+    }
+
+    bool shouldContinueOnFailure( int flags )    { return ( flags & ResultDisposition::ContinueOnFailure ) != 0; }
+    bool shouldSuppressFailure( int flags )      { return ( flags & ResultDisposition::SuppressFail ) != 0; }
+
+} // end namespace Catch
+// end catch_result_type.cpp
+// start catch_run_context.cpp
+
+#include <cassert>
+#include <algorithm>
+#include <sstream>
+
+namespace Catch {
+
+    namespace Generators {
+        struct GeneratorTracker : TestCaseTracking::TrackerBase, IGeneratorTracker {
+            GeneratorBasePtr m_generator;
+
+            GeneratorTracker( TestCaseTracking::NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent )
+            :   TrackerBase( nameAndLocation, ctx, parent )
+            {}
+            ~GeneratorTracker();
+
+            static GeneratorTracker& acquire( TrackerContext& ctx, TestCaseTracking::NameAndLocation const& nameAndLocation ) {
+                std::shared_ptr<GeneratorTracker> tracker;
+
+                ITracker& currentTracker = ctx.currentTracker();
+                // Under specific circumstances, the generator we want
+                // to acquire is also the current tracker. If this is
+                // the case, we have to avoid looking through current
+                // tracker's children, and instead return the current
+                // tracker.
+                // A case where this check is important is e.g.
+                //     for (int i = 0; i < 5; ++i) {
+                //         int n = GENERATE(1, 2);
+                //     }
+                //
+                // without it, the code above creates 5 nested generators.
+                if (currentTracker.nameAndLocation() == nameAndLocation) {
+                    auto thisTracker = currentTracker.parent().findChild(nameAndLocation);
+                    assert(thisTracker);
+                    assert(thisTracker->isGeneratorTracker());
+                    tracker = std::static_pointer_cast<GeneratorTracker>(thisTracker);
+                } else if ( TestCaseTracking::ITrackerPtr childTracker = currentTracker.findChild( nameAndLocation ) ) {
+                    assert( childTracker );
+                    assert( childTracker->isGeneratorTracker() );
+                    tracker = std::static_pointer_cast<GeneratorTracker>( childTracker );
+                } else {
+                    tracker = std::make_shared<GeneratorTracker>( nameAndLocation, ctx, &currentTracker );
+                    currentTracker.addChild( tracker );
+                }
+
+                if( !tracker->isComplete() ) {
+                    tracker->open();
+                }
+
+                return *tracker;
+            }
+
+            // TrackerBase interface
+            bool isGeneratorTracker() const override { return true; }
+            auto hasGenerator() const -> bool override {
+                return !!m_generator;
+            }
+            void close() override {
+                TrackerBase::close();
+                // If a generator has a child (it is followed by a section)
+                // and none of its children have started, then we must wait
+                // until later to start consuming its values.
+                // This catches cases where `GENERATE` is placed between two
+                // `SECTION`s.
+                // **The check for m_children.empty cannot be removed**.
+                // doing so would break `GENERATE` _not_ followed by `SECTION`s.
+                const bool should_wait_for_child = [&]() {
+                    // No children -> nobody to wait for
+                    if ( m_children.empty() ) {
+                        return false;
+                    }
+                    // If at least one child started executing, don't wait
+                    if ( std::find_if(
+                             m_children.begin(),
+                             m_children.end(),
+                             []( TestCaseTracking::ITrackerPtr tracker ) {
+                                 return tracker->hasStarted();
+                             } ) != m_children.end() ) {
+                        return false;
+                    }
+
+                    // No children have started. We need to check if they _can_
+                    // start, and thus we should wait for them, or they cannot
+                    // start (due to filters), and we shouldn't wait for them
+                    auto* parent = m_parent;
+                    // This is safe: there is always at least one section
+                    // tracker in a test case tracking tree
+                    while ( !parent->isSectionTracker() ) {
+                        parent = &( parent->parent() );
+                    }
+                    assert( parent &&
+                            "Missing root (test case) level section" );
+
+                    auto const& parentSection =
+                        static_cast<SectionTracker&>( *parent );
+                    auto const& filters = parentSection.getFilters();
+                    // No filters -> no restrictions on running sections
+                    if ( filters.empty() ) {
+                        return true;
+                    }
+
+                    for ( auto const& child : m_children ) {
+                        if ( child->isSectionTracker() &&
+                             std::find( filters.begin(),
+                                        filters.end(),
+                                        static_cast<SectionTracker&>( *child )
+                                            .trimmedName() ) !=
+                                 filters.end() ) {
+                            return true;
+                        }
+                    }
+                    return false;
+                }();
+
+                // This check is a bit tricky, because m_generator->next()
+                // has a side-effect, where it consumes generator's current
+                // value, but we do not want to invoke the side-effect if
+                // this generator is still waiting for any child to start.
+                if ( should_wait_for_child ||
+                     ( m_runState == CompletedSuccessfully &&
+                       m_generator->next() ) ) {
+                    m_children.clear();
+                    m_runState = Executing;
+                }
+            }
+
+            // IGeneratorTracker interface
+            auto getGenerator() const -> GeneratorBasePtr const& override {
+                return m_generator;
+            }
+            void setGenerator( GeneratorBasePtr&& generator ) override {
+                m_generator = std::move( generator );
+            }
+        };
+        GeneratorTracker::~GeneratorTracker() {}
+    }
+
+    RunContext::RunContext(IConfigPtr const& _config, IStreamingReporterPtr&& reporter)
+    :   m_runInfo(_config->name()),
+        m_context(getCurrentMutableContext()),
+        m_config(_config),
+        m_reporter(std::move(reporter)),
+        m_lastAssertionInfo{ StringRef(), SourceLineInfo("",0), StringRef(), ResultDisposition::Normal },
+        m_includeSuccessfulResults( m_config->includeSuccessfulResults() || m_reporter->getPreferences().shouldReportAllAssertions )
+    {
+        m_context.setRunner(this);
+        m_context.setConfig(m_config);
+        m_context.setResultCapture(this);
+        m_reporter->testRunStarting(m_runInfo);
+    }
+
+    RunContext::~RunContext() {
+        m_reporter->testRunEnded(TestRunStats(m_runInfo, m_totals, aborting()));
+    }
+
+    void RunContext::testGroupStarting(std::string const& testSpec, std::size_t groupIndex, std::size_t groupsCount) {
+        m_reporter->testGroupStarting(GroupInfo(testSpec, groupIndex, groupsCount));
+    }
+
+    void RunContext::testGroupEnded(std::string const& testSpec, Totals const& totals, std::size_t groupIndex, std::size_t groupsCount) {
+        m_reporter->testGroupEnded(TestGroupStats(GroupInfo(testSpec, groupIndex, groupsCount), totals, aborting()));
+    }
+
+    Totals RunContext::runTest(TestCase const& testCase) {
+        Totals prevTotals = m_totals;
+
+        std::string redirectedCout;
+        std::string redirectedCerr;
+
+        auto const& testInfo = testCase.getTestCaseInfo();
+
+        m_reporter->testCaseStarting(testInfo);
+
+        m_activeTestCase = &testCase;
+
+        ITracker& rootTracker = m_trackerContext.startRun();
+        assert(rootTracker.isSectionTracker());
+        static_cast<SectionTracker&>(rootTracker).addInitialFilters(m_config->getSectionsToRun());
+        do {
+            m_trackerContext.startCycle();
+            m_testCaseTracker = &SectionTracker::acquire(m_trackerContext, TestCaseTracking::NameAndLocation(testInfo.name, testInfo.lineInfo));
+            runCurrentTest(redirectedCout, redirectedCerr);
+        } while (!m_testCaseTracker->isSuccessfullyCompleted() && !aborting());
+
+        Totals deltaTotals = m_totals.delta(prevTotals);
+        if (testInfo.expectedToFail() && deltaTotals.testCases.passed > 0) {
+            deltaTotals.assertions.failed++;
+            deltaTotals.testCases.passed--;
+            deltaTotals.testCases.failed++;
+        }
+        m_totals.testCases += deltaTotals.testCases;
+        m_reporter->testCaseEnded(TestCaseStats(testInfo,
+                                  deltaTotals,
+                                  redirectedCout,
+                                  redirectedCerr,
+                                  aborting()));
+
+        m_activeTestCase = nullptr;
+        m_testCaseTracker = nullptr;
+
+        return deltaTotals;
+    }
+
+    IConfigPtr RunContext::config() const {
+        return m_config;
+    }
+
+    IStreamingReporter& RunContext::reporter() const {
+        return *m_reporter;
+    }
+
+    void RunContext::assertionEnded(AssertionResult const & result) {
+        if (result.getResultType() == ResultWas::Ok) {
+            m_totals.assertions.passed++;
+            m_lastAssertionPassed = true;
+        } else if (!result.isOk()) {
+            m_lastAssertionPassed = false;
+            if( m_activeTestCase->getTestCaseInfo().okToFail() )
+                m_totals.assertions.failedButOk++;
+            else
+                m_totals.assertions.failed++;
+        }
+        else {
+            m_lastAssertionPassed = true;
+        }
+
+        // We have no use for the return value (whether messages should be cleared), because messages were made scoped
+        // and should be let to clear themselves out.
+        static_cast<void>(m_reporter->assertionEnded(AssertionStats(result, m_messages, m_totals)));
+
+        if (result.getResultType() != ResultWas::Warning)
+            m_messageScopes.clear();
+
+        // Reset working state
+        resetAssertionInfo();
+        m_lastResult = result;
+    }
+    void RunContext::resetAssertionInfo() {
+        m_lastAssertionInfo.macroName = StringRef();
+        m_lastAssertionInfo.capturedExpression = "{Unknown expression after the reported line}"_sr;
+    }
+
+    bool RunContext::sectionStarted(SectionInfo const & sectionInfo, Counts & assertions) {
+        ITracker& sectionTracker = SectionTracker::acquire(m_trackerContext, TestCaseTracking::NameAndLocation(sectionInfo.name, sectionInfo.lineInfo));
+        if (!sectionTracker.isOpen())
+            return false;
+        m_activeSections.push_back(&sectionTracker);
+
+        m_lastAssertionInfo.lineInfo = sectionInfo.lineInfo;
+
+        m_reporter->sectionStarting(sectionInfo);
+
+        assertions = m_totals.assertions;
+
+        return true;
+    }
+    auto RunContext::acquireGeneratorTracker( StringRef generatorName, SourceLineInfo const& lineInfo ) -> IGeneratorTracker& {
+        using namespace Generators;
+        GeneratorTracker& tracker = GeneratorTracker::acquire(m_trackerContext,
+                                                              TestCaseTracking::NameAndLocation( static_cast<std::string>(generatorName), lineInfo ) );
+        m_lastAssertionInfo.lineInfo = lineInfo;
+        return tracker;
+    }
+
+    bool RunContext::testForMissingAssertions(Counts& assertions) {
+        if (assertions.total() != 0)
+            return false;
+        if (!m_config->warnAboutMissingAssertions())
+            return false;
+        if (m_trackerContext.currentTracker().hasChildren())
+            return false;
+        m_totals.assertions.failed++;
+        assertions.failed++;
+        return true;
+    }
+
+    void RunContext::sectionEnded(SectionEndInfo const & endInfo) {
+        Counts assertions = m_totals.assertions - endInfo.prevAssertions;
+        bool missingAssertions = testForMissingAssertions(assertions);
+
+        if (!m_activeSections.empty()) {
+            m_activeSections.back()->close();
+            m_activeSections.pop_back();
+        }
+
+        m_reporter->sectionEnded(SectionStats(endInfo.sectionInfo, assertions, endInfo.durationInSeconds, missingAssertions));
+        m_messages.clear();
+        m_messageScopes.clear();
+    }
+
+    void RunContext::sectionEndedEarly(SectionEndInfo const & endInfo) {
+        if (m_unfinishedSections.empty())
+            m_activeSections.back()->fail();
+        else
+            m_activeSections.back()->close();
+        m_activeSections.pop_back();
+
+        m_unfinishedSections.push_back(endInfo);
+    }
+
+#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
+    void RunContext::benchmarkPreparing(std::string const& name) {
+        m_reporter->benchmarkPreparing(name);
+    }
+    void RunContext::benchmarkStarting( BenchmarkInfo const& info ) {
+        m_reporter->benchmarkStarting( info );
+    }
+    void RunContext::benchmarkEnded( BenchmarkStats<> const& stats ) {
+        m_reporter->benchmarkEnded( stats );
+    }
+    void RunContext::benchmarkFailed(std::string const & error) {
+        m_reporter->benchmarkFailed(error);
+    }
+#endif // CATCH_CONFIG_ENABLE_BENCHMARKING
+
+    void RunContext::pushScopedMessage(MessageInfo const & message) {
+        m_messages.push_back(message);
+    }
+
+    void RunContext::popScopedMessage(MessageInfo const & message) {
+        m_messages.erase(std::remove(m_messages.begin(), m_messages.end(), message), m_messages.end());
+    }
+
+    void RunContext::emplaceUnscopedMessage( MessageBuilder const& builder ) {
+        m_messageScopes.emplace_back( builder );
+    }
+
+    std::string RunContext::getCurrentTestName() const {
+        return m_activeTestCase
+            ? m_activeTestCase->getTestCaseInfo().name
+            : std::string();
+    }
+
+    const AssertionResult * RunContext::getLastResult() const {
+        return &(*m_lastResult);
+    }
+
+    void RunContext::exceptionEarlyReported() {
+        m_shouldReportUnexpected = false;
+    }
+
+    void RunContext::handleFatalErrorCondition( StringRef message ) {
+        // First notify reporter that bad things happened
+        m_reporter->fatalErrorEncountered(message);
+
+        // Don't rebuild the result -- the stringification itself can cause more fatal errors
+        // Instead, fake a result data.
+        AssertionResultData tempResult( ResultWas::FatalErrorCondition, { false } );
+        tempResult.message = static_cast<std::string>(message);
+        AssertionResult result(m_lastAssertionInfo, tempResult);
+
+        assertionEnded(result);
+
+        handleUnfinishedSections();
+
+        // Recreate section for test case (as we will lose the one that was in scope)
+        auto const& testCaseInfo = m_activeTestCase->getTestCaseInfo();
+        SectionInfo testCaseSection(testCaseInfo.lineInfo, testCaseInfo.name);
+
+        Counts assertions;
+        assertions.failed = 1;
+        SectionStats testCaseSectionStats(testCaseSection, assertions, 0, false);
+        m_reporter->sectionEnded(testCaseSectionStats);
+
+        auto const& testInfo = m_activeTestCase->getTestCaseInfo();
+
+        Totals deltaTotals;
+        deltaTotals.testCases.failed = 1;
+        deltaTotals.assertions.failed = 1;
+        m_reporter->testCaseEnded(TestCaseStats(testInfo,
+                                  deltaTotals,
+                                  std::string(),
+                                  std::string(),
+                                  false));
+        m_totals.testCases.failed++;
+        testGroupEnded(std::string(), m_totals, 1, 1);
+        m_reporter->testRunEnded(TestRunStats(m_runInfo, m_totals, false));
+    }
+
+    bool RunContext::lastAssertionPassed() {
+         return m_lastAssertionPassed;
+    }
+
+    void RunContext::assertionPassed() {
+        m_lastAssertionPassed = true;
+        ++m_totals.assertions.passed;
+        resetAssertionInfo();
+        m_messageScopes.clear();
+    }
+
+    bool RunContext::aborting() const {
+        return m_totals.assertions.failed >= static_cast<std::size_t>(m_config->abortAfter());
+    }
+
+    void RunContext::runCurrentTest(std::string & redirectedCout, std::string & redirectedCerr) {
+        auto const& testCaseInfo = m_activeTestCase->getTestCaseInfo();
+        SectionInfo testCaseSection(testCaseInfo.lineInfo, testCaseInfo.name);
+        m_reporter->sectionStarting(testCaseSection);
+        Counts prevAssertions = m_totals.assertions;
+        double duration = 0;
+        m_shouldReportUnexpected = true;
+        m_lastAssertionInfo = { "TEST_CASE"_sr, testCaseInfo.lineInfo, StringRef(), ResultDisposition::Normal };
+
+        seedRng(*m_config);
+
+        Timer timer;
+        CATCH_TRY {
+            if (m_reporter->getPreferences().shouldRedirectStdOut) {
+#if !defined(CATCH_CONFIG_EXPERIMENTAL_REDIRECT)
+                RedirectedStreams redirectedStreams(redirectedCout, redirectedCerr);
+
+                timer.start();
+                invokeActiveTestCase();
+#else
+                OutputRedirect r(redirectedCout, redirectedCerr);
+                timer.start();
+                invokeActiveTestCase();
+#endif
+            } else {
+                timer.start();
+                invokeActiveTestCase();
+            }
+            duration = timer.getElapsedSeconds();
+        } CATCH_CATCH_ANON (TestFailureException&) {
+            // This just means the test was aborted due to failure
+        } CATCH_CATCH_ALL {
+            // Under CATCH_CONFIG_FAST_COMPILE, unexpected exceptions under REQUIRE assertions
+            // are reported without translation at the point of origin.
+            if( m_shouldReportUnexpected ) {
+                AssertionReaction dummyReaction;
+                handleUnexpectedInflightException( m_lastAssertionInfo, translateActiveException(), dummyReaction );
+            }
+        }
+        Counts assertions = m_totals.assertions - prevAssertions;
+        bool missingAssertions = testForMissingAssertions(assertions);
+
+        m_testCaseTracker->close();
+        handleUnfinishedSections();
+        m_messages.clear();
+        m_messageScopes.clear();
+
+        SectionStats testCaseSectionStats(testCaseSection, assertions, duration, missingAssertions);
+        m_reporter->sectionEnded(testCaseSectionStats);
+    }
+
+    void RunContext::invokeActiveTestCase() {
+        FatalConditionHandlerGuard _(&m_fatalConditionhandler);
+        m_activeTestCase->invoke();
+    }
+
+    void RunContext::handleUnfinishedSections() {
+        // If sections ended prematurely due to an exception we stored their
+        // infos here so we can tear them down outside the unwind process.
+        for (auto it = m_unfinishedSections.rbegin(),
+             itEnd = m_unfinishedSections.rend();
+             it != itEnd;
+             ++it)
+            sectionEnded(*it);
+        m_unfinishedSections.clear();
+    }
+
+    void RunContext::handleExpr(
+        AssertionInfo const& info,
+        ITransientExpression const& expr,
+        AssertionReaction& reaction
+    ) {
+        m_reporter->assertionStarting( info );
+
+        bool negated = isFalseTest( info.resultDisposition );
+        bool result = expr.getResult() != negated;
+
+        if( result ) {
+            if (!m_includeSuccessfulResults) {
+                assertionPassed();
+            }
+            else {
+                reportExpr(info, ResultWas::Ok, &expr, negated);
+            }
+        }
+        else {
+            reportExpr(info, ResultWas::ExpressionFailed, &expr, negated );
+            populateReaction( reaction );
+        }
+    }
+    void RunContext::reportExpr(
+            AssertionInfo const &info,
+            ResultWas::OfType resultType,
+            ITransientExpression const *expr,
+            bool negated ) {
+
+        m_lastAssertionInfo = info;
+        AssertionResultData data( resultType, LazyExpression( negated ) );
+
+        AssertionResult assertionResult{ info, data };
+        assertionResult.m_resultData.lazyExpression.m_transientExpression = expr;
+
+        assertionEnded( assertionResult );
+    }
+
+    void RunContext::handleMessage(
+            AssertionInfo const& info,
+            ResultWas::OfType resultType,
+            StringRef const& message,
+            AssertionReaction& reaction
+    ) {
+        m_reporter->assertionStarting( info );
+
+        m_lastAssertionInfo = info;
+
+        AssertionResultData data( resultType, LazyExpression( false ) );
+        data.message = static_cast<std::string>(message);
+        AssertionResult assertionResult{ m_lastAssertionInfo, data };
+        assertionEnded( assertionResult );
+        if( !assertionResult.isOk() )
+            populateReaction( reaction );
+    }
+    void RunContext::handleUnexpectedExceptionNotThrown(
+            AssertionInfo const& info,
+            AssertionReaction& reaction
+    ) {
+        handleNonExpr(info, Catch::ResultWas::DidntThrowException, reaction);
+    }
+
+    void RunContext::handleUnexpectedInflightException(
+            AssertionInfo const& info,
+            std::string const& message,
+            AssertionReaction& reaction
+    ) {
+        m_lastAssertionInfo = info;
+
+        AssertionResultData data( ResultWas::ThrewException, LazyExpression( false ) );
+        data.message = message;
+        AssertionResult assertionResult{ info, data };
+        assertionEnded( assertionResult );
+        populateReaction( reaction );
+    }
+
+    void RunContext::populateReaction( AssertionReaction& reaction ) {
+        reaction.shouldDebugBreak = m_config->shouldDebugBreak();
+        reaction.shouldThrow = aborting() || (m_lastAssertionInfo.resultDisposition & ResultDisposition::Normal);
+    }
+
+    void RunContext::handleIncomplete(
+            AssertionInfo const& info
+    ) {
+        m_lastAssertionInfo = info;
+
+        AssertionResultData data( ResultWas::ThrewException, LazyExpression( false ) );
+        data.message = "Exception translation was disabled by CATCH_CONFIG_FAST_COMPILE";
+        AssertionResult assertionResult{ info, data };
+        assertionEnded( assertionResult );
+    }
+    void RunContext::handleNonExpr(
+            AssertionInfo const &info,
+            ResultWas::OfType resultType,
+            AssertionReaction &reaction
+    ) {
+        m_lastAssertionInfo = info;
+
+        AssertionResultData data( resultType, LazyExpression( false ) );
+        AssertionResult assertionResult{ info, data };
+        assertionEnded( assertionResult );
+
+        if( !assertionResult.isOk() )
+            populateReaction( reaction );
+    }
+
+    IResultCapture& getResultCapture() {
+        if (auto* capture = getCurrentContext().getResultCapture())
+            return *capture;
+        else
+            CATCH_INTERNAL_ERROR("No result capture instance");
+    }
+
+    void seedRng(IConfig const& config) {
+        if (config.rngSeed() != 0) {
+            std::srand(config.rngSeed());
+            rng().seed(config.rngSeed());
+        }
+    }
+
+    unsigned int rngSeed() {
+        return getCurrentContext().getConfig()->rngSeed();
+    }
+
+}
+// end catch_run_context.cpp
+// start catch_section.cpp
+
+namespace Catch {
+
+    Section::Section( SectionInfo const& info )
+    :   m_info( info ),
+        m_sectionIncluded( getResultCapture().sectionStarted( m_info, m_assertions ) )
+    {
+        m_timer.start();
+    }
+
+    Section::~Section() {
+        if( m_sectionIncluded ) {
+            SectionEndInfo endInfo{ m_info, m_assertions, m_timer.getElapsedSeconds() };
+            if( uncaught_exceptions() )
+                getResultCapture().sectionEndedEarly( endInfo );
+            else
+                getResultCapture().sectionEnded( endInfo );
+        }
+    }
+
+    // This indicates whether the section should be executed or not
+    Section::operator bool() const {
+        return m_sectionIncluded;
+    }
+
+} // end namespace Catch
+// end catch_section.cpp
+// start catch_section_info.cpp
+
+namespace Catch {
+
+    SectionInfo::SectionInfo
+        (   SourceLineInfo const& _lineInfo,
+            std::string const& _name )
+    :   name( _name ),
+        lineInfo( _lineInfo )
+    {}
+
+} // end namespace Catch
+// end catch_section_info.cpp
+// start catch_session.cpp
+
+// start catch_session.h
+
+#include <memory>
+
+namespace Catch {
+
+    class Session : NonCopyable {
+    public:
+
+        Session();
+        ~Session() override;
+
+        void showHelp() const;
+        void libIdentify();
+
+        int applyCommandLine( int argc, char const * const * argv );
+    #if defined(CATCH_CONFIG_WCHAR) && defined(_WIN32) && defined(UNICODE)
+        int applyCommandLine( int argc, wchar_t const * const * argv );
+    #endif
+
+        void useConfigData( ConfigData const& configData );
+
+        template<typename CharT>
+        int run(int argc, CharT const * const argv[]) {
+            if (m_startupExceptions)
+                return 1;
+            int returnCode = applyCommandLine(argc, argv);
+            if (returnCode == 0)
+                returnCode = run();
+            return returnCode;
+        }
+
+        int run();
+
+        clara::Parser const& cli() const;
+        void cli( clara::Parser const& newParser );
+        ConfigData& configData();
+        Config& config();
+    private:
+        int runInternal();
+
+        clara::Parser m_cli;
+        ConfigData m_configData;
+        std::shared_ptr<Config> m_config;
+        bool m_startupExceptions = false;
+    };
+
+} // end namespace Catch
+
+// end catch_session.h
+// start catch_version.h
+
+#include <iosfwd>
+
+namespace Catch {
+
+    // Versioning information
+    struct Version {
+        Version( Version const& ) = delete;
+        Version& operator=( Version const& ) = delete;
+        Version(    unsigned int _majorVersion,
+                    unsigned int _minorVersion,
+                    unsigned int _patchNumber,
+                    char const * const _branchName,
+                    unsigned int _buildNumber );
+
+        unsigned int const majorVersion;
+        unsigned int const minorVersion;
+        unsigned int const patchNumber;
+
+        // buildNumber is only used if branchName is not null
+        char const * const branchName;
+        unsigned int const buildNumber;
+
+        friend std::ostream& operator << ( std::ostream& os, Version const& version );
+    };
+
+    Version const& libraryVersion();
+}
+
+// end catch_version.h
+#include <cstdlib>
+#include <iomanip>
+#include <set>
+#include <iterator>
+
+namespace Catch {
+
+    namespace {
+        const int MaxExitCode = 255;
+
+        IStreamingReporterPtr createReporter(std::string const& reporterName, IConfigPtr const& config) {
+            auto reporter = Catch::getRegistryHub().getReporterRegistry().create(reporterName, config);
+            CATCH_ENFORCE(reporter, "No reporter registered with name: '" << reporterName << "'");
+
+            return reporter;
+        }
+
+        IStreamingReporterPtr makeReporter(std::shared_ptr<Config> const& config) {
+            if (Catch::getRegistryHub().getReporterRegistry().getListeners().empty()) {
+                return createReporter(config->getReporterName(), config);
+            }
+
+            // On older platforms, returning std::unique_ptr<ListeningReporter>
+            // when the return type is std::unique_ptr<IStreamingReporter>
+            // doesn't compile without a std::move call. However, this causes
+            // a warning on newer platforms. Thus, we have to work around
+            // it a bit and downcast the pointer manually.
+            auto ret = std::unique_ptr<IStreamingReporter>(new ListeningReporter);
+            auto& multi = static_cast<ListeningReporter&>(*ret);
+            auto const& listeners = Catch::getRegistryHub().getReporterRegistry().getListeners();
+            for (auto const& listener : listeners) {
+                multi.addListener(listener->create(Catch::ReporterConfig(config)));
+            }
+            multi.addReporter(createReporter(config->getReporterName(), config));
+            return ret;
+        }
+
+        class TestGroup {
+        public:
+            explicit TestGroup(std::shared_ptr<Config> const& config)
+            : m_config{config}
+            , m_context{config, makeReporter(config)}
+            {
+                auto const& allTestCases = getAllTestCasesSorted(*m_config);
+                m_matches = m_config->testSpec().matchesByFilter(allTestCases, *m_config);
+                auto const& invalidArgs = m_config->testSpec().getInvalidArgs();
+
+                if (m_matches.empty() && invalidArgs.empty()) {
+                    for (auto const& test : allTestCases)
+                        if (!test.isHidden())
+                            m_tests.emplace(&test);
+                } else {
+                    for (auto const& match : m_matches)
+                        m_tests.insert(match.tests.begin(), match.tests.end());
+                }
+            }
+
+            Totals execute() {
+                auto const& invalidArgs = m_config->testSpec().getInvalidArgs();
+                Totals totals;
+                m_context.testGroupStarting(m_config->name(), 1, 1);
+                for (auto const& testCase : m_tests) {
+                    if (!m_context.aborting())
+                        totals += m_context.runTest(*testCase);
+                    else
+                        m_context.reporter().skipTest(*testCase);
+                }
+
+                for (auto const& match : m_matches) {
+                    if (match.tests.empty()) {
+                        m_context.reporter().noMatchingTestCases(match.name);
+                        totals.error = -1;
+                    }
+                }
+
+                if (!invalidArgs.empty()) {
+                    for (auto const& invalidArg: invalidArgs)
+                         m_context.reporter().reportInvalidArguments(invalidArg);
+                }
+
+                m_context.testGroupEnded(m_config->name(), totals, 1, 1);
+                return totals;
+            }
+
+        private:
+            using Tests = std::set<TestCase const*>;
+
+            std::shared_ptr<Config> m_config;
+            RunContext m_context;
+            Tests m_tests;
+            TestSpec::Matches m_matches;
+        };
+
+        void applyFilenamesAsTags(Catch::IConfig const& config) {
+            auto& tests = const_cast<std::vector<TestCase>&>(getAllTestCasesSorted(config));
+            for (auto& testCase : tests) {
+                auto tags = testCase.tags;
+
+                std::string filename = testCase.lineInfo.file;
+                auto lastSlash = filename.find_last_of("\\/");
+                if (lastSlash != std::string::npos) {
+                    filename.erase(0, lastSlash);
+                    filename[0] = '#';
+                }
+
+                auto lastDot = filename.find_last_of('.');
+                if (lastDot != std::string::npos) {
+                    filename.erase(lastDot);
+                }
+
+                tags.push_back(std::move(filename));
+                setTags(testCase, tags);
+            }
+        }
+
+    } // anon namespace
+
+    Session::Session() {
+        static bool alreadyInstantiated = false;
+        if( alreadyInstantiated ) {
+            CATCH_TRY { CATCH_INTERNAL_ERROR( "Only one instance of Catch::Session can ever be used" ); }
+            CATCH_CATCH_ALL { getMutableRegistryHub().registerStartupException(); }
+        }
+
+        // There cannot be exceptions at startup in no-exception mode.
+#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
+        const auto& exceptions = getRegistryHub().getStartupExceptionRegistry().getExceptions();
+        if ( !exceptions.empty() ) {
+            config();
+            getCurrentMutableContext().setConfig(m_config);
+
+            m_startupExceptions = true;
+            Colour colourGuard( Colour::Red );
+            Catch::cerr() << "Errors occurred during startup!" << '\n';
+            // iterate over all exceptions and notify user
+            for ( const auto& ex_ptr : exceptions ) {
+                try {
+                    std::rethrow_exception(ex_ptr);
+                } catch ( std::exception const& ex ) {
+                    Catch::cerr() << Column( ex.what() ).indent(2) << '\n';
+                }
+            }
+        }
+#endif
+
+        alreadyInstantiated = true;
+        m_cli = makeCommandLineParser( m_configData );
+    }
+    Session::~Session() {
+        Catch::cleanUp();
+    }
+
+    void Session::showHelp() const {
+        Catch::cout()
+                << "\nCatch v" << libraryVersion() << "\n"
+                << m_cli << std::endl
+                << "For more detailed usage please see the project docs\n" << std::endl;
+    }
+    void Session::libIdentify() {
+        Catch::cout()
+                << std::left << std::setw(16) << "description: " << "A Catch2 test executable\n"
+                << std::left << std::setw(16) << "category: " << "testframework\n"
+                << std::left << std::setw(16) << "framework: " << "Catch Test\n"
+                << std::left << std::setw(16) << "version: " << libraryVersion() << std::endl;
+    }
+
+    int Session::applyCommandLine( int argc, char const * const * argv ) {
+        if( m_startupExceptions )
+            return 1;
+
+        auto result = m_cli.parse( clara::Args( argc, argv ) );
+        if( !result ) {
+            config();
+            getCurrentMutableContext().setConfig(m_config);
+            Catch::cerr()
+                << Colour( Colour::Red )
+                << "\nError(s) in input:\n"
+                << Column( result.errorMessage() ).indent( 2 )
+                << "\n\n";
+            Catch::cerr() << "Run with -? for usage\n" << std::endl;
+            return MaxExitCode;
+        }
+
+        if( m_configData.showHelp )
+            showHelp();
+        if( m_configData.libIdentify )
+            libIdentify();
+        m_config.reset();
+        return 0;
+    }
+
+#if defined(CATCH_CONFIG_WCHAR) && defined(_WIN32) && defined(UNICODE)
+    int Session::applyCommandLine( int argc, wchar_t const * const * argv ) {
+
+        char **utf8Argv = new char *[ argc ];
+
+        for ( int i = 0; i < argc; ++i ) {
+            int bufSize = WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, nullptr, 0, nullptr, nullptr );
+
+            utf8Argv[ i ] = new char[ bufSize ];
+
+            WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, utf8Argv[i], bufSize, nullptr, nullptr );
+        }
+
+        int returnCode = applyCommandLine( argc, utf8Argv );
+
+        for ( int i = 0; i < argc; ++i )
+            delete [] utf8Argv[ i ];
+
+        delete [] utf8Argv;
+
+        return returnCode;
+    }
+#endif
+
+    void Session::useConfigData( ConfigData const& configData ) {
+        m_configData = configData;
+        m_config.reset();
+    }
+
+    int Session::run() {
+        if( ( m_configData.waitForKeypress & WaitForKeypress::BeforeStart ) != 0 ) {
+            Catch::cout() << "...waiting for enter/ return before starting" << std::endl;
+            static_cast<void>(std::getchar());
+        }
+        int exitCode = runInternal();
+        if( ( m_configData.waitForKeypress & WaitForKeypress::BeforeExit ) != 0 ) {
+            Catch::cout() << "...waiting for enter/ return before exiting, with code: " << exitCode << std::endl;
+            static_cast<void>(std::getchar());
+        }
+        return exitCode;
+    }
+
+    clara::Parser const& Session::cli() const {
+        return m_cli;
+    }
+    void Session::cli( clara::Parser const& newParser ) {
+        m_cli = newParser;
+    }
+    ConfigData& Session::configData() {
+        return m_configData;
+    }
+    Config& Session::config() {
+        if( !m_config )
+            m_config = std::make_shared<Config>( m_configData );
+        return *m_config;
+    }
+
+    int Session::runInternal() {
+        if( m_startupExceptions )
+            return 1;
+
+        if (m_configData.showHelp || m_configData.libIdentify) {
+            return 0;
+        }
+
+        CATCH_TRY {
+            config(); // Force config to be constructed
+
+            seedRng( *m_config );
+
+            if( m_configData.filenamesAsTags )
+                applyFilenamesAsTags( *m_config );
+
+            // Handle list request
+            if( Option<std::size_t> listed = list( m_config ) )
+                return static_cast<int>( *listed );
+
+            TestGroup tests { m_config };
+            auto const totals = tests.execute();
+
+            if( m_config->warnAboutNoTests() && totals.error == -1 )
+                return 2;
+
+            // Note that on unices only the lower 8 bits are usually used, clamping
+            // the return value to 255 prevents false negative when some multiple
+            // of 256 tests has failed
+            return (std::min) (MaxExitCode, (std::max) (totals.error, static_cast<int>(totals.assertions.failed)));
+        }
+#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
+        catch( std::exception& ex ) {
+            Catch::cerr() << ex.what() << std::endl;
+            return MaxExitCode;
+        }
+#endif
+    }
+
+} // end namespace Catch
+// end catch_session.cpp
+// start catch_singletons.cpp
+
+#include <vector>
+
+namespace Catch {
+
+    namespace {
+        static auto getSingletons() -> std::vector<ISingleton*>*& {
+            static std::vector<ISingleton*>* g_singletons = nullptr;
+            if( !g_singletons )
+                g_singletons = new std::vector<ISingleton*>();
+            return g_singletons;
+        }
+    }
+
+    ISingleton::~ISingleton() {}
+
+    void addSingleton(ISingleton* singleton ) {
+        getSingletons()->push_back( singleton );
+    }
+    void cleanupSingletons() {
+        auto& singletons = getSingletons();
+        for( auto singleton : *singletons )
+            delete singleton;
+        delete singletons;
+        singletons = nullptr;
+    }
+
+} // namespace Catch
+// end catch_singletons.cpp
+// start catch_startup_exception_registry.cpp
+
+#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
+namespace Catch {
+void StartupExceptionRegistry::add( std::exception_ptr const& exception ) noexcept {
+        CATCH_TRY {
+            m_exceptions.push_back(exception);
+        } CATCH_CATCH_ALL {
+            // If we run out of memory during start-up there's really not a lot more we can do about it
+            std::terminate();
+        }
+    }
+
+    std::vector<std::exception_ptr> const& StartupExceptionRegistry::getExceptions() const noexcept {
+        return m_exceptions;
+    }
+
+} // end namespace Catch
+#endif
+// end catch_startup_exception_registry.cpp
+// start catch_stream.cpp
+
+#include <cstdio>
+#include <iostream>
+#include <fstream>
+#include <sstream>
+#include <vector>
+#include <memory>
+
+namespace Catch {
+
+    Catch::IStream::~IStream() = default;
+
+    namespace Detail { namespace {
+        template<typename WriterF, std::size_t bufferSize=256>
+        class StreamBufImpl : public std::streambuf {
+            char data[bufferSize];
+            WriterF m_writer;
+
+        public:
+            StreamBufImpl() {
+                setp( data, data + sizeof(data) );
+            }
+
+            ~StreamBufImpl() noexcept {
+                StreamBufImpl::sync();
+            }
+
+        private:
+            int overflow( int c ) override {
+                sync();
+
+                if( c != EOF ) {
+                    if( pbase() == epptr() )
+                        m_writer( std::string( 1, static_cast<char>( c ) ) );
+                    else
+                        sputc( static_cast<char>( c ) );
+                }
+                return 0;
+            }
+
+            int sync() override {
+                if( pbase() != pptr() ) {
+                    m_writer( std::string( pbase(), static_cast<std::string::size_type>( pptr() - pbase() ) ) );
+                    setp( pbase(), epptr() );
+                }
+                return 0;
+            }
+        };
+
+        ///////////////////////////////////////////////////////////////////////////
+
+        struct OutputDebugWriter {
+
+            void operator()( std::string const&str ) {
+                writeToDebugConsole( str );
+            }
+        };
+
+        ///////////////////////////////////////////////////////////////////////////
+
+        class FileStream : public IStream {
+            mutable std::ofstream m_ofs;
+        public:
+            FileStream( StringRef filename ) {
+                m_ofs.open( filename.c_str() );
+                CATCH_ENFORCE( !m_ofs.fail(), "Unable to open file: '" << filename << "'" );
+            }
+            ~FileStream() override = default;
+        public: // IStream
+            std::ostream& stream() const override {
+                return m_ofs;
+            }
+        };
+
+        ///////////////////////////////////////////////////////////////////////////
+
+        class CoutStream : public IStream {
+            mutable std::ostream m_os;
+        public:
+            // Store the streambuf from cout up-front because
+            // cout may get redirected when running tests
+            CoutStream() : m_os( Catch::cout().rdbuf() ) {}
+            ~CoutStream() override = default;
+
+        public: // IStream
+            std::ostream& stream() const override { return m_os; }
+        };
+
+        ///////////////////////////////////////////////////////////////////////////
+
+        class DebugOutStream : public IStream {
+            std::unique_ptr<StreamBufImpl<OutputDebugWriter>> m_streamBuf;
+            mutable std::ostream m_os;
+        public:
+            DebugOutStream()
+            :   m_streamBuf( new StreamBufImpl<OutputDebugWriter>() ),
+                m_os( m_streamBuf.get() )
+            {}
+
+            ~DebugOutStream() override = default;
+
+        public: // IStream
+            std::ostream& stream() const override { return m_os; }
+        };
+
+    }} // namespace anon::detail
+
+    ///////////////////////////////////////////////////////////////////////////
+
+    auto makeStream( StringRef const &filename ) -> IStream const* {
+        if( filename.empty() )
+            return new Detail::CoutStream();
+        else if( filename[0] == '%' ) {
+            if( filename == "%debug" )
+                return new Detail::DebugOutStream();
+            else
+                CATCH_ERROR( "Unrecognised stream: '" << filename << "'" );
+        }
+        else
+            return new Detail::FileStream( filename );
+    }
+
+    // This class encapsulates the idea of a pool of ostringstreams that can be reused.
+    struct StringStreams {
+        std::vector<std::unique_ptr<std::ostringstream>> m_streams;
+        std::vector<std::size_t> m_unused;
+        std::ostringstream m_referenceStream; // Used for copy state/ flags from
+
+        auto add() -> std::size_t {
+            if( m_unused.empty() ) {
+                m_streams.push_back( std::unique_ptr<std::ostringstream>( new std::ostringstream ) );
+                return m_streams.size()-1;
+            }
+            else {
+                auto index = m_unused.back();
+                m_unused.pop_back();
+                return index;
+            }
+        }
+
+        void release( std::size_t index ) {
+            m_streams[index]->copyfmt( m_referenceStream ); // Restore initial flags and other state
+            m_unused.push_back(index);
+        }
+    };
+
+    ReusableStringStream::ReusableStringStream()
+    :   m_index( Singleton<StringStreams>::getMutable().add() ),
+        m_oss( Singleton<StringStreams>::getMutable().m_streams[m_index].get() )
+    {}
+
+    ReusableStringStream::~ReusableStringStream() {
+        static_cast<std::ostringstream*>( m_oss )->str("");
+        m_oss->clear();
+        Singleton<StringStreams>::getMutable().release( m_index );
+    }
+
+    auto ReusableStringStream::str() const -> std::string {
+        return static_cast<std::ostringstream*>( m_oss )->str();
+    }
+
+    ///////////////////////////////////////////////////////////////////////////
+
+#ifndef CATCH_CONFIG_NOSTDOUT // If you #define this you must implement these functions
+    std::ostream& cout() { return std::cout; }
+    std::ostream& cerr() { return std::cerr; }
+    std::ostream& clog() { return std::clog; }
+#endif
+}
+// end catch_stream.cpp
+// start catch_string_manip.cpp
+
+#include <algorithm>
+#include <ostream>
+#include <cstring>
+#include <cctype>
+#include <vector>
+
+namespace Catch {
+
+    namespace {
+        char toLowerCh(char c) {
+            return static_cast<char>( std::tolower( static_cast<unsigned char>(c) ) );
+        }
+    }
+
+    bool startsWith( std::string const& s, std::string const& prefix ) {
+        return s.size() >= prefix.size() && std::equal(prefix.begin(), prefix.end(), s.begin());
+    }
+    bool startsWith( std::string const& s, char prefix ) {
+        return !s.empty() && s[0] == prefix;
+    }
+    bool endsWith( std::string const& s, std::string const& suffix ) {
+        return s.size() >= suffix.size() && std::equal(suffix.rbegin(), suffix.rend(), s.rbegin());
+    }
+    bool endsWith( std::string const& s, char suffix ) {
+        return !s.empty() && s[s.size()-1] == suffix;
+    }
+    bool contains( std::string const& s, std::string const& infix ) {
+        return s.find( infix ) != std::string::npos;
+    }
+    void toLowerInPlace( std::string& s ) {
+        std::transform( s.begin(), s.end(), s.begin(), toLowerCh );
+    }
+    std::string toLower( std::string const& s ) {
+        std::string lc = s;
+        toLowerInPlace( lc );
+        return lc;
+    }
+    std::string trim( std::string const& str ) {
+        static char const* whitespaceChars = "\n\r\t ";
+        std::string::size_type start = str.find_first_not_of( whitespaceChars );
+        std::string::size_type end = str.find_last_not_of( whitespaceChars );
+
+        return start != std::string::npos ? str.substr( start, 1+end-start ) : std::string();
+    }
+
+    StringRef trim(StringRef ref) {
+        const auto is_ws = [](char c) {
+            return c == ' ' || c == '\t' || c == '\n' || c == '\r';
+        };
+        size_t real_begin = 0;
+        while (real_begin < ref.size() && is_ws(ref[real_begin])) { ++real_begin; }
+        size_t real_end = ref.size();
+        while (real_end > real_begin && is_ws(ref[real_end - 1])) { --real_end; }
+
+        return ref.substr(real_begin, real_end - real_begin);
+    }
+
+    bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ) {
+        bool replaced = false;
+        std::size_t i = str.find( replaceThis );
+        while( i != std::string::npos ) {
+            replaced = true;
+            str = str.substr( 0, i ) + withThis + str.substr( i+replaceThis.size() );
+            if( i < str.size()-withThis.size() )
+                i = str.find( replaceThis, i+withThis.size() );
+            else
+                i = std::string::npos;
+        }
+        return replaced;
+    }
+
+    std::vector<StringRef> splitStringRef( StringRef str, char delimiter ) {
+        std::vector<StringRef> subStrings;
+        std::size_t start = 0;
+        for(std::size_t pos = 0; pos < str.size(); ++pos ) {
+            if( str[pos] == delimiter ) {
+                if( pos - start > 1 )
+                    subStrings.push_back( str.substr( start, pos-start ) );
+                start = pos+1;
+            }
+        }
+        if( start < str.size() )
+            subStrings.push_back( str.substr( start, str.size()-start ) );
+        return subStrings;
+    }
+
+    pluralise::pluralise( std::size_t count, std::string const& label )
+    :   m_count( count ),
+        m_label( label )
+    {}
+
+    std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ) {
+        os << pluraliser.m_count << ' ' << pluraliser.m_label;
+        if( pluraliser.m_count != 1 )
+            os << 's';
+        return os;
+    }
+
+}
+// end catch_string_manip.cpp
+// start catch_stringref.cpp
+
+#include <algorithm>
+#include <ostream>
+#include <cstring>
+#include <cstdint>
+
+namespace Catch {
+    StringRef::StringRef( char const* rawChars ) noexcept
+    : StringRef( rawChars, static_cast<StringRef::size_type>(std::strlen(rawChars) ) )
+    {}
+
+    auto StringRef::c_str() const -> char const* {
+        CATCH_ENFORCE(isNullTerminated(), "Called StringRef::c_str() on a non-null-terminated instance");
+        return m_start;
+    }
+    auto StringRef::data() const noexcept -> char const* {
+        return m_start;
+    }
+
+    auto StringRef::substr( size_type start, size_type size ) const noexcept -> StringRef {
+        if (start < m_size) {
+            return StringRef(m_start + start, (std::min)(m_size - start, size));
+        } else {
+            return StringRef();
+        }
+    }
+    auto StringRef::operator == ( StringRef const& other ) const noexcept -> bool {
+        return m_size == other.m_size
+            && (std::memcmp( m_start, other.m_start, m_size ) == 0);
+    }
+
+    auto operator << ( std::ostream& os, StringRef const& str ) -> std::ostream& {
+        return os.write(str.data(), str.size());
+    }
+
+    auto operator+=( std::string& lhs, StringRef const& rhs ) -> std::string& {
+        lhs.append(rhs.data(), rhs.size());
+        return lhs;
+    }
+
+} // namespace Catch
+// end catch_stringref.cpp
+// start catch_tag_alias.cpp
+
+namespace Catch {
+    TagAlias::TagAlias(std::string const & _tag, SourceLineInfo _lineInfo): tag(_tag), lineInfo(_lineInfo) {}
+}
+// end catch_tag_alias.cpp
+// start catch_tag_alias_autoregistrar.cpp
+
+namespace Catch {
+
+    RegistrarForTagAliases::RegistrarForTagAliases(char const* alias, char const* tag, SourceLineInfo const& lineInfo) {
+        CATCH_TRY {
+            getMutableRegistryHub().registerTagAlias(alias, tag, lineInfo);
+        } CATCH_CATCH_ALL {
+            // Do not throw when constructing global objects, instead register the exception to be processed later
+            getMutableRegistryHub().registerStartupException();
+        }
+    }
+
+}
+// end catch_tag_alias_autoregistrar.cpp
+// start catch_tag_alias_registry.cpp
+
+#include <sstream>
+
+namespace Catch {
+
+    TagAliasRegistry::~TagAliasRegistry() {}
+
+    TagAlias const* TagAliasRegistry::find( std::string const& alias ) const {
+        auto it = m_registry.find( alias );
+        if( it != m_registry.end() )
+            return &(it->second);
+        else
+            return nullptr;
+    }
+
+    std::string TagAliasRegistry::expandAliases( std::string const& unexpandedTestSpec ) const {
+        std::string expandedTestSpec = unexpandedTestSpec;
+        for( auto const& registryKvp : m_registry ) {
+            std::size_t pos = expandedTestSpec.find( registryKvp.first );
+            if( pos != std::string::npos ) {
+                expandedTestSpec =  expandedTestSpec.substr( 0, pos ) +
+                                    registryKvp.second.tag +
+                                    expandedTestSpec.substr( pos + registryKvp.first.size() );
+            }
+        }
+        return expandedTestSpec;
+    }
+
+    void TagAliasRegistry::add( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) {
+        CATCH_ENFORCE( startsWith(alias, "[@") && endsWith(alias, ']'),
+                      "error: tag alias, '" << alias << "' is not of the form [@alias name].\n" << lineInfo );
+
+        CATCH_ENFORCE( m_registry.insert(std::make_pair(alias, TagAlias(tag, lineInfo))).second,
+                      "error: tag alias, '" << alias << "' already registered.\n"
+                      << "\tFirst seen at: " << find(alias)->lineInfo << "\n"
+                      << "\tRedefined at: " << lineInfo );
+    }
+
+    ITagAliasRegistry::~ITagAliasRegistry() {}
+
+    ITagAliasRegistry const& ITagAliasRegistry::get() {
+        return getRegistryHub().getTagAliasRegistry();
+    }
+
+} // end namespace Catch
+// end catch_tag_alias_registry.cpp
+// start catch_test_case_info.cpp
+
+#include <cctype>
+#include <exception>
+#include <algorithm>
+#include <sstream>
+
+namespace Catch {
+
+    namespace {
+        TestCaseInfo::SpecialProperties parseSpecialTag( std::string const& tag ) {
+            if( startsWith( tag, '.' ) ||
+                tag == "!hide" )
+                return TestCaseInfo::IsHidden;
+            else if( tag == "!throws" )
+                return TestCaseInfo::Throws;
+            else if( tag == "!shouldfail" )
+                return TestCaseInfo::ShouldFail;
+            else if( tag == "!mayfail" )
+                return TestCaseInfo::MayFail;
+            else if( tag == "!nonportable" )
+                return TestCaseInfo::NonPortable;
+            else if( tag == "!benchmark" )
+                return static_cast<TestCaseInfo::SpecialProperties>( TestCaseInfo::Benchmark | TestCaseInfo::IsHidden );
+            else
+                return TestCaseInfo::None;
+        }
+        bool isReservedTag( std::string const& tag ) {
+            return parseSpecialTag( tag ) == TestCaseInfo::None && tag.size() > 0 && !std::isalnum( static_cast<unsigned char>(tag[0]) );
+        }
+        void enforceNotReservedTag( std::string const& tag, SourceLineInfo const& _lineInfo ) {
+            CATCH_ENFORCE( !isReservedTag(tag),
+                          "Tag name: [" << tag << "] is not allowed.\n"
+                          << "Tag names starting with non alphanumeric characters are reserved\n"
+                          << _lineInfo );
+        }
+    }
+
+    TestCase makeTestCase(  ITestInvoker* _testCase,
+                            std::string const& _className,
+                            NameAndTags const& nameAndTags,
+                            SourceLineInfo const& _lineInfo )
+    {
+        bool isHidden = false;
+
+        // Parse out tags
+        std::vector<std::string> tags;
+        std::string desc, tag;
+        bool inTag = false;
+        for (char c : nameAndTags.tags) {
+            if( !inTag ) {
+                if( c == '[' )
+                    inTag = true;
+                else
+                    desc += c;
+            }
+            else {
+                if( c == ']' ) {
+                    TestCaseInfo::SpecialProperties prop = parseSpecialTag( tag );
+                    if( ( prop & TestCaseInfo::IsHidden ) != 0 )
+                        isHidden = true;
+                    else if( prop == TestCaseInfo::None )
+                        enforceNotReservedTag( tag, _lineInfo );
+
+                    // Merged hide tags like `[.approvals]` should be added as
+                    // `[.][approvals]`. The `[.]` is added at later point, so
+                    // we only strip the prefix
+                    if (startsWith(tag, '.') && tag.size() > 1) {
+                        tag.erase(0, 1);
+                    }
+                    tags.push_back( tag );
+                    tag.clear();
+                    inTag = false;
+                }
+                else
+                    tag += c;
+            }
+        }
+        if( isHidden ) {
+            // Add all "hidden" tags to make them behave identically
+            tags.insert( tags.end(), { ".", "!hide" } );
+        }
+
+        TestCaseInfo info( static_cast<std::string>(nameAndTags.name), _className, desc, tags, _lineInfo );
+        return TestCase( _testCase, std::move(info) );
+    }
+
+    void setTags( TestCaseInfo& testCaseInfo, std::vector<std::string> tags ) {
+        std::sort(begin(tags), end(tags));
+        tags.erase(std::unique(begin(tags), end(tags)), end(tags));
+        testCaseInfo.lcaseTags.clear();
+
+        for( auto const& tag : tags ) {
+            std::string lcaseTag = toLower( tag );
+            testCaseInfo.properties = static_cast<TestCaseInfo::SpecialProperties>( testCaseInfo.properties | parseSpecialTag( lcaseTag ) );
+            testCaseInfo.lcaseTags.push_back( lcaseTag );
+        }
+        testCaseInfo.tags = std::move(tags);
+    }
+
+    TestCaseInfo::TestCaseInfo( std::string const& _name,
+                                std::string const& _className,
+                                std::string const& _description,
+                                std::vector<std::string> const& _tags,
+                                SourceLineInfo const& _lineInfo )
+    :   name( _name ),
+        className( _className ),
+        description( _description ),
+        lineInfo( _lineInfo ),
+        properties( None )
+    {
+        setTags( *this, _tags );
+    }
+
+    bool TestCaseInfo::isHidden() const {
+        return ( properties & IsHidden ) != 0;
+    }
+    bool TestCaseInfo::throws() const {
+        return ( properties & Throws ) != 0;
+    }
+    bool TestCaseInfo::okToFail() const {
+        return ( properties & (ShouldFail | MayFail ) ) != 0;
+    }
+    bool TestCaseInfo::expectedToFail() const {
+        return ( properties & (ShouldFail ) ) != 0;
+    }
+
+    std::string TestCaseInfo::tagsAsString() const {
+        std::string ret;
+        // '[' and ']' per tag
+        std::size_t full_size = 2 * tags.size();
+        for (const auto& tag : tags) {
+            full_size += tag.size();
+        }
+        ret.reserve(full_size);
+        for (const auto& tag : tags) {
+            ret.push_back('[');
+            ret.append(tag);
+            ret.push_back(']');
+        }
+
+        return ret;
+    }
+
+    TestCase::TestCase( ITestInvoker* testCase, TestCaseInfo&& info ) : TestCaseInfo( std::move(info) ), test( testCase ) {}
+
+    TestCase TestCase::withName( std::string const& _newName ) const {
+        TestCase other( *this );
+        other.name = _newName;
+        return other;
+    }
+
+    void TestCase::invoke() const {
+        test->invoke();
+    }
+
+    bool TestCase::operator == ( TestCase const& other ) const {
+        return  test.get() == other.test.get() &&
+                name == other.name &&
+                className == other.className;
+    }
+
+    bool TestCase::operator < ( TestCase const& other ) const {
+        return name < other.name;
+    }
+
+    TestCaseInfo const& TestCase::getTestCaseInfo() const
+    {
+        return *this;
+    }
+
+} // end namespace Catch
+// end catch_test_case_info.cpp
+// start catch_test_case_registry_impl.cpp
+
+#include <algorithm>
+#include <sstream>
+
+namespace Catch {
+
+    namespace {
+        struct TestHasher {
+            using hash_t = uint64_t;
+
+            explicit TestHasher( hash_t hashSuffix ):
+                m_hashSuffix{ hashSuffix } {}
+
+            uint32_t operator()( TestCase const& t ) const {
+                // FNV-1a hash with multiplication fold.
+                const hash_t prime = 1099511628211u;
+                hash_t hash = 14695981039346656037u;
+                for ( const char c : t.name ) {
+                    hash ^= c;
+                    hash *= prime;
+                }
+                hash ^= m_hashSuffix;
+                hash *= prime;
+                const uint32_t low{ static_cast<uint32_t>( hash ) };
+                const uint32_t high{ static_cast<uint32_t>( hash >> 32 ) };
+                return low * high;
+            }
+
+        private:
+            hash_t m_hashSuffix;
+        };
+    } // end unnamed namespace
+
+    std::vector<TestCase> sortTests( IConfig const& config, std::vector<TestCase> const& unsortedTestCases ) {
+        switch( config.runOrder() ) {
+            case RunTests::InDeclarationOrder:
+                // already in declaration order
+                break;
+
+            case RunTests::InLexicographicalOrder: {
+                std::vector<TestCase> sorted = unsortedTestCases;
+                std::sort( sorted.begin(), sorted.end() );
+                return sorted;
+            }
+
+            case RunTests::InRandomOrder: {
+                seedRng( config );
+                TestHasher h{ config.rngSeed() };
+
+                using hashedTest = std::pair<TestHasher::hash_t, TestCase const*>;
+                std::vector<hashedTest> indexed_tests;
+                indexed_tests.reserve( unsortedTestCases.size() );
+
+                for (auto const& testCase : unsortedTestCases) {
+                    indexed_tests.emplace_back(h(testCase), &testCase);
+                }
+
+                std::sort(indexed_tests.begin(), indexed_tests.end(),
+                          [](hashedTest const& lhs, hashedTest const& rhs) {
+                          if (lhs.first == rhs.first) {
+                              return lhs.second->name < rhs.second->name;
+                          }
+                          return lhs.first < rhs.first;
+                });
+
+                std::vector<TestCase> sorted;
+                sorted.reserve( indexed_tests.size() );
+
+                for (auto const& hashed : indexed_tests) {
+                    sorted.emplace_back(*hashed.second);
+                }
+
+                return sorted;
+            }
+        }
+        return unsortedTestCases;
+    }
+
+    bool isThrowSafe( TestCase const& testCase, IConfig const& config ) {
+        return !testCase.throws() || config.allowThrows();
+    }
+
+    bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ) {
+        return testSpec.matches( testCase ) && isThrowSafe( testCase, config );
+    }
+
+    void enforceNoDuplicateTestCases( std::vector<TestCase> const& functions ) {
+        std::set<TestCase> seenFunctions;
+        for( auto const& function : functions ) {
+            auto prev = seenFunctions.insert( function );
+            CATCH_ENFORCE( prev.second,
+                    "error: TEST_CASE( \"" << function.name << "\" ) already defined.\n"
+                    << "\tFirst seen at " << prev.first->getTestCaseInfo().lineInfo << "\n"
+                    << "\tRedefined at " << function.getTestCaseInfo().lineInfo );
+        }
+    }
+
+    std::vector<TestCase> filterTests( std::vector<TestCase> const& testCases, TestSpec const& testSpec, IConfig const& config ) {
+        std::vector<TestCase> filtered;
+        filtered.reserve( testCases.size() );
+        for (auto const& testCase : testCases) {
+            if ((!testSpec.hasFilters() && !testCase.isHidden()) ||
+                (testSpec.hasFilters() && matchTest(testCase, testSpec, config))) {
+                filtered.push_back(testCase);
+            }
+        }
+        return filtered;
+    }
+    std::vector<TestCase> const& getAllTestCasesSorted( IConfig const& config ) {
+        return getRegistryHub().getTestCaseRegistry().getAllTestsSorted( config );
+    }
+
+    void TestRegistry::registerTest( TestCase const& testCase ) {
+        std::string name = testCase.getTestCaseInfo().name;
+        if( name.empty() ) {
+            ReusableStringStream rss;
+            rss << "Anonymous test case " << ++m_unnamedCount;
+            return registerTest( testCase.withName( rss.str() ) );
+        }
+        m_functions.push_back( testCase );
+    }
+
+    std::vector<TestCase> const& TestRegistry::getAllTests() const {
+        return m_functions;
+    }
+    std::vector<TestCase> const& TestRegistry::getAllTestsSorted( IConfig const& config ) const {
+        if( m_sortedFunctions.empty() )
+            enforceNoDuplicateTestCases( m_functions );
+
+        if(  m_currentSortOrder != config.runOrder() || m_sortedFunctions.empty() ) {
+            m_sortedFunctions = sortTests( config, m_functions );
+            m_currentSortOrder = config.runOrder();
+        }
+        return m_sortedFunctions;
+    }
+
+    ///////////////////////////////////////////////////////////////////////////
+    TestInvokerAsFunction::TestInvokerAsFunction( void(*testAsFunction)() ) noexcept : m_testAsFunction( testAsFunction ) {}
+
+    void TestInvokerAsFunction::invoke() const {
+        m_testAsFunction();
+    }
+
+    std::string extractClassName( StringRef const& classOrQualifiedMethodName ) {
+        std::string className(classOrQualifiedMethodName);
+        if( startsWith( className, '&' ) )
+        {
+            std::size_t lastColons = className.rfind( "::" );
+            std::size_t penultimateColons = className.rfind( "::", lastColons-1 );
+            if( penultimateColons == std::string::npos )
+                penultimateColons = 1;
+            className = className.substr( penultimateColons, lastColons-penultimateColons );
+        }
+        return className;
+    }
+
+} // end namespace Catch
+// end catch_test_case_registry_impl.cpp
+// start catch_test_case_tracker.cpp
+
+#include <algorithm>
+#include <cassert>
+#include <stdexcept>
+#include <memory>
+#include <sstream>
+
+#if defined(__clang__)
+#    pragma clang diagnostic push
+#    pragma clang diagnostic ignored "-Wexit-time-destructors"
+#endif
+
+namespace Catch {
+namespace TestCaseTracking {
+
+    NameAndLocation::NameAndLocation( std::string const& _name, SourceLineInfo const& _location )
+    :   name( _name ),
+        location( _location )
+    {}
+
+    ITracker::~ITracker() = default;
+
+    ITracker& TrackerContext::startRun() {
+        m_rootTracker = std::make_shared<SectionTracker>( NameAndLocation( "{root}", CATCH_INTERNAL_LINEINFO ), *this, nullptr );
+        m_currentTracker = nullptr;
+        m_runState = Executing;
+        return *m_rootTracker;
+    }
+
+    void TrackerContext::endRun() {
+        m_rootTracker.reset();
+        m_currentTracker = nullptr;
+        m_runState = NotStarted;
+    }
+
+    void TrackerContext::startCycle() {
+        m_currentTracker = m_rootTracker.get();
+        m_runState = Executing;
+    }
+    void TrackerContext::completeCycle() {
+        m_runState = CompletedCycle;
+    }
+
+    bool TrackerContext::completedCycle() const {
+        return m_runState == CompletedCycle;
+    }
+    ITracker& TrackerContext::currentTracker() {
+        return *m_currentTracker;
+    }
+    void TrackerContext::setCurrentTracker( ITracker* tracker ) {
+        m_currentTracker = tracker;
+    }
+
+    TrackerBase::TrackerBase( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ):
+        ITracker(nameAndLocation),
+        m_ctx( ctx ),
+        m_parent( parent )
+    {}
+
+    bool TrackerBase::isComplete() const {
+        return m_runState == CompletedSuccessfully || m_runState == Failed;
+    }
+    bool TrackerBase::isSuccessfullyCompleted() const {
+        return m_runState == CompletedSuccessfully;
+    }
+    bool TrackerBase::isOpen() const {
+        return m_runState != NotStarted && !isComplete();
+    }
+    bool TrackerBase::hasChildren() const {
+        return !m_children.empty();
+    }
+
+    void TrackerBase::addChild( ITrackerPtr const& child ) {
+        m_children.push_back( child );
+    }
+
+    ITrackerPtr TrackerBase::findChild( NameAndLocation const& nameAndLocation ) {
+        auto it = std::find_if( m_children.begin(), m_children.end(),
+            [&nameAndLocation]( ITrackerPtr const& tracker ){
+                return
+                    tracker->nameAndLocation().location == nameAndLocation.location &&
+                    tracker->nameAndLocation().name == nameAndLocation.name;
+            } );
+        return( it != m_children.end() )
+            ? *it
+            : nullptr;
+    }
+    ITracker& TrackerBase::parent() {
+        assert( m_parent ); // Should always be non-null except for root
+        return *m_parent;
+    }
+
+    void TrackerBase::openChild() {
+        if( m_runState != ExecutingChildren ) {
+            m_runState = ExecutingChildren;
+            if( m_parent )
+                m_parent->openChild();
+        }
+    }
+
+    bool TrackerBase::isSectionTracker() const { return false; }
+    bool TrackerBase::isGeneratorTracker() const { return false; }
+
+    void TrackerBase::open() {
+        m_runState = Executing;
+        moveToThis();
+        if( m_parent )
+            m_parent->openChild();
+    }
+
+    void TrackerBase::close() {
+
+        // Close any still open children (e.g. generators)
+        while( &m_ctx.currentTracker() != this )
+            m_ctx.currentTracker().close();
+
+        switch( m_runState ) {
+            case NeedsAnotherRun:
+                break;
+
+            case Executing:
+                m_runState = CompletedSuccessfully;
+                break;
+            case ExecutingChildren:
+                if( std::all_of(m_children.begin(), m_children.end(), [](ITrackerPtr const& t){ return t->isComplete(); }) )
+                    m_runState = CompletedSuccessfully;
+                break;
+
+            case NotStarted:
+            case CompletedSuccessfully:
+            case Failed:
+                CATCH_INTERNAL_ERROR( "Illogical state: " << m_runState );
+
+            default:
+                CATCH_INTERNAL_ERROR( "Unknown state: " << m_runState );
+        }
+        moveToParent();
+        m_ctx.completeCycle();
+    }
+    void TrackerBase::fail() {
+        m_runState = Failed;
+        if( m_parent )
+            m_parent->markAsNeedingAnotherRun();
+        moveToParent();
+        m_ctx.completeCycle();
+    }
+    void TrackerBase::markAsNeedingAnotherRun() {
+        m_runState = NeedsAnotherRun;
+    }
+
+    void TrackerBase::moveToParent() {
+        assert( m_parent );
+        m_ctx.setCurrentTracker( m_parent );
+    }
+    void TrackerBase::moveToThis() {
+        m_ctx.setCurrentTracker( this );
+    }
+
+    SectionTracker::SectionTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent )
+    :   TrackerBase( nameAndLocation, ctx, parent ),
+        m_trimmed_name(trim(nameAndLocation.name))
+    {
+        if( parent ) {
+            while( !parent->isSectionTracker() )
+                parent = &parent->parent();
+
+            SectionTracker& parentSection = static_cast<SectionTracker&>( *parent );
+            addNextFilters( parentSection.m_filters );
+        }
+    }
+
+    bool SectionTracker::isComplete() const {
+        bool complete = true;
+
+        if (m_filters.empty()
+            || m_filters[0] == ""
+            || std::find(m_filters.begin(), m_filters.end(), m_trimmed_name) != m_filters.end()) {
+            complete = TrackerBase::isComplete();
+        }
+        return complete;
+    }
+
+    bool SectionTracker::isSectionTracker() const { return true; }
+
+    SectionTracker& SectionTracker::acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation ) {
+        std::shared_ptr<SectionTracker> section;
+
+        ITracker& currentTracker = ctx.currentTracker();
+        if( ITrackerPtr childTracker = currentTracker.findChild( nameAndLocation ) ) {
+            assert( childTracker );
+            assert( childTracker->isSectionTracker() );
+            section = std::static_pointer_cast<SectionTracker>( childTracker );
+        }
+        else {
+            section = std::make_shared<SectionTracker>( nameAndLocation, ctx, &currentTracker );
+            currentTracker.addChild( section );
+        }
+        if( !ctx.completedCycle() )
+            section->tryOpen();
+        return *section;
+    }
+
+    void SectionTracker::tryOpen() {
+        if( !isComplete() )
+            open();
+    }
+
+    void SectionTracker::addInitialFilters( std::vector<std::string> const& filters ) {
+        if( !filters.empty() ) {
+            m_filters.reserve( m_filters.size() + filters.size() + 2 );
+            m_filters.emplace_back(""); // Root - should never be consulted
+            m_filters.emplace_back(""); // Test Case - not a section filter
+            m_filters.insert( m_filters.end(), filters.begin(), filters.end() );
+        }
+    }
+    void SectionTracker::addNextFilters( std::vector<std::string> const& filters ) {
+        if( filters.size() > 1 )
+            m_filters.insert( m_filters.end(), filters.begin()+1, filters.end() );
+    }
+
+    std::vector<std::string> const& SectionTracker::getFilters() const {
+        return m_filters;
+    }
+
+    std::string const& SectionTracker::trimmedName() const {
+        return m_trimmed_name;
+    }
+
+} // namespace TestCaseTracking
+
+using TestCaseTracking::ITracker;
+using TestCaseTracking::TrackerContext;
+using TestCaseTracking::SectionTracker;
+
+} // namespace Catch
+
+#if defined(__clang__)
+#    pragma clang diagnostic pop
+#endif
+// end catch_test_case_tracker.cpp
+// start catch_test_registry.cpp
+
+namespace Catch {
+
+    auto makeTestInvoker( void(*testAsFunction)() ) noexcept -> ITestInvoker* {
+        return new(std::nothrow) TestInvokerAsFunction( testAsFunction );
+    }
+
+    NameAndTags::NameAndTags( StringRef const& name_ , StringRef const& tags_ ) noexcept : name( name_ ), tags( tags_ ) {}
+
+    AutoReg::AutoReg( ITestInvoker* invoker, SourceLineInfo const& lineInfo, StringRef const& classOrMethod, NameAndTags const& nameAndTags ) noexcept {
+        CATCH_TRY {
+            getMutableRegistryHub()
+                    .registerTest(
+                        makeTestCase(
+                            invoker,
+                            extractClassName( classOrMethod ),
+                            nameAndTags,
+                            lineInfo));
+        } CATCH_CATCH_ALL {
+            // Do not throw when constructing global objects, instead register the exception to be processed later
+            getMutableRegistryHub().registerStartupException();
+        }
+    }
+
+    AutoReg::~AutoReg() = default;
+}
+// end catch_test_registry.cpp
+// start catch_test_spec.cpp
+
+#include <algorithm>
+#include <string>
+#include <vector>
+#include <memory>
+
+namespace Catch {
+
+    TestSpec::Pattern::Pattern( std::string const& name )
+    : m_name( name )
+    {}
+
+    TestSpec::Pattern::~Pattern() = default;
+
+    std::string const& TestSpec::Pattern::name() const {
+        return m_name;
+    }
+
+    TestSpec::NamePattern::NamePattern( std::string const& name, std::string const& filterString )
+    : Pattern( filterString )
+    , m_wildcardPattern( toLower( name ), CaseSensitive::No )
+    {}
+
+    bool TestSpec::NamePattern::matches( TestCaseInfo const& testCase ) const {
+        return m_wildcardPattern.matches( testCase.name );
+    }
+
+    TestSpec::TagPattern::TagPattern( std::string const& tag, std::string const& filterString )
+    : Pattern( filterString )
+    , m_tag( toLower( tag ) )
+    {}
+
+    bool TestSpec::TagPattern::matches( TestCaseInfo const& testCase ) const {
+        return std::find(begin(testCase.lcaseTags),
+                         end(testCase.lcaseTags),
+                         m_tag) != end(testCase.lcaseTags);
+    }
+
+    TestSpec::ExcludedPattern::ExcludedPattern( PatternPtr const& underlyingPattern )
+    : Pattern( underlyingPattern->name() )
+    , m_underlyingPattern( underlyingPattern )
+    {}
+
+    bool TestSpec::ExcludedPattern::matches( TestCaseInfo const& testCase ) const {
+        return !m_underlyingPattern->matches( testCase );
+    }
+
+    bool TestSpec::Filter::matches( TestCaseInfo const& testCase ) const {
+        return std::all_of( m_patterns.begin(), m_patterns.end(), [&]( PatternPtr const& p ){ return p->matches( testCase ); } );
+    }
+
+    std::string TestSpec::Filter::name() const {
+        std::string name;
+        for( auto const& p : m_patterns )
+            name += p->name();
+        return name;
+    }
+
+    bool TestSpec::hasFilters() const {
+        return !m_filters.empty();
+    }
+
+    bool TestSpec::matches( TestCaseInfo const& testCase ) const {
+        return std::any_of( m_filters.begin(), m_filters.end(), [&]( Filter const& f ){ return f.matches( testCase ); } );
+    }
+
+    TestSpec::Matches TestSpec::matchesByFilter( std::vector<TestCase> const& testCases, IConfig const& config ) const
+    {
+        Matches matches( m_filters.size() );
+        std::transform( m_filters.begin(), m_filters.end(), matches.begin(), [&]( Filter const& filter ){
+            std::vector<TestCase const*> currentMatches;
+            for( auto const& test : testCases )
+                if( isThrowSafe( test, config ) && filter.matches( test ) )
+                    currentMatches.emplace_back( &test );
+            return FilterMatch{ filter.name(), currentMatches };
+        } );
+        return matches;
+    }
+
+    const TestSpec::vectorStrings& TestSpec::getInvalidArgs() const{
+        return  (m_invalidArgs);
+    }
+
+}
+// end catch_test_spec.cpp
+// start catch_test_spec_parser.cpp
+
+namespace Catch {
+
+    TestSpecParser::TestSpecParser( ITagAliasRegistry const& tagAliases ) : m_tagAliases( &tagAliases ) {}
+
+    TestSpecParser& TestSpecParser::parse( std::string const& arg ) {
+        m_mode = None;
+        m_exclusion = false;
+        m_arg = m_tagAliases->expandAliases( arg );
+        m_escapeChars.clear();
+        m_substring.reserve(m_arg.size());
+        m_patternName.reserve(m_arg.size());
+        m_realPatternPos = 0;
+
+        for( m_pos = 0; m_pos < m_arg.size(); ++m_pos )
+          //if visitChar fails
+           if( !visitChar( m_arg[m_pos] ) ){
+               m_testSpec.m_invalidArgs.push_back(arg);
+               break;
+           }
+        endMode();
+        return *this;
+    }
+    TestSpec TestSpecParser::testSpec() {
+        addFilter();
+        return m_testSpec;
+    }
+    bool TestSpecParser::visitChar( char c ) {
+        if( (m_mode != EscapedName) && (c == '\\') ) {
+            escape();
+            addCharToPattern(c);
+            return true;
+        }else if((m_mode != EscapedName) && (c == ',') )  {
+            return separate();
+        }
+
+        switch( m_mode ) {
+        case None:
+            if( processNoneChar( c ) )
+                return true;
+            break;
+        case Name:
+            processNameChar( c );
+            break;
+        case EscapedName:
+            endMode();
+            addCharToPattern(c);
+            return true;
+        default:
+        case Tag:
+        case QuotedName:
+            if( processOtherChar( c ) )
+                return true;
+            break;
+        }
+
+        m_substring += c;
+        if( !isControlChar( c ) ) {
+            m_patternName += c;
+            m_realPatternPos++;
+        }
+        return true;
+    }
+    // Two of the processing methods return true to signal the caller to return
+    // without adding the given character to the current pattern strings
+    bool TestSpecParser::processNoneChar( char c ) {
+        switch( c ) {
+        case ' ':
+            return true;
+        case '~':
+            m_exclusion = true;
+            return false;
+        case '[':
+            startNewMode( Tag );
+            return false;
+        case '"':
+            startNewMode( QuotedName );
+            return false;
+        default:
+            startNewMode( Name );
+            return false;
+        }
+    }
+    void TestSpecParser::processNameChar( char c ) {
+        if( c == '[' ) {
+            if( m_substring == "exclude:" )
+                m_exclusion = true;
+            else
+                endMode();
+            startNewMode( Tag );
+        }
+    }
+    bool TestSpecParser::processOtherChar( char c ) {
+        if( !isControlChar( c ) )
+            return false;
+        m_substring += c;
+        endMode();
+        return true;
+    }
+    void TestSpecParser::startNewMode( Mode mode ) {
+        m_mode = mode;
+    }
+    void TestSpecParser::endMode() {
+        switch( m_mode ) {
+        case Name:
+        case QuotedName:
+            return addNamePattern();
+        case Tag:
+            return addTagPattern();
+        case EscapedName:
+            revertBackToLastMode();
+            return;
+        case None:
+        default:
+            return startNewMode( None );
+        }
+    }
+    void TestSpecParser::escape() {
+        saveLastMode();
+        m_mode = EscapedName;
+        m_escapeChars.push_back(m_realPatternPos);
+    }
+    bool TestSpecParser::isControlChar( char c ) const {
+        switch( m_mode ) {
+            default:
+                return false;
+            case None:
+                return c == '~';
+            case Name:
+                return c == '[';
+            case EscapedName:
+                return true;
+            case QuotedName:
+                return c == '"';
+            case Tag:
+                return c == '[' || c == ']';
+        }
+    }
+
+    void TestSpecParser::addFilter() {
+        if( !m_currentFilter.m_patterns.empty() ) {
+            m_testSpec.m_filters.push_back( m_currentFilter );
+            m_currentFilter = TestSpec::Filter();
+        }
+    }
+
+    void TestSpecParser::saveLastMode() {
+      lastMode = m_mode;
+    }
+
+    void TestSpecParser::revertBackToLastMode() {
+      m_mode = lastMode;
+    }
+
+    bool TestSpecParser::separate() {
+      if( (m_mode==QuotedName) || (m_mode==Tag) ){
+         //invalid argument, signal failure to previous scope.
+         m_mode = None;
+         m_pos = m_arg.size();
+         m_substring.clear();
+         m_patternName.clear();
+         m_realPatternPos = 0;
+         return false;
+      }
+      endMode();
+      addFilter();
+      return true; //success
+    }
+
+    std::string TestSpecParser::preprocessPattern() {
+        std::string token = m_patternName;
+        for (std::size_t i = 0; i < m_escapeChars.size(); ++i)
+            token = token.substr(0, m_escapeChars[i] - i) + token.substr(m_escapeChars[i] - i + 1);
+        m_escapeChars.clear();
+        if (startsWith(token, "exclude:")) {
+            m_exclusion = true;
+            token = token.substr(8);
+        }
+
+        m_patternName.clear();
+        m_realPatternPos = 0;
+
+        return token;
+    }
+
+    void TestSpecParser::addNamePattern() {
+        auto token = preprocessPattern();
+
+        if (!token.empty()) {
+            TestSpec::PatternPtr pattern = std::make_shared<TestSpec::NamePattern>(token, m_substring);
+            if (m_exclusion)
+                pattern = std::make_shared<TestSpec::ExcludedPattern>(pattern);
+            m_currentFilter.m_patterns.push_back(pattern);
+        }
+        m_substring.clear();
+        m_exclusion = false;
+        m_mode = None;
+    }
+
+    void TestSpecParser::addTagPattern() {
+        auto token = preprocessPattern();
+
+        if (!token.empty()) {
+            // If the tag pattern is the "hide and tag" shorthand (e.g. [.foo])
+            // we have to create a separate hide tag and shorten the real one
+            if (token.size() > 1 && token[0] == '.') {
+                token.erase(token.begin());
+                TestSpec::PatternPtr pattern = std::make_shared<TestSpec::TagPattern>(".", m_substring);
+                if (m_exclusion) {
+                    pattern = std::make_shared<TestSpec::ExcludedPattern>(pattern);
+                }
+                m_currentFilter.m_patterns.push_back(pattern);
+            }
+
+            TestSpec::PatternPtr pattern = std::make_shared<TestSpec::TagPattern>(token, m_substring);
+
+            if (m_exclusion) {
+                pattern = std::make_shared<TestSpec::ExcludedPattern>(pattern);
+            }
+            m_currentFilter.m_patterns.push_back(pattern);
+        }
+        m_substring.clear();
+        m_exclusion = false;
+        m_mode = None;
+    }
+
+    TestSpec parseTestSpec( std::string const& arg ) {
+        return TestSpecParser( ITagAliasRegistry::get() ).parse( arg ).testSpec();
+    }
+
+} // namespace Catch
+// end catch_test_spec_parser.cpp
+// start catch_timer.cpp
+
+#include <chrono>
+
+static const uint64_t nanosecondsInSecond = 1000000000;
+
+namespace Catch {
+
+    auto getCurrentNanosecondsSinceEpoch() -> uint64_t {
+        return std::chrono::duration_cast<std::chrono::nanoseconds>( std::chrono::high_resolution_clock::now().time_since_epoch() ).count();
+    }
+
+    namespace {
+        auto estimateClockResolution() -> uint64_t {
+            uint64_t sum = 0;
+            static const uint64_t iterations = 1000000;
+
+            auto startTime = getCurrentNanosecondsSinceEpoch();
+
+            for( std::size_t i = 0; i < iterations; ++i ) {
+
+                uint64_t ticks;
+                uint64_t baseTicks = getCurrentNanosecondsSinceEpoch();
+                do {
+                    ticks = getCurrentNanosecondsSinceEpoch();
+                } while( ticks == baseTicks );
+
+                auto delta = ticks - baseTicks;
+                sum += delta;
+
+                // If we have been calibrating for over 3 seconds -- the clock
+                // is terrible and we should move on.
+                // TBD: How to signal that the measured resolution is probably wrong?
+                if (ticks > startTime + 3 * nanosecondsInSecond) {
+                    return sum / ( i + 1u );
+                }
+            }
+
+            // We're just taking the mean, here. To do better we could take the std. dev and exclude outliers
+            // - and potentially do more iterations if there's a high variance.
+            return sum/iterations;
+        }
+    }
+    auto getEstimatedClockResolution() -> uint64_t {
+        static auto s_resolution = estimateClockResolution();
+        return s_resolution;
+    }
+
+    void Timer::start() {
+       m_nanoseconds = getCurrentNanosecondsSinceEpoch();
+    }
+    auto Timer::getElapsedNanoseconds() const -> uint64_t {
+        return getCurrentNanosecondsSinceEpoch() - m_nanoseconds;
+    }
+    auto Timer::getElapsedMicroseconds() const -> uint64_t {
+        return getElapsedNanoseconds()/1000;
+    }
+    auto Timer::getElapsedMilliseconds() const -> unsigned int {
+        return static_cast<unsigned int>(getElapsedMicroseconds()/1000);
+    }
+    auto Timer::getElapsedSeconds() const -> double {
+        return getElapsedMicroseconds()/1000000.0;
+    }
+
+} // namespace Catch
+// end catch_timer.cpp
+// start catch_tostring.cpp
+
+#if defined(__clang__)
+#    pragma clang diagnostic push
+#    pragma clang diagnostic ignored "-Wexit-time-destructors"
+#    pragma clang diagnostic ignored "-Wglobal-constructors"
+#endif
+
+// Enable specific decls locally
+#if !defined(CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER)
+#define CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER
+#endif
+
+#include <cmath>
+#include <iomanip>
+
+namespace Catch {
+
+namespace Detail {
+
+    const std::string unprintableString = "{?}";
+
+    namespace {
+        const int hexThreshold = 255;
+
+        struct Endianness {
+            enum Arch { Big, Little };
+
+            static Arch which() {
+                int one = 1;
+                // If the lowest byte we read is non-zero, we can assume
+                // that little endian format is used.
+                auto value = *reinterpret_cast<char*>(&one);
+                return value ? Little : Big;
+            }
+        };
+    }
+
+    std::string rawMemoryToString( const void *object, std::size_t size ) {
+        // Reverse order for little endian architectures
+        int i = 0, end = static_cast<int>( size ), inc = 1;
+        if( Endianness::which() == Endianness::Little ) {
+            i = end-1;
+            end = inc = -1;
+        }
+
+        unsigned char const *bytes = static_cast<unsigned char const *>(object);
+        ReusableStringStream rss;
+        rss << "0x" << std::setfill('0') << std::hex;
+        for( ; i != end; i += inc )
+             rss << std::setw(2) << static_cast<unsigned>(bytes[i]);
+       return rss.str();
+    }
+}
+
+template<typename T>
+std::string fpToString( T value, int precision ) {
+    if (Catch::isnan(value)) {
+        return "nan";
+    }
+
+    ReusableStringStream rss;
+    rss << std::setprecision( precision )
+        << std::fixed
+        << value;
+    std::string d = rss.str();
+    std::size_t i = d.find_last_not_of( '0' );
+    if( i != std::string::npos && i != d.size()-1 ) {
+        if( d[i] == '.' )
+            i++;
+        d = d.substr( 0, i+1 );
+    }
+    return d;
+}
+
+//// ======================================================= ////
+//
+//   Out-of-line defs for full specialization of StringMaker
+//
+//// ======================================================= ////
+
+std::string StringMaker<std::string>::convert(const std::string& str) {
+    if (!getCurrentContext().getConfig()->showInvisibles()) {
+        return '"' + str + '"';
+    }
+
+    std::string s("\"");
+    for (char c : str) {
+        switch (c) {
+        case '\n':
+            s.append("\\n");
+            break;
+        case '\t':
+            s.append("\\t");
+            break;
+        default:
+            s.push_back(c);
+            break;
+        }
+    }
+    s.append("\"");
+    return s;
+}
+
+#ifdef CATCH_CONFIG_CPP17_STRING_VIEW
+std::string StringMaker<std::string_view>::convert(std::string_view str) {
+    return ::Catch::Detail::stringify(std::string{ str });
+}
+#endif
+
+std::string StringMaker<char const*>::convert(char const* str) {
+    if (str) {
+        return ::Catch::Detail::stringify(std::string{ str });
+    } else {
+        return{ "{null string}" };
+    }
+}
+std::string StringMaker<char*>::convert(char* str) {
+    if (str) {
+        return ::Catch::Detail::stringify(std::string{ str });
+    } else {
+        return{ "{null string}" };
+    }
+}
+
+#ifdef CATCH_CONFIG_WCHAR
+std::string StringMaker<std::wstring>::convert(const std::wstring& wstr) {
+    std::string s;
+    s.reserve(wstr.size());
+    for (auto c : wstr) {
+        s += (c <= 0xff) ? static_cast<char>(c) : '?';
+    }
+    return ::Catch::Detail::stringify(s);
+}
+
+# ifdef CATCH_CONFIG_CPP17_STRING_VIEW
+std::string StringMaker<std::wstring_view>::convert(std::wstring_view str) {
+    return StringMaker<std::wstring>::convert(std::wstring(str));
+}
+# endif
+
+std::string StringMaker<wchar_t const*>::convert(wchar_t const * str) {
+    if (str) {
+        return ::Catch::Detail::stringify(std::wstring{ str });
+    } else {
+        return{ "{null string}" };
+    }
+}
+std::string StringMaker<wchar_t *>::convert(wchar_t * str) {
+    if (str) {
+        return ::Catch::Detail::stringify(std::wstring{ str });
+    } else {
+        return{ "{null string}" };
+    }
+}
+#endif
+
+#if defined(CATCH_CONFIG_CPP17_BYTE)
+#include <cstddef>
+std::string StringMaker<std::byte>::convert(std::byte value) {
+    return ::Catch::Detail::stringify(std::to_integer<unsigned long long>(value));
+}
+#endif // defined(CATCH_CONFIG_CPP17_BYTE)
+
+std::string StringMaker<int>::convert(int value) {
+    return ::Catch::Detail::stringify(static_cast<long long>(value));
+}
+std::string StringMaker<long>::convert(long value) {
+    return ::Catch::Detail::stringify(static_cast<long long>(value));
+}
+std::string StringMaker<long long>::convert(long long value) {
+    ReusableStringStream rss;
+    rss << value;
+    if (value > Detail::hexThreshold) {
+        rss << " (0x" << std::hex << value << ')';
+    }
+    return rss.str();
+}
+
+std::string StringMaker<unsigned int>::convert(unsigned int value) {
+    return ::Catch::Detail::stringify(static_cast<unsigned long long>(value));
+}
+std::string StringMaker<unsigned long>::convert(unsigned long value) {
+    return ::Catch::Detail::stringify(static_cast<unsigned long long>(value));
+}
+std::string StringMaker<unsigned long long>::convert(unsigned long long value) {
+    ReusableStringStream rss;
+    rss << value;
+    if (value > Detail::hexThreshold) {
+        rss << " (0x" << std::hex << value << ')';
+    }
+    return rss.str();
+}
+
+std::string StringMaker<bool>::convert(bool b) {
+    return b ? "true" : "false";
+}
+
+std::string StringMaker<signed char>::convert(signed char value) {
+    if (value == '\r') {
+        return "'\\r'";
+    } else if (value == '\f') {
+        return "'\\f'";
+    } else if (value == '\n') {
+        return "'\\n'";
+    } else if (value == '\t') {
+        return "'\\t'";
+    } else if ('\0' <= value && value < ' ') {
+        return ::Catch::Detail::stringify(static_cast<unsigned int>(value));
+    } else {
+        char chstr[] = "' '";
+        chstr[1] = value;
+        return chstr;
+    }
+}
+std::string StringMaker<char>::convert(char c) {
+    return ::Catch::Detail::stringify(static_cast<signed char>(c));
+}
+std::string StringMaker<unsigned char>::convert(unsigned char c) {
+    return ::Catch::Detail::stringify(static_cast<char>(c));
+}
+
+std::string StringMaker<std::nullptr_t>::convert(std::nullptr_t) {
+    return "nullptr";
+}
+
+int StringMaker<float>::precision = 5;
+
+std::string StringMaker<float>::convert(float value) {
+    return fpToString(value, precision) + 'f';
+}
+
+int StringMaker<double>::precision = 10;
+
+std::string StringMaker<double>::convert(double value) {
+    return fpToString(value, precision);
+}
+
+std::string ratio_string<std::atto>::symbol() { return "a"; }
+std::string ratio_string<std::femto>::symbol() { return "f"; }
+std::string ratio_string<std::pico>::symbol() { return "p"; }
+std::string ratio_string<std::nano>::symbol() { return "n"; }
+std::string ratio_string<std::micro>::symbol() { return "u"; }
+std::string ratio_string<std::milli>::symbol() { return "m"; }
+
+} // end namespace Catch
+
+#if defined(__clang__)
+#    pragma clang diagnostic pop
+#endif
+
+// end catch_tostring.cpp
+// start catch_totals.cpp
+
+namespace Catch {
+
+    Counts Counts::operator - ( Counts const& other ) const {
+        Counts diff;
+        diff.passed = passed - other.passed;
+        diff.failed = failed - other.failed;
+        diff.failedButOk = failedButOk - other.failedButOk;
+        return diff;
+    }
+
+    Counts& Counts::operator += ( Counts const& other ) {
+        passed += other.passed;
+        failed += other.failed;
+        failedButOk += other.failedButOk;
+        return *this;
+    }
+
+    std::size_t Counts::total() const {
+        return passed + failed + failedButOk;
+    }
+    bool Counts::allPassed() const {
+        return failed == 0 && failedButOk == 0;
+    }
+    bool Counts::allOk() const {
+        return failed == 0;
+    }
+
+    Totals Totals::operator - ( Totals const& other ) const {
+        Totals diff;
+        diff.assertions = assertions - other.assertions;
+        diff.testCases = testCases - other.testCases;
+        return diff;
+    }
+
+    Totals& Totals::operator += ( Totals const& other ) {
+        assertions += other.assertions;
+        testCases += other.testCases;
+        return *this;
+    }
+
+    Totals Totals::delta( Totals const& prevTotals ) const {
+        Totals diff = *this - prevTotals;
+        if( diff.assertions.failed > 0 )
+            ++diff.testCases.failed;
+        else if( diff.assertions.failedButOk > 0 )
+            ++diff.testCases.failedButOk;
+        else
+            ++diff.testCases.passed;
+        return diff;
+    }
+
+}
+// end catch_totals.cpp
+// start catch_uncaught_exceptions.cpp
+
+// start catch_config_uncaught_exceptions.hpp
+
+//              Copyright Catch2 Authors
+// Distributed under the Boost Software License, Version 1.0.
+//   (See accompanying file LICENSE_1_0.txt or copy at
+//        https://www.boost.org/LICENSE_1_0.txt)
+
+// SPDX-License-Identifier: BSL-1.0
+
+#ifndef CATCH_CONFIG_UNCAUGHT_EXCEPTIONS_HPP
+#define CATCH_CONFIG_UNCAUGHT_EXCEPTIONS_HPP
+
+#if defined(_MSC_VER)
+#  if _MSC_VER >= 1900 // Visual Studio 2015 or newer
+#    define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS
+#  endif
+#endif
+
+#include <exception>
+
+#if defined(__cpp_lib_uncaught_exceptions) \
+    && !defined(CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS)
+
+#  define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS
+#endif // __cpp_lib_uncaught_exceptions
+
+#if defined(CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) \
+    && !defined(CATCH_CONFIG_NO_CPP17_UNCAUGHT_EXCEPTIONS) \
+    && !defined(CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS)
+
+#  define CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS
+#endif
+
+#endif // CATCH_CONFIG_UNCAUGHT_EXCEPTIONS_HPP
+// end catch_config_uncaught_exceptions.hpp
+#include <exception>
+
+namespace Catch {
+    bool uncaught_exceptions() {
+#if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
+        return false;
+#elif defined(CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS)
+        return std::uncaught_exceptions() > 0;
+#else
+        return std::uncaught_exception();
+#endif
+  }
+} // end namespace Catch
+// end catch_uncaught_exceptions.cpp
+// start catch_version.cpp
+
+#include <ostream>
+
+namespace Catch {
+
+    Version::Version
+        (   unsigned int _majorVersion,
+            unsigned int _minorVersion,
+            unsigned int _patchNumber,
+            char const * const _branchName,
+            unsigned int _buildNumber )
+    :   majorVersion( _majorVersion ),
+        minorVersion( _minorVersion ),
+        patchNumber( _patchNumber ),
+        branchName( _branchName ),
+        buildNumber( _buildNumber )
+    {}
+
+    std::ostream& operator << ( std::ostream& os, Version const& version ) {
+        os  << version.majorVersion << '.'
+            << version.minorVersion << '.'
+            << version.patchNumber;
+        // branchName is never null -> 0th char is \0 if it is empty
+        if (version.branchName[0]) {
+            os << '-' << version.branchName
+               << '.' << version.buildNumber;
+        }
+        return os;
+    }
+
+    Version const& libraryVersion() {
+        static Version version( 2, 13, 7, "", 0 );
+        return version;
+    }
+
+}
+// end catch_version.cpp
+// start catch_wildcard_pattern.cpp
+
+namespace Catch {
+
+    WildcardPattern::WildcardPattern( std::string const& pattern,
+                                      CaseSensitive::Choice caseSensitivity )
+    :   m_caseSensitivity( caseSensitivity ),
+        m_pattern( normaliseString( pattern ) )
+    {
+        if( startsWith( m_pattern, '*' ) ) {
+            m_pattern = m_pattern.substr( 1 );
+            m_wildcard = WildcardAtStart;
+        }
+        if( endsWith( m_pattern, '*' ) ) {
+            m_pattern = m_pattern.substr( 0, m_pattern.size()-1 );
+            m_wildcard = static_cast<WildcardPosition>( m_wildcard | WildcardAtEnd );
+        }
+    }
+
+    bool WildcardPattern::matches( std::string const& str ) const {
+        switch( m_wildcard ) {
+            case NoWildcard:
+                return m_pattern == normaliseString( str );
+            case WildcardAtStart:
+                return endsWith( normaliseString( str ), m_pattern );
+            case WildcardAtEnd:
+                return startsWith( normaliseString( str ), m_pattern );
+            case WildcardAtBothEnds:
+                return contains( normaliseString( str ), m_pattern );
+            default:
+                CATCH_INTERNAL_ERROR( "Unknown enum" );
+        }
+    }
+
+    std::string WildcardPattern::normaliseString( std::string const& str ) const {
+        return trim( m_caseSensitivity == CaseSensitive::No ? toLower( str ) : str );
+    }
+}
+// end catch_wildcard_pattern.cpp
+// start catch_xmlwriter.cpp
+
+#include <iomanip>
+#include <type_traits>
+
+namespace Catch {
+
+namespace {
+
+    size_t trailingBytes(unsigned char c) {
+        if ((c & 0xE0) == 0xC0) {
+            return 2;
+        }
+        if ((c & 0xF0) == 0xE0) {
+            return 3;
+        }
+        if ((c & 0xF8) == 0xF0) {
+            return 4;
+        }
+        CATCH_INTERNAL_ERROR("Invalid multibyte utf-8 start byte encountered");
+    }
+
+    uint32_t headerValue(unsigned char c) {
+        if ((c & 0xE0) == 0xC0) {
+            return c & 0x1F;
+        }
+        if ((c & 0xF0) == 0xE0) {
+            return c & 0x0F;
+        }
+        if ((c & 0xF8) == 0xF0) {
+            return c & 0x07;
+        }
+        CATCH_INTERNAL_ERROR("Invalid multibyte utf-8 start byte encountered");
+    }
+
+    void hexEscapeChar(std::ostream& os, unsigned char c) {
+        std::ios_base::fmtflags f(os.flags());
+        os << "\\x"
+            << std::uppercase << std::hex << std::setfill('0') << std::setw(2)
+            << static_cast<int>(c);
+        os.flags(f);
+    }
+
+    bool shouldNewline(XmlFormatting fmt) {
+        return !!(static_cast<std::underlying_type<XmlFormatting>::type>(fmt & XmlFormatting::Newline));
+    }
+
+    bool shouldIndent(XmlFormatting fmt) {
+        return !!(static_cast<std::underlying_type<XmlFormatting>::type>(fmt & XmlFormatting::Indent));
+    }
+
+} // anonymous namespace
+
+    XmlFormatting operator | (XmlFormatting lhs, XmlFormatting rhs) {
+        return static_cast<XmlFormatting>(
+            static_cast<std::underlying_type<XmlFormatting>::type>(lhs) |
+            static_cast<std::underlying_type<XmlFormatting>::type>(rhs)
+        );
+    }
+
+    XmlFormatting operator & (XmlFormatting lhs, XmlFormatting rhs) {
+        return static_cast<XmlFormatting>(
+            static_cast<std::underlying_type<XmlFormatting>::type>(lhs) &
+            static_cast<std::underlying_type<XmlFormatting>::type>(rhs)
+        );
+    }
+
+    XmlEncode::XmlEncode( std::string const& str, ForWhat forWhat )
+    :   m_str( str ),
+        m_forWhat( forWhat )
+    {}
+
+    void XmlEncode::encodeTo( std::ostream& os ) const {
+        // Apostrophe escaping not necessary if we always use " to write attributes
+        // (see: http://www.w3.org/TR/xml/#syntax)
+
+        for( std::size_t idx = 0; idx < m_str.size(); ++ idx ) {
+            unsigned char c = m_str[idx];
+            switch (c) {
+            case '<':   os << "&lt;"; break;
+            case '&':   os << "&amp;"; break;
+
+            case '>':
+                // See: http://www.w3.org/TR/xml/#syntax
+                if (idx > 2 && m_str[idx - 1] == ']' && m_str[idx - 2] == ']')
+                    os << "&gt;";
+                else
+                    os << c;
+                break;
+
+            case '\"':
+                if (m_forWhat == ForAttributes)
+                    os << "&quot;";
+                else
+                    os << c;
+                break;
+
+            default:
+                // Check for control characters and invalid utf-8
+
+                // Escape control characters in standard ascii
+                // see http://stackoverflow.com/questions/404107/why-are-control-characters-illegal-in-xml-1-0
+                if (c < 0x09 || (c > 0x0D && c < 0x20) || c == 0x7F) {
+                    hexEscapeChar(os, c);
+                    break;
+                }
+
+                // Plain ASCII: Write it to stream
+                if (c < 0x7F) {
+                    os << c;
+                    break;
+                }
+
+                // UTF-8 territory
+                // Check if the encoding is valid and if it is not, hex escape bytes.
+                // Important: We do not check the exact decoded values for validity, only the encoding format
+                // First check that this bytes is a valid lead byte:
+                // This means that it is not encoded as 1111 1XXX
+                // Or as 10XX XXXX
+                if (c <  0xC0 ||
+                    c >= 0xF8) {
+                    hexEscapeChar(os, c);
+                    break;
+                }
+
+                auto encBytes = trailingBytes(c);
+                // Are there enough bytes left to avoid accessing out-of-bounds memory?
+                if (idx + encBytes - 1 >= m_str.size()) {
+                    hexEscapeChar(os, c);
+                    break;
+                }
+                // The header is valid, check data
+                // The next encBytes bytes must together be a valid utf-8
+                // This means: bitpattern 10XX XXXX and the extracted value is sane (ish)
+                bool valid = true;
+                uint32_t value = headerValue(c);
+                for (std::size_t n = 1; n < encBytes; ++n) {
+                    unsigned char nc = m_str[idx + n];
+                    valid &= ((nc & 0xC0) == 0x80);
+                    value = (value << 6) | (nc & 0x3F);
+                }
+
+                if (
+                    // Wrong bit pattern of following bytes
+                    (!valid) ||
+                    // Overlong encodings
+                    (value < 0x80) ||
+                    (0x80 <= value && value < 0x800   && encBytes > 2) ||
+                    (0x800 < value && value < 0x10000 && encBytes > 3) ||
+                    // Encoded value out of range
+                    (value >= 0x110000)
+                    ) {
+                    hexEscapeChar(os, c);
+                    break;
+                }
+
+                // If we got here, this is in fact a valid(ish) utf-8 sequence
+                for (std::size_t n = 0; n < encBytes; ++n) {
+                    os << m_str[idx + n];
+                }
+                idx += encBytes - 1;
+                break;
+            }
+        }
+    }
+
+    std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode ) {
+        xmlEncode.encodeTo( os );
+        return os;
+    }
+
+    XmlWriter::ScopedElement::ScopedElement( XmlWriter* writer, XmlFormatting fmt )
+    :   m_writer( writer ),
+        m_fmt(fmt)
+    {}
+
+    XmlWriter::ScopedElement::ScopedElement( ScopedElement&& other ) noexcept
+    :   m_writer( other.m_writer ),
+        m_fmt(other.m_fmt)
+    {
+        other.m_writer = nullptr;
+        other.m_fmt = XmlFormatting::None;
+    }
+    XmlWriter::ScopedElement& XmlWriter::ScopedElement::operator=( ScopedElement&& other ) noexcept {
+        if ( m_writer ) {
+            m_writer->endElement();
+        }
+        m_writer = other.m_writer;
+        other.m_writer = nullptr;
+        m_fmt = other.m_fmt;
+        other.m_fmt = XmlFormatting::None;
+        return *this;
+    }
+
+    XmlWriter::ScopedElement::~ScopedElement() {
+        if (m_writer) {
+            m_writer->endElement(m_fmt);
+        }
+    }
+
+    XmlWriter::ScopedElement& XmlWriter::ScopedElement::writeText( std::string const& text, XmlFormatting fmt ) {
+        m_writer->writeText( text, fmt );
+        return *this;
+    }
+
+    XmlWriter::XmlWriter( std::ostream& os ) : m_os( os )
+    {
+        writeDeclaration();
+    }
+
+    XmlWriter::~XmlWriter() {
+        while (!m_tags.empty()) {
+            endElement();
+        }
+        newlineIfNecessary();
+    }
+
+    XmlWriter& XmlWriter::startElement( std::string const& name, XmlFormatting fmt ) {
+        ensureTagClosed();
+        newlineIfNecessary();
+        if (shouldIndent(fmt)) {
+            m_os << m_indent;
+            m_indent += "  ";
+        }
+        m_os << '<' << name;
+        m_tags.push_back( name );
+        m_tagIsOpen = true;
+        applyFormatting(fmt);
+        return *this;
+    }
+
+    XmlWriter::ScopedElement XmlWriter::scopedElement( std::string const& name, XmlFormatting fmt ) {
+        ScopedElement scoped( this, fmt );
+        startElement( name, fmt );
+        return scoped;
+    }
+
+    XmlWriter& XmlWriter::endElement(XmlFormatting fmt) {
+        m_indent = m_indent.substr(0, m_indent.size() - 2);
+
+        if( m_tagIsOpen ) {
+            m_os << "/>";
+            m_tagIsOpen = false;
+        } else {
+            newlineIfNecessary();
+            if (shouldIndent(fmt)) {
+                m_os << m_indent;
+            }
+            m_os << "</" << m_tags.back() << ">";
+        }
+        m_os << std::flush;
+        applyFormatting(fmt);
+        m_tags.pop_back();
+        return *this;
+    }
+
+    XmlWriter& XmlWriter::writeAttribute( std::string const& name, std::string const& attribute ) {
+        if( !name.empty() && !attribute.empty() )
+            m_os << ' ' << name << "=\"" << XmlEncode( attribute, XmlEncode::ForAttributes ) << '"';
+        return *this;
+    }
+
+    XmlWriter& XmlWriter::writeAttribute( std::string const& name, bool attribute ) {
+        m_os << ' ' << name << "=\"" << ( attribute ? "true" : "false" ) << '"';
+        return *this;
+    }
+
+    XmlWriter& XmlWriter::writeText( std::string const& text, XmlFormatting fmt) {
+        if( !text.empty() ){
+            bool tagWasOpen = m_tagIsOpen;
+            ensureTagClosed();
+            if (tagWasOpen && shouldIndent(fmt)) {
+                m_os << m_indent;
+            }
+            m_os << XmlEncode( text );
+            applyFormatting(fmt);
+        }
+        return *this;
+    }
+
+    XmlWriter& XmlWriter::writeComment( std::string const& text, XmlFormatting fmt) {
+        ensureTagClosed();
+        if (shouldIndent(fmt)) {
+            m_os << m_indent;
+        }
+        m_os << "<!--" << text << "-->";
+        applyFormatting(fmt);
+        return *this;
+    }
+
+    void XmlWriter::writeStylesheetRef( std::string const& url ) {
+        m_os << "<?xml-stylesheet type=\"text/xsl\" href=\"" << url << "\"?>\n";
+    }
+
+    XmlWriter& XmlWriter::writeBlankLine() {
+        ensureTagClosed();
+        m_os << '\n';
+        return *this;
+    }
+
+    void XmlWriter::ensureTagClosed() {
+        if( m_tagIsOpen ) {
+            m_os << '>' << std::flush;
+            newlineIfNecessary();
+            m_tagIsOpen = false;
+        }
+    }
+
+    void XmlWriter::applyFormatting(XmlFormatting fmt) {
+        m_needsNewline = shouldNewline(fmt);
+    }
+
+    void XmlWriter::writeDeclaration() {
+        m_os << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
+    }
+
+    void XmlWriter::newlineIfNecessary() {
+        if( m_needsNewline ) {
+            m_os << std::endl;
+            m_needsNewline = false;
+        }
+    }
+}
+// end catch_xmlwriter.cpp
+// start catch_reporter_bases.cpp
+
+#include <cstring>
+#include <cfloat>
+#include <cstdio>
+#include <cassert>
+#include <memory>
+
+namespace Catch {
+    void prepareExpandedExpression(AssertionResult& result) {
+        result.getExpandedExpression();
+    }
+
+    // Because formatting using c++ streams is stateful, drop down to C is required
+    // Alternatively we could use stringstream, but its performance is... not good.
+    std::string getFormattedDuration( double duration ) {
+        // Max exponent + 1 is required to represent the whole part
+        // + 1 for decimal point
+        // + 3 for the 3 decimal places
+        // + 1 for null terminator
+        const std::size_t maxDoubleSize = DBL_MAX_10_EXP + 1 + 1 + 3 + 1;
+        char buffer[maxDoubleSize];
+
+        // Save previous errno, to prevent sprintf from overwriting it
+        ErrnoGuard guard;
+#ifdef _MSC_VER
+        sprintf_s(buffer, "%.3f", duration);
+#else
+        std::sprintf(buffer, "%.3f", duration);
+#endif
+        return std::string(buffer);
+    }
+
+    bool shouldShowDuration( IConfig const& config, double duration ) {
+        if ( config.showDurations() == ShowDurations::Always ) {
+            return true;
+        }
+        if ( config.showDurations() == ShowDurations::Never ) {
+            return false;
+        }
+        const double min = config.minDuration();
+        return min >= 0 && duration >= min;
+    }
+
+    std::string serializeFilters( std::vector<std::string> const& container ) {
+        ReusableStringStream oss;
+        bool first = true;
+        for (auto&& filter : container)
+        {
+            if (!first)
+                oss << ' ';
+            else
+                first = false;
+
+            oss << filter;
+        }
+        return oss.str();
+    }
+
+    TestEventListenerBase::TestEventListenerBase(ReporterConfig const & _config)
+        :StreamingReporterBase(_config) {}
+
+    std::set<Verbosity> TestEventListenerBase::getSupportedVerbosities() {
+        return { Verbosity::Quiet, Verbosity::Normal, Verbosity::High };
+    }
+
+    void TestEventListenerBase::assertionStarting(AssertionInfo const &) {}
+
+    bool TestEventListenerBase::assertionEnded(AssertionStats const &) {
+        return false;
+    }
+
+} // end namespace Catch
+// end catch_reporter_bases.cpp
+// start catch_reporter_compact.cpp
+
+namespace {
+
+#ifdef CATCH_PLATFORM_MAC
+    const char* failedString() { return "FAILED"; }
+    const char* passedString() { return "PASSED"; }
+#else
+    const char* failedString() { return "failed"; }
+    const char* passedString() { return "passed"; }
+#endif
+
+    // Colour::LightGrey
+    Catch::Colour::Code dimColour() { return Catch::Colour::FileName; }
+
+    std::string bothOrAll( std::size_t count ) {
+        return count == 1 ? std::string() :
+               count == 2 ? "both " : "all " ;
+    }
+
+} // anon namespace
+
+namespace Catch {
+namespace {
+// Colour, message variants:
+// - white: No tests ran.
+// -   red: Failed [both/all] N test cases, failed [both/all] M assertions.
+// - white: Passed [both/all] N test cases (no assertions).
+// -   red: Failed N tests cases, failed M assertions.
+// - green: Passed [both/all] N tests cases with M assertions.
+void printTotals(std::ostream& out, const Totals& totals) {
+    if (totals.testCases.total() == 0) {
+        out << "No tests ran.";
+    } else if (totals.testCases.failed == totals.testCases.total()) {
+        Colour colour(Colour::ResultError);
+        const std::string qualify_assertions_failed =
+            totals.assertions.failed == totals.assertions.total() ?
+            bothOrAll(totals.assertions.failed) : std::string();
+        out <<
+            "Failed " << bothOrAll(totals.testCases.failed)
+            << pluralise(totals.testCases.failed, "test case") << ", "
+            "failed " << qualify_assertions_failed <<
+            pluralise(totals.assertions.failed, "assertion") << '.';
+    } else if (totals.assertions.total() == 0) {
+        out <<
+            "Passed " << bothOrAll(totals.testCases.total())
+            << pluralise(totals.testCases.total(), "test case")
+            << " (no assertions).";
+    } else if (totals.assertions.failed) {
+        Colour colour(Colour::ResultError);
+        out <<
+            "Failed " << pluralise(totals.testCases.failed, "test case") << ", "
+            "failed " << pluralise(totals.assertions.failed, "assertion") << '.';
+    } else {
+        Colour colour(Colour::ResultSuccess);
+        out <<
+            "Passed " << bothOrAll(totals.testCases.passed)
+            << pluralise(totals.testCases.passed, "test case") <<
+            " with " << pluralise(totals.assertions.passed, "assertion") << '.';
+    }
+}
+
+// Implementation of CompactReporter formatting
+class AssertionPrinter {
+public:
+    AssertionPrinter& operator= (AssertionPrinter const&) = delete;
+    AssertionPrinter(AssertionPrinter const&) = delete;
+    AssertionPrinter(std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages)
+        : stream(_stream)
+        , result(_stats.assertionResult)
+        , messages(_stats.infoMessages)
+        , itMessage(_stats.infoMessages.begin())
+        , printInfoMessages(_printInfoMessages) {}
+
+    void print() {
+        printSourceInfo();
+
+        itMessage = messages.begin();
+
+        switch (result.getResultType()) {
+        case ResultWas::Ok:
+            printResultType(Colour::ResultSuccess, passedString());
+            printOriginalExpression();
+            printReconstructedExpression();
+            if (!result.hasExpression())
+                printRemainingMessages(Colour::None);
+            else
+                printRemainingMessages();
+            break;
+        case ResultWas::ExpressionFailed:
+            if (result.isOk())
+                printResultType(Colour::ResultSuccess, failedString() + std::string(" - but was ok"));
+            else
+                printResultType(Colour::Error, failedString());
+            printOriginalExpression();
+            printReconstructedExpression();
+            printRemainingMessages();
+            break;
+        case ResultWas::ThrewException:
+            printResultType(Colour::Error, failedString());
+            printIssue("unexpected exception with message:");
+            printMessage();
+            printExpressionWas();
+            printRemainingMessages();
+            break;
+        case ResultWas::FatalErrorCondition:
+            printResultType(Colour::Error, failedString());
+            printIssue("fatal error condition with message:");
+            printMessage();
+            printExpressionWas();
+            printRemainingMessages();
+            break;
+        case ResultWas::DidntThrowException:
+            printResultType(Colour::Error, failedString());
+            printIssue("expected exception, got none");
+            printExpressionWas();
+            printRemainingMessages();
+            break;
+        case ResultWas::Info:
+            printResultType(Colour::None, "info");
+            printMessage();
+            printRemainingMessages();
+            break;
+        case ResultWas::Warning:
+            printResultType(Colour::None, "warning");
+            printMessage();
+            printRemainingMessages();
+            break;
+        case ResultWas::ExplicitFailure:
+            printResultType(Colour::Error, failedString());
+            printIssue("explicitly");
+            printRemainingMessages(Colour::None);
+            break;
+            // These cases are here to prevent compiler warnings
+        case ResultWas::Unknown:
+        case ResultWas::FailureBit:
+        case ResultWas::Exception:
+            printResultType(Colour::Error, "** internal error **");
+            break;
+        }
+    }
+
+private:
+    void printSourceInfo() const {
+        Colour colourGuard(Colour::FileName);
+        stream << result.getSourceInfo() << ':';
+    }
+
+    void printResultType(Colour::Code colour, std::string const& passOrFail) const {
+        if (!passOrFail.empty()) {
+            {
+                Colour colourGuard(colour);
+                stream << ' ' << passOrFail;
+            }
+            stream << ':';
+        }
+    }
+
+    void printIssue(std::string const& issue) const {
+        stream << ' ' << issue;
+    }
+
+    void printExpressionWas() {
+        if (result.hasExpression()) {
+            stream << ';';
+            {
+                Colour colour(dimColour());
+                stream << " expression was:";
+            }
+            printOriginalExpression();
+        }
+    }
+
+    void printOriginalExpression() const {
+        if (result.hasExpression()) {
+            stream << ' ' << result.getExpression();
+        }
+    }
+
+    void printReconstructedExpression() const {
+        if (result.hasExpandedExpression()) {
+            {
+                Colour colour(dimColour());
+                stream << " for: ";
+            }
+            stream << result.getExpandedExpression();
+        }
+    }
+
+    void printMessage() {
+        if (itMessage != messages.end()) {
+            stream << " '" << itMessage->message << '\'';
+            ++itMessage;
+        }
+    }
+
+    void printRemainingMessages(Colour::Code colour = dimColour()) {
+        if (itMessage == messages.end())
+            return;
+
+        const auto itEnd = messages.cend();
+        const auto N = static_cast<std::size_t>(std::distance(itMessage, itEnd));
+
+        {
+            Colour colourGuard(colour);
+            stream << " with " << pluralise(N, "message") << ':';
+        }
+
+        while (itMessage != itEnd) {
+            // If this assertion is a warning ignore any INFO messages
+            if (printInfoMessages || itMessage->type != ResultWas::Info) {
+                printMessage();
+                if (itMessage != itEnd) {
+                    Colour colourGuard(dimColour());
+                    stream << " and";
+                }
+                continue;
+            }
+            ++itMessage;
+        }
+    }
+
+private:
+    std::ostream& stream;
+    AssertionResult const& result;
+    std::vector<MessageInfo> messages;
+    std::vector<MessageInfo>::const_iterator itMessage;
+    bool printInfoMessages;
+};
+
+} // anon namespace
+
+        std::string CompactReporter::getDescription() {
+            return "Reports test results on a single line, suitable for IDEs";
+        }
+
+        void CompactReporter::noMatchingTestCases( std::string const& spec ) {
+            stream << "No test cases matched '" << spec << '\'' << std::endl;
+        }
+
+        void CompactReporter::assertionStarting( AssertionInfo const& ) {}
+
+        bool CompactReporter::assertionEnded( AssertionStats const& _assertionStats ) {
+            AssertionResult const& result = _assertionStats.assertionResult;
+
+            bool printInfoMessages = true;
+
+            // Drop out if result was successful and we're not printing those
+            if( !m_config->includeSuccessfulResults() && result.isOk() ) {
+                if( result.getResultType() != ResultWas::Warning )
+                    return false;
+                printInfoMessages = false;
+            }
+
+            AssertionPrinter printer( stream, _assertionStats, printInfoMessages );
+            printer.print();
+
+            stream << std::endl;
+            return true;
+        }
+
+        void CompactReporter::sectionEnded(SectionStats const& _sectionStats) {
+            double dur = _sectionStats.durationInSeconds;
+            if ( shouldShowDuration( *m_config, dur ) ) {
+                stream << getFormattedDuration( dur ) << " s: " << _sectionStats.sectionInfo.name << std::endl;
+            }
+        }
+
+        void CompactReporter::testRunEnded( TestRunStats const& _testRunStats ) {
+            printTotals( stream, _testRunStats.totals );
+            stream << '\n' << std::endl;
+            StreamingReporterBase::testRunEnded( _testRunStats );
+        }
+
+        CompactReporter::~CompactReporter() {}
+
+    CATCH_REGISTER_REPORTER( "compact", CompactReporter )
+
+} // end namespace Catch
+// end catch_reporter_compact.cpp
+// start catch_reporter_console.cpp
+
+#include <cfloat>
+#include <cstdio>
+
+#if defined(_MSC_VER)
+#pragma warning(push)
+#pragma warning(disable:4061) // Not all labels are EXPLICITLY handled in switch
+ // Note that 4062 (not all labels are handled and default is missing) is enabled
+#endif
+
+#if defined(__clang__)
+#  pragma clang diagnostic push
+// For simplicity, benchmarking-only helpers are always enabled
+#  pragma clang diagnostic ignored "-Wunused-function"
+#endif
+
+namespace Catch {
+
+namespace {
+
+// Formatter impl for ConsoleReporter
+class ConsoleAssertionPrinter {
+public:
+    ConsoleAssertionPrinter& operator= (ConsoleAssertionPrinter const&) = delete;
+    ConsoleAssertionPrinter(ConsoleAssertionPrinter const&) = delete;
+    ConsoleAssertionPrinter(std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages)
+        : stream(_stream),
+        stats(_stats),
+        result(_stats.assertionResult),
+        colour(Colour::None),
+        message(result.getMessage()),
+        messages(_stats.infoMessages),
+        printInfoMessages(_printInfoMessages) {
+        switch (result.getResultType()) {
+        case ResultWas::Ok:
+            colour = Colour::Success;
+            passOrFail = "PASSED";
+            //if( result.hasMessage() )
+            if (_stats.infoMessages.size() == 1)
+                messageLabel = "with message";
+            if (_stats.infoMessages.size() > 1)
+                messageLabel = "with messages";
+            break;
+        case ResultWas::ExpressionFailed:
+            if (result.isOk()) {
+                colour = Colour::Success;
+                passOrFail = "FAILED - but was ok";
+            } else {
+                colour = Colour::Error;
+                passOrFail = "FAILED";
+            }
+            if (_stats.infoMessages.size() == 1)
+                messageLabel = "with message";
+            if (_stats.infoMessages.size() > 1)
+                messageLabel = "with messages";
+            break;
+        case ResultWas::ThrewException:
+            colour = Colour::Error;
+            passOrFail = "FAILED";
+            messageLabel = "due to unexpected exception with ";
+            if (_stats.infoMessages.size() == 1)
+                messageLabel += "message";
+            if (_stats.infoMessages.size() > 1)
+                messageLabel += "messages";
+            break;
+        case ResultWas::FatalErrorCondition:
+            colour = Colour::Error;
+            passOrFail = "FAILED";
+            messageLabel = "due to a fatal error condition";
+            break;
+        case ResultWas::DidntThrowException:
+            colour = Colour::Error;
+            passOrFail = "FAILED";
+            messageLabel = "because no exception was thrown where one was expected";
+            break;
+        case ResultWas::Info:
+            messageLabel = "info";
+            break;
+        case ResultWas::Warning:
+            messageLabel = "warning";
+            break;
+        case ResultWas::ExplicitFailure:
+            passOrFail = "FAILED";
+            colour = Colour::Error;
+            if (_stats.infoMessages.size() == 1)
+                messageLabel = "explicitly with message";
+            if (_stats.infoMessages.size() > 1)
+                messageLabel = "explicitly with messages";
+            break;
+            // These cases are here to prevent compiler warnings
+        case ResultWas::Unknown:
+        case ResultWas::FailureBit:
+        case ResultWas::Exception:
+            passOrFail = "** internal error **";
+            colour = Colour::Error;
+            break;
+        }
+    }
+
+    void print() const {
+        printSourceInfo();
+        if (stats.totals.assertions.total() > 0) {
+            printResultType();
+            printOriginalExpression();
+            printReconstructedExpression();
+        } else {
+            stream << '\n';
+        }
+        printMessage();
+    }
+
+private:
+    void printResultType() const {
+        if (!passOrFail.empty()) {
+            Colour colourGuard(colour);
+            stream << passOrFail << ":\n";
+        }
+    }
+    void printOriginalExpression() const {
+        if (result.hasExpression()) {
+            Colour colourGuard(Colour::OriginalExpression);
+            stream << "  ";
+            stream << result.getExpressionInMacro();
+            stream << '\n';
+        }
+    }
+    void printReconstructedExpression() const {
+        if (result.hasExpandedExpression()) {
+            stream << "with expansion:\n";
+            Colour colourGuard(Colour::ReconstructedExpression);
+            stream << Column(result.getExpandedExpression()).indent(2) << '\n';
+        }
+    }
+    void printMessage() const {
+        if (!messageLabel.empty())
+            stream << messageLabel << ':' << '\n';
+        for (auto const& msg : messages) {
+            // If this assertion is a warning ignore any INFO messages
+            if (printInfoMessages || msg.type != ResultWas::Info)
+                stream << Column(msg.message).indent(2) << '\n';
+        }
+    }
+    void printSourceInfo() const {
+        Colour colourGuard(Colour::FileName);
+        stream << result.getSourceInfo() << ": ";
+    }
+
+    std::ostream& stream;
+    AssertionStats const& stats;
+    AssertionResult const& result;
+    Colour::Code colour;
+    std::string passOrFail;
+    std::string messageLabel;
+    std::string message;
+    std::vector<MessageInfo> messages;
+    bool printInfoMessages;
+};
+
+std::size_t makeRatio(std::size_t number, std::size_t total) {
+    std::size_t ratio = total > 0 ? CATCH_CONFIG_CONSOLE_WIDTH * number / total : 0;
+    return (ratio == 0 && number > 0) ? 1 : ratio;
+}
+
+std::size_t& findMax(std::size_t& i, std::size_t& j, std::size_t& k) {
+    if (i > j && i > k)
+        return i;
+    else if (j > k)
+        return j;
+    else
+        return k;
+}
+
+struct ColumnInfo {
+    enum Justification { Left, Right };
+    std::string name;
+    int width;
+    Justification justification;
+};
+struct ColumnBreak {};
+struct RowBreak {};
+
+class Duration {
+    enum class Unit {
+        Auto,
+        Nanoseconds,
+        Microseconds,
+        Milliseconds,
+        Seconds,
+        Minutes
+    };
+    static const uint64_t s_nanosecondsInAMicrosecond = 1000;
+    static const uint64_t s_nanosecondsInAMillisecond = 1000 * s_nanosecondsInAMicrosecond;
+    static const uint64_t s_nanosecondsInASecond = 1000 * s_nanosecondsInAMillisecond;
+    static const uint64_t s_nanosecondsInAMinute = 60 * s_nanosecondsInASecond;
+
+    double m_inNanoseconds;
+    Unit m_units;
+
+public:
+    explicit Duration(double inNanoseconds, Unit units = Unit::Auto)
+        : m_inNanoseconds(inNanoseconds),
+        m_units(units) {
+        if (m_units == Unit::Auto) {
+            if (m_inNanoseconds < s_nanosecondsInAMicrosecond)
+                m_units = Unit::Nanoseconds;
+            else if (m_inNanoseconds < s_nanosecondsInAMillisecond)
+                m_units = Unit::Microseconds;
+            else if (m_inNanoseconds < s_nanosecondsInASecond)
+                m_units = Unit::Milliseconds;
+            else if (m_inNanoseconds < s_nanosecondsInAMinute)
+                m_units = Unit::Seconds;
+            else
+                m_units = Unit::Minutes;
+        }
+
+    }
+
+    auto value() const -> double {
+        switch (m_units) {
+        case Unit::Microseconds:
+            return m_inNanoseconds / static_cast<double>(s_nanosecondsInAMicrosecond);
+        case Unit::Milliseconds:
+            return m_inNanoseconds / static_cast<double>(s_nanosecondsInAMillisecond);
+        case Unit::Seconds:
+            return m_inNanoseconds / static_cast<double>(s_nanosecondsInASecond);
+        case Unit::Minutes:
+            return m_inNanoseconds / static_cast<double>(s_nanosecondsInAMinute);
+        default:
+            return m_inNanoseconds;
+        }
+    }
+    auto unitsAsString() const -> std::string {
+        switch (m_units) {
+        case Unit::Nanoseconds:
+            return "ns";
+        case Unit::Microseconds:
+            return "us";
+        case Unit::Milliseconds:
+            return "ms";
+        case Unit::Seconds:
+            return "s";
+        case Unit::Minutes:
+            return "m";
+        default:
+            return "** internal error **";
+        }
+
+    }
+    friend auto operator << (std::ostream& os, Duration const& duration) -> std::ostream& {
+        return os << duration.value() << ' ' << duration.unitsAsString();
+    }
+};
+} // end anon namespace
+
+class TablePrinter {
+    std::ostream& m_os;
+    std::vector<ColumnInfo> m_columnInfos;
+    std::ostringstream m_oss;
+    int m_currentColumn = -1;
+    bool m_isOpen = false;
+
+public:
+    TablePrinter( std::ostream& os, std::vector<ColumnInfo> columnInfos )
+    :   m_os( os ),
+        m_columnInfos( std::move( columnInfos ) ) {}
+
+    auto columnInfos() const -> std::vector<ColumnInfo> const& {
+        return m_columnInfos;
+    }
+
+    void open() {
+        if (!m_isOpen) {
+            m_isOpen = true;
+            *this << RowBreak();
+
+			Columns headerCols;
+			Spacer spacer(2);
+			for (auto const& info : m_columnInfos) {
+				headerCols += Column(info.name).width(static_cast<std::size_t>(info.width - 2));
+				headerCols += spacer;
+			}
+			m_os << headerCols << '\n';
+
+            m_os << Catch::getLineOfChars<'-'>() << '\n';
+        }
+    }
+    void close() {
+        if (m_isOpen) {
+            *this << RowBreak();
+            m_os << std::endl;
+            m_isOpen = false;
+        }
+    }
+
+    template<typename T>
+    friend TablePrinter& operator << (TablePrinter& tp, T const& value) {
+        tp.m_oss << value;
+        return tp;
+    }
+
+    friend TablePrinter& operator << (TablePrinter& tp, ColumnBreak) {
+        auto colStr = tp.m_oss.str();
+        const auto strSize = colStr.size();
+        tp.m_oss.str("");
+        tp.open();
+        if (tp.m_currentColumn == static_cast<int>(tp.m_columnInfos.size() - 1)) {
+            tp.m_currentColumn = -1;
+            tp.m_os << '\n';
+        }
+        tp.m_currentColumn++;
+
+        auto colInfo = tp.m_columnInfos[tp.m_currentColumn];
+        auto padding = (strSize + 1 < static_cast<std::size_t>(colInfo.width))
+            ? std::string(colInfo.width - (strSize + 1), ' ')
+            : std::string();
+        if (colInfo.justification == ColumnInfo::Left)
+            tp.m_os << colStr << padding << ' ';
+        else
+            tp.m_os << padding << colStr << ' ';
+        return tp;
+    }
+
+    friend TablePrinter& operator << (TablePrinter& tp, RowBreak) {
+        if (tp.m_currentColumn > 0) {
+            tp.m_os << '\n';
+            tp.m_currentColumn = -1;
+        }
+        return tp;
+    }
+};
+
+ConsoleReporter::ConsoleReporter(ReporterConfig const& config)
+    : StreamingReporterBase(config),
+    m_tablePrinter(new TablePrinter(config.stream(),
+        [&config]() -> std::vector<ColumnInfo> {
+        if (config.fullConfig()->benchmarkNoAnalysis())
+        {
+            return{
+                { "benchmark name", CATCH_CONFIG_CONSOLE_WIDTH - 43, ColumnInfo::Left },
+                { "     samples", 14, ColumnInfo::Right },
+                { "  iterations", 14, ColumnInfo::Right },
+                { "        mean", 14, ColumnInfo::Right }
+            };
+        }
+        else
+        {
+            return{
+                { "benchmark name", CATCH_CONFIG_CONSOLE_WIDTH - 43, ColumnInfo::Left },
+                { "samples      mean       std dev", 14, ColumnInfo::Right },
+                { "iterations   low mean   low std dev", 14, ColumnInfo::Right },
+                { "estimated    high mean  high std dev", 14, ColumnInfo::Right }
+            };
+        }
+    }())) {}
+ConsoleReporter::~ConsoleReporter() = default;
+
+std::string ConsoleReporter::getDescription() {
+    return "Reports test results as plain lines of text";
+}
+
+void ConsoleReporter::noMatchingTestCases(std::string const& spec) {
+    stream << "No test cases matched '" << spec << '\'' << std::endl;
+}
+
+void ConsoleReporter::reportInvalidArguments(std::string const&arg){
+    stream << "Invalid Filter: " << arg << std::endl;
+}
+
+void ConsoleReporter::assertionStarting(AssertionInfo const&) {}
+
+bool ConsoleReporter::assertionEnded(AssertionStats const& _assertionStats) {
+    AssertionResult const& result = _assertionStats.assertionResult;
+
+    bool includeResults = m_config->includeSuccessfulResults() || !result.isOk();
+
+    // Drop out if result was successful but we're not printing them.
+    if (!includeResults && result.getResultType() != ResultWas::Warning)
+        return false;
+
+    lazyPrint();
+
+    ConsoleAssertionPrinter printer(stream, _assertionStats, includeResults);
+    printer.print();
+    stream << std::endl;
+    return true;
+}
+
+void ConsoleReporter::sectionStarting(SectionInfo const& _sectionInfo) {
+    m_tablePrinter->close();
+    m_headerPrinted = false;
+    StreamingReporterBase::sectionStarting(_sectionInfo);
+}
+void ConsoleReporter::sectionEnded(SectionStats const& _sectionStats) {
+    m_tablePrinter->close();
+    if (_sectionStats.missingAssertions) {
+        lazyPrint();
+        Colour colour(Colour::ResultError);
+        if (m_sectionStack.size() > 1)
+            stream << "\nNo assertions in section";
+        else
+            stream << "\nNo assertions in test case";
+        stream << " '" << _sectionStats.sectionInfo.name << "'\n" << std::endl;
+    }
+    double dur = _sectionStats.durationInSeconds;
+    if (shouldShowDuration(*m_config, dur)) {
+        stream << getFormattedDuration(dur) << " s: " << _sectionStats.sectionInfo.name << std::endl;
+    }
+    if (m_headerPrinted) {
+        m_headerPrinted = false;
+    }
+    StreamingReporterBase::sectionEnded(_sectionStats);
+}
+
+#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
+void ConsoleReporter::benchmarkPreparing(std::string const& name) {
+	lazyPrintWithoutClosingBenchmarkTable();
+
+	auto nameCol = Column(name).width(static_cast<std::size_t>(m_tablePrinter->columnInfos()[0].width - 2));
+
+	bool firstLine = true;
+	for (auto line : nameCol) {
+		if (!firstLine)
+			(*m_tablePrinter) << ColumnBreak() << ColumnBreak() << ColumnBreak();
+		else
+			firstLine = false;
+
+		(*m_tablePrinter) << line << ColumnBreak();
+	}
+}
+
+void ConsoleReporter::benchmarkStarting(BenchmarkInfo const& info) {
+    (*m_tablePrinter) << info.samples << ColumnBreak()
+        << info.iterations << ColumnBreak();
+    if (!m_config->benchmarkNoAnalysis())
+        (*m_tablePrinter) << Duration(info.estimatedDuration) << ColumnBreak();
+}
+void ConsoleReporter::benchmarkEnded(BenchmarkStats<> const& stats) {
+    if (m_config->benchmarkNoAnalysis())
+    {
+        (*m_tablePrinter) << Duration(stats.mean.point.count()) << ColumnBreak();
+    }
+    else
+    {
+        (*m_tablePrinter) << ColumnBreak()
+            << Duration(stats.mean.point.count()) << ColumnBreak()
+            << Duration(stats.mean.lower_bound.count()) << ColumnBreak()
+            << Duration(stats.mean.upper_bound.count()) << ColumnBreak() << ColumnBreak()
+            << Duration(stats.standardDeviation.point.count()) << ColumnBreak()
+            << Duration(stats.standardDeviation.lower_bound.count()) << ColumnBreak()
+            << Duration(stats.standardDeviation.upper_bound.count()) << ColumnBreak() << ColumnBreak() << ColumnBreak() << ColumnBreak() << ColumnBreak();
+    }
+}
+
+void ConsoleReporter::benchmarkFailed(std::string const& error) {
+	Colour colour(Colour::Red);
+    (*m_tablePrinter)
+        << "Benchmark failed (" << error << ')'
+        << ColumnBreak() << RowBreak();
+}
+#endif // CATCH_CONFIG_ENABLE_BENCHMARKING
+
+void ConsoleReporter::testCaseEnded(TestCaseStats const& _testCaseStats) {
+    m_tablePrinter->close();
+    StreamingReporterBase::testCaseEnded(_testCaseStats);
+    m_headerPrinted = false;
+}
+void ConsoleReporter::testGroupEnded(TestGroupStats const& _testGroupStats) {
+    if (currentGroupInfo.used) {
+        printSummaryDivider();
+        stream << "Summary for group '" << _testGroupStats.groupInfo.name << "':\n";
+        printTotals(_testGroupStats.totals);
+        stream << '\n' << std::endl;
+    }
+    StreamingReporterBase::testGroupEnded(_testGroupStats);
+}
+void ConsoleReporter::testRunEnded(TestRunStats const& _testRunStats) {
+    printTotalsDivider(_testRunStats.totals);
+    printTotals(_testRunStats.totals);
+    stream << std::endl;
+    StreamingReporterBase::testRunEnded(_testRunStats);
+}
+void ConsoleReporter::testRunStarting(TestRunInfo const& _testInfo) {
+    StreamingReporterBase::testRunStarting(_testInfo);
+    printTestFilters();
+}
+
+void ConsoleReporter::lazyPrint() {
+
+    m_tablePrinter->close();
+    lazyPrintWithoutClosingBenchmarkTable();
+}
+
+void ConsoleReporter::lazyPrintWithoutClosingBenchmarkTable() {
+
+    if (!currentTestRunInfo.used)
+        lazyPrintRunInfo();
+    if (!currentGroupInfo.used)
+        lazyPrintGroupInfo();
+
+    if (!m_headerPrinted) {
+        printTestCaseAndSectionHeader();
+        m_headerPrinted = true;
+    }
+}
+void ConsoleReporter::lazyPrintRunInfo() {
+    stream << '\n' << getLineOfChars<'~'>() << '\n';
+    Colour colour(Colour::SecondaryText);
+    stream << currentTestRunInfo->name
+        << " is a Catch v" << libraryVersion() << " host application.\n"
+        << "Run with -? for options\n\n";
+
+    if (m_config->rngSeed() != 0)
+        stream << "Randomness seeded to: " << m_config->rngSeed() << "\n\n";
+
+    currentTestRunInfo.used = true;
+}
+void ConsoleReporter::lazyPrintGroupInfo() {
+    if (!currentGroupInfo->name.empty() && currentGroupInfo->groupsCounts > 1) {
+        printClosedHeader("Group: " + currentGroupInfo->name);
+        currentGroupInfo.used = true;
+    }
+}
+void ConsoleReporter::printTestCaseAndSectionHeader() {
+    assert(!m_sectionStack.empty());
+    printOpenHeader(currentTestCaseInfo->name);
+
+    if (m_sectionStack.size() > 1) {
+        Colour colourGuard(Colour::Headers);
+
+        auto
+            it = m_sectionStack.begin() + 1, // Skip first section (test case)
+            itEnd = m_sectionStack.end();
+        for (; it != itEnd; ++it)
+            printHeaderString(it->name, 2);
+    }
+
+    SourceLineInfo lineInfo = m_sectionStack.back().lineInfo;
+
+    stream << getLineOfChars<'-'>() << '\n';
+    Colour colourGuard(Colour::FileName);
+    stream << lineInfo << '\n';
+    stream << getLineOfChars<'.'>() << '\n' << std::endl;
+}
+
+void ConsoleReporter::printClosedHeader(std::string const& _name) {
+    printOpenHeader(_name);
+    stream << getLineOfChars<'.'>() << '\n';
+}
+void ConsoleReporter::printOpenHeader(std::string const& _name) {
+    stream << getLineOfChars<'-'>() << '\n';
+    {
+        Colour colourGuard(Colour::Headers);
+        printHeaderString(_name);
+    }
+}
+
+// if string has a : in first line will set indent to follow it on
+// subsequent lines
+void ConsoleReporter::printHeaderString(std::string const& _string, std::size_t indent) {
+    std::size_t i = _string.find(": ");
+    if (i != std::string::npos)
+        i += 2;
+    else
+        i = 0;
+    stream << Column(_string).indent(indent + i).initialIndent(indent) << '\n';
+}
+
+struct SummaryColumn {
+
+    SummaryColumn( std::string _label, Colour::Code _colour )
+    :   label( std::move( _label ) ),
+        colour( _colour ) {}
+    SummaryColumn addRow( std::size_t count ) {
+        ReusableStringStream rss;
+        rss << count;
+        std::string row = rss.str();
+        for (auto& oldRow : rows) {
+            while (oldRow.size() < row.size())
+                oldRow = ' ' + oldRow;
+            while (oldRow.size() > row.size())
+                row = ' ' + row;
+        }
+        rows.push_back(row);
+        return *this;
+    }
+
+    std::string label;
+    Colour::Code colour;
+    std::vector<std::string> rows;
+
+};
+
+void ConsoleReporter::printTotals( Totals const& totals ) {
+    if (totals.testCases.total() == 0) {
+        stream << Colour(Colour::Warning) << "No tests ran\n";
+    } else if (totals.assertions.total() > 0 && totals.testCases.allPassed()) {
+        stream << Colour(Colour::ResultSuccess) << "All tests passed";
+        stream << " ("
+            << pluralise(totals.assertions.passed, "assertion") << " in "
+            << pluralise(totals.testCases.passed, "test case") << ')'
+            << '\n';
+    } else {
+
+        std::vector<SummaryColumn> columns;
+        columns.push_back(SummaryColumn("", Colour::None)
+                          .addRow(totals.testCases.total())
+                          .addRow(totals.assertions.total()));
+        columns.push_back(SummaryColumn("passed", Colour::Success)
+                          .addRow(totals.testCases.passed)
+                          .addRow(totals.assertions.passed));
+        columns.push_back(SummaryColumn("failed", Colour::ResultError)
+                          .addRow(totals.testCases.failed)
+                          .addRow(totals.assertions.failed));
+        columns.push_back(SummaryColumn("failed as expected", Colour::ResultExpectedFailure)
+                          .addRow(totals.testCases.failedButOk)
+                          .addRow(totals.assertions.failedButOk));
+
+        printSummaryRow("test cases", columns, 0);
+        printSummaryRow("assertions", columns, 1);
+    }
+}
+void ConsoleReporter::printSummaryRow(std::string const& label, std::vector<SummaryColumn> const& cols, std::size_t row) {
+    for (auto col : cols) {
+        std::string value = col.rows[row];
+        if (col.label.empty()) {
+            stream << label << ": ";
+            if (value != "0")
+                stream << value;
+            else
+                stream << Colour(Colour::Warning) << "- none -";
+        } else if (value != "0") {
+            stream << Colour(Colour::LightGrey) << " | ";
+            stream << Colour(col.colour)
+                << value << ' ' << col.label;
+        }
+    }
+    stream << '\n';
+}
+
+void ConsoleReporter::printTotalsDivider(Totals const& totals) {
+    if (totals.testCases.total() > 0) {
+        std::size_t failedRatio = makeRatio(totals.testCases.failed, totals.testCases.total());
+        std::size_t failedButOkRatio = makeRatio(totals.testCases.failedButOk, totals.testCases.total());
+        std::size_t passedRatio = makeRatio(totals.testCases.passed, totals.testCases.total());
+        while (failedRatio + failedButOkRatio + passedRatio < CATCH_CONFIG_CONSOLE_WIDTH - 1)
+            findMax(failedRatio, failedButOkRatio, passedRatio)++;
+        while (failedRatio + failedButOkRatio + passedRatio > CATCH_CONFIG_CONSOLE_WIDTH - 1)
+            findMax(failedRatio, failedButOkRatio, passedRatio)--;
+
+        stream << Colour(Colour::Error) << std::string(failedRatio, '=');
+        stream << Colour(Colour::ResultExpectedFailure) << std::string(failedButOkRatio, '=');
+        if (totals.testCases.allPassed())
+            stream << Colour(Colour::ResultSuccess) << std::string(passedRatio, '=');
+        else
+            stream << Colour(Colour::Success) << std::string(passedRatio, '=');
+    } else {
+        stream << Colour(Colour::Warning) << std::string(CATCH_CONFIG_CONSOLE_WIDTH - 1, '=');
+    }
+    stream << '\n';
+}
+void ConsoleReporter::printSummaryDivider() {
+    stream << getLineOfChars<'-'>() << '\n';
+}
+
+void ConsoleReporter::printTestFilters() {
+    if (m_config->testSpec().hasFilters()) {
+        Colour guard(Colour::BrightYellow);
+        stream << "Filters: " << serializeFilters(m_config->getTestsOrTags()) << '\n';
+    }
+}
+
+CATCH_REGISTER_REPORTER("console", ConsoleReporter)
+
+} // end namespace Catch
+
+#if defined(_MSC_VER)
+#pragma warning(pop)
+#endif
+
+#if defined(__clang__)
+#  pragma clang diagnostic pop
+#endif
+// end catch_reporter_console.cpp
+// start catch_reporter_junit.cpp
+
+#include <cassert>
+#include <sstream>
+#include <ctime>
+#include <algorithm>
+#include <iomanip>
+
+namespace Catch {
+
+    namespace {
+        std::string getCurrentTimestamp() {
+            // Beware, this is not reentrant because of backward compatibility issues
+            // Also, UTC only, again because of backward compatibility (%z is C++11)
+            time_t rawtime;
+            std::time(&rawtime);
+            auto const timeStampSize = sizeof("2017-01-16T17:06:45Z");
+
+#ifdef _MSC_VER
+            std::tm timeInfo = {};
+            gmtime_s(&timeInfo, &rawtime);
+#else
+            std::tm* timeInfo;
+            timeInfo = std::gmtime(&rawtime);
+#endif
+
+            char timeStamp[timeStampSize];
+            const char * const fmt = "%Y-%m-%dT%H:%M:%SZ";
+
+#ifdef _MSC_VER
+            std::strftime(timeStamp, timeStampSize, fmt, &timeInfo);
+#else
+            std::strftime(timeStamp, timeStampSize, fmt, timeInfo);
+#endif
+            return std::string(timeStamp, timeStampSize-1);
+        }
+
+        std::string fileNameTag(const std::vector<std::string> &tags) {
+            auto it = std::find_if(begin(tags),
+                                   end(tags),
+                                   [] (std::string const& tag) {return tag.front() == '#'; });
+            if (it != tags.end())
+                return it->substr(1);
+            return std::string();
+        }
+
+        // Formats the duration in seconds to 3 decimal places.
+        // This is done because some genius defined Maven Surefire schema
+        // in a way that only accepts 3 decimal places, and tools like
+        // Jenkins use that schema for validation JUnit reporter output.
+        std::string formatDuration( double seconds ) {
+            ReusableStringStream rss;
+            rss << std::fixed << std::setprecision( 3 ) << seconds;
+            return rss.str();
+        }
+
+    } // anonymous namespace
+
+    JunitReporter::JunitReporter( ReporterConfig const& _config )
+        :   CumulativeReporterBase( _config ),
+            xml( _config.stream() )
+        {
+            m_reporterPrefs.shouldRedirectStdOut = true;
+            m_reporterPrefs.shouldReportAllAssertions = true;
+        }
+
+    JunitReporter::~JunitReporter() {}
+
+    std::string JunitReporter::getDescription() {
+        return "Reports test results in an XML format that looks like Ant's junitreport target";
+    }
+
+    void JunitReporter::noMatchingTestCases( std::string const& /*spec*/ ) {}
+
+    void JunitReporter::testRunStarting( TestRunInfo const& runInfo )  {
+        CumulativeReporterBase::testRunStarting( runInfo );
+        xml.startElement( "testsuites" );
+    }
+
+    void JunitReporter::testGroupStarting( GroupInfo const& groupInfo ) {
+        suiteTimer.start();
+        stdOutForSuite.clear();
+        stdErrForSuite.clear();
+        unexpectedExceptions = 0;
+        CumulativeReporterBase::testGroupStarting( groupInfo );
+    }
+
+    void JunitReporter::testCaseStarting( TestCaseInfo const& testCaseInfo ) {
+        m_okToFail = testCaseInfo.okToFail();
+    }
+
+    bool JunitReporter::assertionEnded( AssertionStats const& assertionStats ) {
+        if( assertionStats.assertionResult.getResultType() == ResultWas::ThrewException && !m_okToFail )
+            unexpectedExceptions++;
+        return CumulativeReporterBase::assertionEnded( assertionStats );
+    }
+
+    void JunitReporter::testCaseEnded( TestCaseStats const& testCaseStats ) {
+        stdOutForSuite += testCaseStats.stdOut;
+        stdErrForSuite += testCaseStats.stdErr;
+        CumulativeReporterBase::testCaseEnded( testCaseStats );
+    }
+
+    void JunitReporter::testGroupEnded( TestGroupStats const& testGroupStats ) {
+        double suiteTime = suiteTimer.getElapsedSeconds();
+        CumulativeReporterBase::testGroupEnded( testGroupStats );
+        writeGroup( *m_testGroups.back(), suiteTime );
+    }
+
+    void JunitReporter::testRunEndedCumulative() {
+        xml.endElement();
+    }
+
+    void JunitReporter::writeGroup( TestGroupNode const& groupNode, double suiteTime ) {
+        XmlWriter::ScopedElement e = xml.scopedElement( "testsuite" );
+
+        TestGroupStats const& stats = groupNode.value;
+        xml.writeAttribute( "name", stats.groupInfo.name );
+        xml.writeAttribute( "errors", unexpectedExceptions );
+        xml.writeAttribute( "failures", stats.totals.assertions.failed-unexpectedExceptions );
+        xml.writeAttribute( "tests", stats.totals.assertions.total() );
+        xml.writeAttribute( "hostname", "tbd" ); // !TBD
+        if( m_config->showDurations() == ShowDurations::Never )
+            xml.writeAttribute( "time", "" );
+        else
+            xml.writeAttribute( "time", formatDuration( suiteTime ) );
+        xml.writeAttribute( "timestamp", getCurrentTimestamp() );
+
+        // Write properties if there are any
+        if (m_config->hasTestFilters() || m_config->rngSeed() != 0) {
+            auto properties = xml.scopedElement("properties");
+            if (m_config->hasTestFilters()) {
+                xml.scopedElement("property")
+                    .writeAttribute("name", "filters")
+                    .writeAttribute("value", serializeFilters(m_config->getTestsOrTags()));
+            }
+            if (m_config->rngSeed() != 0) {
+                xml.scopedElement("property")
+                    .writeAttribute("name", "random-seed")
+                    .writeAttribute("value", m_config->rngSeed());
+            }
+        }
+
+        // Write test cases
+        for( auto const& child : groupNode.children )
+            writeTestCase( *child );
+
+        xml.scopedElement( "system-out" ).writeText( trim( stdOutForSuite ), XmlFormatting::Newline );
+        xml.scopedElement( "system-err" ).writeText( trim( stdErrForSuite ), XmlFormatting::Newline );
+    }
+
+    void JunitReporter::writeTestCase( TestCaseNode const& testCaseNode ) {
+        TestCaseStats const& stats = testCaseNode.value;
+
+        // All test cases have exactly one section - which represents the
+        // test case itself. That section may have 0-n nested sections
+        assert( testCaseNode.children.size() == 1 );
+        SectionNode const& rootSection = *testCaseNode.children.front();
+
+        std::string className = stats.testInfo.className;
+
+        if( className.empty() ) {
+            className = fileNameTag(stats.testInfo.tags);
+            if ( className.empty() )
+                className = "global";
+        }
+
+        if ( !m_config->name().empty() )
+            className = m_config->name() + "." + className;
+
+        writeSection( className, "", rootSection, stats.testInfo.okToFail() );
+    }
+
+    void JunitReporter::writeSection( std::string const& className,
+                                      std::string const& rootName,
+                                      SectionNode const& sectionNode,
+                                      bool testOkToFail) {
+        std::string name = trim( sectionNode.stats.sectionInfo.name );
+        if( !rootName.empty() )
+            name = rootName + '/' + name;
+
+        if( !sectionNode.assertions.empty() ||
+            !sectionNode.stdOut.empty() ||
+            !sectionNode.stdErr.empty() ) {
+            XmlWriter::ScopedElement e = xml.scopedElement( "testcase" );
+            if( className.empty() ) {
+                xml.writeAttribute( "classname", name );
+                xml.writeAttribute( "name", "root" );
+            }
+            else {
+                xml.writeAttribute( "classname", className );
+                xml.writeAttribute( "name", name );
+            }
+            xml.writeAttribute( "time", formatDuration( sectionNode.stats.durationInSeconds ) );
+            // This is not ideal, but it should be enough to mimic gtest's
+            // junit output.
+            // Ideally the JUnit reporter would also handle `skipTest`
+            // events and write those out appropriately.
+            xml.writeAttribute( "status", "run" );
+
+            if (sectionNode.stats.assertions.failedButOk) {
+                xml.scopedElement("skipped")
+                    .writeAttribute("message", "TEST_CASE tagged with !mayfail");
+            }
+
+            writeAssertions( sectionNode );
+
+            if( !sectionNode.stdOut.empty() )
+                xml.scopedElement( "system-out" ).writeText( trim( sectionNode.stdOut ), XmlFormatting::Newline );
+            if( !sectionNode.stdErr.empty() )
+                xml.scopedElement( "system-err" ).writeText( trim( sectionNode.stdErr ), XmlFormatting::Newline );
+        }
+        for( auto const& childNode : sectionNode.childSections )
+            if( className.empty() )
+                writeSection( name, "", *childNode, testOkToFail );
+            else
+                writeSection( className, name, *childNode, testOkToFail );
+    }
+
+    void JunitReporter::writeAssertions( SectionNode const& sectionNode ) {
+        for( auto const& assertion : sectionNode.assertions )
+            writeAssertion( assertion );
+    }
+
+    void JunitReporter::writeAssertion( AssertionStats const& stats ) {
+        AssertionResult const& result = stats.assertionResult;
+        if( !result.isOk() ) {
+            std::string elementName;
+            switch( result.getResultType() ) {
+                case ResultWas::ThrewException:
+                case ResultWas::FatalErrorCondition:
+                    elementName = "error";
+                    break;
+                case ResultWas::ExplicitFailure:
+                case ResultWas::ExpressionFailed:
+                case ResultWas::DidntThrowException:
+                    elementName = "failure";
+                    break;
+
+                // We should never see these here:
+                case ResultWas::Info:
+                case ResultWas::Warning:
+                case ResultWas::Ok:
+                case ResultWas::Unknown:
+                case ResultWas::FailureBit:
+                case ResultWas::Exception:
+                    elementName = "internalError";
+                    break;
+            }
+
+            XmlWriter::ScopedElement e = xml.scopedElement( elementName );
+
+            xml.writeAttribute( "message", result.getExpression() );
+            xml.writeAttribute( "type", result.getTestMacroName() );
+
+            ReusableStringStream rss;
+            if (stats.totals.assertions.total() > 0) {
+                rss << "FAILED" << ":\n";
+                if (result.hasExpression()) {
+                    rss << "  ";
+                    rss << result.getExpressionInMacro();
+                    rss << '\n';
+                }
+                if (result.hasExpandedExpression()) {
+                    rss << "with expansion:\n";
+                    rss << Column(result.getExpandedExpression()).indent(2) << '\n';
+                }
+            } else {
+                rss << '\n';
+            }
+
+            if( !result.getMessage().empty() )
+                rss << result.getMessage() << '\n';
+            for( auto const& msg : stats.infoMessages )
+                if( msg.type == ResultWas::Info )
+                    rss << msg.message << '\n';
+
+            rss << "at " << result.getSourceInfo();
+            xml.writeText( rss.str(), XmlFormatting::Newline );
+        }
+    }
+
+    CATCH_REGISTER_REPORTER( "junit", JunitReporter )
+
+} // end namespace Catch
+// end catch_reporter_junit.cpp
+// start catch_reporter_listening.cpp
+
+#include <cassert>
+
+namespace Catch {
+
+    ListeningReporter::ListeningReporter() {
+        // We will assume that listeners will always want all assertions
+        m_preferences.shouldReportAllAssertions = true;
+    }
+
+    void ListeningReporter::addListener( IStreamingReporterPtr&& listener ) {
+        m_listeners.push_back( std::move( listener ) );
+    }
+
+    void ListeningReporter::addReporter(IStreamingReporterPtr&& reporter) {
+        assert(!m_reporter && "Listening reporter can wrap only 1 real reporter");
+        m_reporter = std::move( reporter );
+        m_preferences.shouldRedirectStdOut = m_reporter->getPreferences().shouldRedirectStdOut;
+    }
+
+    ReporterPreferences ListeningReporter::getPreferences() const {
+        return m_preferences;
+    }
+
+    std::set<Verbosity> ListeningReporter::getSupportedVerbosities() {
+        return std::set<Verbosity>{ };
+    }
+
+    void ListeningReporter::noMatchingTestCases( std::string const& spec ) {
+        for ( auto const& listener : m_listeners ) {
+            listener->noMatchingTestCases( spec );
+        }
+        m_reporter->noMatchingTestCases( spec );
+    }
+
+    void ListeningReporter::reportInvalidArguments(std::string const&arg){
+        for ( auto const& listener : m_listeners ) {
+            listener->reportInvalidArguments( arg );
+        }
+        m_reporter->reportInvalidArguments( arg );
+    }
+
+#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
+    void ListeningReporter::benchmarkPreparing( std::string const& name ) {
+		for (auto const& listener : m_listeners) {
+			listener->benchmarkPreparing(name);
+		}
+		m_reporter->benchmarkPreparing(name);
+	}
+    void ListeningReporter::benchmarkStarting( BenchmarkInfo const& benchmarkInfo ) {
+        for ( auto const& listener : m_listeners ) {
+            listener->benchmarkStarting( benchmarkInfo );
+        }
+        m_reporter->benchmarkStarting( benchmarkInfo );
+    }
+    void ListeningReporter::benchmarkEnded( BenchmarkStats<> const& benchmarkStats ) {
+        for ( auto const& listener : m_listeners ) {
+            listener->benchmarkEnded( benchmarkStats );
+        }
+        m_reporter->benchmarkEnded( benchmarkStats );
+    }
+
+	void ListeningReporter::benchmarkFailed( std::string const& error ) {
+		for (auto const& listener : m_listeners) {
+			listener->benchmarkFailed(error);
+		}
+		m_reporter->benchmarkFailed(error);
+	}
+#endif // CATCH_CONFIG_ENABLE_BENCHMARKING
+
+    void ListeningReporter::testRunStarting( TestRunInfo const& testRunInfo ) {
+        for ( auto const& listener : m_listeners ) {
+            listener->testRunStarting( testRunInfo );
+        }
+        m_reporter->testRunStarting( testRunInfo );
+    }
+
+    void ListeningReporter::testGroupStarting( GroupInfo const& groupInfo ) {
+        for ( auto const& listener : m_listeners ) {
+            listener->testGroupStarting( groupInfo );
+        }
+        m_reporter->testGroupStarting( groupInfo );
+    }
+
+    void ListeningReporter::testCaseStarting( TestCaseInfo const& testInfo ) {
+        for ( auto const& listener : m_listeners ) {
+            listener->testCaseStarting( testInfo );
+        }
+        m_reporter->testCaseStarting( testInfo );
+    }
+
+    void ListeningReporter::sectionStarting( SectionInfo const& sectionInfo ) {
+        for ( auto const& listener : m_listeners ) {
+            listener->sectionStarting( sectionInfo );
+        }
+        m_reporter->sectionStarting( sectionInfo );
+    }
+
+    void ListeningReporter::assertionStarting( AssertionInfo const& assertionInfo ) {
+        for ( auto const& listener : m_listeners ) {
+            listener->assertionStarting( assertionInfo );
+        }
+        m_reporter->assertionStarting( assertionInfo );
+    }
+
+    // The return value indicates if the messages buffer should be cleared:
+    bool ListeningReporter::assertionEnded( AssertionStats const& assertionStats ) {
+        for( auto const& listener : m_listeners ) {
+            static_cast<void>( listener->assertionEnded( assertionStats ) );
+        }
+        return m_reporter->assertionEnded( assertionStats );
+    }
+
+    void ListeningReporter::sectionEnded( SectionStats const& sectionStats ) {
+        for ( auto const& listener : m_listeners ) {
+            listener->sectionEnded( sectionStats );
+        }
+        m_reporter->sectionEnded( sectionStats );
+    }
+
+    void ListeningReporter::testCaseEnded( TestCaseStats const& testCaseStats ) {
+        for ( auto const& listener : m_listeners ) {
+            listener->testCaseEnded( testCaseStats );
+        }
+        m_reporter->testCaseEnded( testCaseStats );
+    }
+
+    void ListeningReporter::testGroupEnded( TestGroupStats const& testGroupStats ) {
+        for ( auto const& listener : m_listeners ) {
+            listener->testGroupEnded( testGroupStats );
+        }
+        m_reporter->testGroupEnded( testGroupStats );
+    }
+
+    void ListeningReporter::testRunEnded( TestRunStats const& testRunStats ) {
+        for ( auto const& listener : m_listeners ) {
+            listener->testRunEnded( testRunStats );
+        }
+        m_reporter->testRunEnded( testRunStats );
+    }
+
+    void ListeningReporter::skipTest( TestCaseInfo const& testInfo ) {
+        for ( auto const& listener : m_listeners ) {
+            listener->skipTest( testInfo );
+        }
+        m_reporter->skipTest( testInfo );
+    }
+
+    bool ListeningReporter::isMulti() const {
+        return true;
+    }
+
+} // end namespace Catch
+// end catch_reporter_listening.cpp
+// start catch_reporter_xml.cpp
+
+#if defined(_MSC_VER)
+#pragma warning(push)
+#pragma warning(disable:4061) // Not all labels are EXPLICITLY handled in switch
+                              // Note that 4062 (not all labels are handled
+                              // and default is missing) is enabled
+#endif
+
+namespace Catch {
+    XmlReporter::XmlReporter( ReporterConfig const& _config )
+    :   StreamingReporterBase( _config ),
+        m_xml(_config.stream())
+    {
+        m_reporterPrefs.shouldRedirectStdOut = true;
+        m_reporterPrefs.shouldReportAllAssertions = true;
+    }
+
+    XmlReporter::~XmlReporter() = default;
+
+    std::string XmlReporter::getDescription() {
+        return "Reports test results as an XML document";
+    }
+
+    std::string XmlReporter::getStylesheetRef() const {
+        return std::string();
+    }
+
+    void XmlReporter::writeSourceInfo( SourceLineInfo const& sourceInfo ) {
+        m_xml
+            .writeAttribute( "filename", sourceInfo.file )
+            .writeAttribute( "line", sourceInfo.line );
+    }
+
+    void XmlReporter::noMatchingTestCases( std::string const& s ) {
+        StreamingReporterBase::noMatchingTestCases( s );
+    }
+
+    void XmlReporter::testRunStarting( TestRunInfo const& testInfo ) {
+        StreamingReporterBase::testRunStarting( testInfo );
+        std::string stylesheetRef = getStylesheetRef();
+        if( !stylesheetRef.empty() )
+            m_xml.writeStylesheetRef( stylesheetRef );
+        m_xml.startElement( "Catch" );
+        if( !m_config->name().empty() )
+            m_xml.writeAttribute( "name", m_config->name() );
+        if (m_config->testSpec().hasFilters())
+            m_xml.writeAttribute( "filters", serializeFilters( m_config->getTestsOrTags() ) );
+        if( m_config->rngSeed() != 0 )
+            m_xml.scopedElement( "Randomness" )
+                .writeAttribute( "seed", m_config->rngSeed() );
+    }
+
+    void XmlReporter::testGroupStarting( GroupInfo const& groupInfo ) {
+        StreamingReporterBase::testGroupStarting( groupInfo );
+        m_xml.startElement( "Group" )
+            .writeAttribute( "name", groupInfo.name );
+    }
+
+    void XmlReporter::testCaseStarting( TestCaseInfo const& testInfo ) {
+        StreamingReporterBase::testCaseStarting(testInfo);
+        m_xml.startElement( "TestCase" )
+            .writeAttribute( "name", trim( testInfo.name ) )
+            .writeAttribute( "description", testInfo.description )
+            .writeAttribute( "tags", testInfo.tagsAsString() );
+
+        writeSourceInfo( testInfo.lineInfo );
+
+        if ( m_config->showDurations() == ShowDurations::Always )
+            m_testCaseTimer.start();
+        m_xml.ensureTagClosed();
+    }
+
+    void XmlReporter::sectionStarting( SectionInfo const& sectionInfo ) {
+        StreamingReporterBase::sectionStarting( sectionInfo );
+        if( m_sectionDepth++ > 0 ) {
+            m_xml.startElement( "Section" )
+                .writeAttribute( "name", trim( sectionInfo.name ) );
+            writeSourceInfo( sectionInfo.lineInfo );
+            m_xml.ensureTagClosed();
+        }
+    }
+
+    void XmlReporter::assertionStarting( AssertionInfo const& ) { }
+
+    bool XmlReporter::assertionEnded( AssertionStats const& assertionStats ) {
+
+        AssertionResult const& result = assertionStats.assertionResult;
+
+        bool includeResults = m_config->includeSuccessfulResults() || !result.isOk();
+
+        if( includeResults || result.getResultType() == ResultWas::Warning ) {
+            // Print any info messages in <Info> tags.
+            for( auto const& msg : assertionStats.infoMessages ) {
+                if( msg.type == ResultWas::Info && includeResults ) {
+                    m_xml.scopedElement( "Info" )
+                            .writeText( msg.message );
+                } else if ( msg.type == ResultWas::Warning ) {
+                    m_xml.scopedElement( "Warning" )
+                            .writeText( msg.message );
+                }
+            }
+        }
+
+        // Drop out if result was successful but we're not printing them.
+        if( !includeResults && result.getResultType() != ResultWas::Warning )
+            return true;
+
+        // Print the expression if there is one.
+        if( result.hasExpression() ) {
+            m_xml.startElement( "Expression" )
+                .writeAttribute( "success", result.succeeded() )
+                .writeAttribute( "type", result.getTestMacroName() );
+
+            writeSourceInfo( result.getSourceInfo() );
+
+            m_xml.scopedElement( "Original" )
+                .writeText( result.getExpression() );
+            m_xml.scopedElement( "Expanded" )
+                .writeText( result.getExpandedExpression() );
+        }
+
+        // And... Print a result applicable to each result type.
+        switch( result.getResultType() ) {
+            case ResultWas::ThrewException:
+                m_xml.startElement( "Exception" );
+                writeSourceInfo( result.getSourceInfo() );
+                m_xml.writeText( result.getMessage() );
+                m_xml.endElement();
+                break;
+            case ResultWas::FatalErrorCondition:
+                m_xml.startElement( "FatalErrorCondition" );
+                writeSourceInfo( result.getSourceInfo() );
+                m_xml.writeText( result.getMessage() );
+                m_xml.endElement();
+                break;
+            case ResultWas::Info:
+                m_xml.scopedElement( "Info" )
+                    .writeText( result.getMessage() );
+                break;
+            case ResultWas::Warning:
+                // Warning will already have been written
+                break;
+            case ResultWas::ExplicitFailure:
+                m_xml.startElement( "Failure" );
+                writeSourceInfo( result.getSourceInfo() );
+                m_xml.writeText( result.getMessage() );
+                m_xml.endElement();
+                break;
+            default:
+                break;
+        }
+
+        if( result.hasExpression() )
+            m_xml.endElement();
+
+        return true;
+    }
+
+    void XmlReporter::sectionEnded( SectionStats const& sectionStats ) {
+        StreamingReporterBase::sectionEnded( sectionStats );
+        if( --m_sectionDepth > 0 ) {
+            XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResults" );
+            e.writeAttribute( "successes", sectionStats.assertions.passed );
+            e.writeAttribute( "failures", sectionStats.assertions.failed );
+            e.writeAttribute( "expectedFailures", sectionStats.assertions.failedButOk );
+
+            if ( m_config->showDurations() == ShowDurations::Always )
+                e.writeAttribute( "durationInSeconds", sectionStats.durationInSeconds );
+
+            m_xml.endElement();
+        }
+    }
+
+    void XmlReporter::testCaseEnded( TestCaseStats const& testCaseStats ) {
+        StreamingReporterBase::testCaseEnded( testCaseStats );
+        XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResult" );
+        e.writeAttribute( "success", testCaseStats.totals.assertions.allOk() );
+
+        if ( m_config->showDurations() == ShowDurations::Always )
+            e.writeAttribute( "durationInSeconds", m_testCaseTimer.getElapsedSeconds() );
+
+        if( !testCaseStats.stdOut.empty() )
+            m_xml.scopedElement( "StdOut" ).writeText( trim( testCaseStats.stdOut ), XmlFormatting::Newline );
+        if( !testCaseStats.stdErr.empty() )
+            m_xml.scopedElement( "StdErr" ).writeText( trim( testCaseStats.stdErr ), XmlFormatting::Newline );
+
+        m_xml.endElement();
+    }
+
+    void XmlReporter::testGroupEnded( TestGroupStats const& testGroupStats ) {
+        StreamingReporterBase::testGroupEnded( testGroupStats );
+        // TODO: Check testGroupStats.aborting and act accordingly.
+        m_xml.scopedElement( "OverallResults" )
+            .writeAttribute( "successes", testGroupStats.totals.assertions.passed )
+            .writeAttribute( "failures", testGroupStats.totals.assertions.failed )
+            .writeAttribute( "expectedFailures", testGroupStats.totals.assertions.failedButOk );
+        m_xml.scopedElement( "OverallResultsCases")
+            .writeAttribute( "successes", testGroupStats.totals.testCases.passed )
+            .writeAttribute( "failures", testGroupStats.totals.testCases.failed )
+            .writeAttribute( "expectedFailures", testGroupStats.totals.testCases.failedButOk );
+        m_xml.endElement();
+    }
+
+    void XmlReporter::testRunEnded( TestRunStats const& testRunStats ) {
+        StreamingReporterBase::testRunEnded( testRunStats );
+        m_xml.scopedElement( "OverallResults" )
+            .writeAttribute( "successes", testRunStats.totals.assertions.passed )
+            .writeAttribute( "failures", testRunStats.totals.assertions.failed )
+            .writeAttribute( "expectedFailures", testRunStats.totals.assertions.failedButOk );
+        m_xml.scopedElement( "OverallResultsCases")
+            .writeAttribute( "successes", testRunStats.totals.testCases.passed )
+            .writeAttribute( "failures", testRunStats.totals.testCases.failed )
+            .writeAttribute( "expectedFailures", testRunStats.totals.testCases.failedButOk );
+        m_xml.endElement();
+    }
+
+#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
+    void XmlReporter::benchmarkPreparing(std::string const& name) {
+        m_xml.startElement("BenchmarkResults")
+            .writeAttribute("name", name);
+    }
+
+    void XmlReporter::benchmarkStarting(BenchmarkInfo const &info) {
+        m_xml.writeAttribute("samples", info.samples)
+            .writeAttribute("resamples", info.resamples)
+            .writeAttribute("iterations", info.iterations)
+            .writeAttribute("clockResolution", info.clockResolution)
+            .writeAttribute("estimatedDuration", info.estimatedDuration)
+            .writeComment("All values in nano seconds");
+    }
+
+    void XmlReporter::benchmarkEnded(BenchmarkStats<> const& benchmarkStats) {
+        m_xml.startElement("mean")
+            .writeAttribute("value", benchmarkStats.mean.point.count())
+            .writeAttribute("lowerBound", benchmarkStats.mean.lower_bound.count())
+            .writeAttribute("upperBound", benchmarkStats.mean.upper_bound.count())
+            .writeAttribute("ci", benchmarkStats.mean.confidence_interval);
+        m_xml.endElement();
+        m_xml.startElement("standardDeviation")
+            .writeAttribute("value", benchmarkStats.standardDeviation.point.count())
+            .writeAttribute("lowerBound", benchmarkStats.standardDeviation.lower_bound.count())
+            .writeAttribute("upperBound", benchmarkStats.standardDeviation.upper_bound.count())
+            .writeAttribute("ci", benchmarkStats.standardDeviation.confidence_interval);
+        m_xml.endElement();
+        m_xml.startElement("outliers")
+            .writeAttribute("variance", benchmarkStats.outlierVariance)
+            .writeAttribute("lowMild", benchmarkStats.outliers.low_mild)
+            .writeAttribute("lowSevere", benchmarkStats.outliers.low_severe)
+            .writeAttribute("highMild", benchmarkStats.outliers.high_mild)
+            .writeAttribute("highSevere", benchmarkStats.outliers.high_severe);
+        m_xml.endElement();
+        m_xml.endElement();
+    }
+
+    void XmlReporter::benchmarkFailed(std::string const &error) {
+        m_xml.scopedElement("failed").
+            writeAttribute("message", error);
+        m_xml.endElement();
+    }
+#endif // CATCH_CONFIG_ENABLE_BENCHMARKING
+
+    CATCH_REGISTER_REPORTER( "xml", XmlReporter )
+
+} // end namespace Catch
+
+#if defined(_MSC_VER)
+#pragma warning(pop)
+#endif
+// end catch_reporter_xml.cpp
+
+namespace Catch {
+    LeakDetector leakDetector;
+}
+
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+
+// end catch_impl.hpp
+#endif
+
+#ifdef CATCH_CONFIG_MAIN
+// start catch_default_main.hpp
+
+#ifndef __OBJC__
+
+#if defined(CATCH_CONFIG_WCHAR) && defined(CATCH_PLATFORM_WINDOWS) && defined(_UNICODE) && !defined(DO_NOT_USE_WMAIN)
+// Standard C/C++ Win32 Unicode wmain entry point
+extern "C" int wmain (int argc, wchar_t * argv[], wchar_t * []) {
+#else
+// Standard C/C++ main entry point
+int main (int argc, char * argv[]) {
+#endif
+
+    return Catch::Session().run( argc, argv );
+}
+
+#else // __OBJC__
+
+// Objective-C entry point
+int main (int argc, char * const argv[]) {
+#if !CATCH_ARC_ENABLED
+    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
+#endif
+
+    Catch::registerTestMethods();
+    int result = Catch::Session().run( argc, (char**)argv );
+
+#if !CATCH_ARC_ENABLED
+    [pool drain];
+#endif
+
+    return result;
+}
+
+#endif // __OBJC__
+
+// end catch_default_main.hpp
+#endif
+
+#if !defined(CATCH_CONFIG_IMPL_ONLY)
+
+#ifdef CLARA_CONFIG_MAIN_NOT_DEFINED
+#  undef CLARA_CONFIG_MAIN
+#endif
+
+#if !defined(CATCH_CONFIG_DISABLE)
+//////
+// If this config identifier is defined then all CATCH macros are prefixed with CATCH_
+#ifdef CATCH_CONFIG_PREFIX_ALL
+
+#define CATCH_REQUIRE( ... ) INTERNAL_CATCH_TEST( "CATCH_REQUIRE", Catch::ResultDisposition::Normal, __VA_ARGS__ )
+#define CATCH_REQUIRE_FALSE( ... ) INTERNAL_CATCH_TEST( "CATCH_REQUIRE_FALSE", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, __VA_ARGS__ )
+
+#define CATCH_REQUIRE_THROWS( ... ) INTERNAL_CATCH_THROWS( "CATCH_REQUIRE_THROWS", Catch::ResultDisposition::Normal, __VA_ARGS__ )
+#define CATCH_REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CATCH_REQUIRE_THROWS_AS", exceptionType, Catch::ResultDisposition::Normal, expr )
+#define CATCH_REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "CATCH_REQUIRE_THROWS_WITH", Catch::ResultDisposition::Normal, matcher, expr )
+#if !defined(CATCH_CONFIG_DISABLE_MATCHERS)
+#define CATCH_REQUIRE_THROWS_MATCHES( expr, exceptionType, matcher ) INTERNAL_CATCH_THROWS_MATCHES( "CATCH_REQUIRE_THROWS_MATCHES", exceptionType, Catch::ResultDisposition::Normal, matcher, expr )
+#endif// CATCH_CONFIG_DISABLE_MATCHERS
+#define CATCH_REQUIRE_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "CATCH_REQUIRE_NOTHROW", Catch::ResultDisposition::Normal, __VA_ARGS__ )
+
+#define CATCH_CHECK( ... ) INTERNAL_CATCH_TEST( "CATCH_CHECK", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
+#define CATCH_CHECK_FALSE( ... ) INTERNAL_CATCH_TEST( "CATCH_CHECK_FALSE", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, __VA_ARGS__ )
+#define CATCH_CHECKED_IF( ... ) INTERNAL_CATCH_IF( "CATCH_CHECKED_IF", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
+#define CATCH_CHECKED_ELSE( ... ) INTERNAL_CATCH_ELSE( "CATCH_CHECKED_ELSE", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
+#define CATCH_CHECK_NOFAIL( ... ) INTERNAL_CATCH_TEST( "CATCH_CHECK_NOFAIL", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, __VA_ARGS__ )
+
+#define CATCH_CHECK_THROWS( ... )  INTERNAL_CATCH_THROWS( "CATCH_CHECK_THROWS", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
+#define CATCH_CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CATCH_CHECK_THROWS_AS", exceptionType, Catch::ResultDisposition::ContinueOnFailure, expr )
+#define CATCH_CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "CATCH_CHECK_THROWS_WITH", Catch::ResultDisposition::ContinueOnFailure, matcher, expr )
+#if !defined(CATCH_CONFIG_DISABLE_MATCHERS)
+#define CATCH_CHECK_THROWS_MATCHES( expr, exceptionType, matcher ) INTERNAL_CATCH_THROWS_MATCHES( "CATCH_CHECK_THROWS_MATCHES", exceptionType, Catch::ResultDisposition::ContinueOnFailure, matcher, expr )
+#endif // CATCH_CONFIG_DISABLE_MATCHERS
+#define CATCH_CHECK_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "CATCH_CHECK_NOTHROW", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
+
+#if !defined(CATCH_CONFIG_DISABLE_MATCHERS)
+#define CATCH_CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "CATCH_CHECK_THAT", matcher, Catch::ResultDisposition::ContinueOnFailure, arg )
+
+#define CATCH_REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "CATCH_REQUIRE_THAT", matcher, Catch::ResultDisposition::Normal, arg )
+#endif // CATCH_CONFIG_DISABLE_MATCHERS
+
+#define CATCH_INFO( msg ) INTERNAL_CATCH_INFO( "CATCH_INFO", msg )
+#define CATCH_UNSCOPED_INFO( msg ) INTERNAL_CATCH_UNSCOPED_INFO( "CATCH_UNSCOPED_INFO", msg )
+#define CATCH_WARN( msg ) INTERNAL_CATCH_MSG( "CATCH_WARN", Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, msg )
+#define CATCH_CAPTURE( ... ) INTERNAL_CATCH_CAPTURE( INTERNAL_CATCH_UNIQUE_NAME(capturer), "CATCH_CAPTURE",__VA_ARGS__ )
+
+#define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ )
+#define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ )
+#define CATCH_METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ )
+#define CATCH_REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ )
+#define CATCH_SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ )
+#define CATCH_DYNAMIC_SECTION( ... ) INTERNAL_CATCH_DYNAMIC_SECTION( __VA_ARGS__ )
+#define CATCH_FAIL( ... ) INTERNAL_CATCH_MSG( "CATCH_FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, __VA_ARGS__ )
+#define CATCH_FAIL_CHECK( ... ) INTERNAL_CATCH_MSG( "CATCH_FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
+#define CATCH_SUCCEED( ... ) INTERNAL_CATCH_MSG( "CATCH_SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
+
+#define CATCH_ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE()
+
+#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
+#define CATCH_TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ )
+#define CATCH_TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG( __VA_ARGS__ )
+#define CATCH_TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
+#define CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ )
+#define CATCH_TEMPLATE_PRODUCT_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE( __VA_ARGS__ )
+#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( __VA_ARGS__ )
+#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, __VA_ARGS__ )
+#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ )
+#else
+#define CATCH_TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ ) )
+#define CATCH_TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG( __VA_ARGS__ ) )
+#define CATCH_TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ ) )
+#define CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ ) )
+#define CATCH_TEMPLATE_PRODUCT_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE( __VA_ARGS__ ) )
+#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( __VA_ARGS__ ) )
+#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, __VA_ARGS__ ) )
+#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ ) )
+#endif
+
+#if !defined(CATCH_CONFIG_RUNTIME_STATIC_REQUIRE)
+#define CATCH_STATIC_REQUIRE( ... )       static_assert(   __VA_ARGS__ ,      #__VA_ARGS__ );     CATCH_SUCCEED( #__VA_ARGS__ )
+#define CATCH_STATIC_REQUIRE_FALSE( ... ) static_assert( !(__VA_ARGS__), "!(" #__VA_ARGS__ ")" ); CATCH_SUCCEED( #__VA_ARGS__ )
+#else
+#define CATCH_STATIC_REQUIRE( ... )       CATCH_REQUIRE( __VA_ARGS__ )
+#define CATCH_STATIC_REQUIRE_FALSE( ... ) CATCH_REQUIRE_FALSE( __VA_ARGS__ )
+#endif
+
+// "BDD-style" convenience wrappers
+#define CATCH_SCENARIO( ... ) CATCH_TEST_CASE( "Scenario: " __VA_ARGS__ )
+#define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ )
+#define CATCH_GIVEN( desc )     INTERNAL_CATCH_DYNAMIC_SECTION( "    Given: " << desc )
+#define CATCH_AND_GIVEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( "And given: " << desc )
+#define CATCH_WHEN( desc )      INTERNAL_CATCH_DYNAMIC_SECTION( "     When: " << desc )
+#define CATCH_AND_WHEN( desc )  INTERNAL_CATCH_DYNAMIC_SECTION( " And when: " << desc )
+#define CATCH_THEN( desc )      INTERNAL_CATCH_DYNAMIC_SECTION( "     Then: " << desc )
+#define CATCH_AND_THEN( desc )  INTERNAL_CATCH_DYNAMIC_SECTION( "      And: " << desc )
+
+#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
+#define CATCH_BENCHMARK(...) \
+    INTERNAL_CATCH_BENCHMARK(INTERNAL_CATCH_UNIQUE_NAME(____C_A_T_C_H____B_E_N_C_H____), INTERNAL_CATCH_GET_1_ARG(__VA_ARGS__,,), INTERNAL_CATCH_GET_2_ARG(__VA_ARGS__,,))
+#define CATCH_BENCHMARK_ADVANCED(name) \
+    INTERNAL_CATCH_BENCHMARK_ADVANCED(INTERNAL_CATCH_UNIQUE_NAME(____C_A_T_C_H____B_E_N_C_H____), name)
+#endif // CATCH_CONFIG_ENABLE_BENCHMARKING
+
+// If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required
+#else
+
+#define REQUIRE( ... ) INTERNAL_CATCH_TEST( "REQUIRE", Catch::ResultDisposition::Normal, __VA_ARGS__  )
+#define REQUIRE_FALSE( ... ) INTERNAL_CATCH_TEST( "REQUIRE_FALSE", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, __VA_ARGS__ )
+
+#define REQUIRE_THROWS( ... ) INTERNAL_CATCH_THROWS( "REQUIRE_THROWS", Catch::ResultDisposition::Normal, __VA_ARGS__ )
+#define REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "REQUIRE_THROWS_AS", exceptionType, Catch::ResultDisposition::Normal, expr )
+#define REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "REQUIRE_THROWS_WITH", Catch::ResultDisposition::Normal, matcher, expr )
+#if !defined(CATCH_CONFIG_DISABLE_MATCHERS)
+#define REQUIRE_THROWS_MATCHES( expr, exceptionType, matcher ) INTERNAL_CATCH_THROWS_MATCHES( "REQUIRE_THROWS_MATCHES", exceptionType, Catch::ResultDisposition::Normal, matcher, expr )
+#endif // CATCH_CONFIG_DISABLE_MATCHERS
+#define REQUIRE_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "REQUIRE_NOTHROW", Catch::ResultDisposition::Normal, __VA_ARGS__ )
+
+#define CHECK( ... ) INTERNAL_CATCH_TEST( "CHECK", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
+#define CHECK_FALSE( ... ) INTERNAL_CATCH_TEST( "CHECK_FALSE", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, __VA_ARGS__ )
+#define CHECKED_IF( ... ) INTERNAL_CATCH_IF( "CHECKED_IF", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
+#define CHECKED_ELSE( ... ) INTERNAL_CATCH_ELSE( "CHECKED_ELSE", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
+#define CHECK_NOFAIL( ... ) INTERNAL_CATCH_TEST( "CHECK_NOFAIL", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, __VA_ARGS__ )
+
+#define CHECK_THROWS( ... )  INTERNAL_CATCH_THROWS( "CHECK_THROWS", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
+#define CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CHECK_THROWS_AS", exceptionType, Catch::ResultDisposition::ContinueOnFailure, expr )
+#define CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "CHECK_THROWS_WITH", Catch::ResultDisposition::ContinueOnFailure, matcher, expr )
+#if !defined(CATCH_CONFIG_DISABLE_MATCHERS)
+#define CHECK_THROWS_MATCHES( expr, exceptionType, matcher ) INTERNAL_CATCH_THROWS_MATCHES( "CHECK_THROWS_MATCHES", exceptionType, Catch::ResultDisposition::ContinueOnFailure, matcher, expr )
+#endif // CATCH_CONFIG_DISABLE_MATCHERS
+#define CHECK_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "CHECK_NOTHROW", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
+
+#if !defined(CATCH_CONFIG_DISABLE_MATCHERS)
+#define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "CHECK_THAT", matcher, Catch::ResultDisposition::ContinueOnFailure, arg )
+
+#define REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "REQUIRE_THAT", matcher, Catch::ResultDisposition::Normal, arg )
+#endif // CATCH_CONFIG_DISABLE_MATCHERS
+
+#define INFO( msg ) INTERNAL_CATCH_INFO( "INFO", msg )
+#define UNSCOPED_INFO( msg ) INTERNAL_CATCH_UNSCOPED_INFO( "UNSCOPED_INFO", msg )
+#define WARN( msg ) INTERNAL_CATCH_MSG( "WARN", Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, msg )
+#define CAPTURE( ... ) INTERNAL_CATCH_CAPTURE( INTERNAL_CATCH_UNIQUE_NAME(capturer), "CAPTURE",__VA_ARGS__ )
+
+#define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ )
+#define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ )
+#define METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ )
+#define REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ )
+#define SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ )
+#define DYNAMIC_SECTION( ... ) INTERNAL_CATCH_DYNAMIC_SECTION( __VA_ARGS__ )
+#define FAIL( ... ) INTERNAL_CATCH_MSG( "FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, __VA_ARGS__ )
+#define FAIL_CHECK( ... ) INTERNAL_CATCH_MSG( "FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
+#define SUCCEED( ... ) INTERNAL_CATCH_MSG( "SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
+#define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE()
+
+#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
+#define TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ )
+#define TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG( __VA_ARGS__ )
+#define TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
+#define TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ )
+#define TEMPLATE_PRODUCT_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE( __VA_ARGS__ )
+#define TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( __VA_ARGS__ )
+#define TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, __VA_ARGS__ )
+#define TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ )
+#define TEMPLATE_LIST_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE(__VA_ARGS__)
+#define TEMPLATE_LIST_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD( className, __VA_ARGS__ )
+#else
+#define TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ ) )
+#define TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG( __VA_ARGS__ ) )
+#define TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ ) )
+#define TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ ) )
+#define TEMPLATE_PRODUCT_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE( __VA_ARGS__ ) )
+#define TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( __VA_ARGS__ ) )
+#define TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, __VA_ARGS__ ) )
+#define TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ ) )
+#define TEMPLATE_LIST_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE( __VA_ARGS__ ) )
+#define TEMPLATE_LIST_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD( className, __VA_ARGS__ ) )
+#endif
+
+#if !defined(CATCH_CONFIG_RUNTIME_STATIC_REQUIRE)
+#define STATIC_REQUIRE( ... )       static_assert(   __VA_ARGS__,  #__VA_ARGS__ ); SUCCEED( #__VA_ARGS__ )
+#define STATIC_REQUIRE_FALSE( ... ) static_assert( !(__VA_ARGS__), "!(" #__VA_ARGS__ ")" ); SUCCEED( "!(" #__VA_ARGS__ ")" )
+#else
+#define STATIC_REQUIRE( ... )       REQUIRE( __VA_ARGS__ )
+#define STATIC_REQUIRE_FALSE( ... ) REQUIRE_FALSE( __VA_ARGS__ )
+#endif
+
+#endif
+
+#define CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature )
+
+// "BDD-style" convenience wrappers
+#define SCENARIO( ... ) TEST_CASE( "Scenario: " __VA_ARGS__ )
+#define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ )
+
+#define GIVEN( desc )     INTERNAL_CATCH_DYNAMIC_SECTION( "    Given: " << desc )
+#define AND_GIVEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( "And given: " << desc )
+#define WHEN( desc )      INTERNAL_CATCH_DYNAMIC_SECTION( "     When: " << desc )
+#define AND_WHEN( desc )  INTERNAL_CATCH_DYNAMIC_SECTION( " And when: " << desc )
+#define THEN( desc )      INTERNAL_CATCH_DYNAMIC_SECTION( "     Then: " << desc )
+#define AND_THEN( desc )  INTERNAL_CATCH_DYNAMIC_SECTION( "      And: " << desc )
+
+#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
+#define BENCHMARK(...) \
+    INTERNAL_CATCH_BENCHMARK(INTERNAL_CATCH_UNIQUE_NAME(____C_A_T_C_H____B_E_N_C_H____), INTERNAL_CATCH_GET_1_ARG(__VA_ARGS__,,), INTERNAL_CATCH_GET_2_ARG(__VA_ARGS__,,))
+#define BENCHMARK_ADVANCED(name) \
+    INTERNAL_CATCH_BENCHMARK_ADVANCED(INTERNAL_CATCH_UNIQUE_NAME(____C_A_T_C_H____B_E_N_C_H____), name)
+#endif // CATCH_CONFIG_ENABLE_BENCHMARKING
+
+using Catch::Detail::Approx;
+
+#else // CATCH_CONFIG_DISABLE
+
+//////
+// If this config identifier is defined then all CATCH macros are prefixed with CATCH_
+#ifdef CATCH_CONFIG_PREFIX_ALL
+
+#define CATCH_REQUIRE( ... )        (void)(0)
+#define CATCH_REQUIRE_FALSE( ... )  (void)(0)
+
+#define CATCH_REQUIRE_THROWS( ... ) (void)(0)
+#define CATCH_REQUIRE_THROWS_AS( expr, exceptionType ) (void)(0)
+#define CATCH_REQUIRE_THROWS_WITH( expr, matcher )     (void)(0)
+#if !defined(CATCH_CONFIG_DISABLE_MATCHERS)
+#define CATCH_REQUIRE_THROWS_MATCHES( expr, exceptionType, matcher ) (void)(0)
+#endif// CATCH_CONFIG_DISABLE_MATCHERS
+#define CATCH_REQUIRE_NOTHROW( ... ) (void)(0)
+
+#define CATCH_CHECK( ... )         (void)(0)
+#define CATCH_CHECK_FALSE( ... )   (void)(0)
+#define CATCH_CHECKED_IF( ... )    if (__VA_ARGS__)
+#define CATCH_CHECKED_ELSE( ... )  if (!(__VA_ARGS__))
+#define CATCH_CHECK_NOFAIL( ... )  (void)(0)
+
+#define CATCH_CHECK_THROWS( ... )  (void)(0)
+#define CATCH_CHECK_THROWS_AS( expr, exceptionType ) (void)(0)
+#define CATCH_CHECK_THROWS_WITH( expr, matcher )     (void)(0)
+#if !defined(CATCH_CONFIG_DISABLE_MATCHERS)
+#define CATCH_CHECK_THROWS_MATCHES( expr, exceptionType, matcher ) (void)(0)
+#endif // CATCH_CONFIG_DISABLE_MATCHERS
+#define CATCH_CHECK_NOTHROW( ... ) (void)(0)
+
+#if !defined(CATCH_CONFIG_DISABLE_MATCHERS)
+#define CATCH_CHECK_THAT( arg, matcher )   (void)(0)
+
+#define CATCH_REQUIRE_THAT( arg, matcher ) (void)(0)
+#endif // CATCH_CONFIG_DISABLE_MATCHERS
+
+#define CATCH_INFO( msg )          (void)(0)
+#define CATCH_UNSCOPED_INFO( msg ) (void)(0)
+#define CATCH_WARN( msg )          (void)(0)
+#define CATCH_CAPTURE( msg )       (void)(0)
+
+#define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ))
+#define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ))
+#define CATCH_METHOD_AS_TEST_CASE( method, ... )
+#define CATCH_REGISTER_TEST_CASE( Function, ... ) (void)(0)
+#define CATCH_SECTION( ... )
+#define CATCH_DYNAMIC_SECTION( ... )
+#define CATCH_FAIL( ... ) (void)(0)
+#define CATCH_FAIL_CHECK( ... ) (void)(0)
+#define CATCH_SUCCEED( ... ) (void)(0)
+
+#define CATCH_ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ))
+
+#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
+#define CATCH_TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(__VA_ARGS__)
+#define CATCH_TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG_NO_REGISTRATION(__VA_ARGS__)
+#define CATCH_TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(className, __VA_ARGS__)
+#define CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG_NO_REGISTRATION(className, __VA_ARGS__ )
+#define CATCH_TEMPLATE_PRODUCT_TEST_CASE( ... ) CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ )
+#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ )
+#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
+#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
+#else
+#define CATCH_TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(__VA_ARGS__) )
+#define CATCH_TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG_NO_REGISTRATION(__VA_ARGS__) )
+#define CATCH_TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(className, __VA_ARGS__ ) )
+#define CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG_NO_REGISTRATION(className, __VA_ARGS__ ) )
+#define CATCH_TEMPLATE_PRODUCT_TEST_CASE( ... ) CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ )
+#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ )
+#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
+#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
+#endif
+
+// "BDD-style" convenience wrappers
+#define CATCH_SCENARIO( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ))
+#define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), className )
+#define CATCH_GIVEN( desc )
+#define CATCH_AND_GIVEN( desc )
+#define CATCH_WHEN( desc )
+#define CATCH_AND_WHEN( desc )
+#define CATCH_THEN( desc )
+#define CATCH_AND_THEN( desc )
+
+#define CATCH_STATIC_REQUIRE( ... )       (void)(0)
+#define CATCH_STATIC_REQUIRE_FALSE( ... ) (void)(0)
+
+// If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required
+#else
+
+#define REQUIRE( ... )       (void)(0)
+#define REQUIRE_FALSE( ... ) (void)(0)
+
+#define REQUIRE_THROWS( ... ) (void)(0)
+#define REQUIRE_THROWS_AS( expr, exceptionType ) (void)(0)
+#define REQUIRE_THROWS_WITH( expr, matcher ) (void)(0)
+#if !defined(CATCH_CONFIG_DISABLE_MATCHERS)
+#define REQUIRE_THROWS_MATCHES( expr, exceptionType, matcher ) (void)(0)
+#endif // CATCH_CONFIG_DISABLE_MATCHERS
+#define REQUIRE_NOTHROW( ... ) (void)(0)
+
+#define CHECK( ... ) (void)(0)
+#define CHECK_FALSE( ... ) (void)(0)
+#define CHECKED_IF( ... ) if (__VA_ARGS__)
+#define CHECKED_ELSE( ... ) if (!(__VA_ARGS__))
+#define CHECK_NOFAIL( ... ) (void)(0)
+
+#define CHECK_THROWS( ... )  (void)(0)
+#define CHECK_THROWS_AS( expr, exceptionType ) (void)(0)
+#define CHECK_THROWS_WITH( expr, matcher ) (void)(0)
+#if !defined(CATCH_CONFIG_DISABLE_MATCHERS)
+#define CHECK_THROWS_MATCHES( expr, exceptionType, matcher ) (void)(0)
+#endif // CATCH_CONFIG_DISABLE_MATCHERS
+#define CHECK_NOTHROW( ... ) (void)(0)
+
+#if !defined(CATCH_CONFIG_DISABLE_MATCHERS)
+#define CHECK_THAT( arg, matcher ) (void)(0)
+
+#define REQUIRE_THAT( arg, matcher ) (void)(0)
+#endif // CATCH_CONFIG_DISABLE_MATCHERS
+
+#define INFO( msg ) (void)(0)
+#define UNSCOPED_INFO( msg ) (void)(0)
+#define WARN( msg ) (void)(0)
+#define CAPTURE( msg ) (void)(0)
+
+#define TEST_CASE( ... )  INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ))
+#define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ))
+#define METHOD_AS_TEST_CASE( method, ... )
+#define REGISTER_TEST_CASE( Function, ... ) (void)(0)
+#define SECTION( ... )
+#define DYNAMIC_SECTION( ... )
+#define FAIL( ... ) (void)(0)
+#define FAIL_CHECK( ... ) (void)(0)
+#define SUCCEED( ... ) (void)(0)
+#define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ))
+
+#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
+#define TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(__VA_ARGS__)
+#define TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG_NO_REGISTRATION(__VA_ARGS__)
+#define TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(className, __VA_ARGS__)
+#define TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG_NO_REGISTRATION(className, __VA_ARGS__ )
+#define TEMPLATE_PRODUCT_TEST_CASE( ... ) TEMPLATE_TEST_CASE( __VA_ARGS__ )
+#define TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) TEMPLATE_TEST_CASE( __VA_ARGS__ )
+#define TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
+#define TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
+#else
+#define TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(__VA_ARGS__) )
+#define TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG_NO_REGISTRATION(__VA_ARGS__) )
+#define TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(className, __VA_ARGS__ ) )
+#define TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG_NO_REGISTRATION(className, __VA_ARGS__ ) )
+#define TEMPLATE_PRODUCT_TEST_CASE( ... ) TEMPLATE_TEST_CASE( __VA_ARGS__ )
+#define TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) TEMPLATE_TEST_CASE( __VA_ARGS__ )
+#define TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
+#define TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
+#endif
+
+#define STATIC_REQUIRE( ... )       (void)(0)
+#define STATIC_REQUIRE_FALSE( ... ) (void)(0)
+
+#endif
+
+#define CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION_NO_REG( INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ), signature )
+
+// "BDD-style" convenience wrappers
+#define SCENARIO( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ) )
+#define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), className )
+
+#define GIVEN( desc )
+#define AND_GIVEN( desc )
+#define WHEN( desc )
+#define AND_WHEN( desc )
+#define THEN( desc )
+#define AND_THEN( desc )
+
+using Catch::Detail::Approx;
+
+#endif
+
+#endif // ! CATCH_CONFIG_IMPL_ONLY
+
+// start catch_reenable_warnings.h
+
+
+#ifdef __clang__
+#    ifdef __ICC // icpc defines the __clang__ macro
+#        pragma warning(pop)
+#    else
+#        pragma clang diagnostic pop
+#    endif
+#elif defined __GNUC__
+#    pragma GCC diagnostic pop
+#endif
+
+// end catch_reenable_warnings.h
+// end catch.hpp
+#endif // TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED
+
diff --git a/src/hs/Main.hs b/src/hs/Main.hs
new file mode 100644
--- /dev/null
+++ b/src/hs/Main.hs
@@ -0,0 +1,6 @@
+module Main where
+
+import Sound.Tidal.Link (hello)
+
+main :: IO ()
+main = hello
diff --git a/src/hs/Sound/Tidal/Link.hsc b/src/hs/Sound/Tidal/Link.hsc
new file mode 100644
--- /dev/null
+++ b/src/hs/Sound/Tidal/Link.hsc
@@ -0,0 +1,139 @@
+{-# LANGUAGE ForeignFunctionInterface #-}
+
+module Sound.Tidal.Link where
+
+#include "abl_link.h"
+
+import Foreign
+import Foreign.C.Types
+import Data.Int()
+
+data AbletonLinkImpl
+data SessionStateImpl
+
+newtype AbletonLink = AbletonLink (Ptr AbletonLinkImpl)
+newtype SessionState = SessionState (Ptr SessionStateImpl)
+
+instance Show AbletonLink where
+  show _ = "-unshowable-"
+
+instance Show SessionState where
+  show _ = "-unshowable-"
+
+type Beat    = CDouble
+type BPM     = CDouble
+type Micros  = Int64
+type Quantum = CDouble
+
+instance Storable AbletonLink where
+  alignment _ = #{alignment abl_link}
+  sizeOf    _ = #{size abl_link}
+  peek ptr = do
+    impl <- #{peek abl_link,impl} ptr
+    return (AbletonLink impl)
+  poke ptr (AbletonLink impl) = do
+    #{poke abl_link,impl} ptr impl
+
+instance Storable SessionState where
+  alignment _ = #{alignment abl_link_session_state}
+  sizeOf    _ = #{size abl_link_session_state}
+  peek ptr = do
+    impl <- #{peek abl_link_session_state,impl} ptr
+    return (SessionState impl)
+  poke ptr (SessionState impl) = do
+    #{poke abl_link_session_state,impl} ptr impl
+
+foreign import ccall "abl_link.h abl_link_create"
+  create :: BPM -> IO AbletonLink
+
+foreign import ccall "abl_link.h abl_link_enable"
+  abl_link_enable :: AbletonLink -> CBool -> IO ()
+
+setEnabled :: Bool -> AbletonLink -> IO ()
+setEnabled True al = abl_link_enable al (CBool 1)
+setEnabled False al = abl_link_enable al (CBool 0)
+
+enable :: AbletonLink -> IO ()
+enable = setEnabled True
+
+disable :: AbletonLink -> IO ()
+disable = setEnabled False
+
+foreign import ccall "abl_link.h abl_link_create_session_state"
+  createSessionState :: IO SessionState
+
+foreign import ccall "abl_link.h abl_link_capture_app_session_state"
+  captureAppSessionState :: AbletonLink -> SessionState -> IO ()
+
+createAndCaptureAppSessionState :: AbletonLink -> IO SessionState
+createAndCaptureAppSessionState al = do
+  sessionState <- createSessionState
+  captureAppSessionState al sessionState
+  return sessionState
+
+foreign import ccall "abl_link.h abl_link_commit_app_session_state"
+  commitAppSessionState :: AbletonLink -> SessionState -> IO ()
+
+foreign import ccall "abl_link.h abl_link_destroy_session_state"
+  destroySessionState :: SessionState -> IO ()
+
+commitAndDestroyAppSessionState :: AbletonLink -> SessionState -> IO ()
+commitAndDestroyAppSessionState al ss = do
+  commitAppSessionState al ss
+  destroySessionState ss
+
+foreign import ccall "abl_link.h abl_link_clock_micros"
+  clock :: AbletonLink -> IO Micros
+
+foreign import ccall "abl_link.h abl_link_beat_at_time"
+  beatAtTime :: SessionState -> Micros -> Quantum -> IO Beat
+
+foreign import ccall "abl_link.h abl_link_time_at_beat"
+  timeAtBeat :: SessionState -> Beat -> Quantum -> IO Micros
+
+foreign import ccall "abl_link.h abl_link_tempo"
+  getTempo :: SessionState -> IO BPM
+
+foreign import ccall "abl_link.h abl_link_set_tempo"
+  setTempo :: SessionState -> BPM -> Micros -> IO ()
+
+foreign import ccall "abl_link.h abl_link_request_beat_at_time"
+  requestBeatAtTime :: SessionState -> Beat -> Micros -> Quantum -> IO ()
+
+foreign import ccall "abl_link.h abl_link_force_beat_at_time"
+  forceBeatAtTime :: SessionState -> Beat -> Micros -> Quantum -> IO ()
+
+-- |Test
+hello :: IO ()
+hello = do
+    print "hello"
+    link <- create 88
+    print "Created link"
+    _ <- getLine
+    print "gotline"
+    now <- clock link
+    print $ "Now: " ++ show now
+    print "gotline"
+    enable link
+    print "Link enabled"
+    _ <- getLine
+    print "gotline"
+    sessionState <- createSessionState
+    print "Created sessionState"
+    _ <- getLine
+    print "gotline"
+    captureAppSessionState link sessionState
+    _line_1 <- getLine
+    print "gotline"
+    setTempo sessionState 130 now
+    beat <- beatAtTime sessionState now 1
+    print $ "beat: " ++ show beat
+    _line_2 <- getLine
+    print "gotline"
+    now' <- clock link
+    print $ "Now': " ++ show now'
+    beat' <- beatAtTime sessionState now' 1
+    print $ "beat': " ++ show beat'
+    commitAndDestroyAppSessionState link sessionState
+    _line_3 <- getLine
+    print $ "done"
diff --git a/tidal-link.cabal b/tidal-link.cabal
new file mode 100644
--- /dev/null
+++ b/tidal-link.cabal
@@ -0,0 +1,87 @@
+cabal-version:       2.4
+name:                tidal-link
+version:             1.0
+synopsis:            Ableton Link integration for Tidal
+-- description:
+homepage:            http://tidalcycles.org/
+license:             GPL-3.0-only
+license-file:        LICENSE
+author:              Pierre Krafft
+maintainer:          Pierre Krafft <kpierre@outlook.com>, Alex McLean <alex@slab.org>
+Stability:           Experimental
+Copyright:           (c) Pierre Krafft and contributors, 2021
+category:            Sound
+build-type:          Simple
+tested-with:         GHC == 9.2.4
+
+extra-source-files:
+  README.md
+  link/**/*.hpp
+  link/**/*.ipp
+  link/**/*.h
+
+description: Ableton Link integration for Tidal, to let Tidal sync with external clocks
+
+library
+  ghc-options: -Wall
+  hs-source-dirs: src/hs
+
+  default-language:    Haskell2010
+
+  Exposed-modules:     Sound.Tidal.Link
+
+  Build-depends:
+      base >=4.8 && <5
+
+  if os(windows)
+    if impl(ghc >= 9.4.0)
+      extra-libraries:
+          c++
+          iphlpapi
+          winmm
+          ws2_32
+    else
+      extra-libraries:
+          stdc++
+          iphlpapi
+          winmm
+          ws2_32
+    cxx-options:
+      -DLINK_PLATFORM_WINDOWS=1 -Wno-multichar -Wno-subobject-linkage
+    cxx-sources: link/extensions/abl_link/src/abl_link.cpp
+  elif os(darwin)
+    extra-libraries:
+        stdc++
+    cxx-options:
+      -DLINK_PLATFORM_MACOSX=1 -std=c++14 -Wno-multichar -Wno-subobject-linkage
+    cxx-sources: link/extensions/abl_link/src/abl_link.cpp
+  else
+    extra-libraries:
+        stdc++
+    cxx-options:
+      -DLINK_PLATFORM_LINUX=1 -std=c++14 -Wno-multichar -Wno-subobject-linkage
+    cxx-sources: link/extensions/abl_link/src/abl_link.cpp
+
+  Build-depends:
+      base >=4.8 && <5
+
+  include-dirs:
+    link/include
+    link/modules/asio-standalone/asio/include
+    link/extensions/abl_link/include
+
+source-repository head
+  type:     git
+  location: https://github.com/tidalcycles/Tidal
+
+executable linktest
+  ghc-options: -Wall
+  hs-source-dirs:
+                 src/hs
+  main-is: Main.hs
+
+  default-language:    Haskell2010
+
+  Build-depends:
+      base >=4.8 && <5,
+      tidal-link
