[
  {
    "path": ".gitignore",
    "content": "### Gradle ###\n.gradle\n/build/\n\n# Ignore Gradle GUI config\ngradle-app.setting\n\n# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)\n!gradle-wrapper.jar\n\n# Cache of project\n.gradletasknamecache\n\n# # Work around https://youtrack.jetbrains.com/issue/IDEA-116898\n# gradle/wrapper/gradle-wrapper.propertiesgradletasknamecache\n\n\n### IntelliJ IDEA ###\n\n.idea/\n\n## File-based project format:\n*.iws\n\n## Plugin-specific files:\n\n# IntelliJ\n/out/\n\n# mpeltonen/sbt-idea plugin\n.idea_modules/\n\n# JIRA plugin\natlassian-ide-plugin.xml\n\n# Crashlytics plugin (for Android Studio and IntelliJ)\ncom_crashlytics_export_strings.xml\ncrashlytics.properties\ncrashlytics-build.properties\nfabric.properties\n"
  },
  {
    "path": ".travis.yml",
    "content": "language: java\n\njdk:\n    - openjdk8\n\nbefore_cache:\n    - rm -f  $HOME/.gradle/caches/modules-2/modules-2.lock\n    - rm -fr $HOME/.gradle/caches/*/plugin-resolution/\ncache:\n    directories:\n        - $HOME/.gradle/\n\nafter_success:\n    - ./gradlew jacocoTestReport && ./codecov.sh\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "# Change Log\n\nAll notable changes to this project will be documented in this file.\n\nThe format is based on [Keep a Changelog](http://keepachangelog.com/)\nand this project adheres to [Semantic Versioning](http://semver.org/).\n\n## 2.0.7 - 2018-05-08\n\n### Fixed\n\n- [Issue #54](https://github.com/xenomachina/kotlin-argparser/issues/54)\n  Allow the dot character in options and arguments. Thanks @tgockel!\n\n- [Issue #47](https://github.com/xenomachina/kotlin-argparser/issues/47)\n  If an option looks at the value of another option it can see the\n  current value. If no value has been set a `MissingValueException` is thrown.\n\n## 2.0.6 - 2018-03-26\n\n### Changed\n\n- Help text formatting now treats multi-newlines as paragraph separators, while\n  single newlines are still treated like spaces. Thanks @leomillon!\n\n## 2.0.5 - 2018-03-20\n\n### Changed\n\n- Releasing to Maven Central in addition to Bintray. This is probably the only\n  really externally visible change.\n\n- Upgraded a bunch of dependencies, including gradlew.\n    - gradle -> 4.5.1\n    - dokka -> = 0.9.16\n    - gradle_bintray -> = 1.8.0\n    - gradle_release -> = 2.6.0\n    - kotlin -> 1.2.30\n    - xenocom -> 0.0.6\n\n## 2.0.4 - 2018-01-18\n\n### Added\n\n- If the `programName` passed to `mainBody` is null, then the\n  system property `com.xenomachina.argparser.programName` is used, if set.\n\n- The `parseInto` method can be used as an inline alternative to `force`.\n  Thanks @shanethehat!\n\n- [Issue #24](https://github.com/xenomachina/kotlin-argparser/issues/18):\n `default` can now accept a lambda, making it possible to defer computation of\n  defaults until actually required.\n  Thanks @shanethehat!\n\n### Changed\n\n- All instances of `progName` have been renamed to `programName`.\n\n- The gradle wrapper has been updated.\n  Thanks @ColinHebert!\n\n## 2.0.3 - 2017-06-12\n\n### Fixed\n\n- [Issue #18](https://github.com/xenomachina/kotlin-argparser/issues/18)\n\n## 2.0.2 - 2017-06-12\n\n### Fixed\n\n- [Issue #19](https://github.com/xenomachina/kotlin-argparser/issues/19) by\n  updating xenocom dependency to 0.0.5. Also updated kotlin to 1.1.2-5 for good\n  measure.\n\n## 2.0.1 - 2017-05-15\n\n### Changed\n\n- [Issue #14](https://github.com/xenomachina/kotlin-argparser/issues/14) —\n  previously, automatic option naming would turn \"camelCase\" into\n  \"--camelCase\". Now it is converted to \"--camel-case\".\n\n- Likewise, positinal argument auto-naming used to convert \"camelCase\" into\n  \"CAMELCASE\". Now it is converted to \"CAMEL-CASE\".\n\n- Improve help formatting w/long program names\n\n- README formatting improved.\n  Thanks @konfilios!\n\n### Fixed\n\n- [Issue #17](https://github.com/xenomachina/kotlin-argparser/issues/17) —\n  specifying 0 for the columns should format help without line wrapping.\n  Previously, this did not work as documented, and would instead wrap text in\n  very narrow columns.\n\n- [Issue #15](https://github.com/xenomachina/kotlin-argparser/issues/15)\n  — make it possible to specify 'argName' on all variants of 'storing' and\n  `adding`\n\n\n## 2.0.0 - 2017-04-21\n\n### Added\n\n- `ArgParser.option` is now a public method, so it's possible to create many\n  new option types that were not previously possible. The existing option types\n  are all written in terms of `option`, so they can be used to get an idea of\n  how it works.\n\n- More tests have been added.\n\n- Started using keepachangelog.com format for CHANGELOG.md\n\n- Made minor improvements to release process\n\n### Changed\n\n- The `storing`, `adding` and `positionalList` methods of `ArgParser` have had\n  their parameters slightly reordered to be consistent with the other methods.\n  This is an incompatible change. The name(s) come first, if any, followed by\n  `help`. Other parameters appear after `help`, with the `transform` function,\n  if any, last. It is recommended that clients either pass the transform as a\n  block (ie: with braces) or as a named parameter, as any future new parameters\n  will necessarily change its position in the list.\n\n- Delegate and DelegateProvider are now abstract classes with internal\n  constructors. This makes it much easier for me to separate internal and\n  public parts of their API. This is an incompatible change, however it\n  shouldn't really affect you unless you were trying to implement `Delegate`,\n  which was't supported to begin with.\n\n- `default` methods on both `Delegate` and `DelegateProvider` are now extension\n  methods.  This makes it possible to generalize the type when adding a\n  default. This is most noticable when using a nullable value (or `null`\n  itself) for the default, though may also be useful in other cases (eg: a\n  \"storing\" that always produces a `Rectangle`, but you want the default to be\n  a `Circle`.  The resulting delegate will be a `Delegate<Shape>`.)\n\n- Registration of delegates now takes place at binding-time rather than\n  construction time. This should be pretty indistinguishable from the old\n  behavior unless you're creating delegates without binding them.\n\n- Help formatting has been improved so that it's far less likely to wrap option\n  names in the usage table.\n\n- There have been numerous bugfixes, particularly around positionals\n\n\n## 1.1.0 - 2017-03-09\n\n### Added\n\n- Auto-naming of options and positionals.\n    - Each of the ArgParser methods that takes names and returns a Delegate<T> has\n      an overload that takes no name, but returns a DelegateProvider<T>.\n\n    - A DelegateProvider<T> has an `operator fun provideDelegate` that returns a\n      Delegate<T>, using a name derived from the name of the property the\n      DelegateProvider is being bound to.\n\n### Removed\n\n- `addValidtator` is now deprecated. Use `addValidator` instead.\n\n### Fixed\n\n- Removed documentation of `option` from `README.md`, as it is internal\n\n- Corrected spelling of `addValidator`. `addValidtator` is still there, but\n  deprecated. It'll probably be removed in the next release, barring the\n  addition of potato functionality.\n\n## 1.0.2 - 2017-03-07\n\n### Changed\n\n- Upgrade to Kotlin 1.1, extract xenocom package.\n\n## 1.0.1 - 2017-01-30\n\n### Fixed\n\n- Fix small bug where `runMain` didn't have a default value for `columns`\n  parameter. (Now defaults to null.)\n\n## 1.0.0 - 2017-01-27\n\n### Added\n\n- Initial release\n"
  },
  {
    "path": "COPYING",
    "content": "                  GNU LESSER GENERAL PUBLIC LICENSE\n                       Version 2.1, February 1999\n\n Copyright (C) 1991, 1999 Free Software Foundation, Inc.\n 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n Everyone is permitted to copy and distribute verbatim copies\n of this license document, but changing it is not allowed.\n\n[This is the first released version of the Lesser GPL.  It also counts\n as the successor of the GNU Library Public License, version 2, hence\n the version number 2.1.]\n\n                            Preamble\n\n  The licenses for most software are designed to take away your\nfreedom to share and change it.  By contrast, the GNU General Public\nLicenses are intended to guarantee your freedom to share and change\nfree software--to make sure the software is free for all its users.\n\n  This license, the Lesser General Public License, applies to some\nspecially designated software packages--typically libraries--of the\nFree Software Foundation and other authors who decide to use it.  You\ncan use it too, but we suggest you first think carefully about whether\nthis license or the ordinary General Public License is the better\nstrategy to use in any particular case, based on the explanations below.\n\n  When we speak of free software, we are referring to freedom of use,\nnot price.  Our General Public Licenses are designed to make sure that\nyou have the freedom to distribute copies of free software (and charge\nfor this service if you wish); that you receive source code or can get\nit if you want it; that you can change the software and use pieces of\nit in new free programs; and that you are informed that you can do\nthese things.\n\n  To protect your rights, we need to make restrictions that forbid\ndistributors to deny you these rights or to ask you to surrender these\nrights.  These restrictions translate to certain responsibilities for\nyou if you distribute copies of the library or if you modify it.\n\n  For example, if you distribute copies of the library, whether gratis\nor for a fee, you must give the recipients all the rights that we gave\nyou.  You must make sure that they, too, receive or can get the source\ncode.  If you link other code with the library, you must provide\ncomplete object files to the recipients, so that they can relink them\nwith the library after making changes to the library and recompiling\nit.  And you must show them these terms so they know their rights.\n\n  We protect your rights with a two-step method: (1) we copyright the\nlibrary, and (2) we offer you this license, which gives you legal\npermission to copy, distribute and/or modify the library.\n\n  To protect each distributor, we want to make it very clear that\nthere is no warranty for the free library.  Also, if the library is\nmodified by someone else and passed on, the recipients should know\nthat what they have is not the original version, so that the original\nauthor's reputation will not be affected by problems that might be\nintroduced by others.\n\f\n  Finally, software patents pose a constant threat to the existence of\nany free program.  We wish to make sure that a company cannot\neffectively restrict the users of a free program by obtaining a\nrestrictive license from a patent holder.  Therefore, we insist that\nany patent license obtained for a version of the library must be\nconsistent with the full freedom of use specified in this license.\n\n  Most GNU software, including some libraries, is covered by the\nordinary GNU General Public License.  This license, the GNU Lesser\nGeneral Public License, applies to certain designated libraries, and\nis quite different from the ordinary General Public License.  We use\nthis license for certain libraries in order to permit linking those\nlibraries into non-free programs.\n\n  When a program is linked with a library, whether statically or using\na shared library, the combination of the two is legally speaking a\ncombined work, a derivative of the original library.  The ordinary\nGeneral Public License therefore permits such linking only if the\nentire combination fits its criteria of freedom.  The Lesser General\nPublic License permits more lax criteria for linking other code with\nthe library.\n\n  We call this license the \"Lesser\" General Public License because it\ndoes Less to protect the user's freedom than the ordinary General\nPublic License.  It also provides other free software developers Less\nof an advantage over competing non-free programs.  These disadvantages\nare the reason we use the ordinary General Public License for many\nlibraries.  However, the Lesser license provides advantages in certain\nspecial circumstances.\n\n  For example, on rare occasions, there may be a special need to\nencourage the widest possible use of a certain library, so that it becomes\na de-facto standard.  To achieve this, non-free programs must be\nallowed to use the library.  A more frequent case is that a free\nlibrary does the same job as widely used non-free libraries.  In this\ncase, there is little to gain by limiting the free library to free\nsoftware only, so we use the Lesser General Public License.\n\n  In other cases, permission to use a particular library in non-free\nprograms enables a greater number of people to use a large body of\nfree software.  For example, permission to use the GNU C Library in\nnon-free programs enables many more people to use the whole GNU\noperating system, as well as its variant, the GNU/Linux operating\nsystem.\n\n  Although the Lesser General Public License is Less protective of the\nusers' freedom, it does ensure that the user of a program that is\nlinked with the Library has the freedom and the wherewithal to run\nthat program using a modified version of the Library.\n\n  The precise terms and conditions for copying, distribution and\nmodification follow.  Pay close attention to the difference between a\n\"work based on the library\" and a \"work that uses the library\".  The\nformer contains code derived from the library, whereas the latter must\nbe combined with the library in order to run.\n\f\n                  GNU LESSER GENERAL PUBLIC LICENSE\n   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION\n\n  0. This License Agreement applies to any software library or other\nprogram which contains a notice placed by the copyright holder or\nother authorized party saying it may be distributed under the terms of\nthis Lesser General Public License (also called \"this License\").\nEach licensee is addressed as \"you\".\n\n  A \"library\" means a collection of software functions and/or data\nprepared so as to be conveniently linked with application programs\n(which use some of those functions and data) to form executables.\n\n  The \"Library\", below, refers to any such software library or work\nwhich has been distributed under these terms.  A \"work based on the\nLibrary\" means either the Library or any derivative work under\ncopyright law: that is to say, a work containing the Library or a\nportion of it, either verbatim or with modifications and/or translated\nstraightforwardly into another language.  (Hereinafter, translation is\nincluded without limitation in the term \"modification\".)\n\n  \"Source code\" for a work means the preferred form of the work for\nmaking modifications to it.  For a library, complete source code means\nall the source code for all modules it contains, plus any associated\ninterface definition files, plus the scripts used to control compilation\nand installation of the library.\n\n  Activities other than copying, distribution and modification are not\ncovered by this License; they are outside its scope.  The act of\nrunning a program using the Library is not restricted, and output from\nsuch a program is covered only if its contents constitute a work based\non the Library (independent of the use of the Library in a tool for\nwriting it).  Whether that is true depends on what the Library does\nand what the program that uses the Library does.\n\n  1. You may copy and distribute verbatim copies of the Library's\ncomplete source code as you receive it, in any medium, provided that\nyou conspicuously and appropriately publish on each copy an\nappropriate copyright notice and disclaimer of warranty; keep intact\nall the notices that refer to this License and to the absence of any\nwarranty; and distribute a copy of this License along with the\nLibrary.\n\n  You may charge a fee for the physical act of transferring a copy,\nand you may at your option offer warranty protection in exchange for a\nfee.\n\f\n  2. You may modify your copy or copies of the Library or any portion\nof it, thus forming a work based on the Library, and copy and\ndistribute such modifications or work under the terms of Section 1\nabove, provided that you also meet all of these conditions:\n\n    a) The modified work must itself be a software library.\n\n    b) You must cause the files modified to carry prominent notices\n    stating that you changed the files and the date of any change.\n\n    c) You must cause the whole of the work to be licensed at no\n    charge to all third parties under the terms of this License.\n\n    d) If a facility in the modified Library refers to a function or a\n    table of data to be supplied by an application program that uses\n    the facility, other than as an argument passed when the facility\n    is invoked, then you must make a good faith effort to ensure that,\n    in the event an application does not supply such function or\n    table, the facility still operates, and performs whatever part of\n    its purpose remains meaningful.\n\n    (For example, a function in a library to compute square roots has\n    a purpose that is entirely well-defined independent of the\n    application.  Therefore, Subsection 2d requires that any\n    application-supplied function or table used by this function must\n    be optional: if the application does not supply it, the square\n    root function must still compute square roots.)\n\nThese requirements apply to the modified work as a whole.  If\nidentifiable sections of that work are not derived from the Library,\nand can be reasonably considered independent and separate works in\nthemselves, then this License, and its terms, do not apply to those\nsections when you distribute them as separate works.  But when you\ndistribute the same sections as part of a whole which is a work based\non the Library, the distribution of the whole must be on the terms of\nthis License, whose permissions for other licensees extend to the\nentire whole, and thus to each and every part regardless of who wrote\nit.\n\nThus, it is not the intent of this section to claim rights or contest\nyour rights to work written entirely by you; rather, the intent is to\nexercise the right to control the distribution of derivative or\ncollective works based on the Library.\n\nIn addition, mere aggregation of another work not based on the Library\nwith the Library (or with a work based on the Library) on a volume of\na storage or distribution medium does not bring the other work under\nthe scope of this License.\n\n  3. You may opt to apply the terms of the ordinary GNU General Public\nLicense instead of this License to a given copy of the Library.  To do\nthis, you must alter all the notices that refer to this License, so\nthat they refer to the ordinary GNU General Public License, version 2,\ninstead of to this License.  (If a newer version than version 2 of the\nordinary GNU General Public License has appeared, then you can specify\nthat version instead if you wish.)  Do not make any other change in\nthese notices.\n\f\n  Once this change is made in a given copy, it is irreversible for\nthat copy, so the ordinary GNU General Public License applies to all\nsubsequent copies and derivative works made from that copy.\n\n  This option is useful when you wish to copy part of the code of\nthe Library into a program that is not a library.\n\n  4. You may copy and distribute the Library (or a portion or\nderivative of it, under Section 2) in object code or executable form\nunder the terms of Sections 1 and 2 above provided that you accompany\nit with the complete corresponding machine-readable source code, which\nmust be distributed under the terms of Sections 1 and 2 above on a\nmedium customarily used for software interchange.\n\n  If distribution of object code is made by offering access to copy\nfrom a designated place, then offering equivalent access to copy the\nsource code from the same place satisfies the requirement to\ndistribute the source code, even though third parties are not\ncompelled to copy the source along with the object code.\n\n  5. A program that contains no derivative of any portion of the\nLibrary, but is designed to work with the Library by being compiled or\nlinked with it, is called a \"work that uses the Library\".  Such a\nwork, in isolation, is not a derivative work of the Library, and\ntherefore falls outside the scope of this License.\n\n  However, linking a \"work that uses the Library\" with the Library\ncreates an executable that is a derivative of the Library (because it\ncontains portions of the Library), rather than a \"work that uses the\nlibrary\".  The executable is therefore covered by this License.\nSection 6 states terms for distribution of such executables.\n\n  When a \"work that uses the Library\" uses material from a header file\nthat is part of the Library, the object code for the work may be a\nderivative work of the Library even though the source code is not.\nWhether this is true is especially significant if the work can be\nlinked without the Library, or if the work is itself a library.  The\nthreshold for this to be true is not precisely defined by law.\n\n  If such an object file uses only numerical parameters, data\nstructure layouts and accessors, and small macros and small inline\nfunctions (ten lines or less in length), then the use of the object\nfile is unrestricted, regardless of whether it is legally a derivative\nwork.  (Executables containing this object code plus portions of the\nLibrary will still fall under Section 6.)\n\n  Otherwise, if the work is a derivative of the Library, you may\ndistribute the object code for the work under the terms of Section 6.\nAny executables containing that work also fall under Section 6,\nwhether or not they are linked directly with the Library itself.\n\f\n  6. As an exception to the Sections above, you may also combine or\nlink a \"work that uses the Library\" with the Library to produce a\nwork containing portions of the Library, and distribute that work\nunder terms of your choice, provided that the terms permit\nmodification of the work for the customer's own use and reverse\nengineering for debugging such modifications.\n\n  You must give prominent notice with each copy of the work that the\nLibrary is used in it and that the Library and its use are covered by\nthis License.  You must supply a copy of this License.  If the work\nduring execution displays copyright notices, you must include the\ncopyright notice for the Library among them, as well as a reference\ndirecting the user to the copy of this License.  Also, you must do one\nof these things:\n\n    a) Accompany the work with the complete corresponding\n    machine-readable source code for the Library including whatever\n    changes were used in the work (which must be distributed under\n    Sections 1 and 2 above); and, if the work is an executable linked\n    with the Library, with the complete machine-readable \"work that\n    uses the Library\", as object code and/or source code, so that the\n    user can modify the Library and then relink to produce a modified\n    executable containing the modified Library.  (It is understood\n    that the user who changes the contents of definitions files in the\n    Library will not necessarily be able to recompile the application\n    to use the modified definitions.)\n\n    b) Use a suitable shared library mechanism for linking with the\n    Library.  A suitable mechanism is one that (1) uses at run time a\n    copy of the library already present on the user's computer system,\n    rather than copying library functions into the executable, and (2)\n    will operate properly with a modified version of the library, if\n    the user installs one, as long as the modified version is\n    interface-compatible with the version that the work was made with.\n\n    c) Accompany the work with a written offer, valid for at\n    least three years, to give the same user the materials\n    specified in Subsection 6a, above, for a charge no more\n    than the cost of performing this distribution.\n\n    d) If distribution of the work is made by offering access to copy\n    from a designated place, offer equivalent access to copy the above\n    specified materials from the same place.\n\n    e) Verify that the user has already received a copy of these\n    materials or that you have already sent this user a copy.\n\n  For an executable, the required form of the \"work that uses the\nLibrary\" must include any data and utility programs needed for\nreproducing the executable from it.  However, as a special exception,\nthe materials to be distributed need not include anything that is\nnormally distributed (in either source or binary form) with the major\ncomponents (compiler, kernel, and so on) of the operating system on\nwhich the executable runs, unless that component itself accompanies\nthe executable.\n\n  It may happen that this requirement contradicts the license\nrestrictions of other proprietary libraries that do not normally\naccompany the operating system.  Such a contradiction means you cannot\nuse both them and the Library together in an executable that you\ndistribute.\n\f\n  7. You may place library facilities that are a work based on the\nLibrary side-by-side in a single library together with other library\nfacilities not covered by this License, and distribute such a combined\nlibrary, provided that the separate distribution of the work based on\nthe Library and of the other library facilities is otherwise\npermitted, and provided that you do these two things:\n\n    a) Accompany the combined library with a copy of the same work\n    based on the Library, uncombined with any other library\n    facilities.  This must be distributed under the terms of the\n    Sections above.\n\n    b) Give prominent notice with the combined library of the fact\n    that part of it is a work based on the Library, and explaining\n    where to find the accompanying uncombined form of the same work.\n\n  8. You may not copy, modify, sublicense, link with, or distribute\nthe Library except as expressly provided under this License.  Any\nattempt otherwise to copy, modify, sublicense, link with, or\ndistribute the Library is void, and will automatically terminate your\nrights under this License.  However, parties who have received copies,\nor rights, from you under this License will not have their licenses\nterminated so long as such parties remain in full compliance.\n\n  9. You are not required to accept this License, since you have not\nsigned it.  However, nothing else grants you permission to modify or\ndistribute the Library or its derivative works.  These actions are\nprohibited by law if you do not accept this License.  Therefore, by\nmodifying or distributing the Library (or any work based on the\nLibrary), you indicate your acceptance of this License to do so, and\nall its terms and conditions for copying, distributing or modifying\nthe Library or works based on it.\n\n  10. Each time you redistribute the Library (or any work based on the\nLibrary), the recipient automatically receives a license from the\noriginal licensor to copy, distribute, link with or modify the Library\nsubject to these terms and conditions.  You may not impose any further\nrestrictions on the recipients' exercise of the rights granted herein.\nYou are not responsible for enforcing compliance by third parties with\nthis License.\n\f\n  11. If, as a consequence of a court judgment or allegation of patent\ninfringement or for any other reason (not limited to patent issues),\nconditions are imposed on you (whether by court order, agreement or\notherwise) that contradict the conditions of this License, they do not\nexcuse you from the conditions of this License.  If you cannot\ndistribute so as to satisfy simultaneously your obligations under this\nLicense and any other pertinent obligations, then as a consequence you\nmay not distribute the Library at all.  For example, if a patent\nlicense would not permit royalty-free redistribution of the Library by\nall those who receive copies directly or indirectly through you, then\nthe only way you could satisfy both it and this License would be to\nrefrain entirely from distribution of the Library.\n\nIf any portion of this section is held invalid or unenforceable under any\nparticular circumstance, the balance of the section is intended to apply,\nand the section as a whole is intended to apply in other circumstances.\n\nIt is not the purpose of this section to induce you to infringe any\npatents or other property right claims or to contest validity of any\nsuch claims; this section has the sole purpose of protecting the\nintegrity of the free software distribution system which is\nimplemented by public license practices.  Many people have made\ngenerous contributions to the wide range of software distributed\nthrough that system in reliance on consistent application of that\nsystem; it is up to the author/donor to decide if he or she is willing\nto distribute software through any other system and a licensee cannot\nimpose that choice.\n\nThis section is intended to make thoroughly clear what is believed to\nbe a consequence of the rest of this License.\n\n  12. If the distribution and/or use of the Library is restricted in\ncertain countries either by patents or by copyrighted interfaces, the\noriginal copyright holder who places the Library under this License may add\nan explicit geographical distribution limitation excluding those countries,\nso that distribution is permitted only in or among countries not thus\nexcluded.  In such case, this License incorporates the limitation as if\nwritten in the body of this License.\n\n  13. The Free Software Foundation may publish revised and/or new\nversions of the Lesser General Public License from time to time.\nSuch new versions will be similar in spirit to the present version,\nbut may differ in detail to address new problems or concerns.\n\nEach version is given a distinguishing version number.  If the Library\nspecifies a version number of this License which applies to it and\n\"any later version\", you have the option of following the terms and\nconditions either of that version or of any later version published by\nthe Free Software Foundation.  If the Library does not specify a\nlicense version number, you may choose any version ever published by\nthe Free Software Foundation.\n\f\n  14. If you wish to incorporate parts of the Library into other free\nprograms whose distribution conditions are incompatible with these,\nwrite to the author to ask for permission.  For software which is\ncopyrighted by the Free Software Foundation, write to the Free\nSoftware Foundation; we sometimes make exceptions for this.  Our\ndecision will be guided by the two goals of preserving the free status\nof all derivatives of our free software and of promoting the sharing\nand reuse of software generally.\n\n                            NO WARRANTY\n\n  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO\nWARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.\nEXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR\nOTHER PARTIES PROVIDE THE LIBRARY \"AS IS\" WITHOUT WARRANTY OF ANY\nKIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\nPURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE\nLIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME\nTHE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.\n\n  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN\nWRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY\nAND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU\nFOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR\nCONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE\nLIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING\nRENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A\nFAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF\nSUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH\nDAMAGES.\n\n                     END OF TERMS AND CONDITIONS\n\f\n           How to Apply These Terms to Your New Libraries\n\n  If you develop a new library, and you want it to be of the greatest\npossible use to the public, we recommend making it free software that\neveryone can redistribute and change.  You can do so by permitting\nredistribution under these terms (or, alternatively, under the terms of the\nordinary General Public License).\n\n  To apply these terms, attach the following notices to the library.  It is\nsafest to attach them to the start of each source file to most effectively\nconvey the exclusion of warranty; and each file should have at least the\n\"copyright\" line and a pointer to where the full notice is found.\n\n    <one line to give the library's name and a brief idea of what it does.>\n    Copyright (C) <year>  <name of author>\n\n    This library is free software; you can redistribute it and/or\n    modify it under the terms of the GNU Lesser General Public\n    License as published by the Free Software Foundation; either\n    version 2.1 of the License, or (at your option) any later version.\n\n    This library is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n    Lesser General Public License for more details.\n\n    You should have received a copy of the GNU Lesser General Public\n    License along with this library; if not, write to the Free Software\n    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\nAlso add information on how to contact you by electronic and paper mail.\n\nYou should also get your employer (if you work as a programmer) or your\nschool, if any, to sign a \"copyright disclaimer\" for the library, if\nnecessary.  Here is a sample; alter the names:\n\n  Yoyodyne, Inc., hereby disclaims all copyright interest in the\n  library `Frob' (a library for tweaking knobs) written by James Random Hacker.\n\n  <signature of Ty Coon>, 1 April 1990\n  Ty Coon, President of Vice\n\nThat's all there is to it!\n"
  },
  {
    "path": "README.md",
    "content": "# <img alt=\"Kotlin --argparser\" src=\"https://rawgit.com/xenomachina/kotlin-argparser/master/logo.svg\" style=\"transform:scale(.6)\" >\n\n<!--\nRemoved until either Bintray makes a badge with a configurable label, or\nshields.io can make a reliable bintray badge.\n\n[![Bintray](https://img.shields.io/bintray/v/xenomachina/maven/kotlin-argparser.svg)](https://bintray.com/xenomachina/maven/kotlin-argparser/%5FlatestVersion)\n-->\n\n[![Maven Central](https://img.shields.io/maven-central/v/com.xenomachina/kotlin-argparser.svg)](https://mvnrepository.com/artifact/com.xenomachina/kotlin-argparser)\n[![Build Status](https://travis-ci.org/xenomachina/kotlin-argparser.svg?branch=master)](https://travis-ci.org/xenomachina/kotlin-argparser)\n[![codebeat badge](https://codebeat.co/badges/902174e2-31be-4f9d-a4ba-40178b075d2a)](https://codebeat.co/projects/github-com-xenomachina-kotlin-argparser-master)\n[![Awesome Kotlin Badge](https://kotlin.link/awesome-kotlin.svg)](https://github.com/KotlinBy/awesome-kotlin)\n[![Javadocs](https://www.javadoc.io/badge/com.xenomachina/kotlin-argparser.svg)](https://www.javadoc.io/doc/com.xenomachina/kotlin-argparser)\n[![License: LGPL 2.1](https://img.shields.io/badge/license-LGPL--2.1-blue.svg)](https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html)\n\n\nThis is a library for parsing command-line arguments.  It can parse both\noptions and positional arguments.  It aims to be easy to use and concise yet\npowerful and robust.\n\n\n## Overview\n\nDefining options and positional arguments is as simple as:\n\n```kotlin\nimport com.xenomachina.argparser.ArgParser\n\nclass MyArgs(parser: ArgParser) {\n    val v by parser.flagging(\"enable verbose mode\")\n\n    val name by parser.storing(\"name of the user\")\n\n    val count by parser.storing(\"number of the widgets\") { toInt() }\n\n    val source by parser.positional(\"source filename\")\n\n    val destination by parser.positional(\"destination filename\")\n}\n```\n\nAn instance of `MyArgs` will represent the set of parsed arguments. Each option\nand positional argument is declared as a property that delegates through a\ndelegate factory method on an instance of `ArgParser`.\n\nThe name of an option is inferred from the name of the property it is bound to.\nThe options above are named `-v`, `--name` and `--count`, respectively. There\nare also two positional arguments.\n\nDirect control over an option's name is also possible, and for most types of\noptions it is also possible to have multiple names, like a short and long name:\n\n\n```kotlin\nclass MyArgs(parser: ArgParser) {\n    val verbose by parser.flagging(\n        \"-v\", \"--verbose\",\n        help = \"enable verbose mode\")\n\n    val name by parser.storing(\n        \"-N\", \"--name\",\n        help = \"name of the user\")\n\n    val count by parser.storing(\n        \"-c\", \"--count\",\n        help = \"number of widgets\") { toInt() }\n\n    val source by parser.positional(\n        \"SOURCE\",\n        help = \"source filename\")\n\n    val destination by parser.positional(\n        \"DEST\",\n        help = \"destination filename\")\n}\n```\n\nThe unparsed command-line arguments are passed to the `ArgParser` instance at\nconstruction:\n\n```kotlin\nfun main(args: Array<String>) = mainBody {\n    ArgParser(args).parseInto(::MyArgs).run {\n        println(\"Hello, ${name}!\")\n        println(\"I'm going to move ${count} widgets from ${source} to ${destination}.\")\n        // TODO: move widgets\n    }\n}\n```\n\nSee [kotlin-argparser-example](https://github.com/xenomachina/kotlin-argparser-example)\nfor a complete example project.\n\n\n## Nomenclature\n\nOptions, arguments, flags... what's the difference?\n\nAn application's `main` function is passed an array of strings. These are\nthe *unparsed command-line arguments*, or *unparsed arguments* for short.\n\nThe unparsed arguments can then be parsed into *options*, which start\nwith a hyphen (\"`-`\"), and *positional arguments*. For example, in the command\n`ls -l /tmp/`, the unparsed arguments would be `\"-l\", \"/tmp\"` where `-l`\nis an option, while `/tmp/` is a positional argument.\n\nOptions can also have *option arguments*. In the command `ls --time-style=iso`,\nthe option is `--time-style` and that options argument is `iso`. Note that in\nparsing a single unparsed argument can be split into an option and an option\nargument, or even into multiple options in some cases.\n\nA *flag* is a boolean option which has no arguments and which is false if not\nprovided, but true if provided. The `-l` option of `ls` is a flag.\n\n## Option Types\n\n### Boolean Flags\n\nBoolean flags are created by asking the parser for a `flagging` delegate.  One\nor more option names, may be provided:\n\n```kotlin\nval verbose by parser.flagging(\"-v\", \"--verbose\",\n                               help = \"enable verbose mode\")\n```\n\nHere the presence of either `-v` or `--verbose` options in the\narguments will cause the `Boolean` property `verbose` to be `true`, otherwise\nit will be `false`.\n\n### Storing a Single Argument\n\nSingle argument options are created by asking the parser for a\n`storing` delegate.\n\n```kotlin\nval name by parser.storing(\"-N\", \"--name\",\n                           help = \"name of the user\")\n```\n\nHere either `-N` or `--name` with an argument will cause the `name` property to\nhave that argument as its value.\n\nA function can also be supplied to transform the argument into the desired\ntype. Here the `size` property will be an `Int` rather than a `String`:\n\n```kotlin\nval size by parser.storing(\"-c\", \"--count\",\n                           help = \"number of widgets\") { toInt() }\n```\n\n### Adding to a Collection\n\nOptions that add to a `Collection` each time they appear in the arguments are\ncreated with using the `adding` delegate. Just like `storing` delegates, a\ntransform function may optionally be supplied:\n\n```kotlin\nval includeDirs by parser.adding(\n        \"-I\", help = \"directory to search for header files\") { File(this) }\n```\n\nNow each time the `-I` option appears, its transformed argument is appended to\n`includeDirs`.\n\n### Mapping from an option to a fixed value\n\nFor choosing between a fixed set of values (typically, but not necessarily,\nfrom an enum), a `mapping` delegate can be used:\n\n```kotlin\nval mode by parser.mapping(\n        \"--fast\" to Mode.FAST,\n        \"--small\" to Mode.SMALL,\n        \"--quiet\" to Mode.QUIET,\n        help = \"mode of operation\")\n```\n\nHere the `mode` property will be set to the corresponding `ArgParser.Mode` value depending\non which of `--fast`, `--small`, and `--quiet` appears (last) in the arguments.\n\n`mapping` is one of the few cases where it is not possible to infer the option\nname from the property name.\n\n### More advanced options\n\nFor all other types of options, the `option` method should be used. The\nmethods mentioned above are, in fact, convenience methods built on top of the\n`option` method.\n\nFor example, it is possible to create an option that has multiple arguments:\n\n```kotlin\n  fun ArgParser.putting(vararg names: String, help: String) =\n          option<MutableMap<String, String>>(*names,\n                  argNames = listOf(\"KEY\", \"VALUE\"),\n                  help = help) {\n              value.orElse { mutableMapOf<String, String>() }.apply {\n                  put(arguments.first(), arguments.last()) }\n          }\n```\n\nNote that the `option` method does not have an auto-naming overload. If you\nneed this capability, create a `DelegateProvider` that creates your `Delegate`:\n\n```kotlin\n  fun ArgParser.putting(help: String) =\n          ArgParser.DelegateProvider { identifier ->\n              putting(identifierToOptionName(identifier), help = help) }\n```\n\n\n## Positional Arguments\n\nPositional arguments are collected by using the `positional` and\n`positionalList` methods.\n\nFor a single positional argument:\n\n```kotlin\nval destination by parser.positional(\"destination filename\")\n```\n\nAn explicit name may also be specified:\n\n```kotlin\nval destination by parser.positional(\"DEST\",\n                                     help = \"destination filename\")\n```\n\nThe name (\"DEST\", here) is used in error handling and help text.\n\nFor a list of positional arguments:\n\n```kotlin\nval sources by parser.positionalList(\"SOURCE\", 1..Int.MAX_VALUE,\n                                     help = \"source filename\")\n```\n\nThe range indicates how many arguments should be collected, and defaults to the\nvalue shown in this example. As the name suggests, the resulting property will\nbe a `List`.\n\nBoth of these methods accept an optional transform function for converting\narguments from `String` to whatever type is actually desired:\n\n```kotlin\nval destination by parser.positional(\"DEST\",\n                                     help = \"...\") { File(this) }\n\nval sources by parser.positionalList(\"SOURCE\", 1..Int.MAX_VALUE,\n                                     help = \"...\") { File(this) }\n```\n\n\n## Modifying Delegates\n\nThe delegates returned by any of these methods also have a few methods for setting\noptional attributes:\n\n### Adding a Default Value\n\nCertain types of delegates (notably `storing`, `mapping`, and `positional`)\nhave no default value, and hence will be required options unless a default\nvalue is provided. This is done with the `default` method:\n\n```kotlin\nval name by parser.storing(\"-N\", \"--name\", help = \"...\").default(\"John Doe\")\n```\n\nNote that it *is* possible to use `null` for the default, though this may\nrequire specifying the type parameter for `default` explicitly:\n\n```kotlin\nval name by parser.storing(\"-N\", \"--name\", help = \"...\").default<String?>(null)\n```\n\nThe type of the resulting property be nullable (a `String?` in this case).\n\n\n### Adding a Validator\n\nSometimes it's easier to validate an option at the end of parsing, in which\ncase the `addValidator` method can be used.\n\n```kotlin\nval percentages by parser.adding(\"--percentages\", help = \"...\") { toInt() }\n        .addValidator {\n              if (value.sum() != 100)\n                  throw InvalidArgumentException(\n                          \"Percentages must add up to 100%\")\n        }\n```\n\n## Error Handling\n\nIf the parser determines that execution should not continue it will throw a\n`SystemExitException` which has a status code appropriate for passing to\n`exitProcess` as well as a message for the user.\n\nThese exceptions can be caused by user error, or even if the user requests help\n(eg: via the `--help` option).\n\nIt is recommended that transform functions (given to `storing`,\n`positionalList`, etc.) and post-parsing validation, including that performed\nvia, `addValidator` also throw a `SystemExitException` on failure.\n\nAs a convenience, these exceptions can be handled by using the `mainBody`\nfunction:\n\n```kotlin\nclass ParsedArgs(parser: ArgParser) {\n    val name by positional(\"The user's name\").default(\"world\")\n}\n\nfun main(args: Array<String>) = mainBody {\n    ArgParser(args).parseInto(::ParsedArgs).run {\n        println(\"Hello, {name}!\")\n    }\n}\n```\n\n## Parsing\n\nParsing of command-line arguments is performed sequentially. So long as\noption-processing is enabled, each not-yet-processed command-line argument that\nstarts with a hyphen (`-`) is treated as an option.\n\n### Short Options\n\nShort options start with a single hyphen. If the option takes an argument, the\nargument can either be appended:\n\n```bash\n# \"-o\" with argument \"ARGUMENT\"\nmy_program -oARGUMENT\n```\n\nor can be the following command-line argument:\n\n```bash\n# \"-o\" with argument \"ARGUMENT\"\nmy_program -o ARGUMENT\n```\n\nZero argument short options can also be appended to each other without\nintermediate hyphens:\n\n```bash\n# \"-x\", \"-y\" and \"-z\" options\nmy_program -xyz\n```\n\nAn option that accepts arguments is also allowed at the end of such a chain:\n\n```bash\n# \"-x\", \"-y\" and \"-z\" options, with argument for \"-z\"\nmy_program -xyzARGUMENT\n```\n\n### Long Options\n\nLong options start with a double hyphen (`--`). An argument to a long option\ncan\neither be delimited with an equal sign (`=`):\n\n```bash\n# \"--foo\" with argument \"ARGUMENT\"\nmy_program --foo=ARGUMENT\n```\n\nor can be the following command-line argument:\n\n```bash\n# \"--foo\" with argument \"ARGUMENT\"\nmy_program --foo ARGUMENT\n```\n\n### Multi-argument Options\n\nMulti-argument options are supported, though currently not by any of the\nconvenience methods. Option-arguments after the first must be separate\ncommand-line arguments, for both an long and short forms of an option.\n\n### Positional Arguments\n\nIn GNU mode (the default), options can be interspersed with positional\narguments, but in POSIX mode the first positional argument that is encountered\ndisables option processing for the remaining arguments. In either mode, if the\nargument \"--\" is encountered while option processing is enabled, then option\nprocessing is disabled for the rest of the command-line. Once the options and\noption-arguments have been eliminated, what remains are considered to be\npositional arguments.\n\nEach positional argument delegate can specify a minimum and maximum number of\narguments it is willing to collect.\n\nThe positional arguments are distributed to the delegates by allocating each\npositional delegate at least as many arguments as it requires. If more than the\nminimum number of positional arguments have been supplied then additional\narguments will be allocated to the first delegate up to its maximum, then the\nsecond, and so on, until all arguments have been allocated to a delegate.\n\nThis makes it easy to create a program that behaves like `grep`:\n\n```kotlin\nclass Args(parser: ArgParser) {\n    // accept 1 regex followed by n filenames\n    val regex by parser.positional(\"REGEX\",\n            help = \"regular expression to search for\")\n    val files by parser.positionalList(\"FILE\",\n            help = \"file to search in\")\n}\n```\n\nAnd equally easy to create a program that behaves like `cp`:\n\n```kotlin\nclass Args(parser: ArgParser) {\n    // accept n source files followed by 1 destination\n    val sources by parser.positionalList(\"SOURCE\",\n            help = \"source file\")\n    val destination by parser.positional(\"DEST\",\n            help = \"destination file\")\n}\n```\n\n\n## Forcing Parsing\n\nParsing normally does not begin until a delegate's value is accessed. Sometimes\nthis is not desirable, so it is possible to enforce the parsing of arguments\ninto a class of values. This ensures that all arguments that are required are\nprovided, and all arguments provided are consumed.\n\nForcing can be done in a separate step using the `force` method:\n\n```kotlin\nval parser = ArgParser(args)\nval parsedArgs = ParsedArgs(parser)\nparser.force()\n// now you can use parsedArgs\n```\n\nAlternatively, forcing can be done inline via the `parseInto` method:\n\n```kotlin\nval parsedArgs = ArgParser(args).parseInto(::ParsedArgs)\n// now you can use parsedArgs\n```\n\nIn both cases exceptions will be thrown where parsing or validation errors are found.    \n\n## Help Formatting\n\nBy default, `ArgParser` will add a `--help` option (short name `-h`) for\ndisplaying usage information. If this option is present a `ShowHelpException` will be thrown.\nIf the default exception handling is being used (see [Error Handling](#error-handling)) the\nprogram will halt and print a help message like the one below, based on the `ArgParser`\nconfiguration:\n\n    usage: program_name [-h] [-n] [-I INCLUDE]... -o OUTPUT\n                        [-v]... SOURCE... DEST\n\n\n    This is the prologue. Lorem ipsum dolor sit amet, consectetur\n    adipiscing elit. Aliquam malesuada maximus eros. Fusce\n    luctus risus eget quam consectetur, eu auctor est\n    ullamcorper. Maecenas eget suscipit dui, sed sodales erat.\n    Phasellus.\n\n\n    required arguments:\n      -o OUTPUT,          directory in which all output should\n      --output OUTPUT     be generated\n\n\n    optional arguments:\n      -h, --help          show this help message and exit\n\n      -n, --dry-run       don't do anything\n\n      -I INCLUDE,         search in this directory for header\n      --include INCLUDE   files\n\n      -v, --verbose       increase verbosity\n\n\n    positional arguments:\n      SOURCE              source file\n\n      DEST                destination file\n\n\n    This is the epilogue. Lorem ipsum dolor sit amet,\n    consectetur adipiscing elit. Donec vel tortor nunc. Sed eu\n    massa sed turpis auctor faucibus. Donec vel pellentesque\n    tortor. Ut ultrices tempus lectus fermentum vestibulum.\n    Phasellus.\n\nThe creation of the `--help` option can be disabled by passing `null` as the\n`helpFormatter` when constructing the `ArgParser`, or configured by manually\nconstructing a `HelpFormatter` instance. In the above example a\n`DefaultHelpFormatter` was created with the prologue and epilogue.\n\n\n## Caveats\n\n- This library should be considered to be *very beta*. While there are no plans\n  to make any breaking changes to the API, it's possible that there may be some\n  until it is mature.\n\n- Upon reading the value any of the delegated properties created by an\n  `ArgParser`, the arguments used to construct that `ArgParser` will be\n  parsed. This means it's important that you don't attempt to create delegates\n  on an `ArgParser` after any of its existing delegated properties have been\n  read. Attempting to do so will cause an `IllegalStateException`. It would be\n  nice if Kotlin had facilities for doing some of the work of `ArgParser` at\n  compile time rather than run time, but so far the run time errors seem to be\n  reasonably easy to avoid.\n\n\n## Configuring Your Build\n\n<!-- TODO move detailed instructions elsewhere, just have brief instructions here -->\n\nKotlin-argparser binaries are hosted on Maven Central and also Bintray's\nJCenter.\n\nIn Gradle, add something like this in your `build.gradle`:\n\n```groovy\n// you probably already have this part\nbuildscript {\n    repositories {\n        mavenCentral() // or jcenter()\n    }\n}\n\ndependencies {\n    compile \"com.xenomachina:kotlin-argparser:$kotlin_argparser_version\"\n}\n```\n\nIn Maven add something like this to your `pom.xml`:\n\n```xml\n<dependency>\n    <groupId>com.xenomachina</groupId>\n    <artifactId>kotlin-argparser</artifactId>\n    <version>VERSION</version>\n</dependency>\n```\n\nInformation on setting up other build systems, as well as the current version\nnumber, can be found on\n[MVN Repository's page for Kotlin-argparser](https://mvnrepository.com/artifact/com.xenomachina/kotlin-argparser/latest).\n\n## Thanks\n\nThanks to the creators of Python's\n[`argparse`](https://docs.python.org/3/library/argparse.html) module, which\nprovided the initial inspiration for this library.\n\nThanks also to the team behind [Kotlin](https://kotlinlang.org/).\n\nFinally, thanks to all of the people who have contributed\n[code](https://github.com/xenomachina/kotlin-argparser/graphs/contributors)\nand/or\n[issues](https://github.com/xenomachina/kotlin-argparser/issues).\n"
  },
  {
    "path": "build.gradle",
    "content": "// Copyright © 2016 Laurence Gonsalves\n//\n// This file is part of kotlin-argparser, a library which can be found at\n// http://github.com/xenomachina/kotlin-argparser\n//\n// This library is free software; you can redistribute it and/or modify it\n// under the terms of the GNU Lesser General Public License as published by the\n// Free Software Foundation; either version 2.1 of the License, or (at your\n// option) any later version.\n//\n// This library is distributed in the hope that it will be useful, but WITHOUT\n// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License\n// for more details.\n//\n// You should have received a copy of the GNU Lesser General Public License\n// along with this library; if not, see http://www.gnu.org/licenses/\n\nbuildscript {\n    repositories {\n        mavenCentral()\n        jcenter()\n        maven {\n            url \"https://plugins.gradle.org/m2/\"\n        }\n    }\n\n    dependencies {\n        classpath \"org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version\"\n        classpath \"org.jetbrains.dokka:dokka-gradle-plugin:$dokka_version\"\n        classpath \"com.jfrog.bintray.gradle:gradle-bintray-plugin:$gradle_bintray_version\"\n        classpath \"gradle.plugin.io.gitlab.arturbosch.detekt:detekt-gradle-plugin:$detekt_version\"\n    }\n}\n\nplugins {\n    id 'com.palantir.git-version' version '0.12.0-rc2'\n    id 'org.jmailen.kotlinter' version '1.12.0'\n}\n\napply plugin: 'maven'\napply plugin: 'kotlin'\napply plugin: 'java'\napply plugin: 'org.jetbrains.dokka'\napply plugin: 'signing'\napply plugin: 'com.jfrog.bintray'\napply plugin: 'maven-publish'\napply plugin: 'jacoco'\napply plugin: \"io.gitlab.arturbosch.detekt\"\n\nassert name == 'kotlin-argparser'\ndescription = 'Concise, easy, powerful and robust command line argument parsing for Kotlin'\n\ngroup 'com.xenomachina'\nversion = gitVersion()\n\nproject.ext {\n    githubUser = \"xenomachina\"\n    vcsDev = \"https://github.com/$githubUser\"\n    githubRepo = \"$githubUser/$name\"\n    vcsUrl = \"https://github.com/$githubRepo\"\n}\n\nsourceCompatibility = 1.6\n\nrepositories {\n    mavenCentral()\n    jcenter()\n}\n\ntest {\n  useJUnitPlatform()\n}\n\ndependencies {\n    compile \"org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version\"\n    compile \"com.xenomachina:xenocom:$xenocom_version\"\n\n    testCompile \"io.kotlintest:kotlintest-runner-junit5:$kotlintest_version\"\n    testCompile \"org.slf4j:slf4j-simple:$slf4j_version\"\n    // This is to ensure that kotlintest uses the correct version of\n    // kotlin-reflect\n    testCompile \"org.jetbrains.kotlin:kotlin-reflect:$kotlin_version\"\n}\n\nsourceSets {\n    main.java.srcDirs += 'src/main/kotlin'\n}\n\n//////////////////////////////////////////////////////////////////////////////\n// Detekt config\n//////////////////////////////////////////////////////////////////////////////\n\ndetekt {\n    // remove this when plugin stops choosing latest version by default\n    version = \"$detekt_version\"\n\n    defaultProfile {\n        input = file(\"src/main/kotlin\")\n\n        filters = \".*/resources/.*,.*/build/.*\"\n        config = file(\"detekt.yml\")\n    }\n}\n\n//////////////////////////////////////////////////////////////////////////////\n// Dokka config\n//////////////////////////////////////////////////////////////////////////////\n\ndokka {\n    moduleName = project.name\n\n    // TODO: includes = ['Module.md']\n\n    linkMapping {\n        dir = \"src/main/kotlin\"\n        url = \"$project.ext.vcsUrl/blob/master/src/main/kotlin\"\n        suffix = \"#L\"\n    }\n    sourceDirs = files('src/main/kotlin')\n}\n\ntask dokkaJavadoc(type: org.jetbrains.dokka.gradle.DokkaTask) {\n    outputFormat = \"javadoc\"\n    outputDirectory = javadoc.destinationDir\n\n    linkMapping {\n        dir = \"src/main/kotlin\"\n        url = \"$project.ext.vcsUrl/blob/master/src/main/kotlin\"\n        suffix = \"#L\"\n    }\n    sourceDirs = files('src/main/kotlin')\n}\n\n\n//Based on comment by @jnizet at https://github.com/Kotlin/dokka/issues/42\ntask javadocJar(type: Jar, dependsOn: dokkaJavadoc) {\n    classifier = 'javadoc'\n    from javadoc.destinationDir\n}\n\ntask sourcesJar(type: Jar, dependsOn: classes) {\n    classifier = 'sources'\n    from sourceSets.main.allSource\n}\n\nartifacts {\n    archives javadocJar, sourcesJar\n}\n\nif (System.env.CI != \"true\") {\n    // Some of the stuff in here can break continuous integration, and none of\n    // it is necessary in CI.\n\n    //////////////////////////////////////////////////////////////////////////////\n    // POM config\n    //////////////////////////////////////////////////////////////////////////////\n\n    def pomConfig = {\n        packaging 'jar'\n\n        name project.name\n        description project.description\n        url project.ext.vcsUrl\n\n        scm {\n            connection \"scm:git:$project.ext.vcsUrl\"\n            developerConnection \"scm:git:$project.ext.vcsDev\"\n            url \"$project.ext.vcsUrl\"\n        }\n\n        licenses {\n            license {\n                name \"GNU Lesser General Public License, Version 2.1\"\n                url \"https://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt\"\n                distribution \"repo\"\n            }\n        }\n\n        developers {\n            developer {\n                id \"xenomachina\"\n                name \"Laurence Gonsalves\"\n\n                // State-of-the art anti-scraper encryption. ;-)\n                email \"moc.anihcamonex@ecnerual\".reverse()\n            }\n        }\n    }\n\n    //////////////////////////////////////////////////////////////////////////////\n    // Maven Central upload\n    //////////////////////////////////////////////////////////////////////////////\n\n    signing {\n        useGpgCmd()\n        sign configurations.archives\n    }\n\n    def ossrhUsernameOrEmpty = hasProperty('ossrhUsername') ? ossrhUsername : ''\n    def ossrhPasswordOrEmpty = hasProperty('ossrhPassword') ? ossrhPassword : ''\n\n    uploadArchives {\n        repositories {\n            mavenDeployer {\n                beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) }\n\n                repository(url: \"https://oss.sonatype.org/service/local/staging/deploy/maven2/\") {\n                    authentication(userName: ossrhUsernameOrEmpty, password: ossrhPasswordOrEmpty)\n                }\n\n                snapshotRepository(url: \"https://oss.sonatype.org/content/repositories/snapshots/\") {\n                    authentication(userName: ossrhUsernameOrEmpty, password: ossrhPasswordOrEmpty)\n                }\n\n                pom.project pomConfig\n            }\n        }\n    }\n\n    //////////////////////////////////////////////////////////////////////////////\n    // bintray upload\n    //////////////////////////////////////////////////////////////////////////////\n\n    // Based on https://github.com/bintray/gradle-bintray-plugin\n    bintray {\n      user = System.getenv('BINTRAY_USER')\n      key = System.getenv('BINTRAY_KEY')\n\n      pkg {\n        repo = 'maven'\n        name = project.name\n        desc = project.description\n\n        licenses = ['LGPL-2.1']\n        vcsUrl = \"$project.ext.vcsUrl\"\n        websiteUrl = \"$project.ext.vcsUrl\"\n        issueTrackerUrl = \"$project.ext.vcsUrl/issues\"\n        githubRepo = project.ext.githubRepo\n        githubReleaseNotesFile = 'CHANGELOG.md'\n\n        version {\n          name = project.version\n          desc = \"$project.name version $project.version\"\n          released = new Date()\n          vcsTag = \"$project.version\"\n        }\n      }\n\n      publications = ['MyPublication']\n    }\n\n    // Create the publication with the pom configuration:\n    publishing {\n        publications {\n            MyPublication(MavenPublication) {\n                from components.java\n                artifact sourcesJar\n                artifact javadocJar\n\n                pom.withXml {\n                    def root = asNode()\n                    root.children().last() + pomConfig\n                }\n            }\n        }\n    }\n}\n\n//////////////////////////////////////////////////////////////////////////////\n// jacoco (codecov.io) plugin config\n//////////////////////////////////////////////////////////////////////////////\n\njacocoTestReport {\n    reports {\n        xml.enabled true\n        html.enabled false\n    }\n}\n"
  },
  {
    "path": "codecov.sh",
    "content": "#!/usr/bin/env bash\n\nset -e +o pipefail\n\nVERSION=\"8fda091\"\n\nurl=\"https://codecov.io\"\nenv=\"$CODECOV_ENV\"\nservice=\"\"\ntoken=\"\"\nsearch_in=\"\"\nflags=\"\"\nexit_with=0\ncurlargs=\"\"\ncurlawsargs=\"\"\ndump=\"0\"\nclean=\"0\"\ncurl_s=\"-s\"\nname=\"$CODECOV_NAME\"\ninclude_cov=\"\"\nexclude_cov=\"\"\nddp=\"$(echo ~)/Library/Developer/Xcode/DerivedData\"\nxp=\"\"\nfiles=\"\"\ncacert=\"$CODECOV_CA_BUNDLE\"\ngcov_ignore=\"\"\ngcov_include=\"\"\n\nft_gcov=\"1\"\nft_coveragepy=\"1\"\nft_fix=\"1\"\nft_search=\"1\"\nft_s3=\"1\"\nft_xcode=\"1\"\nft_network=\"1\"\nft_xcodeplist=\"0\"\n\n_git_root=$(git rev-parse --show-toplevel 2>/dev/null || hg root 2>/dev/null || echo $PWD)\ngit_root=\"$_git_root\"\nremote_addr=\"\"\nif [ \"$git_root\" = \"$PWD\" ];\nthen\n  git_root=\".\"\nfi\n\nurl_o=\"\"\npr_o=\"\"\nbuild_o=\"\"\ncommit_o=\"\"\nsearch_in_o=\"\"\ntag_o=\"\"\nbranch_o=\"\"\nslug_o=\"\"\n\ncommit=\"$VCS_COMMIT_ID\"\nbranch=\"$VCS_BRANCH_NAME\"\npr=\"$VCS_PULL_REQUEST\"\nslug=\"$VCS_SLUG\"\ntag=\"$VCS_TAG\"\nbuild_url=\"$CI_BUILD_URL\"\nbuild=\"$CI_BUILD_ID\"\njob=\"$CI_JOB_ID\"\n\nbeta_xcode_partials=\"\"\n\nproj_root=\"$git_root\"\ngcov_exe=\"gcov\"\ngcov_arg=\"\"\n\nb=\"\\033[0;36m\"\ng=\"\\033[0;32m\"\nr=\"\\033[0;31m\"\ne=\"\\033[0;90m\"\nx=\"\\033[0m\"\n\nshow_help() {\ncat << EOF\n\n                Codecov Bash $VERSION\n\n          Global report uploading tool for Codecov\n       Documentation at https://docs.codecov.io/docs\n    Contribute at https://github.com/codecov/codecov-bash\n\n\n    -h          Display this help and exit\n    -f FILE     Target file(s) to upload\n\n                 -f \"path/to/file\"     only upload this file\n                                       skips searching unless provided patterns below\n\n                 -f '!*.bar'           ignore all files at pattern *.bar\n                 -f '*.foo'            include all files at pattern *.foo\n                 Must use single quotes.\n                 This is non-exclusive, use -s \"*.foo\" to match specific paths.\n\n    -s DIR       Directory to search for coverage reports.\n                 Already searches project root and artifact folders.\n    -t TOKEN     Set the private repository token\n                 (option) set environment variable CODECOV_TOKEN=:uuid\n\n                 -t @/path/to/token_file\n                 -t uuid\n\n    -n NAME      Custom defined name of the upload. Visible in Codecov UI\n\n    -e ENV       Specify environment variables to be included with this build\n                 Also accepting environment variables: CODECOV_ENV=VAR,VAR2\n\n                 -e VAR,VAR2\n\n    -X feature   Toggle functionalities\n\n                 -X gcov          Disable gcov\n                 -X coveragepy    Disable python coverage\n                 -X fix           Disable report fixing\n                 -X search        Disable searching for reports\n                 -X xcode         Disable xcode processing\n                 -X network       Disable uploading the file network\n\n    -R root dir  Used when not in git/hg project to identify project root directory\n    -F flag      Flag the upload to group coverage metrics\n\n                 -F unittests        This upload is only unittests\n                 -F integration      This upload is only integration tests\n                 -F ui,chrome        This upload is Chrome - UI tests\n\n    -c           Move discovered coverage reports to the trash\n    -Z           Exit with 1 if not successful. Default will Exit with 0\n\n    -- xcode --\n    -D           Custom Derived Data Path for Coverage.profdata and gcov processing\n                 Default '~/Library/Developer/Xcode/DerivedData'\n    -J           Specify packages to build coverage.\n                 This can significantly reduces time to build coverage reports.\n\n                 -J 'MyAppName'      Will match \"MyAppName\" and \"MyAppNameTests\"\n                 -J '^ExampleApp$'   Will match only \"ExampleApp\" not \"ExampleAppTests\"\n\n    -- gcov --\n    -g GLOB      Paths to ignore during gcov gathering\n    -G GLOB      Paths to include during gcov gathering\n    -p dir       Project root directory\n                 Also used when preparing gcov\n    -x gcovexe   gcov executable to run. Defaults to 'gcov'\n    -a gcovargs  extra arguments to pass to gcov\n\n    -- Override CI Environment Variables --\n       These variables are automatically detected by popular CI providers\n\n    -B branch    Specify the branch name\n    -C sha       Specify the commit sha\n    -P pr        Specify the pull request number\n    -b build     Specify the build number\n    -T tag       Specify the git tag\n\n    -- Enterprise --\n    -u URL       Set the target url for Enterprise customers\n                 Not required when retrieving the bash uploader from your CCE\n                 (option) Set environment variable CODECOV_URL=https://my-hosted-codecov.com\n    -r SLUG      owner/repo slug used instead of the private repo token in Enterprise\n                 (option) set environment variable CODECOV_SLUG=:owner/:repo\n                 (option) set in your codecov.yml \"codecov.slug\"\n    -S PATH      File path to your cacert.pem file used to verify ssl with Codecov Enterprise (optional)\n                 (option) Set environment variable: CODECOV_CA_BUNDLE=\"/path/to/ca.pem\"\n    -U curlargs  Extra curl arguments to communicate with Codecov. e.g., -U \"--proxy http://http-proxy\"\n    -A curlargs  Extra curl arguments to communicate with AWS.\n\n    -- Debugging --\n    -d           Dont upload and dump to stdout\n    -K           Remove color from the output\n    -v           Verbose mode\n\nEOF\n}\n\n\nsay() {\n  echo -e \"$1\"\n}\n\n\nurlencode() {\n  echo \"$1\" | curl -Gso /dev/null -w %{url_effective} --data-urlencode @- \"\" | cut -c 3- | sed -e 's/%0A//'\n}\n\n\nswiftcov() {\n  _dir=$(dirname \"$1\")\n  for _type in app framework xctest\n  do\n    find \"$_dir\" -name \"*.$_type\" | while read f\n    do\n      _proj=${f##*/}\n      _proj=${_proj%.\"$_type\"}\n      if [ \"$2\" = \"\" ] || [ \"$(echo \"$_proj\" | grep -i \"$2\")\" != \"\" ];\n      then\n        say \"    $g+$x Building reports for $_proj $_type\"\n        dest=$([ -f \"$f/$_proj\" ] && echo \"$f/$_proj\" || echo \"$f/Contents/MacOS/$_proj\")\n        _proj_name=$(echo \"$_proj\" | sed -e 's/[[:space:]]//g')\n        xcrun llvm-cov show $beta_xcode_partials -instr-profile \"$1\" \"$dest\" > \"$_proj_name.$_type.coverage.txt\" \\\n         || say \"    ${r}x>${x} llvm-cov failed to produce results for $dest\"\n      fi\n    done\n  done\n}\n\n\n# Credits to: https://gist.github.com/pkuczynski/8665367\nparse_yaml() {\n   local prefix=$2\n   local s='[[:space:]]*' w='[a-zA-Z0-9_]*' fs=$(echo @|tr @ '\\034')\n   sed -ne \"s|^\\($s\\)\\($w\\)$s:$s\\\"\\(.*\\)\\\"$s\\$|\\1$fs\\2$fs\\3|p\" \\\n        -e \"s|^\\($s\\)\\($w\\)$s:$s\\(.*\\)$s\\$|\\1$fs\\2$fs\\3|p\" $1 |\n   awk -F$fs '{\n      indent = length($1)/2;\n      vname[indent] = $2;\n      for (i in vname) {if (i > indent) {delete vname[i]}}\n      if (length($3) > 0) {\n         vn=\"\"; if (indent > 0) {vn=(vn)(vname[0])(\"_\")}\n         printf(\"%s%s%s=\\\"%s\\\"\\n\", \"'$prefix'\",vn, $2, $3);\n      }\n   }'\n}\n\n\nif [ $# != 0 ];\nthen\n  while getopts \"a:A:b:B:cC:dD:e:f:F:g:G:hJ:Kn:p:P:r:R:s:S:t:T:u:U:vx:X:Z\" o\n  do\n    case \"$o\" in\n      \"a\")\n        gcov_arg=$OPTARG\n        ;;\n      \"A\")\n        curlawsargs=\"$OPTARG\"\n        ;;\n      \"b\")\n        build_o=\"$OPTARG\"\n        ;;\n      \"B\")\n        branch_o=\"$OPTARG\"\n        ;;\n      \"c\")\n        clean=\"1\"\n        ;;\n      \"C\")\n        commit_o=\"$OPTARG\"\n        ;;\n      \"d\")\n        dump=\"1\"\n        ;;\n      \"D\")\n        ddp=\"$OPTARG\"\n        ;;\n      \"e\")\n        env=\"$env,$OPTARG\"\n        ;;\n      \"f\")\n        if [ \"${OPTARG::1}\" = \"!\" ];\n        then\n          exclude_cov=\"$exclude_cov -not -path '${OPTARG:1}'\"\n\n        elif [[ \"$OPTARG\" = *\"*\"* ]];\n        then\n          include_cov=\"$include_cov -or -name '$OPTARG'\"\n\n        else\n          ft_search=0\n          if [ \"$files\" = \"\" ];\n          then\n            files=\"$OPTARG\"\n          else\n            files=\"$files\n$OPTARG\"\n          fi\n        fi\n        ;;\n      \"F\")\n        if [ \"$flags\" = \"\" ];\n        then\n          flags=\"$OPTARG\"\n        else\n          flags=\"$flags,$OPTARG\"\n        fi\n        ;;\n      \"g\")\n        gcov_ignore=\"$gcov_ignore -not -path '$OPTARG'\"\n        ;;\n      \"G\")\n        gcov_include=\"$gcov_include -path '$OPTARG'\"\n        ;;\n      \"h\")\n        show_help\n        exit 0;\n        ;;\n      \"J\")\n        if [ \"$xp\" = \"\" ];\n        then\n          xp=\"$OPTARG\"\n        else\n          xp=\"$xp\\|$OPTARG\"\n        fi\n        ;;\n      \"K\")\n        b=\"\"\n        g=\"\"\n        r=\"\"\n        e=\"\"\n        x=\"\"\n        ;;\n      \"n\")\n        name=\"$OPTARG\"\n        ;;\n      \"p\")\n        proj_root=\"$OPTARG\"\n        ;;\n      \"P\")\n        pr_o=\"$OPTARG\"\n        ;;\n      \"r\")\n        slug_o=\"$OPTARG\"\n        ;;\n      \"R\")\n        git_root=\"$OPTARG\"\n        ;;\n      \"s\")\n        if [ \"$search_in_o\" = \"\" ];\n        then\n          search_in_o=\"$OPTARG\"\n        else\n          search_in_o=\"$search_in_o $OPTARG\"\n        fi\n        ;;\n      \"S\")\n        cacert=\"--cacert \\\"$OPTARG\\\"\"\n        ;;\n      \"t\")\n        if [ \"${OPTARG::1}\" = \"@\" ];\n        then\n          token=$(cat \"${OPTARG:1}\" | tr -d ' \\n')\n        else\n          token=\"$OPTARG\"\n        fi\n        ;;\n      \"T\")\n        tag_o=\"$OPTARG\"\n        ;;\n      \"u\")\n        url_o=$(echo \"$OPTARG\" | sed -e 's/\\/$//')\n        ;;\n      \"U\")\n        curlargs=\"$OPTARG\"\n        ;;\n      \"v\")\n        set -x\n        curl_s=\"\"\n        ;;\n      \"x\")\n        gcov_exe=$OPTARG\n        ;;\n      \"X\")\n        if [ \"$OPTARG\" = \"gcov\" ];\n        then\n          ft_gcov=\"0\"\n        elif [ \"$OPTARG\" = \"coveragepy\" ] || [ \"$OPTARG\" = \"py\" ];\n        then\n          ft_coveragepy=\"0\"\n        elif [ \"$OPTARG\" = \"xcodeplist\" ];\n        then\n          ft_xcodeplist=\"1\"\n          ft_xcode=\"0\"\n        elif [ \"$OPTARG\" = \"fix\" ] || [ \"$OPTARG\" = \"fixes\" ];\n        then\n          ft_fix=\"0\"\n        elif [ \"$OPTARG\" = \"xcode\" ];\n        then\n          ft_xcode=\"0\"\n        elif [ \"$OPTARG\" = \"search\" ];\n        then\n          ft_search=\"0\"\n        elif [ \"$OPTARG\" = \"xcodepartials\" ];\n        then\n          beta_xcode_partials=\"-use-color\"\n        elif [ \"$OPTARG\" = \"network\" ];\n        then\n          ft_network=\"0\"\n        fi\n        ;;\n      \"Z\")\n        exit_with=1\n        ;;\n    esac\n  done\nfi\n\nsay \"\n  _____          _\n / ____|        | |\n| |     ___   __| | ___  ___ _____   __\n| |    / _ \\\\ / _\\` |/ _ \\\\/ __/ _ \\\\ \\\\ / /\n| |___| (_) | (_| |  __/ (_| (_) \\\\ V /\n \\\\_____\\\\___/ \\\\__,_|\\\\___|\\\\___\\\\___/ \\\\_/\n                              Bash-$VERSION\n\n\"\n\nsearch_in=\"$proj_root\"\n\nif [ \"$JENKINS_URL\" != \"\" ];\nthen\n  say \"$e==>$x Jenkins CI detected.\"\n  # https://wiki.jenkins-ci.org/display/JENKINS/Building+a+software+project\n  # https://wiki.jenkins-ci.org/display/JENKINS/GitHub+pull+request+builder+plugin#GitHubpullrequestbuilderplugin-EnvironmentVariables\n  service=\"jenkins\"\n  branch=$([ ! -z \"$ghprbSourceBranch\" ] && echo \"$ghprbSourceBranch\" || \\\n           [ ! -z \"$GIT_BRANCH\" ] && echo \"$GIT_BRANCH\" || \\\n           [ ! -z \"$BRANCH_NAME\" ] && echo \"$BRANCH_NAME\")\n  commit=$([ ! -z \"$ghprbActualCommit\" ] && echo \"$ghprbActualCommit\" || \\\n           echo \"$GIT_COMMIT\")\n  build=\"$BUILD_NUMBER\"\n  pr=\"${ghprbPullId:=$CHANGE_ID}\"\n  build_url=$(urlencode \"$BUILD_URL\")\n\nelif [ \"$CI\" = \"true\" ] && [ \"$TRAVIS\" = \"true\" ] && [ \"$SHIPPABLE\" != \"true\" ];\nthen\n  say \"$e==>$x Travis CI detected.\"\n  # http://docs.travis-ci.com/user/ci-environment/#Environment-variables\n  service=\"travis\"\n  branch=\"$TRAVIS_BRANCH\"\n  commit=\"$TRAVIS_COMMIT\"\n  build=\"$TRAVIS_JOB_NUMBER\"\n  pr=\"$TRAVIS_PULL_REQUEST\"\n  job=\"$TRAVIS_JOB_ID\"\n  slug=\"$TRAVIS_REPO_SLUG\"\n  tag=\"$TRAVIS_TAG\"\n  env=\"$env,TRAVIS_OS_NAME\"\n\n  language=$(printenv | grep \"TRAVIS_.*_VERSION\" | head -1)\n  if [ \"$language\" != \"\" ];\n  then\n    env=\"$env,${language%=*}\"\n  fi\n\nelif [ \"$CI\" = \"true\" ] && [ \"$CI_NAME\" = \"codeship\" ];\nthen\n  say \"$e==>$x Codeship CI detected.\"\n  # https://www.codeship.io/documentation/continuous-integration/set-environment-variables/\n  service=\"codeship\"\n  branch=\"$CI_BRANCH\"\n  build=\"$CI_BUILD_NUMBER\"\n  build_url=$(urlencode \"$CI_BUILD_URL\")\n  commit=\"$CI_COMMIT_ID\"\n\nelif [ \"$TEAMCITY_VERSION\" != \"\" ];\nthen\n  say \"$e==>$x TeamCity CI detected.\"\n  # https://confluence.jetbrains.com/display/TCD8/Predefined+Build+Parameters\n  # https://confluence.jetbrains.com/plugins/servlet/mobile#content/view/74847298\n  if [ \"$TEAMCITY_BUILD_BRANCH\" = '' ];\n  then\n    echo \"    Teamcity does not automatically make build parameters available as environment variables.\"\n    echo \"    Add the following environment parameters to the build configuration\"\n    echo \"    env.TEAMCITY_BUILD_BRANCH = %teamcity.build.branch%\"\n    echo \"    env.TEAMCITY_BUILD_ID = %teamcity.build.id%\"\n    echo \"    env.TEAMCITY_BUILD_URL = %teamcity.serverUrl%/viewLog.html?buildId=%teamcity.build.id%\"\n    echo \"    env.TEAMCITY_BUILD_COMMIT = %system.build.vcs.number%\"\n    echo \"    env.TEAMCITY_BUILD_REPOSITORY = %vcsroot.<YOUR TEAMCITY VCS NAME>.url%\"\n  fi\n  service=\"teamcity\"\n  branch=\"$TEAMCITY_BUILD_BRANCH\"\n  build=\"$TEAMCITY_BUILD_ID\"\n  build_url=$(urlencode \"$TEAMCITY_BUILD_URL\")\n  if [ \"$TEAMCITY_BUILD_COMMIT\" != \"\" ];\n  then\n    commit=\"$TEAMCITY_BUILD_COMMIT\"\n  else\n    commit=\"$BUILD_VCS_NUMBER\"\n  fi\n  remote_addr=\"$TEAMCITY_BUILD_REPOSITORY\"\n\nelif [ \"$CI\" = \"true\" ] && [ \"$CIRCLECI\" = \"true\" ];\nthen\n  say \"$e==>$x Circle CI detected.\"\n  # https://circleci.com/docs/environment-variables\n  service=\"circleci\"\n  branch=\"$CIRCLE_BRANCH\"\n  build=\"$CIRCLE_BUILD_NUM\"\n  job=\"$CIRCLE_NODE_INDEX\"\n  if [ \"$CIRCLE_PROJECT_REPONAME\" != \"\" ];\n  then\n    slug=\"$CIRCLE_PROJECT_USERNAME/$CIRCLE_PROJECT_REPONAME\"\n  else\n    # git@github.com:owner/repo.git\n    slug=\"${CIRCLE_REPOSITORY_URL##*:}\"\n    # owner/repo.git\n    slug=\"${slug%%.git}\"\n  fi\n  pr=\"$CIRCLE_PR_NUMBER\"\n  commit=\"$CIRCLE_SHA1\"\n  search_in=\"$search_in $CIRCLE_ARTIFACTS $CIRCLE_TEST_REPORTS\"\n\nelif [ \"$BUDDYBUILD_BRANCH\" != \"\" ];\nthen\n  say \"$e==>$x buddybuild detected\"\n  # http://docs.buddybuild.com/v6/docs/custom-prebuild-and-postbuild-steps\n  service=\"buddybuild\"\n  branch=\"$BUDDYBUILD_BRANCH\"\n  build=\"$BUDDYBUILD_BUILD_NUMBER\"\n  build_url=\"https://dashboard.buddybuild.com/public/apps/$BUDDYBUILD_APP_ID/build/$BUDDYBUILD_BUILD_ID\"\n  # BUDDYBUILD_TRIGGERED_BY\n  if [ \"$ddp\" = \"$(echo ~)/Library/Developer/Xcode/DerivedData\" ];\n  then\n    ddp=\"/private/tmp/sandbox/${BUDDYBUILD_APP_ID}/bbtest\"\n  fi\n\nelif [ \"${bamboo_planRepository_revision}\" != \"\" ];\nthen\n  say \"$e==>$x Bamboo detected\"\n  # https://confluence.atlassian.com/bamboo/bamboo-variables-289277087.html#Bamboovariables-Build-specificvariables\n  service=\"bamboo\"\n  commit=\"${bamboo_planRepository_revision}\"\n  branch=\"${bamboo_planRepository_branch}\"\n  build=\"${bamboo_buildNumber}\"\n  build_url=\"${bamboo_buildResultsUrl}\"\n  remote_addr=\"${bamboo_planRepository_repositoryUrl}\"\n\nelif [ \"$CI\" = \"true\" ] && [ \"$BITRISE_IO\" = \"true\" ];\nthen\n  # http://devcenter.bitrise.io/faq/available-environment-variables/\n  say \"$e==>$x Bitrise CI detected.\"\n  service=\"bitrise\"\n  branch=\"$BITRISE_GIT_BRANCH\"\n  build=\"$BITRISE_BUILD_NUMBER\"\n  build_url=$(urlencode \"$BITRISE_BUILD_URL\")\n  pr=\"$BITRISE_PULL_REQUEST\"\n  if [ \"$GIT_CLONE_COMMIT_HASH\" != \"\" ];\n  then\n    commit=\"$GIT_CLONE_COMMIT_HASH\"\n  fi\n\nelif [ \"$CI\" = \"true\" ] && [ \"$SEMAPHORE\" = \"true\" ];\nthen\n  say \"$e==>$x Semaphore CI detected.\"\n  # https://semaphoreapp.com/docs/available-environment-variables.html\n  service=\"semaphore\"\n  branch=\"$BRANCH_NAME\"\n  build=\"$SEMAPHORE_BUILD_NUMBER\"\n  job=\"$SEMAPHORE_CURRENT_THREAD\"\n  pr=\"$PULL_REQUEST_NUMBER\"\n  slug=\"$SEMAPHORE_REPO_SLUG\"\n  commit=\"$REVISION\"\n  env=\"$env,SEMAPHORE_TRIGGER_SOURCE\"\n\nelif [ \"$CI\" = \"true\" ] && [ \"$BUILDKITE\" = \"true\" ];\nthen\n  say \"$e==>$x Buildkite CI detected.\"\n  # https://buildkite.com/docs/guides/environment-variables\n  service=\"buildkite\"\n  branch=\"$BUILDKITE_BRANCH\"\n  build=\"$BUILDKITE_BUILD_NUMBER\"\n  job=\"$BUILDKITE_JOB_ID\"\n  build_url=$(urlencode \"$BUILDKITE_BUILD_URL\")\n  slug=\"$BUILDKITE_PROJECT_SLUG\"\n  commit=\"$BUILDKITE_COMMIT\"\n\nelif [ \"$CI\" = \"true\" ] && [ \"$DRONE\" = \"true\" ];\nthen\n  say \"$e==>$x Drone CI detected.\"\n  # http://docs.drone.io/env.html\n  # drone commits are not full shas\n  service=\"drone.io\"\n  branch=\"$DRONE_BRANCH\"\n  build=\"$DRONE_BUILD_NUMBER\"\n  build_url=$(urlencode \"${DRONE_BUILD_URL:-$CI_BUILD_URL}\")\n  pr=\"$DRONE_PULL_REQUEST\"\n  job=\"$DRONE_JOB_NUMBER\"\n  tag=\"$DRONE_TAG\"\n\nelif [ \"$HEROKU_TEST_RUN_BRANCH\" != \"\" ];\nthen\n  say \"$e==>$x Heroku CI detected.\"\n  # https://devcenter.heroku.com/articles/heroku-ci#environment-variables\n  service=\"heroku\"\n  branch=\"$HEROKU_TEST_RUN_BRANCH\"\n  build=\"$HEROKU_TEST_RUN_ID\"\n\nelif [ \"$CI\" = \"True\" ] && [ \"$APPVEYOR\" = \"True\" ];\nthen\n  say \"$e==>$x Appveyor CI detected.\"\n  # http://www.appveyor.com/docs/environment-variables\n  service=\"appveyor\"\n  branch=\"$APPVEYOR_REPO_BRANCH\"\n  build=$(urlencode \"$APPVEYOR_JOB_ID\")\n  pr=\"$APPVEYOR_PULL_REQUEST_NUMBER\"\n  job=\"$APPVEYOR_ACCOUNT_NAME%2F$APPVEYOR_PROJECT_SLUG%2F$APPVEYOR_BUILD_VERSION\"\n  slug=\"$APPVEYOR_REPO_NAME\"\n  commit=\"$APPVEYOR_REPO_COMMIT\"\n\nelif [ \"$CI\" = \"true\" ] && [ \"$WERCKER_GIT_BRANCH\" != \"\" ];\nthen\n  say \"$e==>$x Wercker CI detected.\"\n  # http://devcenter.wercker.com/articles/steps/variables.html\n  service=\"wercker\"\n  branch=\"$WERCKER_GIT_BRANCH\"\n  build=\"$WERCKER_MAIN_PIPELINE_STARTED\"\n  slug=\"$WERCKER_GIT_OWNER/$WERCKER_GIT_REPOSITORY\"\n  commit=\"$WERCKER_GIT_COMMIT\"\n\nelif [ \"$CI\" = \"true\" ] && [ \"$MAGNUM\" = \"true\" ];\nthen\n  say \"$e==>$x Magnum CI detected.\"\n  # https://magnum-ci.com/docs/environment\n  service=\"magnum\"\n  branch=\"$CI_BRANCH\"\n  build=\"$CI_BUILD_NUMBER\"\n  commit=\"$CI_COMMIT\"\n\nelif [ \"$CI\" = \"true\" ] && [ \"$SNAP_CI\" = \"true\" ];\nthen\n  say \"$e==>$x Snap CI detected.\"\n  # https://docs.snap-ci.com/environment-variables/\n  service=\"snap\"\n  branch=$([ \"$SNAP_BRANCH\" != \"\" ] && echo \"$SNAP_BRANCH\" || echo \"$SNAP_UPSTREAM_BRANCH\")\n  build=\"$SNAP_PIPELINE_COUNTER\"\n  job=\"$SNAP_STAGE_NAME\"\n  pr=\"$SNAP_PULL_REQUEST_NUMBER\"\n  commit=$([ \"$SNAP_COMMIT\" != \"\" ] && echo \"$SNAP_COMMIT\" || echo \"$SNAP_UPSTREAM_COMMIT\")\n  env=\"$env,DISPLAY\"\n\nelif [ \"$SHIPPABLE\" = \"true\" ];\nthen\n  say \"$e==>$x Shippable CI detected.\"\n  # http://docs.shippable.com/ci_configure/\n  service=\"shippable\"\n  branch=$([ \"$HEAD_BRANCH\" != \"\" ] && echo \"$HEAD_BRANCH\" || echo \"$BRANCH\")\n  build=\"$BUILD_NUMBER\"\n  build_url=$(urlencode \"$BUILD_URL\")\n  pr=\"$PULL_REQUEST\"\n  slug=\"$REPO_FULL_NAME\"\n  commit=\"$COMMIT\"\n\nelif [ \"$TDDIUM\" = \"true\" ];\nthen\n  say \"Solano CI detected.\"\n  # http://docs.solanolabs.com/Setup/tddium-set-environment-variables/\n  service=\"solano\"\n  commit=\"$TDDIUM_CURRENT_COMMIT\"\n  branch=\"$TDDIUM_CURRENT_BRANCH\"\n  build=\"$TDDIUM_TID\"\n  pr=\"$TDDIUM_PR_ID\"\n\nelif [ \"$GREENHOUSE\" = \"true\" ];\nthen\n  say \"$e==>$x Greenhouse CI detected.\"\n  # http://docs.greenhouseci.com/docs/environment-variables-files\n  service=\"greenhouse\"\n  branch=\"$GREENHOUSE_BRANCH\"\n  build=\"$GREENHOUSE_BUILD_NUMBER\"\n  build_url=$(urlencode \"$GREENHOUSE_BUILD_URL\")\n  pr=\"$GREENHOUSE_PULL_REQUEST\"\n  commit=\"$GREENHOUSE_COMMIT\"\n  search_in=\"$search_in $GREENHOUSE_EXPORT_DIR\"\n\nelif [ \"$GITLAB_CI\" != \"\" ];\nthen\n  say \"$e==>$x GitLab CI detected.\"\n  # http://doc.gitlab.com/ce/ci/variables/README.html\n  service=\"gitlab\"\n  branch=\"$CI_BUILD_REF_NAME\"\n  build=\"$CI_BUILD_ID\"\n  remote_addr=\"${CI_BUILD_REPO:-$CI_REPOSITORY_URL}\"\n  commit=\"$CI_BUILD_REF\"\n\nelse\n  say \"${r}x>${x} No CI provider detected.\"\n  say \"    Testing inside Docker? ${b}http://docs.codecov.io/docs/testing-with-docker${x}\"\n  say \"    Testing with Tox? ${b}https://docs.codecov.io/docs/python#section-testing-with-tox${x}\"\n\nfi\n\nsay \"    ${e}project root:${x} $git_root\"\n\n# find branch, commit, repo from git command\nif [ \"$GIT_BRANCH\" != \"\" ];\nthen\n  branch=\"$GIT_BRANCH\"\n\nelif [ \"$branch\" = \"\" ];\nthen\n  branch=$(git rev-parse --abbrev-ref HEAD 2>/dev/null || hg branch 2>/dev/null || echo \"\")\n  if [ \"$branch\" = \"HEAD\" ];\n  then\n    branch=\"\"\n  fi\nfi\n\nif [ \"$commit_o\" = \"\" ];\nthen\n  # merge commit -> actual commit\n  mc=$(git log -1 --pretty=%B 2>/dev/null | tr -d '[[:space:]]' || true)\n  if [[ \"$mc\" =~ ^Merge[[:space:]][a-z0-9]{40}[[:space:]]into[[:space:]][a-z0-9]{40}$ ]];\n  then\n    # Merge xxx into yyy\n    say \"    Fixing merge commit sha\"\n    commit=$(echo \"$mc\" | cut -d' ' -f2)\n  elif [ \"$GIT_COMMIT\" != \"\" ];\n  then\n    commit=\"$GIT_COMMIT\"\n  elif [ \"$commit\" = \"\" ];\n  then\n    commit=$(git log -1 --format=\"%H\" 2>/dev/null || hg id -i --debug 2>/dev/null | tr -d '+' || echo \"\")\n  fi\nelse\n  commit=\"$commit_o\"\nfi\n\nif [ \"$CODECOV_TOKEN\" != \"\" ] && [ \"$token\" = \"\" ];\nthen\n  say \"${e}-->${x} token set from env\"\n  token=\"$CODECOV_TOKEN\"\nfi\n\nif [ \"$CODECOV_URL\" != \"\" ] && [ \"$url_o\" = \"\" ];\nthen\n  say \"${e}-->${x} url set from env\"\n  url_o=$(echo \"$CODECOV_URL\" | sed -e 's/\\/$//')\nfi\n\nif [ \"$CODECOV_SLUG\" != \"\" ];\nthen\n  say \"${e}-->${x} slug set from env\"\n  slug_o=\"$CODECOV_SLUG\"\n\nelif [ \"$slug\" = \"\" ];\nthen\n  if [ \"$remote_addr\" = \"\" ];\n  then\n    remote_addr=$(git config --get remote.origin.url || hg paths default || echo '')\n  fi\n  if [ \"$remote_addr\" != \"\" ];\n  then\n    if echo \"$remote_addr\" | grep -q \"//\"; then\n      # https\n      slug=$(echo \"$remote_addr\" | cut -d / -f 4,5 | sed -e 's/\\.git$//')\n    else\n      # ssh\n      slug=$(echo \"$remote_addr\" | cut -d : -f 2 | sed -e 's/\\.git$//')\n    fi\n  fi\n  if [ \"$slug\" = \"/\" ];\n  then\n    slug=\"\"\n  fi\nfi\n\nyaml=$(cd \"$git_root\" && \\\n       git ls-files \"*codecov.yml\" \"*codecov.yaml\" 2>/dev/null \\\n       || hg locate \"*codecov.yml\" \"*codecov.yaml\" 2>/dev/null \\\n       || echo '')\nyaml=$(echo \"$yaml\" | head -1)\n\nif [ \"$yaml\" != \"\" ];\nthen\n  say \"    ${e}Yaml found at:${x} $yaml\"\n  config=$(parse_yaml \"$git_root/$yaml\" || echo '')\n\n  # TODO validate the yaml here\n\n  if [ \"$(echo \"$config\" | grep 'codecov_token=\"')\" != \"\" ] && [ \"$token\" = \"\" ];\n  then\n    say \"${e}-->${x} token set from yaml\"\n    token=\"$(echo \"$config\" | grep 'codecov_token=\"' | sed -e 's/codecov_token=\"//' | sed -e 's/\"\\.*//')\"\n  fi\n\n  if [ \"$(echo \"$config\" | grep 'codecov_url=\"')\" != \"\" ] && [ \"$url_o\" = \"\" ];\n  then\n    say \"${e}-->${x} url set from yaml\"\n    url_o=\"$(echo \"$config\" | grep 'codecov_url=\"' | sed -e 's/codecov_url=\"//' | sed -e 's/\"\\.*//')\"\n  fi\n\n  if [ \"$(echo \"$config\" | grep 'codecov_slug=\"')\" != \"\" ] && [ \"$slug_o\" = \"\" ];\n  then\n    say \"${e}-->${x} slug set from yaml\"\n    slug_o=\"$(echo \"$config\" | grep 'codecov_slug=\"' | sed -e 's/codecov_slug=\"//' | sed -e 's/\"\\.*//')\"\n  fi\nelse\n  say \"    ${g}Yaml not found, that's ok! Learn more at${x} ${b}http://docs.codecov.io/docs/codecov-yaml${x}\"\n\nfi\n\nif [ \"$branch_o\" != \"\" ];\nthen\n  branch=$(urlencode \"$branch_o\")\nelse\n  branch=$(urlencode \"$branch\")\nfi\n\nquery=\"branch=$branch\\\n       &commit=$commit\\\n       &build=$([ \"$build_o\" = \"\" ] && echo \"$build\" || echo \"$build_o\")\\\n       &build_url=$build_url\\\n       &name=$(urlencode \"$name\")\\\n       &tag=$([ \"$tag_o\" = \"\" ] && echo \"$tag\" || echo \"$tag_o\")\\\n       &slug=$([ \"$slug_o\" = \"\" ] && urlencode \"$slug\" || urlencode \"$slug_o\")\\\n       &yaml=$(urlencode \"$yaml\")\\\n       &service=$service\\\n       &flags=$flags\\\n       &pr=$([ \"$pr_o\" = \"\" ] && echo \"${pr##\\#}\" || echo \"${pr_o##\\#}\")\\\n       &job=$job\"\n\nif [ \"$ft_search\" = \"1\" ];\nthen\n  # detect bower comoponents location\n  bower_components=\"bower_components\"\n  bower_rc=$(cd \"$git_root\" && cat .bowerrc 2>/dev/null || echo \"\")\n  if [ \"$bower_rc\" != \"\" ];\n  then\n    bower_components=$(echo \"$bower_rc\" | tr -d '\\n' | grep '\"directory\"' | cut -d'\"' -f4 | sed -e 's/\\/$//')\n    if [ \"$bower_components\" = \"\" ];\n    then\n      bower_components=\"bower_components\"\n    fi\n  fi\n\n  # Swift Coverage\n  if [ \"$ft_xcode\" = \"1\" ] && [ -d \"$ddp\" ];\n  then\n    say \"${e}==>${x} Processing Xcode reports\"\n    say \"    DerivedData folder: $ddp\"\n    profdata_files=$(find \"$ddp\" -name '*.profdata' 2>/dev/null || echo '')\n    if [ \"$profdata_files\" != \"\" ];\n    then\n      # xcode via profdata\n      if [ \"$xp\" = \"\" ];\n      then\n        # xp=$(xcodebuild -showBuildSettings 2>/dev/null | grep -i \"^\\s*PRODUCT_NAME\" | sed -e 's/.*= \\(.*\\)/\\1/')\n        # say \" ${e}->${x} Speed up Xcode processing by adding ${e}-J '$xp'${x}\"\n        say \"    ${g}hint${x} Speed up Swift processing by using use ${g}-J 'AppName'${x} (regexp accepted)\"\n        say \"    ${g}hint${x} This will remove Pods/ from your report. Also ${b}https://docs.codecov.io/docs/ignoring-paths${x}\"\n      fi\n      while read -r profdata;\n      do\n        if [ \"$profdata\" != \"\" ];\n        then\n          swiftcov \"$profdata\" \"$xp\"\n        fi\n      done <<< \"$profdata_files\"\n    else\n      say \"    ${e}->${x} No Swift coverage found\"\n    fi\n\n    # Obj-C Gcov Coverage\n    if [ \"$ft_gcov\" = \"1\" ];\n    then\n      say \"    ${e}->${x} Running $gcov_exe for Obj-C\"\n      bash -c \"find $ddp -type f -name '*.gcda' $gcov_include $gcov_ignore -exec $gcov_exe -pbcu $gcov_arg {} +\" || true\n    fi\n  fi\n\n  if [ \"$ft_xcodeplist\" = \"1\" ] && [ -d \"$ddp\" ];\n  then\n    say \"${e}==>${x} Processing Xcode plists\"\n    plists_files=$(find \"$ddp\" -name '*.xccoverage' 2>/dev/null || echo '')\n    if [ \"$plists_files\" != \"\" ];\n    then\n      while read -r plist;\n      do\n        if [ \"$plist\" != \"\" ];\n        then\n          say \"    ${g}Found${x} plist file at $plist\"\n          plutil -convert xml1 -o \"$(basename \"$plist\").plist\" -- $plist\n        fi\n      done <<< \"$plists_files\"\n    fi\n  fi\n\n  # Gcov Coverage\n  if [ \"$ft_gcov\" = \"1\" ];\n  then\n    say \"${e}==>${x} Running gcov in $proj_root ${e}(disable via -X gcov)${x}\"\n    bash -c \"find $proj_root -type f -name '*.gcno' $gcov_include $gcov_ignore -exec $gcov_exe -pb $gcov_arg {} +\" || true\n  else\n    say \"${e}==>${x} gcov disabled\"\n  fi\n\n  # Python Coverage\n  if [ \"$ft_coveragepy\" = \"1\" ];\n  then\n    if [ ! -f coverage.xml ];\n    then\n      if which coverage >/dev/null 2>&1;\n      then\n        say \"${e}==>${x} Python coveragepy exists ${e}disable via -X coveragepy${x}\"\n\n        dotcoverage=$(find \"$git_root\" -name '.coverage' -or -name '.coverage.*' | head -1 || echo '')\n        if [ \"$dotcoverage\" != \"\" ];\n        then\n          cd \"$(dirname \"$dotcoverage\")\"\n          if [ ! -f .coverage ];\n          then\n            say \"    ${e}->${x} Running coverage combine\"\n            coverage combine\n          fi\n          say \"    ${e}->${x} Running coverage xml\"\n          if [ \"$(coverage xml -i)\" != \"No data to report.\" ];\n          then\n            files=\"$files\n$PWD/coverage.xml\"\n          else\n            say \"    ${r}No data to report.${x}\"\n          fi\n          cd \"$proj_root\"\n        else\n          say \"    ${r}No .coverage file found.${x}\"\n        fi\n      else\n        say \"${e}==>${x} Python coveragepy not found\"\n      fi\n    fi\n  else\n    say \"${e}==>${x} Python coveragepy disabled\"\n  fi\n\n  if [ \"$search_in_o\" != \"\" ];\n  then\n    # location override\n    search_in=\"$search_in_o\"\n  fi\n\n  say \"$e==>$x Searching for coverage reports in:\"\n  for _path in $search_in\n  do\n    say \"    ${g}+${x} $_path\"\n  done\n\n  patterns=\"find $search_in -type f \\( -name '*coverage*.*' \\\n                     -or -name 'nosetests.xml' \\\n                     -or -name 'jacoco*.xml' \\\n                     -or -name 'clover.xml' \\\n                     -or -name 'report.xml' \\\n                     -or -name '*.codecov.*' \\\n                     -or -name 'codecov.*' \\\n                     -or -name 'cobertura.xml' \\\n                     -or -name 'excoveralls.json' \\\n                     -or -name 'luacov.report.out' \\\n                     -or -name 'coverage-final.json' \\\n                     -or -name 'naxsi.info' \\\n                     -or -name 'lcov.info' \\\n                     -or -name 'lcov.dat' \\\n                     -or -name '*.lcov' \\\n                     -or -name '*.clover' \\\n                     -or -name 'cover.out' \\\n                     -or -name 'gcov.info' \\\n                     -or -name '*.gcov' \\\n                     -or -name '*.lst' \\\n                     $include_cov \\) \\\n                    $exclude_cov \\\n                    -not -name '*.profdata' \\\n                    -not -name 'coverage-summary.json' \\\n                    -not -name 'phpunit-code-coverage.xml' \\\n                    -not -name 'remapInstanbul.coverage*.json' \\\n                    -not -name 'phpunit-coverage.xml' \\\n                    -not -name '*codecov.yml' \\\n                    -not -name '*.serialized' \\\n                    -not -name '.coverage*' \\\n                    -not -name '.*coveragerc' \\\n                    -not -name '*.sh' \\\n                    -not -name '*.bat' \\\n                    -not -name '*.ps1' \\\n                    -not -name '*.cmake' \\\n                    -not -name '*.dox' \\\n                    -not -name '*.ec' \\\n                    -not -name '*.rst' \\\n                    -not -name '*.h' \\\n                    -not -name '*.scss' \\\n                    -not -name '*.o' \\\n                    -not -name '*.proto' \\\n                    -not -name '*.sbt' \\\n                    -not -name '*.xcoverage.*' \\\n                    -not -name '*.gz' \\\n                    -not -name '*.conf' \\\n                    -not -name '*.p12' \\\n                    -not -name '*.csv' \\\n                    -not -name '*.rsp' \\\n                    -not -name '*.m4' \\\n                    -not -name '*.pem' \\\n                    -not -name '*~' \\\n                    -not -name '*.exe' \\\n                    -not -name '*.am' \\\n                    -not -name '*.template' \\\n                    -not -name '*.cp' \\\n                    -not -name '*.bw' \\\n                    -not -name '*.crt' \\\n                    -not -name '*.log' \\\n                    -not -name '*.cmake' \\\n                    -not -name '*.pth' \\\n                    -not -name '*.in' \\\n                    -not -name '*.jar*' \\\n                    -not -name '*.pom*' \\\n                    -not -name '*.png' \\\n                    -not -name '*.jpg' \\\n                    -not -name '*.sql' \\\n                    -not -name '*.jpeg' \\\n                    -not -name '*.svg' \\\n                    -not -name '*.gif' \\\n                    -not -name '*.csv' \\\n                    -not -name '*.snapshot' \\\n                    -not -name '*.mak*' \\\n                    -not -name '*.bash' \\\n                    -not -name '*.data' \\\n                    -not -name '*.py' \\\n                    -not -name '*.class' \\\n                    -not -name '*.xcconfig' \\\n                    -not -name '*.ec' \\\n                    -not -name '*.coverage' \\\n                    -not -name '*.pyc' \\\n                    -not -name '*.cfg' \\\n                    -not -name '*.egg' \\\n                    -not -name '*.ru' \\\n                    -not -name '*.css' \\\n                    -not -name '*.less' \\\n                    -not -name '*.pyo' \\\n                    -not -name '*.whl' \\\n                    -not -name '*.html' \\\n                    -not -name '*.ftl' \\\n                    -not -name '*.erb' \\\n                    -not -name '*.rb' \\\n                    -not -name '*.js' \\\n                    -not -name '*.jade' \\\n                    -not -name '*.db' \\\n                    -not -name '*.md' \\\n                    -not -name '*.cpp' \\\n                    -not -name '*.gradle' \\\n                    -not -name '*.tar.tz' \\\n                    -not -name '*.scss' \\\n                    -not -name 'include.lst' \\\n                    -not -name 'fullLocaleNames.lst' \\\n                    -not -name 'inputFiles.lst' \\\n                    -not -name 'createdFiles.lst' \\\n                    -not -name 'scoverage.measurements.*' \\\n                    -not -name 'test_*_coverage.txt' \\\n                    -not -name 'testrunner-coverage*' \\\n                    -not -path '*/vendor/*' \\\n                    -not -path '*/htmlcov/*' \\\n                    -not -path '*/virtualenv/*' \\\n                    -not -path '*/js/generated/coverage/*' \\\n                    -not -path '*/.virtualenv/*' \\\n                    -not -path '*/virtualenvs/*' \\\n                    -not -path '*/.virtualenvs/*' \\\n                    -not -path '*/.env/*' \\\n                    -not -path '*/.envs/*' \\\n                    -not -path '*/env/*' \\\n                    -not -path '*/envs/*' \\\n                    -not -path '*/.venv/*' \\\n                    -not -path '*/.venvs/*' \\\n                    -not -path '*/venv/*' \\\n                    -not -path '*/venvs/*' \\\n                    -not -path '*/.git/*' \\\n                    -not -path '*/.hg/*' \\\n                    -not -path '*/.tox/*' \\\n                    -not -path '*/__pycache__/*' \\\n                    -not -path '*/.egg-info*' \\\n                    -not -path '*/$bower_components/*' \\\n                    -not -path '*/node_modules/*' \\\n                    -not -path '*/conftest_*.c.gcov' 2>/dev/null\"\n  files=$(eval \"$patterns\" || echo '')\n\nelif [ \"$include_cov\" != \"\" ];\nthen\n  files=$(eval \"find $search_in -type f \\( ${include_cov:5} \\)$exclude_cov 2>/dev/null\" || echo '')\nfi\n\nnum_of_files=$(echo \"$files\" | wc -l | tr -d ' ')\nif [ \"$num_of_files\" != '' ] && [ \"$files\" != '' ];\nthen\n  say \"    ${e}->${x} Found $num_of_files reports\"\nfi\n\n# no files found\nif [ \"$files\" = \"\" ];\nthen\n  say \"${r}-->${x} No coverage report found.\"\n  say \"    Please visit ${b}http://docs.codecov.io/docs/supported-languages${x}\"\n  exit ${exit_with};\nfi\n\nif [ \"$ft_network\" == \"1\" ];\nthen\n  say \"${e}==>${x} Detecting git/mercurial file structure\"\n  network=$(cd \"$git_root\" && git ls-files 2>/dev/null || hg locate 2>/dev/null || echo \"\")\n  if [ \"$network\" = \"\" ];\n  then\n    network=$(find \"$git_root\" -type f \\\n                   -not -path '*/virtualenv/*' \\\n                   -not -path '*/.virtualenv/*' \\\n                   -not -path '*/virtualenvs/*' \\\n                   -not -path '*/.virtualenvs/*' \\\n                   -not -path '*.png' \\\n                   -not -path '*.gif' \\\n                   -not -path '*.jpg' \\\n                   -not -path '*.jpeg' \\\n                   -not -path '*.md' \\\n                   -not -path '*/.env/*' \\\n                   -not -path '*/.envs/*' \\\n                   -not -path '*/env/*' \\\n                   -not -path '*/envs/*' \\\n                   -not -path '*/.venv/*' \\\n                   -not -path '*/.venvs/*' \\\n                   -not -path '*/venv/*' \\\n                   -not -path '*/venvs/*' \\\n                   -not -path '*/build/lib/*' \\\n                   -not -path '*/.git/*' \\\n                   -not -path '*/.egg-info/*' \\\n                   -not -path '*/shunit2-2.1.6/*' \\\n                   -not -path '*/vendor/*' \\\n                   -not -path '*/js/generated/coverage/*' \\\n                   -not -path '*/__pycache__/*' \\\n                   -not -path '*/node_modules/*' \\\n                   -not -path \"*/$bower_components/*\" 2>/dev/null || echo '')\n  fi\nfi\n\nupload_file=`mktemp /tmp/codecov.XXXXXX`\nadjustments_file=`mktemp /tmp/codecov.adjustments.XXXXXX`\n\ncleanup() {\n    rm -f $upload_file $adjustments_file\n}\n\ntrap cleanup INT ABRT TERM\n\nif [ \"$env\" != \"\" ];\nthen\n  inc_env=\"\"\n  say \"${e}==>${x} Appending build variables\"\n  for varname in $(echo \"$env\" | tr ',' ' ')\n  do\n    if [ \"$varname\" != \"\" ];\n    then\n      say \"    ${g}+${x} $varname\"\n      inc_env=\"${inc_env}${varname}=$(eval echo \"\\$${varname}\")\n\"\n    fi\n  done\n\necho \"$inc_env<<<<<< ENV\" >> $upload_file\nfi\n\nif [ \"$ft_network\" == \"1\" ];\nthen\n  i=\"woff|eot|otf\"  # fonts\n  i=\"$i|gif|png|jpg|jpeg|psd\"  # images\n  i=\"$i|ptt|pptx|numbers|pages|md|txt|xlsx|docx|doc|pdf\"  # docs\n  i=\"$i|yml|yaml|.gitignore\"  # supporting docs\n  echo \"$network\" | grep -vwE \"($i)$\" >> $upload_file\n  echo \"<<<<<< network\" >> $upload_file\nfi\n\nfr=0\nsay \"${e}==>${x} Reading reports\"\nwhile IFS='' read -r file;\ndo\n  # read the coverage file\n  if [ \"$(echo \"$file\" | tr -d ' ')\" != '' ];\n  then\n    if [ -f \"$file\" ];\n    then\n      report_len=$(wc -c < \"$file\")\n      if [ \"$report_len\" -ne 0 ];\n      then\n        say \"    ${g}+${x} $file ${e}bytes=$(echo \"$report_len\" | tr -d ' ')${x}\"\n        # append to to upload\n        echo \"# path=$(echo \"$file\" | sed \"s|^$git_root/||\")\" >> $upload_file\n        cat \"$file\" >> $upload_file\n        echo \"<<<<<< EOF\" >> $upload_file\n        fr=1\n        if [ \"$clean\" = \"1\" ];\n        then\n          rm \"$file\"\n        fi\n      else\n        say \"    ${r}-${x} Skipping empty file $file\"\n      fi\n    else\n      say \"    ${r}-${x} file not found at $file\"\n    fi\n  fi\ndone <<< \"$(echo -e \"$files\")\"\n\nif [ \"$fr\" = \"0\" ];\nthen\n  say \"${r}-->${x} No coverage data found.\"\n  say \"    Please visit ${b}http://docs.codecov.io/docs/supported-languages${x}\"\n  say \"    search for your projects language to learn how to collect reports.\"\n  exit ${exit_with};\nfi\n\nif [ \"$ft_fix\" = \"1\" ];\nthen\n  say \"${e}==>${x} Appending adjustments\"\n  say \"    ${b}http://docs.codecov.io/docs/fixing-reports${x}\"\n\n  empty_line='^[[:space:]]*$'\n  # //\n  syntax_comment='^[[:space:]]*//.*'\n  # /* or */\n  syntax_comment_block='^[[:space:]]*(\\/\\*|\\*\\/)[[:space:]]*$'\n  # { or }\n  syntax_bracket='^[[:space:]]*[\\{\\}][[:space:]]*(//.*)?$'\n  # [ or ]\n  syntax_list='^[[:space:]]*[][][[:space:]]*(//.*)?$'\n\n  skip_dirs=\"-not -path '*/$bower_components/*' \\\n             -not -path '*/node_modules/*'\"\n\n  cut_and_join() {\n    awk 'BEGIN { FS=\":\" }\n         $3 ~ /\\/\\*/ || $3 ~ /\\*\\// { print $0 ; next }\n         $1!=key { if (key!=\"\") print out ; key=$1 ; out=$1\":\"$2 ; next }\n         { out=out\",\"$2 }\n         END { print out }' 2>/dev/null\n  }\n\n  if echo \"$network\" | grep -m1 '.kt$' 1>/dev/null;\n  then\n    # skip brackets and comments\n    find \"$git_root\" -type f \\\n                     -name '*.kt' \\\n                     -exec \\\n      grep -nIHE -e $syntax_bracket \\\n                 -e $syntax_comment_block {} \\; \\\n      | cut_and_join \\\n      >> $adjustments_file \\\n      || echo ''\n\n    # last line in file\n    find \"$git_root\" -type f \\\n                     -name '*.kt' -exec \\\n      wc -l {} \\; \\\n      | while read l; do echo \"EOF: $l\"; done \\\n      2>/dev/null \\\n      >> $adjustments_file \\\n      || echo ''\n\n  fi\n\n  if echo \"$network\" | grep -m1 '.go$' 1>/dev/null;\n  then\n    # skip empty lines, comments, and brackets\n    find \"$git_root\" -type f \\\n                     -not -path '*/vendor/*' \\\n                     -name '*.go' \\\n                     -exec \\\n      grep -nIHE \\\n           -e $empty_line \\\n           -e $syntax_comment \\\n           -e $syntax_comment_block \\\n           -e $syntax_bracket \\\n           {} \\; \\\n      | cut_and_join \\\n      >> $adjustments_file \\\n      || echo ''\n  fi\n\n  if echo \"$network\" | grep -m1 '.jsx$' 1>/dev/null;\n  then\n    # skip empty lines, comments, and brackets\n    find \"$git_root\" -type f \\\n                     -name '*.jsx' \\\n                     $skip_dirs \\\n                     -exec \\\n      grep -nIHE \\\n           -e $empty_line \\\n           -e $syntax_comment \\\n           -e $syntax_bracket \\\n           {} \\; \\\n      | cut_and_join \\\n      >> $adjustments_file \\\n      || echo ''\n  fi\n\n  if echo \"$network\" | grep -m1 '.php$' 1>/dev/null;\n  then\n    # skip empty lines, comments, and brackets\n    find \"$git_root\" -type f \\\n                     -not -path '*/vendor/*' \\\n                     -name '*.php' \\\n                     -exec \\\n      grep -nIHE \\\n           -e $syntax_list \\\n           -e $syntax_bracket \\\n           -e '^[[:space:]]*\\);[[:space:]]*(//.*)?$' \\\n           {} \\; \\\n      | cut_and_join \\\n      >> $adjustments_file \\\n      || echo ''\n  fi\n\n  if echo \"$network\" | grep -m1 '\\(.cpp\\|.h\\|.cxx\\|.c\\|.hpp\\|.m\\)$' 1>/dev/null;\n  then\n    # skip brackets\n    find \"$git_root\" -type f \\\n                     $skip_dirs \\\n         \\( \\\n           -name '*.h' \\\n           -or -name '*.cpp' \\\n           -or -name '*.cxx' \\\n           -or -name '*.m' \\\n           -or -name '*.c' \\\n           -or -name '*.hpp' \\\n         \\) -exec \\\n      grep -nIHE \\\n           -e $empty_line \\\n           -e $syntax_bracket \\\n           -e '// LCOV_EXCL' \\\n           {} \\; \\\n      | cut_and_join \\\n      >> $adjustments_file \\\n      || echo ''\n\n    # skip brackets\n    find \"$git_root\" -type f \\\n                     $skip_dirs \\\n         \\( \\\n           -name '*.h' \\\n           -or -name '*.cpp' \\\n           -or -name '*.cxx' \\\n           -or -name '*.m' \\\n           -or -name '*.c' \\\n           -or -name '*.hpp' \\\n         \\) -exec \\\n      grep -nIH '// LCOV_EXCL' \\\n           {} \\; \\\n      >> $adjustments_file \\\n      || echo ''\n\n  fi\n\n  found=$(cat $adjustments_file | tr -d ' ')\n\n  if [ \"$found\" != \"\" ];\n  then\n    say \"    ${g}+${x} Found adjustments\"\n    echo \"# path=fixes\" >> $upload_file\n    cat $adjustments_file >> $upload_file\n    echo \"<<<<<< EOF\" >> $upload_file\n    rm -rf $adjustments_file\n  else\n    say \"    ${e}->${x} No adjustments found\"\n  fi\nfi\n\nif [ \"$url_o\" != \"\" ];\nthen\n  url=\"$url_o\"\nfi\n\nif [ \"$dump\" != \"0\" ];\nthen\n  # trim whitespace from query\n  echo \"$url/upload/v4?$(echo \"package=bash-$VERSION&token=$token&$query\" | tr -d ' ')\"\n  cat $upload_file\nelse\n\n  query=$(echo \"${query}\" | tr -d ' ')\n  say \"${e}==>${x} Uploading reports\"\n  say \"    ${e}url:${x} $url\"\n  say \"    ${e}query:${x} $query\"\n\n  # now add token to query\n  query=$(echo \"package=bash-$VERSION&token=$token&$query\" | tr -d ' ')\n\n  if [ \"$ft_s3\" = \"1\" ];\n  then\n    i=\"0\"\n    while [ $i -lt 4 ]\n    do\n      i=$[$i+1]\n      say \"    ${e}->${x} Pinging Codecov\"\n      res=$(curl $curl_s -X POST $curlargs $cacert \"$url/upload/v4?$query\" -H 'Accept: text/plain' || true)\n      # a good replay is \"https://codecov.io\" + \"\\n\" + \"https://codecov.s3.amazonaws.com/...\"\n      status=$(echo \"$res\" | head -1 | grep 'HTTP ' | cut -d' ' -f2)\n      if [ \"$status\" = \"\" ];\n      then\n        s3target=$(echo \"$res\" | sed -n 2p)\n        say \"    ${e}->${x} Uploading to S3 $(echo \"$s3target\" | cut -c1-32)\"\n        s3=$(curl $curl_s -fiX PUT $curlawsargs \\\n                  --data-binary @$upload_file \\\n                  -H 'Content-Type: text/plain' \\\n                  -H 'x-amz-acl: public-read' \\\n                  -H 'x-amz-storage-class: REDUCED_REDUNDANCY' \\\n                  \"$s3target\" || true)\n        if [ \"$s3\" != \"\" ];\n        then\n          say \"    ${g}->${x} View reports at ${b}$(echo \"$res\" | sed -n 1p)${x}\"\n          exit 0\n        else\n          say \"    ${r}X>${x} Failed to upload to S3\"\n        fi\n      elif [ \"$status\" = \"400\" ];\n      then\n          # 400 Error\n          say \"${g}${res}${x}\"\n          exit ${exit_with}\n      fi\n      say \"    ${e}->${x} Sleeping for 30s and trying again...\"\n      sleep 30\n    done\n  fi\n\n  say \"    ${e}->${x} Uploading to Codecov\"\n  i=\"0\"\n  while [ $i -lt 4 ]\n  do\n    i=$[$i+1]\n\n    res=$(curl $curl_s -X POST $curlargs $cacert --data-binary @$upload_file \"$url/upload/v2?$query\" -H 'Accept: text/plain' || echo 'HTTP 500')\n    # HTTP 200\n    # http://....\n    status=$(echo \"$res\" | head -1 | cut -d' ' -f2)\n    if [ \"$status\" = \"\" ];\n    then\n      say \"    View reports at ${b}$(echo \"$res\" | head -2 | tail -1)${x}\"\n      exit 0\n\n    elif [ \"${status:0:1}\" = \"5\" ];\n    then\n      say \"    ${e}->${x} Sleeping for 30s and trying again...\"\n      sleep 30\n\n    else\n      say \"    ${g}${res}${x}\"\n      exit 0\n      exit ${exit_with}\n    fi\n\n  done\n\nfi\n\nsay \"    ${r}X> Failed to upload coverage reports${x}\"\nexit ${exit_with}\n\n# EOF\n"
  },
  {
    "path": "detekt.yml",
    "content": "# `git diff detekt-default detekt.yml` to see what's changed from default\n# settings\n\ntest-pattern: # Configure exclusions for test sources\n  patterns: # Test file regexes\n    - '.*/test/.*'\n  exclude-rule-sets:\n    - 'comments'\n  exclude-rules:\n    - 'NamingRules'\n    - 'WildcardImport'\n    - 'MagicNumber'\n    - 'MaxLineLength'\n    - 'LateinitUsage'\n    - 'StringLiteralDuplication'\n    - 'SpreadOperator'\n    - 'TooManyFunctions'\n    - 'ForEachOnRange'\n\nbuild:\n  maxIssues: 10 # TODO: reduce this threshhold\n  weights:\n    # complexity: 2\n    # LongParameterList: 1\n    # style: 1\n    # comments: 1\n\nprocessors:\n  active: true\n  exclude:\n  # - 'FunctionCountProcessor'\n  # - 'PropertyCountProcessor'\n  # - 'ClassCountProcessor'\n  # - 'PackageCountProcessor'\n  # - 'KtFileCountProcessor'\n\nconsole-reports:\n  active: true\n  exclude:\n  #  - 'ProjectStatisticsReport'\n  #  - 'ComplexityReport'\n  #  - 'NotificationReport'\n  #  - 'FindingsReport'\n  #  - 'BuildFailureReport'\n\noutput-reports:\n  active: true\n  exclude:\n  #  - 'HtmlOutputReport'\n  #  - 'PlainOutputReport'\n  #  - 'XmlOutputReport'\n\ncomments:\n  active: true\n  CommentOverPrivateFunction:\n    active: false\n  CommentOverPrivateProperty:\n    active: false\n  EndOfSentenceFormat:\n    active: false\n    endOfSentenceFormat: ([.?!][ \\t\\n\\r\\f<])|([.?!]$)\n  UndocumentedPublicClass:\n    active: false\n    searchInNestedClass: true\n    searchInInnerClass: true\n    searchInInnerObject: true\n    searchInInnerInterface: true\n  UndocumentedPublicFunction:\n    active: false\n\ncomplexity:\n  active: true\n  ComplexCondition:\n    active: true\n    threshold: 4\n  ComplexInterface:\n    active: false\n    threshold: 10\n    includeStaticDeclarations: false\n  ComplexMethod:\n    active: true\n    threshold: 10\n    ignoreSingleWhenExpression: false\n  LabeledExpression:\n    active: false\n  LargeClass:\n    active: true\n    threshold: 150\n  LongMethod:\n    active: true\n    threshold: 20\n  LongParameterList:\n    active: true\n    threshold: 6\n    ignoreDefaultParameters: false\n  MethodOverloading:\n    active: false\n    threshold: 6\n  NestedBlockDepth:\n    active: true\n    threshold: 4\n  StringLiteralDuplication:\n    active: false\n    threshold: 3\n    ignoreAnnotation: true\n    excludeStringsWithLessThan5Characters: true\n    ignoreStringsRegex: '$^'\n  TooManyFunctions:\n    active: true\n    thresholdInFiles: 11\n    thresholdInClasses: 11\n    thresholdInInterfaces: 11\n    thresholdInObjects: 11\n    thresholdInEnums: 11\n    ignoreDeprecated: false\n\nempty-blocks:\n  active: true\n  EmptyCatchBlock:\n    active: true\n    allowedExceptionNameRegex: \"^(_|(ignore|expected).*)\"\n  EmptyClassBlock:\n    active: true\n  EmptyDefaultConstructor:\n    active: true\n  EmptyDoWhileBlock:\n    active: true\n  EmptyElseBlock:\n    active: true\n  EmptyFinallyBlock:\n    active: true\n  EmptyForBlock:\n    active: true\n  EmptyFunctionBlock:\n    active: true\n    ignoreOverriddenFunctions: false\n  EmptyIfBlock:\n    active: true\n  EmptyInitBlock:\n    active: true\n  EmptyKtFile:\n    active: true\n  EmptySecondaryConstructor:\n    active: true\n  EmptyWhenBlock:\n    active: true\n  EmptyWhileBlock:\n    active: true\n\nexceptions:\n  active: true\n  ExceptionRaisedInUnexpectedLocation:\n    active: false\n    methodNames: 'toString,hashCode,equals,finalize'\n  InstanceOfCheckForException:\n    active: false\n  NotImplementedDeclaration:\n    active: false\n  PrintStackTrace:\n    active: false\n  RethrowCaughtException:\n    active: false\n  ReturnFromFinally:\n    active: false\n  SwallowedException:\n    active: false\n  ThrowingExceptionFromFinally:\n    active: false\n  ThrowingExceptionInMain:\n    active: false\n  ThrowingExceptionsWithoutMessageOrCause:\n    active: false\n    exceptions: 'IllegalArgumentException,IllegalStateException,IOException'\n  ThrowingNewInstanceOfSameException:\n    active: false\n  TooGenericExceptionCaught:\n    active: true\n    exceptionNames:\n     - ArrayIndexOutOfBoundsException\n     - Error\n     - Exception\n     - IllegalMonitorStateException\n     - NullPointerException\n     - IndexOutOfBoundsException\n     - RuntimeException\n     - Throwable\n  TooGenericExceptionThrown:\n    active: true\n    exceptionNames:\n     - Error\n     - Exception\n     - Throwable\n     - RuntimeException\n\nformatting:\n  active: true\n  android: false\n  autoCorrect: true\n  ChainWrapping:\n    active: true\n    autoCorrect: true\n  CommentSpacing:\n    active: true\n    autoCorrect: true\n  Filename:\n    active: true\n  FinalNewline:\n    active: true\n    autoCorrect: true\n  ImportOrdering:\n    active: true\n    autoCorrect: true\n  Indentation:\n    active: true\n    autoCorrect: true\n    indentSize: 4\n    continuationIndentSize: 4\n  MaximumLineLength:\n    active: true\n    maxLineLength: 120\n  ModifierOrdering:\n    active: true\n    autoCorrect: true\n  NoBlankLineBeforeRbrace:\n    active: true\n    autoCorrect: true\n  NoConsecutiveBlankLines:\n    active: true\n    autoCorrect: true\n  NoEmptyClassBody:\n    active: true\n    autoCorrect: true\n  NoItParamInMultilineLambda:\n    active: true\n  NoLineBreakAfterElse:\n    active: true\n    autoCorrect: true\n  NoLineBreakBeforeAssignment:\n    active: true\n    autoCorrect: true\n  NoMultipleSpaces:\n    active: true\n    autoCorrect: true\n  NoSemicolons:\n    active: true\n    autoCorrect: true\n  NoTrailingSpaces:\n    active: true\n    autoCorrect: true\n  NoUnitReturn:\n    active: true\n    autoCorrect: true\n  NoUnusedImports:\n    active: true\n    autoCorrect: true\n  NoWildcardImports:\n    active: true\n    autoCorrect: true\n  ParameterListWrapping:\n    active: true\n    autoCorrect: true\n    indentSize: 4\n  SpacingAroundColon:\n    active: true\n    autoCorrect: true\n  SpacingAroundComma:\n    active: true\n    autoCorrect: true\n  SpacingAroundCurly:\n    active: true\n    autoCorrect: true\n  SpacingAroundKeyword:\n    active: true\n    autoCorrect: true\n  SpacingAroundOperators:\n    active: true\n    autoCorrect: true\n  SpacingAroundRangeOperator:\n    active: true\n    autoCorrect: true\n  StringTemplate:\n    active: true\n    autoCorrect: true\n\nnaming:\n  active: true\n  ClassNaming:\n    active: true\n    classPattern: '[A-Z$][a-zA-Z0-9$]*'\n  EnumNaming:\n    active: true\n    enumEntryPattern: '^[A-Z][_a-zA-Z0-9]*'\n  ForbiddenClassName:\n    active: false\n    forbiddenName: ''\n  FunctionMaxLength:\n    active: false\n    maximumFunctionNameLength: 30\n  FunctionMinLength:\n    active: false\n    minimumFunctionNameLength: 3\n  FunctionNaming:\n    active: true\n    functionPattern: '^([a-z$][a-zA-Z$0-9]*)|(`.*`)$'\n    excludeClassPattern: '$^'\n  MatchingDeclarationName:\n    active: true\n  MemberNameEqualsClassName:\n    active: false\n    ignoreOverriddenFunction: true\n  ObjectPropertyNaming:\n    active: true\n    propertyPattern: '[A-Za-z][_A-Za-z0-9]*'\n    constantPattern: '[A-Za-z][_A-Za-z0-9]*'\n  PackageNaming:\n    active: true\n    packagePattern: '^[a-z]+(\\.[a-z][a-z0-9]*)*$'\n  TopLevelPropertyNaming:\n    active: true\n    constantPattern: '[A-Z][_A-Z0-9]*'\n    propertyPattern: '[A-Za-z][_A-Za-z0-9]*'\n    privatePropertyPattern: '(_)?[A-Za-z][_A-Za-z0-9]*'\n  VariableMaxLength:\n    active: false\n    maximumVariableNameLength: 64\n  VariableMinLength:\n    active: false\n    minimumVariableNameLength: 1\n  VariableNaming:\n    active: true\n    variablePattern: '[a-z][A-Za-z0-9]*'\n    privateVariablePattern: '(_)?[a-z][A-Za-z0-9]*'\n    excludeClassPattern: '$^'\n\nperformance:\n  active: true\n  ForEachOnRange:\n    active: true\n  SpreadOperator:\n    active: false\n  UnnecessaryTemporaryInstantiation:\n    active: true\n\npotential-bugs:\n  active: true\n  DuplicateCaseInWhenExpression:\n    active: true\n  EqualsAlwaysReturnsTrueOrFalse:\n    active: false\n  EqualsWithHashCodeExist:\n    active: true\n  ExplicitGarbageCollectionCall:\n    active: true\n  InvalidRange:\n    active: false\n  IteratorHasNextCallsNextMethod:\n    active: false\n  IteratorNotThrowingNoSuchElementException:\n    active: false\n  LateinitUsage:\n    active: false\n    excludeAnnotatedProperties: \"\"\n    ignoreOnClassesPattern: \"\"\n  UnconditionalJumpStatementInLoop:\n    active: false\n  UnreachableCode:\n    active: true\n  UnsafeCallOnNullableType:\n    active: false\n  UnsafeCast:\n    active: false\n  UselessPostfixExpression:\n    active: false\n  WrongEqualsTypeParameter:\n    active: false\n\nstyle:\n  active: true\n  CollapsibleIfStatements:\n    active: false\n  DataClassContainsFunctions:\n    active: false\n    conversionFunctionPrefix: 'to'\n  EqualsNullCall:\n    active: false\n  ExpressionBodySyntax:\n    active: false\n  ForbiddenComment:\n    active: true\n    values: 'FIXME:,STOPSHIP:'\n  ForbiddenImport:\n    active: false\n    imports: ''\n  FunctionOnlyReturningConstant:\n    active: false\n    ignoreOverridableFunction: true\n    excludedFunctions: 'describeContents'\n  LoopWithTooManyJumpStatements:\n    active: false\n    maxJumpCount: 1\n  MagicNumber:\n    active: true\n    ignoreNumbers: '-1,0,1,2'\n    ignoreHashCodeFunction: false\n    ignorePropertyDeclaration: false\n    ignoreConstantDeclaration: true\n    ignoreCompanionObjectPropertyDeclaration: true\n    ignoreAnnotation: false\n    ignoreNamedArgument: true\n    ignoreEnums: false\n  MaxLineLength:\n    active: true\n    maxLineLength: 120\n    excludePackageStatements: false\n    excludeImportStatements: false\n    excludeCommentStatements: false\n  MayBeConst:\n    active: false\n  ModifierOrder:\n    active: true\n  NestedClassesVisibility:\n    active: false\n  NewLineAtEndOfFile:\n    active: true\n  NoTabs:\n    active: false\n  OptionalAbstractKeyword:\n    active: true\n  OptionalUnit:\n    active: false\n  OptionalWhenBraces:\n    active: false\n  ProtectedMemberInFinalClass:\n    active: false\n  RedundantVisibilityModifierRule:\n    active: false\n  ReturnCount:\n    active: true\n    max: 2\n    excludedFunctions: \"equals\"\n  SafeCast:\n    active: true\n  SerialVersionUIDInSerializableClass:\n    active: false\n  SpacingBetweenPackageAndImports:\n    active: false\n  ThrowsCount:\n    active: true\n    max: 2\n  TrailingWhitespace:\n    active: false\n  UnnecessaryAbstractClass:\n    active: false\n  UnnecessaryInheritance:\n    active: false\n  UnnecessaryParentheses:\n    active: false\n  UntilInsteadOfRangeTo:\n    active: false\n  UnusedImports:\n    active: false\n  UnusedPrivateMember:\n    active: false\n    allowedNames: \"(_|ignored|expected)\"\n  UseDataClass:\n    active: false\n    excludeAnnotatedClasses: \"\"\n  UtilityClassWithPublicConstructor:\n    active: false\n  WildcardImport:\n    active: true\n    excludeImports: 'java.util.*,kotlinx.android.synthetic.*'\n\n# vim: sw=2\n"
  },
  {
    "path": "gradle/wrapper/gradle-wrapper.properties",
    "content": "distributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-4.6-bin.zip\nzipStoreBase=GRADLE_USER_HOME\nzipStorePath=wrapper/dists\n"
  },
  {
    "path": "gradle.properties",
    "content": "detekt_version = 1.0.0.RC7\ndokka_version = 0.9.17\ngradle_bintray_version = 1.8.0\nkotlintest_version = 3.1.0\nkotlin_version = 1.2.41\nslf4j_version = 1.7.25\nxenocom_version = 0.0.7\n"
  },
  {
    "path": "gradlew",
    "content": "#!/usr/bin/env sh\n\n##############################################################################\n##\n##  Gradle start up script for UN*X\n##\n##############################################################################\n\n# Attempt to set APP_HOME\n# Resolve links: $0 may be a link\nPRG=\"$0\"\n# Need this for relative symlinks.\nwhile [ -h \"$PRG\" ] ; do\n    ls=`ls -ld \"$PRG\"`\n    link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n    if expr \"$link\" : '/.*' > /dev/null; then\n        PRG=\"$link\"\n    else\n        PRG=`dirname \"$PRG\"`\"/$link\"\n    fi\ndone\nSAVED=\"`pwd`\"\ncd \"`dirname \\\"$PRG\\\"`/\" >/dev/null\nAPP_HOME=\"`pwd -P`\"\ncd \"$SAVED\" >/dev/null\n\nAPP_NAME=\"Gradle\"\nAPP_BASE_NAME=`basename \"$0\"`\n\n# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nDEFAULT_JVM_OPTS=\"\"\n\n# Use the maximum available, or set MAX_FD != -1 to use that value.\nMAX_FD=\"maximum\"\n\nwarn () {\n    echo \"$*\"\n}\n\ndie () {\n    echo\n    echo \"$*\"\n    echo\n    exit 1\n}\n\n# OS specific support (must be 'true' or 'false').\ncygwin=false\nmsys=false\ndarwin=false\nnonstop=false\ncase \"`uname`\" in\n  CYGWIN* )\n    cygwin=true\n    ;;\n  Darwin* )\n    darwin=true\n    ;;\n  MINGW* )\n    msys=true\n    ;;\n  NONSTOP* )\n    nonstop=true\n    ;;\nesac\n\nCLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar\n\n# Determine the Java command to use to start the JVM.\nif [ -n \"$JAVA_HOME\" ] ; then\n    if [ -x \"$JAVA_HOME/jre/sh/java\" ] ; then\n        # IBM's JDK on AIX uses strange locations for the executables\n        JAVACMD=\"$JAVA_HOME/jre/sh/java\"\n    else\n        JAVACMD=\"$JAVA_HOME/bin/java\"\n    fi\n    if [ ! -x \"$JAVACMD\" ] ; then\n        die \"ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\n    fi\nelse\n    JAVACMD=\"java\"\n    which java >/dev/null 2>&1 || die \"ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\nfi\n\n# Increase the maximum file descriptors if we can.\nif [ \"$cygwin\" = \"false\" -a \"$darwin\" = \"false\" -a \"$nonstop\" = \"false\" ] ; then\n    MAX_FD_LIMIT=`ulimit -H -n`\n    if [ $? -eq 0 ] ; then\n        if [ \"$MAX_FD\" = \"maximum\" -o \"$MAX_FD\" = \"max\" ] ; then\n            MAX_FD=\"$MAX_FD_LIMIT\"\n        fi\n        ulimit -n $MAX_FD\n        if [ $? -ne 0 ] ; then\n            warn \"Could not set maximum file descriptor limit: $MAX_FD\"\n        fi\n    else\n        warn \"Could not query maximum file descriptor limit: $MAX_FD_LIMIT\"\n    fi\nfi\n\n# For Darwin, add options to specify how the application appears in the dock\nif $darwin; then\n    GRADLE_OPTS=\"$GRADLE_OPTS \\\"-Xdock:name=$APP_NAME\\\" \\\"-Xdock:icon=$APP_HOME/media/gradle.icns\\\"\"\nfi\n\n# For Cygwin, switch paths to Windows format before running java\nif $cygwin ; then\n    APP_HOME=`cygpath --path --mixed \"$APP_HOME\"`\n    CLASSPATH=`cygpath --path --mixed \"$CLASSPATH\"`\n    JAVACMD=`cygpath --unix \"$JAVACMD\"`\n\n    # We build the pattern for arguments to be converted via cygpath\n    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`\n    SEP=\"\"\n    for dir in $ROOTDIRSRAW ; do\n        ROOTDIRS=\"$ROOTDIRS$SEP$dir\"\n        SEP=\"|\"\n    done\n    OURCYGPATTERN=\"(^($ROOTDIRS))\"\n    # Add a user-defined pattern to the cygpath arguments\n    if [ \"$GRADLE_CYGPATTERN\" != \"\" ] ; then\n        OURCYGPATTERN=\"$OURCYGPATTERN|($GRADLE_CYGPATTERN)\"\n    fi\n    # Now convert the arguments - kludge to limit ourselves to /bin/sh\n    i=0\n    for arg in \"$@\" ; do\n        CHECK=`echo \"$arg\"|egrep -c \"$OURCYGPATTERN\" -`\n        CHECK2=`echo \"$arg\"|egrep -c \"^-\"`                                 ### Determine if an option\n\n        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition\n            eval `echo args$i`=`cygpath --path --ignore --mixed \"$arg\"`\n        else\n            eval `echo args$i`=\"\\\"$arg\\\"\"\n        fi\n        i=$((i+1))\n    done\n    case $i in\n        (0) set -- ;;\n        (1) set -- \"$args0\" ;;\n        (2) set -- \"$args0\" \"$args1\" ;;\n        (3) set -- \"$args0\" \"$args1\" \"$args2\" ;;\n        (4) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" ;;\n        (5) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" ;;\n        (6) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" ;;\n        (7) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" ;;\n        (8) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" ;;\n        (9) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" \"$args8\" ;;\n    esac\nfi\n\n# Escape application args\nsave () {\n    for i do printf %s\\\\n \"$i\" | sed \"s/'/'\\\\\\\\''/g;1s/^/'/;\\$s/\\$/' \\\\\\\\/\" ; done\n    echo \" \"\n}\nAPP_ARGS=$(save \"$@\")\n\n# Collect all arguments for the java command, following the shell quoting and substitution rules\neval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS \"\\\"-Dorg.gradle.appname=$APP_BASE_NAME\\\"\" -classpath \"\\\"$CLASSPATH\\\"\" org.gradle.wrapper.GradleWrapperMain \"$APP_ARGS\"\n\n# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong\nif [ \"$(uname)\" = \"Darwin\" ] && [ \"$HOME\" = \"$PWD\" ]; then\n  cd \"$(dirname \"$0\")\"\nfi\n\nexec \"$JAVACMD\" \"$@\"\n"
  },
  {
    "path": "gradlew.bat",
    "content": "@if \"%DEBUG%\" == \"\" @echo off\r\n@rem ##########################################################################\r\n@rem\r\n@rem  Gradle startup script for Windows\r\n@rem\r\n@rem ##########################################################################\r\n\r\n@rem Set local scope for the variables with windows NT shell\r\nif \"%OS%\"==\"Windows_NT\" setlocal\r\n\r\nset DIRNAME=%~dp0\r\nif \"%DIRNAME%\" == \"\" set DIRNAME=.\r\nset APP_BASE_NAME=%~n0\r\nset APP_HOME=%DIRNAME%\r\n\r\n@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\r\nset DEFAULT_JVM_OPTS=\r\n\r\n@rem Find java.exe\r\nif defined JAVA_HOME goto findJavaFromJavaHome\r\n\r\nset JAVA_EXE=java.exe\r\n%JAVA_EXE% -version >NUL 2>&1\r\nif \"%ERRORLEVEL%\" == \"0\" goto init\r\n\r\necho.\r\necho ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\r\necho.\r\necho Please set the JAVA_HOME variable in your environment to match the\r\necho location of your Java installation.\r\n\r\ngoto fail\r\n\r\n:findJavaFromJavaHome\r\nset JAVA_HOME=%JAVA_HOME:\"=%\r\nset JAVA_EXE=%JAVA_HOME%/bin/java.exe\r\n\r\nif exist \"%JAVA_EXE%\" goto init\r\n\r\necho.\r\necho ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%\r\necho.\r\necho Please set the JAVA_HOME variable in your environment to match the\r\necho location of your Java installation.\r\n\r\ngoto fail\r\n\r\n:init\r\n@rem Get command-line arguments, handling Windows variants\r\n\r\nif not \"%OS%\" == \"Windows_NT\" goto win9xME_args\r\n\r\n:win9xME_args\r\n@rem Slurp the command line arguments.\r\nset CMD_LINE_ARGS=\r\nset _SKIP=2\r\n\r\n:win9xME_args_slurp\r\nif \"x%~1\" == \"x\" goto execute\r\n\r\nset CMD_LINE_ARGS=%*\r\n\r\n:execute\r\n@rem Setup the command line\r\n\r\nset CLASSPATH=%APP_HOME%\\gradle\\wrapper\\gradle-wrapper.jar\r\n\r\n@rem Execute Gradle\r\n\"%JAVA_EXE%\" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% \"-Dorg.gradle.appname=%APP_BASE_NAME%\" -classpath \"%CLASSPATH%\" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%\r\n\r\n:end\r\n@rem End local scope for the variables with windows NT shell\r\nif \"%ERRORLEVEL%\"==\"0\" goto mainEnd\r\n\r\n:fail\r\nrem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of\r\nrem the _cmd.exe /c_ return code!\r\nif  not \"\" == \"%GRADLE_EXIT_CONSOLE%\" exit 1\r\nexit /b 1\r\n\r\n:mainEnd\r\nif \"%OS%\"==\"Windows_NT\" endlocal\r\n\r\n:omega\r\n"
  },
  {
    "path": "settings.gradle",
    "content": "rootProject.name = \"kotlin-argparser\"\n"
  },
  {
    "path": "src/main/kotlin/com/xenomachina/argparser/ArgParser.kt",
    "content": "// Copyright © 2016 Laurence Gonsalves\n//\n// This file is part of kotlin-argparser, a library which can be found at\n// http://github.com/xenomachina/kotlin-argparser\n//\n// This library is free software; you can redistribute it and/or modify it\n// under the terms of the GNU Lesser General Public License as published by the\n// Free Software Foundation; either version 2.1 of the License, or (at your\n// option) any later version.\n//\n// This library is distributed in the hope that it will be useful, but WITHOUT\n// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License\n// for more details.\n//\n// You should have received a copy of the GNU Lesser General Public License\n// along with this library; if not, see http://www.gnu.org/licenses/\n\npackage com.xenomachina.argparser\n\nimport com.xenomachina.argparser.PosixNaming.identifierToArgName\nimport com.xenomachina.argparser.PosixNaming.identifierToOptionName\nimport com.xenomachina.argparser.PosixNaming.optionNameToArgName\nimport com.xenomachina.argparser.PosixNaming.selectRepresentativeOptionName\nimport com.xenomachina.common.Holder\nimport com.xenomachina.common.orElse\nimport java.util.LinkedHashSet\nimport kotlin.reflect.KProperty\n\n/**\n * A command-line option/argument parser.\n *\n * @param args the command line arguments to parse\n * @param mode parsing mode, defaults to GNU-style parsing\n * @param helpFormatter if non-null, creates `--help` and `-h` options that trigger a [ShowHelpException] which will use\n * the supplied [HelpFormatter] to generate a help message.\n */\nclass ArgParser(\n    args: Array<out String>,\n    mode: Mode = Mode.GNU,\n    helpFormatter: HelpFormatter? = DefaultHelpFormatter()\n) {\n\n    enum class Mode {\n        /** For GNU-style option parsing, where options may appear after positional arguments. */\n        GNU,\n\n        /** For POSIX-style option parsing, where options must appear before positional arguments. */\n        POSIX\n    }\n\n    /**\n     * Creates a Delegate for a zero-argument option that returns true if and only the option is present in args.\n     */\n    fun flagging(vararg names: String, help: String): Delegate<Boolean> =\n            option<Boolean>(\n                    *names,\n                    help = help) { true }.default(false)\n\n    /**\n     * Creates a DelegateProvider for a zero-argument option that returns true if and only the option is present in\n     * args.\n     */\n    fun flagging(help: String) =\n            DelegateProvider { identifier -> flagging(identifierToOptionName(identifier), help = help) }\n\n    /**\n     * Creates a Delegate for a zero-argument option that returns the count of how many times the option appears in\n     * args.\n     */\n    fun counting(vararg names: String, help: String): Delegate<Int> =\n            option<Int>(\n                    *names,\n                    isRepeating = true,\n                    help = help) { value.orElse { 0 } + 1 }.default(0)\n\n    /**\n     * Creates a DelegateProvider for a zero-argument option that returns the count of how many times the option appears\n     * in args.\n     */\n    fun counting(help: String) = DelegateProvider {\n        identifier -> counting(identifierToOptionName(identifier), help = help)\n    }\n\n    /**\n     * Creates a Delegate for a single-argument option that stores and returns the option's (transformed) argument.\n     */\n    fun <T> storing(\n        vararg names: String,\n        help: String,\n        argName: String? = null,\n        transform: String.() -> T\n    ): Delegate<T> {\n        val nonNullArgName = argName ?: optionNameToArgName(selectRepresentativeOptionName(names))\n        return option(\n                *names,\n                errorName = nonNullArgName,\n                argNames = listOf(nonNullArgName),\n                help = help) { transform(arguments.first()) }\n    }\n\n    /**\n     * Creates a DelegateProvider for a single-argument option that stores and returns the option's (transformed)\n     * argument.\n     */\n    fun <T> storing(\n        help: String,\n        argName: String? = null,\n        transform: String.() -> T\n    ) = DelegateProvider { identifier ->\n        storing(identifierToOptionName(identifier), help = help, argName = argName, transform = transform)\n    }\n\n    /**\n     * Creates a Delegate for a single-argument option that stores and returns the option's argument.\n     */\n    fun storing(vararg names: String, help: String, argName: String? = null): Delegate<String> =\n            storing(*names, help = help, argName = argName) { this }\n\n    /**\n     * Creates a DelegateProvider for a single-argument option that stores and returns the option's argument.\n     */\n    fun storing(help: String, argName: String? = null) =\n            DelegateProvider { identifier ->\n                storing(identifierToOptionName(identifier), help = help, argName = argName) }\n\n    /**\n     * Creates a Delegate for a single-argument option that adds the option's (transformed) argument to a\n     * MutableCollection each time the option appears in args, and returns said MutableCollection.\n     */\n    fun <E, T : MutableCollection<E>> adding(\n        vararg names: String,\n        help: String,\n        argName: String? = null,\n        initialValue: T,\n        transform: String.() -> E\n    ): Delegate<T> {\n        val nonNullArgName = argName ?: optionNameToArgName(selectRepresentativeOptionName(names))\n        return option<T>(\n                *names,\n                help = help,\n                argNames = listOf(nonNullArgName),\n                isRepeating = true) {\n            val result = value.orElse { initialValue }\n            result.add(transform(arguments.first()))\n            result\n        }.default(initialValue)\n    }\n\n    /**\n     * Creates a DelegateProvider for a single-argument option that adds the option's (transformed) argument to a\n     * MutableCollection each time the option appears in args, and returns said MutableCollection.\n     */\n    fun <E, T : MutableCollection<E>> adding(\n        help: String,\n        argName: String? = null,\n        initialValue: T,\n        transform: String.() -> E\n    ) = DelegateProvider { identifier ->\n        adding(\n            identifierToOptionName(identifier),\n            help = help,\n            argName = argName,\n            initialValue = initialValue,\n            transform = transform)\n    }\n\n    /**\n     * Creates a Delegate for a single-argument option that adds the option's (transformed) argument to a\n     * MutableList each time the option appears in args, and returns said MutableCollection.\n     */\n    fun <T> adding(\n        vararg names: String,\n        help: String,\n        argName: String? = null,\n        transform: String.() -> T\n    ) = adding(*names, help = help, argName = argName, initialValue = mutableListOf(), transform = transform)\n\n    /**\n     * Creates a DelegateProvider for a single-argument option that adds the option's (transformed) argument to a\n     * MutableList each time the option appears in args, and returns said MutableCollection.\n     */\n    fun <T> adding(\n        help: String,\n        argName: String? = null,\n        transform: String.() -> T\n    ) = DelegateProvider { identifier ->\n        adding(identifierToOptionName(identifier), help = help, argName = argName, transform = transform) }\n\n    /**\n     * Creates a Delegate for a single-argument option that adds the option's argument to a MutableList each time the\n     * option appears in args, and returns said MutableCollection.\n     */\n    fun adding(vararg names: String, help: String, argName: String? = null): Delegate<MutableList<String>> =\n            adding(*names, help = help, argName = argName) { this }\n\n    /**\n     * Creates a DelegateProvider for a single-argument option that adds the option's argument to a MutableList each\n     * time the option appears in args, and returns said MutableCollection.\n     */\n    fun adding(help: String) = DelegateProvider { identifier ->\n        adding(identifierToOptionName(identifier), help = help) }\n\n    /**\n     * Creates a Delegate for a zero-argument option that maps from the option's name as it appears in args to one of a\n     * fixed set of values.\n     */\n    fun <T> mapping(vararg pairs: Pair<String, T>, help: String): Delegate<T> =\n            mapping(mapOf(*pairs), help = help)\n\n    /**\n     * Creates a Delegate for a zero-argument option that maps from the option's name as it appears in args to one of a\n     * fixed set of values.\n     */\n    fun <T> mapping(map: Map<String, T>, help: String): Delegate<T> {\n        val names = map.keys.toTypedArray()\n        return option(*names,\n                errorName = map.keys.joinToString(\"|\"),\n                help = help) {\n            // This cannot be null, because the optionName was added to the map\n            // at the same time it was registered with the ArgParser.\n            map[optionName]!!\n        }\n    }\n\n    /**\n     * Creates a Delegate for an option with the specified names.\n     * @param names names of options, with leading \"-\" or \"--\"\n     * @param errorName name to use when talking about this option in error messages, or null to base it upon the\n     * option names\n     * @param help the help text for this option\n     * @param argNames names of this option's arguments\n     * @param isRepeating whether or not it makes sense to repeat this option -- usually used for options where\n     * specifying the option more than once yields a value than cannot be expressed by specifying the option only once\n     * @param handler a function that computes the value of this option from an [OptionInvocation]\n     */\n    fun <T> option(\n        // TODO: add optionalArg: Boolean\n        vararg names: String,\n        help: String,\n        errorName: String? = null,\n        argNames: List<String> = emptyList(),\n        isRepeating: Boolean = false,\n        handler: OptionInvocation<T>.() -> T\n    ): Delegate<T> {\n        val delegate = OptionDelegate<T>(\n                parser = this,\n                errorName = errorName ?: optionNameToArgName(selectRepresentativeOptionName(names)),\n                help = help,\n                optionNames = listOf(*names),\n                argNames = argNames.toList(),\n                isRepeating = isRepeating,\n                handler = handler)\n        return delegate\n    }\n\n    /**\n     * Creates a Delegate for a single positional argument which returns the argument's value.\n     */\n    fun positional(name: String, help: String) = positional(name, help = help) { this }\n\n    /**\n     * Creates a DelegateProvider for a single positional argument which returns the argument's value.\n     */\n    fun positional(help: String) =\n            DelegateProvider { identifier -> positional(identifierToArgName(identifier), help = help) }\n\n    /**\n     * Creates a Delegate for a single positional argument which returns the argument's transformed value.\n     */\n    fun <T> positional(\n        name: String,\n        help: String,\n        transform: String.() -> T\n    ): Delegate<T> {\n        return WrappingDelegate(\n                positionalList(name, help = help, sizeRange = 1..1, transform = transform)\n        ) { it[0] }\n    }\n\n    /**\n     * Creates a DelegateProvider for a single positional argument which returns the argument's transformed value.\n     */\n    fun <T> positional(\n        help: String,\n        transform: String.() -> T\n    ) = DelegateProvider { identifier ->\n        positional(identifierToArgName(identifier), help = help, transform = transform)\n    }\n\n    /**\n     * Creates a Delegate for a sequence of positional arguments which returns a List containing the arguments.\n     */\n    fun positionalList(\n        name: String,\n        help: String,\n        sizeRange: IntRange = 1..Int.MAX_VALUE\n    ) = positionalList(name, help = help, sizeRange = sizeRange) { this }\n\n    /**\n     * Creates a DelegateProvider for a sequence of positional arguments which returns a List containing the arguments.\n     */\n    fun positionalList(\n        help: String,\n        sizeRange: IntRange = 1..Int.MAX_VALUE\n    ) = DelegateProvider { identifier ->\n        positionalList(identifierToArgName(identifier), help = help, sizeRange = sizeRange)\n    }\n\n    /**\n     * Creates a Delegate for a sequence of positional arguments which returns a List containing the transformed\n     * arguments.\n     */\n    fun <T> positionalList(\n        name: String,\n        help: String,\n        sizeRange: IntRange = 1..Int.MAX_VALUE,\n        transform: String.() -> T\n    ): Delegate<List<T>> {\n        sizeRange.run {\n            require(step == 1) { \"step must be 1, not $step\" }\n            require(first <= last) { \"backwards ranges are not allowed: $first > $last\" }\n            require(first >= 0) { \"sizeRange cannot start at $first, must be non-negative\" }\n\n            // Technically, last == 0 is ok but not especially useful, so we\n            // disallow it as it's probably unintentional.\n            require(last > 0) { \"sizeRange only allows $last arguments, must allow at least 1\" }\n        }\n\n        return PositionalDelegate<T>(this, name, sizeRange, help = help, transform = transform)\n    }\n\n    /**\n     * Creates a DelegateProvider for a sequence of positional arguments which returns a List containing the transformed\n     * arguments.\n     */\n    fun <T> positionalList(\n        help: String,\n        sizeRange: IntRange = 1..Int.MAX_VALUE,\n        transform: String.() -> T\n    ) = DelegateProvider { identifier -> positionalList(identifierToArgName(identifier), help, sizeRange, transform) }\n\n    abstract class Delegate<out T> internal constructor() {\n        /** The value associated with this delegate */\n        abstract val value: T\n\n        /** The name used to refer to this delegate's value in error messages */\n        abstract val errorName: String\n\n        /** The user-visible help text for this delegate */\n        abstract val help: String\n\n        /** Add validation logic. Validator should throw a [SystemExitException] on failure. */\n        abstract fun addValidator(validator: Delegate<T>.() -> Unit): Delegate<T>\n\n        /** Allows this object to act as a property delegate */\n        operator fun getValue(thisRef: Any?, property: KProperty<*>): T = value\n\n        /**\n         * Allows this object to act as a property delegate provider.\n         *\n         * It provides itself, and also registers itself with the [ArgParser] at that time.\n         */\n        operator fun provideDelegate(thisRef: Any?, prop: KProperty<*>): ArgParser.Delegate<T> {\n            registerRoot()\n            return this\n        }\n\n        internal abstract val parser: ArgParser\n\n        /**\n         * Indicates whether or not a value has been set for this delegate\n         */\n        internal abstract val hasValue: Boolean\n\n        internal fun checkHasValue() {\n            if (!hasValue) throw MissingValueException(errorName)\n        }\n\n        internal abstract fun validate()\n\n        internal abstract fun toHelpFormatterValue(): HelpFormatter.Value\n\n        internal fun registerRoot() {\n            parser.checkNotParsed()\n            parser.delegates.add(this)\n            registerLeaf(this)\n        }\n\n        internal abstract fun registerLeaf(root: Delegate<*>)\n\n        internal abstract val hasValidators: Boolean\n    }\n\n    /**\n     * Provides a [Delegate] when given a name. This makes it possible to infer\n     * a name for the `Delegate` based on the name it is bound to, rather than\n     * specifying a name explicitly.\n     */\n    class DelegateProvider<out T>(\n        private val default: (() -> T)? = null,\n        internal val ctor: (identifier: String) -> Delegate<T>\n    ) {\n        operator fun provideDelegate(thisRef: Any?, prop: KProperty<*>): Delegate<T> {\n            val delegate = ctor(prop.name)\n            return (if (default == null) delegate\n                    else delegate.default(default)).provideDelegate(thisRef, prop)\n        }\n    }\n\n    /**\n     * @property value a Holder containing the current value associated with this option, or null if unset\n     * @property optionName the name used for this option in this invocation\n     * @property arguments the arguments supplied for this option\n     */\n    data class OptionInvocation<T> internal constructor(\n        // Internal constructor so future versions can add properties\n        // without breaking compatibility.\n        val value: Holder<T>?,\n        val optionName: String,\n        val arguments: List<String>\n    )\n\n    private val shortOptionDelegates = mutableMapOf<Char, OptionDelegate<*>>()\n    private val longOptionDelegates = mutableMapOf<String, OptionDelegate<*>>()\n    private val positionalDelegates = mutableListOf<Pair<PositionalDelegate<*>, Boolean>>()\n    private val delegates = LinkedHashSet<Delegate<*>>()\n\n    internal fun registerOption(name: String, delegate: OptionDelegate<*>) {\n        if (name.startsWith(\"--\")) {\n            require(name.length > 2) { \"long option '$name' must have at least one character after hyphen\" }\n            require(name !in longOptionDelegates) { \"long option '$name' already in use\" }\n            longOptionDelegates.put(name, delegate)\n        } else if (name.startsWith(\"-\")) {\n            require(name.length == 2) { \"short option '$name' can only have one character after hyphen\" }\n            val key = name.get(1)\n            require(key !in shortOptionDelegates) { \"short option '$name' already in use\" }\n            shortOptionDelegates.put(key, delegate)\n        } else {\n            throw IllegalArgumentException(\"illegal option name '$name' -- must start with '-' or '--'\")\n        }\n    }\n\n    internal fun registerPositional(delegate: PositionalDelegate<*>, hasDefault: Boolean) {\n        positionalDelegates.add(delegate to hasDefault)\n    }\n\n    private var inValidation = false\n    private var finished = false\n\n    /**\n     * Ensures that arguments have been parsed and validated.\n     *\n     * @throws SystemExitException if parsing or validation failed.\n     */\n    fun force() {\n        if (!inParse) {\n            if (!finished) {\n                parseOptions\n                if (!inValidation) {\n                    inValidation = true\n                    try {\n                        for (delegate in delegates) delegate.checkHasValue()\n                        for (delegate in delegates) delegate.validate()\n                    } finally {\n                        inValidation = false\n                    }\n                }\n            }\n        }\n    }\n\n    /**\n     * Provides an instance of T, where all arguments have already been parsed and validated\n     */\n    fun <T> parseInto(constructor: (ArgParser) -> T): T {\n        if (builtinDelegateCount != delegates.size) {\n            throw IllegalStateException(\"You can only use the parseInto function with a clean ArgParser instance\")\n        }\n        val provided = constructor(this)\n        force()\n        return provided\n    }\n\n    private var inParse = false\n\n    internal fun checkNotParsed() {\n        if (inParse || finished) throw IllegalStateException(\"arguments have already been parsed\")\n    }\n\n    private val parseOptions by lazy {\n        val positionalArguments = mutableListOf<String>()\n        inParse = true\n        try {\n            var i = 0\n            optionLoop@ while (i < args.size) {\n                val arg = args[i]\n                i += when {\n                    arg == \"--\" -> {\n                        i++\n                        break@optionLoop\n                    }\n                    arg.startsWith(\"--\") ->\n                        parseLongOpt(i, args)\n                    arg.startsWith(\"-\") ->\n                        parseShortOpts(i, args)\n                    else -> {\n                        positionalArguments.add(arg)\n                        when (mode) {\n                            Mode.GNU -> 1\n                            Mode.POSIX -> {\n                                i++\n                                break@optionLoop\n                            }\n                        }\n                    }\n                }\n            }\n\n            // Collect remaining arguments as positional-only arguments\n            positionalArguments.addAll(args.slice(i..args.size - 1))\n\n            parsePositionalArguments(positionalArguments)\n            finished = true\n        } finally {\n            inParse = false\n        }\n    }\n\n    private fun parsePositionalArguments(args: List<String>) {\n        var lastValueName: String? = null\n        var index = 0\n        var remaining = args.size\n        var extra = (remaining - positionalDelegates.map {\n            if (it.second) 0 else it.first.sizeRange.first\n        }.sum()).coerceAtLeast(0)\n        for ((delegate, hasDefault) in positionalDelegates) {\n            val minSize = if (hasDefault) 0 else delegate.sizeRange.first\n            val sizeRange = delegate.sizeRange\n            val chunkSize = (minSize + extra).coerceAtMost(sizeRange.endInclusive)\n            if (chunkSize > remaining) {\n                throw MissingRequiredPositionalArgumentException(delegate.errorName)\n            }\n            if (chunkSize != 0 || !hasDefault) {\n                delegate.parseArguments(args.subList(index, index + chunkSize))\n            }\n            lastValueName = delegate.errorName\n            index += chunkSize\n            remaining -= chunkSize\n            extra -= chunkSize - minSize\n        }\n        if (remaining > 0) {\n            throw UnexpectedPositionalArgumentException(lastValueName)\n        }\n    }\n\n    /**\n     * @param index index into args, starting at a long option, eg: \"--verbose\"\n     * @param args array of command-line arguments\n     * @return number of arguments that have been processed\n     */\n    private fun parseLongOpt(index: Int, args: Array<out String>): Int {\n        val name: String\n        val firstArg: String?\n        val m = NAME_EQUALS_VALUE_REGEX.matchEntire(args[index])\n        if (m == null) {\n            name = args[index]\n            firstArg = null\n        } else {\n            // if NAME_EQUALS_VALUE_REGEX then there must be groups 1 and 2\n            name = m.groups[1]!!.value\n            firstArg = m.groups[2]!!.value\n        }\n        val delegate = longOptionDelegates.get(name)\n        if (delegate == null) {\n            throw UnrecognizedOptionException(name)\n        } else {\n            var consumedArgs = delegate.parseOption(name, firstArg, index + 1, args)\n            if (firstArg != null) {\n                if (consumedArgs < 1) throw UnexpectedOptionArgumentException(name)\n                consumedArgs -= 1\n            }\n            return 1 + consumedArgs\n        }\n    }\n\n    /**\n     * @param index index into args, starting at a set of short options, eg: \"-abXv\"\n     * @param args array of command-line arguments\n     * @return number of arguments that have been processed\n     */\n    private fun parseShortOpts(index: Int, args: Array<out String>): Int {\n        val opts = args[index]\n        var optIndex = 1\n        while (optIndex < opts.length) {\n            val optKey = opts[optIndex]\n            val optName = \"-$optKey\"\n            optIndex++ // optIndex now points just after optKey\n\n            val delegate = shortOptionDelegates.get(optKey)\n            if (delegate == null) {\n                throw UnrecognizedOptionException(optName)\n            } else {\n                val firstArg = if (optIndex >= opts.length) null else opts.substring(optIndex)\n                val consumed = delegate.parseOption(optName, firstArg, index + 1, args)\n                if (consumed > 0) {\n                    return consumed + (if (firstArg == null) 1 else 0)\n                }\n            }\n        }\n        return 1\n    }\n\n    init {\n        if (helpFormatter != null) {\n            option<Unit>(\"-h\", \"--help\",\n                    errorName = \"HELP\", // This should never be used, but we need to say something\n                    help = \"show this help message and exit\") {\n                throw ShowHelpException(helpFormatter, delegates.toList())\n            }.default(Unit).registerRoot()\n        }\n    }\n\n    private val builtinDelegateCount = delegates.size\n}\n\nprivate val NAME_EQUALS_VALUE_REGEX = Regex(\"^([^=]+)=(.*)$\")\ninternal val LEADING_HYPHENS_REGEX = Regex(\"^-{1,2}\")\n\nprivate const val OPTION_CHAR_CLASS = \"[a-zA-Z0-9]\"\ninternal val OPTION_NAME_RE = Regex(\"^(-$OPTION_CHAR_CLASS)|(--$OPTION_CHAR_CLASS+([-_\\\\.]$OPTION_CHAR_CLASS+)*)$\")\n\nprivate const val ARG_INITIAL_CHAR_CLASS = \"[A-Z]\"\nprivate const val ARG_CHAR_CLASS = \"[A-Z0-9]\"\ninternal val ARG_NAME_RE = Regex(\"^$ARG_INITIAL_CHAR_CLASS+([-_\\\\.]$ARG_CHAR_CLASS+)*$\")\n"
  },
  {
    "path": "src/main/kotlin/com/xenomachina/argparser/Default.kt",
    "content": "// Copyright © 2016 Laurence Gonsalves\n//\n// This file is part of kotlin-argparser, a library which can be found at\n// http://github.com/xenomachina/kotlin-argparser\n//\n// This library is free software; you can redistribute it and/or modify it\n// under the terms of the GNU Lesser General Public License as published by the\n// Free Software Foundation; either version 2.1 of the License, or (at your\n// option) any later version.\n//\n// This library is distributed in the hope that it will be useful, but WITHOUT\n// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License\n// for more details.\n//\n// You should have received a copy of the GNU Lesser General Public License\n// along with this library; if not, see http://www.gnu.org/licenses/\n\npackage com.xenomachina.argparser\n\n/**\n * Returns a new `DelegateProvider` with the specified default value.\n *\n * @param newDefault the default value for the resulting [ArgParser.Delegate]\n */\nfun <T> ArgParser.DelegateProvider<T>.default(newDefault: T): ArgParser.DelegateProvider<T> {\n    return ArgParser.DelegateProvider(ctor = ctor, default = { newDefault })\n}\n\n/**\n * Returns a new `DelegateProvider` with the specified default value from a lambda.\n *\n * @param newDefault the default value for the resulting [ArgParser.Delegate]\n */\nfun <T> ArgParser.DelegateProvider<T>.default(newDefault: () -> T): ArgParser.DelegateProvider<T> {\n    return ArgParser.DelegateProvider(ctor = ctor, default = newDefault)\n}\n\n/**\n * Returns a new `Delegate` with the specified default value.\n *\n * @param newDefault the default value for the resulting [ArgParser.Delegate]\n */\nfun <T> ArgParser.Delegate<T>.default(defaultValue: T): ArgParser.Delegate<T> = default { defaultValue }\n\n/**\n * Returns a new `Delegate` with the specified default value as a lambda.\n *\n * @param newDefault the default value for the resulting [ArgParser.Delegate]\n */\nfun <T> ArgParser.Delegate<T>.default(defaultValue: () -> T): ArgParser.Delegate<T> {\n    if (hasValidators) {\n        throw IllegalStateException(\"Cannot add default after adding validators\")\n    }\n    val inner = this\n\n    return object : ArgParser.Delegate<T>() {\n\n        override val hasValidators: Boolean\n            get() = inner.hasValidators\n\n        override fun toHelpFormatterValue(): HelpFormatter.Value = inner.toHelpFormatterValue().copy(isRequired = false)\n\n        override fun validate() {\n            inner.validate()\n        }\n\n        override val parser: ArgParser\n            get() = inner.parser\n\n        override val value: T\n            get() {\n                inner.parser.force()\n                return if (inner.hasValue) inner.value else defaultValue()\n            }\n\n        override val hasValue: Boolean\n            get() = true\n\n        override val errorName: String\n            get() = inner.errorName\n\n        override val help: String\n            get() = inner.help\n\n        override fun addValidator(validator: ArgParser.Delegate<T>.() -> Unit): ArgParser.Delegate<T> =\n                apply { inner.addValidator { validator(this@apply) } }\n\n        override fun registerLeaf(root: ArgParser.Delegate<*>) {\n            inner.registerLeaf(root)\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/kotlin/com/xenomachina/argparser/DefaultHelpFormatter.kt",
    "content": "// Copyright © 2016 Laurence Gonsalves\n//\n// This file is part of kotlin-argparser, a library which can be found at\n// http://github.com/xenomachina/kotlin-argparser\n//\n// This library is free software; you can redistribute it and/or modify it\n// under the terms of the GNU Lesser General Public License as published by the\n// Free Software Foundation; either version 2.1 of the License, or (at your\n// option) any later version.\n//\n// This library is distributed in the hope that it will be useful, but WITHOUT\n// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License\n// for more details.\n//\n// You should have received a copy of the GNU Lesser General Public License\n// along with this library; if not, see http://www.gnu.org/licenses/\n\npackage com.xenomachina.argparser\n\nimport com.xenomachina.text.NBSP_CODEPOINT\nimport com.xenomachina.text.term.codePointWidth\nimport com.xenomachina.text.term.columnize\nimport com.xenomachina.text.term.wrapText\n\n/**\n * Default implementation of [HelpFormatter]. Output is modelled after that of common UNIX utilities and looks\n * something like this:\n *\n * ```\n * usage: program_name     [-h] [-n] [-I INCLUDE]... -o OUTPUT\n *                         [-v]... SOURCE... DEST\n *\n * Does something really useful.\n *\n * required arguments:\n *   -o OUTPUT,            directory in which all output should\n *   --output OUTPUT       be generated\n *\n * optional arguments:\n *   -h, --help            show this help message and exit\n *\n *   -n, --dry-run         don't do anything\n *\n *   -I INCLUDE,           search in this directory for header\n *   --include INCLUDE     files\n *\n *  -v, --verbose         increase verbosity\n *\n * positional arguments:\n *   SOURCE                source file\n *\n *   DEST                  destination file\n *\n * More info is available at http://program-name.example.com/\n * ```\n *\n * @property prologue Text that should appear near the beginning of the help, immediately after the usage summary.\n * @property epilogue Text that should appear at the end of the help.\n */\nclass DefaultHelpFormatter(\n    val prologue: String? = null,\n    val epilogue: String? = null\n) : HelpFormatter {\n    val indent = \"  \"\n    val indentWidth = indent.codePointWidth()\n\n    override fun format(\n        programName: String?,\n        columns: Int,\n        values: List<HelpFormatter.Value>\n    ): String {\n        val effectiveColumns = when {\n            columns < 0 -> throw IllegalArgumentException(\"columns must be non-negative\")\n            columns == 0 -> Int.MAX_VALUE\n            else -> columns\n        }\n        val sb = StringBuilder()\n        appendUsage(sb, effectiveColumns, programName, values)\n        sb.append(\"\\n\")\n\n        if (!prologue.isNullOrEmpty()) {\n            sb.append(\"\\n\\n\")\n            // we just checked that prologue is non-null\n            sb.append(prologue!!.wrapText(effectiveColumns))\n            sb.append(\"\\n\\n\")\n        }\n\n        val required = mutableListOf<HelpFormatter.Value>()\n        val optional = mutableListOf<HelpFormatter.Value>()\n        val positional = mutableListOf<HelpFormatter.Value>()\n\n        for (value in values) {\n            when {\n                value.isPositional -> positional\n                value.isRequired -> required\n                else -> optional\n            }.add(value)\n        }\n        val usageColumns = 2 * indentWidth - 1 + if (columns == 0) {\n            values.map { usageText(it).length }.max() ?: 0\n        } else {\n            // Make left column as narrow as possible without wrapping any of the individual usages, though no wider\n            // than half the screen.\n            (values.map {\n                usageText(it).split(\" \").map { it.length }.max() ?: 0\n            }.max() ?: 0).coerceAtMost(effectiveColumns / 2)\n        }\n\n        appendSection(sb, usageColumns, effectiveColumns, \"required\", required)\n        appendSection(sb, usageColumns, effectiveColumns, \"optional\", optional)\n        appendSection(sb, usageColumns, effectiveColumns, \"positional\", positional)\n\n        if (!epilogue?.trim().isNullOrEmpty()) {\n            sb.append(\"\\n\")\n            // we just checked that epilogue is non-null\n            sb.append(epilogue!!.trim().wrapText(effectiveColumns))\n            sb.append(\"\\n\")\n        }\n\n        return sb.toString()\n    }\n\n    private fun appendSection(\n        sb: StringBuilder,\n        usageColumns: Int,\n        columns: Int,\n        name: String,\n        values: List<HelpFormatter.Value>\n    ) {\n\n        if (!values.isEmpty()) {\n            sb.append(\"\\n\")\n            sb.append(\"$name arguments:\\n\")\n            for (value in values) {\n                val left = usageText(value).wrapText(usageColumns - indentWidth).prependIndent(indent)\n                val right = value.help.wrapText(columns - usageColumns - 2 * indentWidth).prependIndent(indent)\n                sb.append(columnize(left, right, minWidths = intArrayOf(usageColumns)))\n                sb.append(\"\\n\\n\")\n            }\n        }\n    }\n\n    private fun usageText(value: HelpFormatter.Value) =\n            value.usages.map { it.replace(' ', '\\u00a0') }.joinToString(\", \")\n\n    private fun appendUsage(sb: StringBuilder, columns: Int, programName: String?, values: List<HelpFormatter.Value>) {\n        var usageStart = USAGE_PREFIX + (if (programName != null) \" $programName\" else \"\")\n\n        val valueSB = StringBuilder()\n        for (value in values) value.run {\n            if (!usages.isEmpty()) {\n                val usage = usages[0].replace(' ', NBSP_CODEPOINT.toChar())\n                if (isRequired) {\n                    valueSB.append(\" $usage\")\n                } else {\n                    valueSB.append(\" [$usage]\")\n                }\n                if (isRepeating) {\n                    valueSB.append(\"...\")\n                }\n            }\n        }\n\n        if (usageStart.length > columns / 2) {\n            sb.append(usageStart)\n            sb.append(\"\\n\")\n            val valueIndent = (USAGE_PREFIX + \" \" + indent).codePointWidth()\n            val valueColumns = columns - valueIndent\n            sb.append(valueSB.toString().wrapText(valueColumns).prependIndent(\" \".repeat(valueIndent)))\n        } else {\n            usageStart += \" \"\n            val valueColumns = columns - usageStart.length\n            sb.append(columnize(usageStart, valueSB.toString().wrapText(valueColumns)))\n        }\n    }\n}\n\nprivate const val USAGE_PREFIX = \"usage:\"\n"
  },
  {
    "path": "src/main/kotlin/com/xenomachina/argparser/Exceptions.kt",
    "content": "// Copyright © 2016 Laurence Gonsalves\n//\n// This file is part of kotlin-argparser, a library which can be found at\n// http://github.com/xenomachina/kotlin-argparser\n//\n// This library is free software; you can redistribute it and/or modify it\n// under the terms of the GNU Lesser General Public License as published by the\n// Free Software Foundation; either version 2.1 of the License, or (at your\n// option) any later version.\n//\n// This library is distributed in the hope that it will be useful, but WITHOUT\n// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License\n// for more details.\n//\n// You should have received a copy of the GNU Lesser General Public License\n// along with this library; if not, see http://www.gnu.org/licenses/\n\npackage com.xenomachina.argparser\n\nimport java.io.Writer\n\n/**\n * Indicates that the user requested that help should be shown (with the\n * `--help` option, for example).\n */\nclass ShowHelpException internal constructor(\n    private val helpFormatter: HelpFormatter,\n    private val delegates: List<ArgParser.Delegate<*>>\n) : SystemExitException(\"Help was requested\", 0) {\n    override fun printUserMessage(writer: Writer, programName: String?, columns: Int) {\n        writer.write(helpFormatter.format(programName, columns, delegates.map { it.toHelpFormatterValue() }))\n    }\n}\n\n/**\n * Indicates that an unrecognized option was supplied.\n *\n * @property optName the name of the option\n */\nopen class UnrecognizedOptionException(val optName: String) :\n        SystemExitException(\"unrecognized option '$optName'\", 2)\n\n/**\n * Indicates that a value is missing after parsing has completed.\n *\n * @property valueName the name of the missing value\n */\nopen class MissingValueException(val valueName: String) :\n        SystemExitException(\"missing $valueName\", 2)\n\n/**\n * Indicates that the value of a supplied argument is invalid.\n */\nopen class InvalidArgumentException(message: String) : SystemExitException(message, 2)\n\n/**\n * Indicates that a required option argument was not supplied.\n *\n * @property optName the name of the option\n * @property argName the name of the missing argument, or null\n */\nopen class OptionMissingRequiredArgumentException(val optName: String, val argName: String? = null) :\n        SystemExitException(\n            \"option '$optName' is missing \" + (\n                if (argName == null) \"a required argument\"\n                else \"the required argument $argName\"),\n            2)\n\n/**\n * Indicates that a required positional argument was not supplied.\n *\n * @property argName the name of the positional argument\n */\nopen class MissingRequiredPositionalArgumentException(val argName: String) :\n        SystemExitException(\"missing $argName operand\", 2)\n\n/**\n * Indicates that an argument was forced upon an option that does not take one.\n *\n * For example, if the arguments contained \"--foo=bar\" and the \"--foo\" option does not consume any arguments.\n *\n * @property optName the name of the option\n */\nopen class UnexpectedOptionArgumentException(val optName: String) :\n        SystemExitException(\"option '$optName' doesn't allow an argument\", 2)\n\n/**\n * Indicates that there is an unhandled positional argument.\n *\n * @property valueName the name of the missing value\n */\nopen class UnexpectedPositionalArgumentException(val valueName: String?) :\n        SystemExitException(\"unexpected argument${if (valueName == null) \"\" else \" after $valueName\"}\", 2)\n"
  },
  {
    "path": "src/main/kotlin/com/xenomachina/argparser/HelpFormatter.kt",
    "content": "// Copyright © 2016 Laurence Gonsalves\n//\n// This file is part of kotlin-argparser, a library which can be found at\n// http://github.com/xenomachina/kotlin-argparser\n//\n// This library is free software; you can redistribute it and/or modify it\n// under the terms of the GNU Lesser General Public License as published by the\n// Free Software Foundation; either version 2.1 of the License, or (at your\n// option) any later version.\n//\n// This library is distributed in the hope that it will be useful, but WITHOUT\n// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License\n// for more details.\n//\n// You should have received a copy of the GNU Lesser General Public License\n// along with this library; if not, see http://www.gnu.org/licenses/\n\npackage com.xenomachina.argparser\n\n/**\n * Formats help for an [ArgParser].\n */\ninterface HelpFormatter {\n    /**\n     * Formats a help message.\n     *\n     * @param programName name of the program as it should appear in usage information, or null if\n     * program name is unknown.\n     * @param columns width of display help should be formatted for, measured in character cells, or 0 for infinite\n     * width.\n     * @param values [Value] objects describing the arguments types available.\n     */\n    fun format(programName: String?, columns: Int, values: List<Value>): String\n\n    /**\n     * An option or positional argument type which should be formatted for help\n     *\n     * @param usages possible usage strings for this argument type\n     * @param isRequired indicates whether this is required\n     * @param isRepeating indicates whether it makes sense to repeat this argument\n     * @param isPositional indicates whether this is a positional argument\n     * @param help help text provided at Delegate construction time\n     */\n    data class Value(\n        val usages: List<String>,\n        val isRequired: Boolean,\n        val isRepeating: Boolean,\n        val isPositional: Boolean,\n        val help: String\n    )\n}\n"
  },
  {
    "path": "src/main/kotlin/com/xenomachina/argparser/OptionDelegate.kt",
    "content": "// Copyright © 2016 Laurence Gonsalves\n//\n// This file is part of kotlin-argparser, a library which can be found at\n// http://github.com/xenomachina/kotlin-argparser\n//\n// This library is free software; you can redistribute it and/or modify it\n// under the terms of the GNU Lesser General Public License as published by the\n// Free Software Foundation; either version 2.1 of the License, or (at your\n// option) any later version.\n//\n// This library is distributed in the hope that it will be useful, but WITHOUT\n// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License\n// for more details.\n//\n// You should have received a copy of the GNU Lesser General Public License\n// along with this library; if not, see http://www.gnu.org/licenses/\n\npackage com.xenomachina.argparser\n\nimport com.xenomachina.common.Holder\n\ninternal class OptionDelegate<T>(\n    parser: ArgParser,\n    errorName: String,\n    help: String,\n    val optionNames: List<String>,\n    val argNames: List<String>,\n    val isRepeating: Boolean,\n    val handler: ArgParser.OptionInvocation<T>.() -> T\n) : ParsingDelegate<T>(parser, errorName, help) {\n    init {\n        for (optionName in optionNames) {\n            if (!OPTION_NAME_RE.matches(optionName)) {\n                throw IllegalArgumentException(\"$optionName is not a valid option name\")\n            }\n        }\n        for (argName in argNames) {\n            if (!ARG_NAME_RE.matches(argName)) {\n                throw IllegalArgumentException(\"$argName is not a valid argument name\")\n            }\n        }\n    }\n\n    fun parseOption(name: String, firstArg: String?, index: Int, args: Array<out String>): Int {\n        val arguments = mutableListOf<String>()\n        if (!argNames.isEmpty()) {\n            if (firstArg != null) arguments.add(firstArg)\n            val required = argNames.size - arguments.size\n            if (required + index > args.size) {\n                // Only pass an argName if more than one argument.\n                // Naming it when there's just one seems unnecessarily verbose.\n                val argName = if (argNames.size > 1) argNames[args.size - index] else null\n                throw OptionMissingRequiredArgumentException(name, argName)\n            }\n            for (i in 0 until required) {\n                arguments.add(args[index + i])\n            }\n        }\n        val input = ArgParser.OptionInvocation(holder, name, arguments)\n        holder = Holder(handler(input))\n        return argNames.size\n    }\n\n    override fun toHelpFormatterValue(): HelpFormatter.Value {\n        return HelpFormatter.Value(\n                isRequired = (holder == null),\n                isRepeating = isRepeating,\n                usages = if (!argNames.isEmpty()) {\n                    optionNames.map { \"$it ${argNames.joinToString(\" \")}\" }\n                } else {\n                    optionNames\n                },\n                isPositional = false,\n                help = help)\n    }\n\n    override fun registerLeaf(root: ArgParser.Delegate<*>) {\n        for (name in optionNames) {\n            parser.registerOption(name, this)\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/kotlin/com/xenomachina/argparser/ParsingDelegate.kt",
    "content": "// Copyright © 2016 Laurence Gonsalves\n//\n// This file is part of kotlin-argparser, a library which can be found at\n// http://github.com/xenomachina/kotlin-argparser\n//\n// This library is free software; you can redistribute it and/or modify it\n// under the terms of the GNU Lesser General Public License as published by the\n// Free Software Foundation; either version 2.1 of the License, or (at your\n// option) any later version.\n//\n// This library is distributed in the hope that it will be useful, but WITHOUT\n// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License\n// for more details.\n//\n// You should have received a copy of the GNU Lesser General Public License\n// along with this library; if not, see http://www.gnu.org/licenses/\n\npackage com.xenomachina.argparser\n\nimport com.xenomachina.common.Holder\n\ninternal abstract class ParsingDelegate<T>(\n    override val parser: ArgParser,\n    override val errorName: String,\n    override val help: String\n) : ArgParser.Delegate<T>() {\n\n    protected var holder: Holder<T>? = null\n\n    override fun addValidator(validator: ArgParser.Delegate<T>.() -> Unit): ArgParser.Delegate<T> = apply {\n        validators.add(validator)\n    }\n\n    override val hasValidators: Boolean\n        get() = validators.isNotEmpty()\n\n    override val value: T\n        get() {\n            parser.force()\n            checkHasValue()\n            return holder!!.value\n        }\n\n    override val hasValue: Boolean\n        get() = holder != null\n\n    override fun validate() {\n        for (validator in validators) validator()\n    }\n\n    private val validators = mutableListOf<ArgParser.Delegate<T>.() -> Unit>()\n}\n"
  },
  {
    "path": "src/main/kotlin/com/xenomachina/argparser/PositionalDelegate.kt",
    "content": "// Copyright © 2016 Laurence Gonsalves\n//\n// This file is part of kotlin-argparser, a library which can be found at\n// http://github.com/xenomachina/kotlin-argparser\n//\n// This library is free software; you can redistribute it and/or modify it\n// under the terms of the GNU Lesser General Public License as published by the\n// Free Software Foundation; either version 2.1 of the License, or (at your\n// option) any later version.\n//\n// This library is distributed in the hope that it will be useful, but WITHOUT\n// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License\n// for more details.\n//\n// You should have received a copy of the GNU Lesser General Public License\n// along with this library; if not, see http://www.gnu.org/licenses/\n\npackage com.xenomachina.argparser\n\nimport com.xenomachina.common.Holder\n\ninternal class PositionalDelegate<T>(\n    parser: ArgParser,\n    argName: String,\n    val sizeRange: IntRange,\n    help: String,\n    val transform: String.() -> T\n) : ParsingDelegate<List<T>>(parser, argName, help) {\n\n    init {\n        require(ARG_NAME_RE.matches(argName)) { \"$argName is not a valid argument name\" }\n    }\n\n    override fun registerLeaf(root: ArgParser.Delegate<*>) {\n        assert(holder == null)\n        val hasDefault = root.hasValue\n        if (hasDefault && sizeRange.first != 1) {\n            throw IllegalStateException(\n                    \"default value can only be applied to positional that requires a minimum of 1 arguments\")\n        }\n        // TODO: this feels like a bit of a kludge. Consider making .default only work on positional and not\n        // postionalList by having them return different types?\n        parser.registerPositional(this, hasDefault)\n    }\n\n    fun parseArguments(args: List<String>) {\n        holder = Holder(args.map(transform))\n    }\n\n    override fun toHelpFormatterValue(): HelpFormatter.Value {\n        return HelpFormatter.Value(\n                isRequired = sizeRange.first > 0,\n                isRepeating = sizeRange.last > 1,\n                usages = listOf(errorName),\n                isPositional = true,\n                help = help)\n    }\n}\n"
  },
  {
    "path": "src/main/kotlin/com/xenomachina/argparser/PosixNaming.kt",
    "content": "// Copyright © 2016 Laurence Gonsalves\n//\n// This file is part of kotlin-argparser, a library which can be found at\n// http://github.com/xenomachina/kotlin-argparser\n//\n// This library is free software; you can redistribute it and/or modify it\n// under the terms of the GNU Lesser General Public License as published by the\n// Free Software Foundation; either version 2.1 of the License, or (at your\n// option) any later version.\n//\n// This library is distributed in the hope that it will be useful, but WITHOUT\n// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License\n// for more details.\n//\n// You should have received a copy of the GNU Lesser General Public License\n// along with this library; if not, see http://www.gnu.org/licenses/\n\npackage com.xenomachina.argparser\n\n/**\n * Defines rules for POSIX-style argument and option naming.\n */\ninternal object PosixNaming {\n    fun identifierToOptionName(identifier: String): String {\n        return when (identifier.length) {\n            1 -> \"-\" + identifier\n            else -> \"--\" + identifier.camelCaseToUnderscored()\n        }\n    }\n\n    fun String.camelCaseToUnderscored(): String {\n        return replace('_', '-')\n                .replace(Regex(\"(\\\\p{javaLowerCase})(\\\\p{javaUpperCase})\")) { m ->\n                    m.groups[1]!!.value + \"-\" + m.groups[2]!!.value.toLowerCase()\n                }\n    }\n\n    fun identifierToArgName(identifier: String): String {\n        return identifier.camelCaseToUnderscored().toUpperCase()\n    }\n\n    fun selectRepresentativeOptionName(names: Array<out String>): String {\n        if (names.size < 1)\n            throw IllegalArgumentException(\"need at least one option name\")\n        // Return first long option...\n        for (name in names) {\n            if (name.startsWith(\"--\")) {\n                return name\n            }\n        }\n        // ... but failing that just return first option.\n        return names[0]\n    }\n\n    fun optionNameToArgName(name: String) =\n            LEADING_HYPHENS_REGEX.replace(name, \"\").toUpperCase().replace('-', '_')\n}\n"
  },
  {
    "path": "src/main/kotlin/com/xenomachina/argparser/SystemExitException.kt",
    "content": "// Copyright © 2016 Laurence Gonsalves\n//\n// This file is part of kotlin-argparser, a library which can be found at\n// http://github.com/xenomachina/kotlin-argparser\n//\n// This library is free software; you can redistribute it and/or modify it\n// under the terms of the GNU Lesser General Public License as published by the\n// Free Software Foundation; either version 2.1 of the License, or (at your\n// option) any later version.\n//\n// This library is distributed in the hope that it will be useful, but WITHOUT\n// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License\n// for more details.\n//\n// You should have received a copy of the GNU Lesser General Public License\n// along with this library; if not, see http://www.gnu.org/licenses/\n\npackage com.xenomachina.argparser\n\nimport java.io.OutputStreamWriter\nimport java.io.Writer\nimport kotlin.system.exitProcess\n\n/**\n * An exception that wants the process to terminate with a specific status code, and also (optionally) wants to display\n * a message to [System.out] or [System.err].\n *\n * @property returnCode the return code that this process should exit with\n */\nopen class SystemExitException(message: String, val returnCode: Int) : Exception(message) {\n    /**\n     * Prints a message for the user to either `System.err` or `System.out`, and then exits with the appropriate\n     * return code.\n     *\n     * @param programName the name of this program as invoked, or null if not known\n     * @param columns the number of columns to wrap at, or 0 if not to wrap at all\n     */\n    fun printAndExit(programName: String? = null, columns: Int = 0): Nothing {\n        val writer = OutputStreamWriter(if (returnCode == 0) System.out else System.err)\n        printUserMessage(writer, programName, columns)\n        writer.flush()\n        exitProcess(returnCode)\n    }\n\n    /**\n     * Prints a message for the user to the specified `Writer`.\n     *\n     * @param writer where to write message for the user\n     * @param programName the name of this program as invoked, or null if not known\n     * @param columns the number of columns to wrap at, or 0 if not to wrap at all\n     */\n    open fun printUserMessage(writer: Writer, programName: String?, columns: Int) {\n        val leader = if (programName == null) \"\" else \"$programName: \"\n        writer.write(\"$leader$message\\n\")\n    }\n}\n\n/**\n * Calls [SystemExitException.printAndExit] on any `SystemExitException` that\n * is caught.\n *\n * @param programName the name of the program. If null, the system property com.xenomachina.argparser.programName will\n * be used, if set.\n * @param columns the number of columns to wrap any caught\n * `SystemExitException` to.  Specify null for reasonable defaults, or 0 to not\n * wrap at all.\n * @param body the code that may throw a `SystemExitException`\n */\nfun <R> mainBody(programName: String? = null, columns: Int? = null, body: () -> R): R {\n    try {\n        return body()\n    } catch (e: SystemExitException) {\n        e.printAndExit(\n                programName ?: System.getProperty(PROGRAM_NAME_PROPERTY),\n                columns ?: System.getenv(\"COLUMNS\")?.toInt() ?: DEFAULT_COLUMNS)\n    }\n}\n\nprivate const val PROGRAM_NAME_PROPERTY = \"com.xenomachina.argparser.programName\"\nprivate const val DEFAULT_COLUMNS = 80\n"
  },
  {
    "path": "src/main/kotlin/com/xenomachina/argparser/WrappingDelegate.kt",
    "content": "// Copyright © 2016 Laurence Gonsalves\n//\n// This file is part of kotlin-argparser, a library which can be found at\n// http://github.com/xenomachina/kotlin-argparser\n//\n// This library is free software; you can redistribute it and/or modify it\n// under the terms of the GNU Lesser General Public License as published by the\n// Free Software Foundation; either version 2.1 of the License, or (at your\n// option) any later version.\n//\n// This library is distributed in the hope that it will be useful, but WITHOUT\n// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License\n// for more details.\n//\n// You should have received a copy of the GNU Lesser General Public License\n// along with this library; if not, see http://www.gnu.org/licenses/\n\npackage com.xenomachina.argparser\n\ninternal class WrappingDelegate<U, W>(\n    private val inner: ArgParser.Delegate<U>,\n    private val wrap: (U) -> W\n) : ArgParser.Delegate<W>() {\n\n    override val parser: ArgParser\n        get() = inner.parser\n\n    override val value: W\n        get() = wrap(inner.value)\n\n    override val hasValue: Boolean\n        get() = inner.hasValue\n\n    override val errorName: String\n        get() = inner.errorName\n\n    override val help: String\n        get() = inner.help\n\n    override fun validate() {\n        inner.validate()\n    }\n\n    override fun toHelpFormatterValue(): HelpFormatter.Value = inner.toHelpFormatterValue()\n\n    override fun addValidator(validator: ArgParser.Delegate<W>.() -> Unit): ArgParser.Delegate<W> =\n            apply { inner.addValidator { validator(this@WrappingDelegate) } }\n\n    override val hasValidators: Boolean\n        get() = inner.hasValidators\n\n    override fun registerLeaf(root: ArgParser.Delegate<*>) {\n        inner.registerLeaf(root)\n    }\n}\n"
  },
  {
    "path": "src/test/kotlin/com/xenomachina/argparser/ArgParserTest.kt",
    "content": "// Copyright © 2016 Laurence Gonsalves\n//\n// This file is part of kotlin-argparser, a library which can be found at\n// http://github.com/xenomachina/kotlin-argparser\n//\n// This library is free software; you can redistribute it and/or modify it\n// under the terms of the GNU Lesser General Public License as published by the\n// Free Software Foundation; either version 2.1 of the License, or (at your\n// option) any later version.\n//\n// This library is distributed in the hope that it will be useful, but WITHOUT\n// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License\n// for more details.\n//\n// You should have received a copy of the GNU Lesser General Public License\n// along with this library; if not, see http://www.gnu.org/licenses/\n\npackage com.xenomachina.argparser\n\nimport com.xenomachina.argparser.PosixNaming.identifierToOptionName\nimport com.xenomachina.common.orElse\nimport io.kotlintest.matchers.beOfType\nimport io.kotlintest.should\nimport io.kotlintest.shouldBe\nimport io.kotlintest.shouldThrow\nimport io.kotlintest.specs.FunSpec\nimport java.io.File\nimport java.io.StringWriter\n\nclass ArgParserTest : FunSpec({\n    test(\"Option name validation\") {\n        val parser = parserOf()\n\n        // These are all acceptable.\n        parser.option<Int>(\"-x\", help = TEST_HELP) { 0 }\n        parser.option<Int>(\"--x\", help = TEST_HELP) { 0 }\n        parser.option<Int>(\"--xy\", help = TEST_HELP) { 0 }\n        parser.option<Int>(\"-X\", help = TEST_HELP) { 0 }\n        parser.option<Int>(\"--X\", help = TEST_HELP) { 0 }\n        parser.option<Int>(\"--XY\", help = TEST_HELP) { 0 }\n        parser.option<Int>(\"--X-Y\", help = TEST_HELP) { 0 }\n        parser.option<Int>(\"--X_Y\", help = TEST_HELP) { 0 }\n        parser.option<Int>(\"-5\", help = TEST_HELP) { 0 }\n        parser.option<Int>(\"--5\", help = TEST_HELP) { 0 }\n        parser.option<Int>(\"--5Y\", help = TEST_HELP) { 0 }\n        parser.option<Int>(\"--X5\", help = TEST_HELP) { 0 }\n        parser.option<Int>(\"--x.y\", help = TEST_HELP) { 0 }\n\n        shouldThrow<IllegalArgumentException> {\n            parser.option<Int>(\"-_\", help = TEST_HELP) { 0 }\n        }\n\n        shouldThrow<IllegalArgumentException> {\n            parser.option<Int>(\"---x\", help = TEST_HELP) { 0 }\n        }\n\n        shouldThrow<IllegalArgumentException> {\n            parser.option<Int>(\"x\", help = TEST_HELP) { 0 }\n        }\n\n        shouldThrow<IllegalArgumentException> {\n            parser.option<Int>(\"\", help = TEST_HELP) { 0 }\n        }\n\n        shouldThrow<IllegalArgumentException> {\n            parser.option<Int>(\"-xx\", help = TEST_HELP) { 0 }\n        }\n\n        shouldThrow<IllegalArgumentException> {\n            parser.option<Int>(\"--foo bar\", help = TEST_HELP) { 0 }\n        }\n\n        shouldThrow<IllegalArgumentException> {\n            parser.option<Int>(\"--foo--bar\", help = TEST_HELP) { 0 }\n        }\n\n        shouldThrow<IllegalArgumentException> {\n            parser.option<Int>(\"--f!oobar\", help = TEST_HELP) { 0 }\n        }\n\n        shouldThrow<IllegalArgumentException> {\n            parser.option<Int>(\"--.\", help = TEST_HELP) { 0 }\n        }\n\n        shouldThrow<IllegalArgumentException> {\n            parser.option<Int>(\"--.foo\", help = TEST_HELP) { 0 }\n        }\n\n        shouldThrow<IllegalArgumentException> {\n            parser.option<Int>(\"--foo.\", help = TEST_HELP) { 0 }\n        }\n    }\n\n    test(\"Positional name validation\") {\n        val parser = parserOf()\n\n        // These are all acceptable.\n        parser.positional<Int>(\"X\", help = TEST_HELP) { 0 }\n        parser.positional<Int>(\"XYZ\", help = TEST_HELP) { 0 }\n        parser.positional<Int>(\"XY-Z\", help = TEST_HELP) { 0 }\n        parser.positional<Int>(\"XY_Z\", help = TEST_HELP) { 0 }\n        parser.positional<Int>(\"XY.Z\", help = TEST_HELP) { 0 }\n\n        shouldThrow<IllegalArgumentException> {\n            parser.positional<Int>(\"-\", help = TEST_HELP) { 0 }\n        }\n\n        shouldThrow<IllegalArgumentException> {\n            parser.positional<Int>(\"_\", help = TEST_HELP) { 0 }\n        }\n\n        shouldThrow<IllegalArgumentException> {\n            parser.positional<Int>(\"x\", help = TEST_HELP) { 0 }\n        }\n\n        shouldThrow<IllegalArgumentException> {\n            parser.positional<Int>(\"\", help = TEST_HELP) { 0 }\n        }\n\n        shouldThrow<IllegalArgumentException> {\n            parser.positional<Int>(\"-X\", help = TEST_HELP) { 0 }\n        }\n\n        shouldThrow<IllegalArgumentException> {\n            parser.positional<Int>(\"X-\", help = TEST_HELP) { 0 }\n        }\n\n        shouldThrow<IllegalArgumentException> {\n            parser.positional<Int>(\"X--Y\", help = TEST_HELP) { 0 }\n        }\n\n        shouldThrow<IllegalArgumentException> {\n            parser.positional<Int>(\"X!\", help = TEST_HELP) { 0 }\n        }\n\n        shouldThrow<IllegalArgumentException> {\n            parser.positional<Int>(\"5\", help = TEST_HELP) { 0 }\n        }\n\n        shouldThrow<IllegalArgumentException> {\n            parser.positional<Int>(\".\", help = TEST_HELP) { 0 }\n        }\n\n        shouldThrow<IllegalArgumentException> {\n            parser.positional<Int>(\".XY\", help = TEST_HELP) { 0 }\n        }\n\n        shouldThrow<IllegalArgumentException> {\n            parser.positional<Int>(\"XY.\", help = TEST_HELP) { 0 }\n        }\n\n        // This should be acceptable\n        parser.option<Int>(\"--foobar\", argNames = listOf(\"X-Y\"), help = TEST_HELP) { 0 }\n\n        // This should not\n        shouldThrow<IllegalArgumentException> {\n            parser.option<Int>(\"--foobar\", argNames = listOf(\"X--Y\"), help = TEST_HELP) { 0 }\n        }\n    }\n\n    test(\"Argless short options\") {\n        class Args(parser: ArgParser) {\n            val xyz by parser.option<MutableList<String>>(\"-x\", \"-y\", \"-z\",\n                help = TEST_HELP) {\n                value.orElse { mutableListOf<String>() }.apply {\n                    add(\"$optionName\")\n                }\n            }\n        }\n\n        Args(parserOf(\"-x\", \"-y\", \"-z\", \"-z\", \"-y\")).xyz shouldBe listOf(\"-x\", \"-y\", \"-z\", \"-z\", \"-y\")\n\n        Args(parserOf(\"-xyz\")).xyz shouldBe listOf(\"-x\", \"-y\", \"-z\")\n    }\n\n    test(\"Short options with args\") {\n        class Args(parser: ArgParser) {\n            val a by parser.flagging(\"-a\", help = TEST_HELP)\n            val b by parser.flagging(\"-b\", help = TEST_HELP)\n            val c by parser.flagging(\"-c\", help = TEST_HELP)\n            val xyz by parser.option<MutableList<String>>(\"-x\", \"-y\", \"-z\",\n                argNames = oneArgName, help = TEST_HELP) {\n                value.orElse { mutableListOf<String>() }.apply {\n                    add(\"$optionName:${arguments.first()}\")\n                }\n            }\n        }\n\n        // Test with value as separate arg\n        Args(parserOf(\"-x\", \"0\", \"-y\", \"1\", \"-z\", \"2\", \"-z\", \"3\", \"-y\", \"4\")).xyz shouldBe listOf(\"-x:0\", \"-y:1\", \"-z:2\", \"-z:3\", \"-y:4\")\n\n        // Test with value concatenated\n        Args(parserOf(\"-x0\", \"-y1\", \"-z2\", \"-z3\", \"-y4\")).xyz shouldBe listOf(\"-x:0\", \"-y:1\", \"-z:2\", \"-z:3\", \"-y:4\")\n\n        // Test with = between option and value. Note that the \"=\" is treated as part of the option value for short options.\n        Args(parserOf(\"-x=0\", \"-y=1\", \"-z=2\", \"-z=3\", \"-y=4\")).xyz shouldBe listOf(\"-x:=0\", \"-y:=1\", \"-z:=2\", \"-z:=3\", \"-y:=4\")\n\n        // Test chained options. Note that an option with arguments must be last in the chain\n        val chain1 = Args(parserOf(\"-abxc\"))\n        chain1.a shouldBe true\n        chain1.b shouldBe true\n        chain1.c shouldBe false\n        chain1.xyz shouldBe listOf(\"-x:c\")\n\n        val chain2 = Args(parserOf(\"-axbc\"))\n        chain2.a shouldBe true\n        chain2.b shouldBe false\n        chain2.c shouldBe false\n        chain2.xyz shouldBe listOf(\"-x:bc\")\n    }\n\n    test(\"Mixed short options\") {\n        class Args(parser: ArgParser) {\n            val def by parser.option<MutableList<String>>(\"-d\", \"-e\", \"-f\",\n                help = TEST_HELP) {\n                value.orElse { mutableListOf<String>() }.apply {\n                    add(\"$optionName\")\n                }\n            }\n            val abc by parser.option<MutableList<String>>(\"-a\", \"-b\", \"-c\",\n                help = TEST_HELP) {\n                value.orElse { mutableListOf<String>() }.apply {\n                    add(\"$optionName\")\n                }\n            }\n        }\n\n        Args(parserOf(\"-adbefccbafed\")).run {\n            def shouldBe listOf(\"-d\", \"-e\", \"-f\", \"-f\", \"-e\", \"-d\")\n            abc shouldBe listOf(\"-a\", \"-b\", \"-c\", \"-c\", \"-b\", \"-a\")\n        }\n    }\n\n    test(\"Mixed short options with args\") {\n        class Args(parser: ArgParser) {\n            val def by parser.option<MutableList<String>>(\"-d\", \"-e\", \"-f\",\n                help = TEST_HELP) {\n                value.orElse { mutableListOf<String>() }.apply {\n                    add(\"$optionName\")\n                }\n            }\n            val abc by parser.option<MutableList<String>>(\"-a\", \"-b\", \"-c\",\n                help = TEST_HELP) {\n                value.orElse { mutableListOf<String>() }.apply {\n                    add(\"$optionName\")\n                }\n            }\n            val xyz by parser.option<MutableList<String>>(\"-x\", \"-y\", \"-z\",\n                argNames = oneArgName,\n                help = TEST_HELP) {\n                value.orElse { mutableListOf<String>() }.apply {\n                    add(\"$optionName:${arguments.first()}\")\n                }\n            }\n        }\n\n        Args(parserOf(\"-adecfy5\", \"-x0\", \"-bzxy\")).run {\n            abc shouldBe listOf(\"-a\", \"-c\", \"-b\")\n            def shouldBe listOf(\"-d\", \"-e\", \"-f\")\n            xyz shouldBe listOf(\"-y:5\", \"-x:0\", \"-z:xy\")\n        }\n    }\n\n    test(\"Argless long options\") {\n        class Args(parser: ArgParser) {\n            val xyz by parser.option<MutableList<String>>(\"--xray\", \"--yellow\", \"--zebra\",\n                help = TEST_HELP) {\n                value.orElse { mutableListOf<String>() }.apply {\n                    add(\"$optionName\")\n                }\n            }\n        }\n\n        Args(parserOf(\"--xray\", \"--yellow\", \"--zebra\", \"--zebra\", \"--yellow\")).xyz shouldBe listOf(\"--xray\", \"--yellow\", \"--zebra\", \"--zebra\", \"--yellow\")\n\n        Args(parserOf(\"--xray\", \"--yellow\", \"--zebra\")).xyz shouldBe listOf(\"--xray\", \"--yellow\", \"--zebra\")\n    }\n\n    test(\"Dotted long options\") {\n        class Args(parser: ArgParser) {\n            val xyz by parser.option<MutableList<String>>(\"--x.ray\", \"--color.yellow\", \"--animal.zebra\",\n                help = TEST_HELP) {\n                value.orElse { mutableListOf<String>() }.apply {\n                    add(\"$optionName\")\n                }\n            }\n        }\n\n        Args(parserOf(\"--x.ray\", \"--animal.zebra\", \"--color.yellow\", \"--x.ray\")).xyz shouldBe listOf(\"--x.ray\", \"--animal.zebra\", \"--color.yellow\", \"--x.ray\")\n    }\n\n    test(\"Long options with one arg\") {\n        class Args(parser: ArgParser) {\n            val xyz by parser.option<MutableList<String>>(\"--xray\", \"--yellow\", \"--zaphod\",\n                argNames = oneArgName,\n                help = TEST_HELP) {\n                value.orElse { mutableListOf<String>() }.apply {\n                    add(\"$optionName:${arguments.first()}\")\n                }\n            }\n        }\n\n        // Test with value as separate arg\n        Args(parserOf(\"--xray\", \"0\", \"--yellow\", \"1\", \"--zaphod\", \"2\", \"--zaphod\", \"3\", \"--yellow\", \"4\")).xyz shouldBe listOf(\"--xray:0\", \"--yellow:1\", \"--zaphod:2\", \"--zaphod:3\", \"--yellow:4\")\n\n        // Test with = between option and value\n        Args(parserOf(\"--xray=0\", \"--yellow=1\", \"--zaphod=2\", \"--zaphod=3\", \"--yellow=4\")).xyz shouldBe listOf(\"--xray:0\", \"--yellow:1\", \"--zaphod:2\", \"--zaphod:3\", \"--yellow:4\")\n\n        shouldThrow<UnrecognizedOptionException> {\n            Args(parserOf(\"--xray0\", \"--yellow1\", \"--zaphod2\", \"--zaphod3\", \"--yellow4\")).xyz\n        }.run {\n            message shouldBe \"unrecognized option '--xray0'\"\n        }\n    }\n\n    test(\"Long options with multiple args\") {\n        class Args(parser: ArgParser) {\n            val xyz by parser.option<MutableList<String>>(\"--xray\", \"--yak\", \"--zaphod\",\n                argNames = listOf(\"COLOR\", \"SIZE\", \"FLAVOR\"),\n                help = TEST_HELP) {\n                value.orElse { mutableListOf<String>() }.apply { add(\"$optionName:$arguments\") }\n            }\n        }\n\n        // Test with value as separate arg\n        Args(parserOf(\"--xray\", \"red\", \"5\", \"salty\")).xyz shouldBe listOf(\"--xray:[red, 5, salty]\")\n\n        Args(parserOf(\"--zaphod\", \"green\", \"42\", \"sweet\", \"--yak\", \"blue\", \"7\", \"bitter\")).xyz shouldBe listOf(\n            \"--zaphod:[green, 42, sweet]\", \"--yak:[blue, 7, bitter]\")\n\n        // Note that something that looks like an option is consumed as an argument if it appears where an argument\n        // should be. This is expected behavior.\n        Args(parserOf(\"--zaphod\", \"green\", \"42\", \"--yak\")).xyz shouldBe listOf(\n            \"--zaphod:[green, 42, --yak]\")\n\n        shouldThrow<OptionMissingRequiredArgumentException> {\n            Args(parserOf(\"--zaphod\", \"green\", \"42\", \"sweet\", \"--yak\", \"blue\", \"7\")).xyz\n        }.run {\n            message shouldBe \"option '--yak' is missing the required argument FLAVOR\"\n        }\n\n        shouldThrow<OptionMissingRequiredArgumentException> {\n            Args(parserOf(\"--zaphod\", \"green\")).xyz\n        }.run {\n            message shouldBe \"option '--zaphod' is missing the required argument SIZE\"\n        }\n\n        shouldThrow<OptionMissingRequiredArgumentException> {\n            Args(parserOf(\"--xray\")).xyz\n        }.run {\n            message shouldBe \"option '--xray' is missing the required argument COLOR\"\n        }\n    }\n\n    test(\"Delegate provider\") {\n        fun ArgParser.putting(vararg names: String, help: String) =\n            option<MutableMap<String, String>>(*names,\n                argNames = listOf(\"KEY\", \"VALUE\"),\n                help = help) {\n                value.orElse { mutableMapOf<String, String>() }.apply {\n                    put(arguments.first(), arguments.last()) }\n            }\n\n        fun ArgParser.putting(help: String) =\n            ArgParser.DelegateProvider { identifier ->\n                putting(identifierToOptionName(identifier), help = help) }\n\n        class Args(parser: ArgParser) {\n            val dict by parser.putting(TEST_HELP)\n        }\n\n        // Test with value as separate arg\n        Args(parserOf(\"--dict\", \"red\", \"5\")).dict shouldBe mapOf(\"red\" to \"5\")\n\n        Args(parserOf(\n            \"--dict\", \"green\", \"42\",\n            \"--dict\", \"blue\", \"7\"\n        )).dict shouldBe mapOf(\n            \"green\" to \"42\",\n            \"blue\" to \"7\")\n\n        // Note that something that looks like an option is consumed as an argument if it appears where an argument\n        // should be. This is expected behavior.\n        Args(parserOf(\"--dict\", \"green\", \"--dict\")).dict shouldBe mapOf(\"green\" to \"--dict\")\n\n        shouldThrow<OptionMissingRequiredArgumentException> {\n            Args(parserOf(\"--dict\", \"green\", \"42\", \"--dict\", \"blue\")).dict\n        }.run {\n            message shouldBe \"option '--dict' is missing the required argument VALUE\"\n        }\n\n        shouldThrow<OptionMissingRequiredArgumentException> {\n            Args(parserOf(\"--dict\")).dict\n        }.run {\n            message shouldBe \"option '--dict' is missing the required argument KEY\"\n        }\n    }\n\n    test(\"Default\") {\n        class Args(parser: ArgParser) {\n            val x by parser.storing(\"-x\",\n                help = TEST_HELP) { toInt() }.default(5)\n        }\n\n        // Test with no value\n        Args(parserOf()).x shouldBe 5\n\n        // Test with value\n        Args(parserOf(\"-x6\")).x shouldBe 6\n\n        // Test with value as separate arg\n        Args(parserOf(\"-x\", \"7\")).x shouldBe 7\n\n        // Test with multiple values\n        Args(parserOf(\"-x9\", \"-x8\")).x shouldBe 8\n    }\n\n    test(\"DDefault with providerefault\") {\n        class Args(parser: ArgParser) {\n            val x by parser.storing(help = TEST_HELP) { toInt() }.default(5)\n        }\n\n        // Test with no value\n        Args(parserOf()).x shouldBe 5\n\n        // Test with value\n        Args(parserOf(\"-x6\")).x shouldBe 6\n\n        // Test with value as separate arg\n        Args(parserOf(\"-x\", \"7\")).x shouldBe 7\n\n        // Test with multiple values\n        Args(parserOf(\"-x9\", \"-x8\")).x shouldBe 8\n    }\n\n    test(\"Default with la\") {\n        class Args(parser: ArgParser) {\n            var defaultCalled = false\n            val x by parser.storing(help = TEST_HELP) { toInt() }.default { defaultCalled = true; 5 }\n        }\n\n        // Test default hasn't been called\n        Args(parserOf(\"-x6\")).defaultCalled shouldBe false\n\n        // Test with no value\n        val args = Args(parserOf())\n        args.x shouldBe 5\n        args.defaultCalled shouldBe true\n    }\n\n    test(\"Flag\") {\n        class Args(parser: ArgParser) {\n            val x by parser.flagging(\"-x\", \"--ecks\",\n                help = TEST_HELP)\n            val y by parser.flagging(\"-y\",\n                help = TEST_HELP)\n            val z by parser.flagging(\"--zed\",\n                help = TEST_HELP)\n        }\n\n        Args(parserOf(\"-x\", \"-y\", \"--zed\", \"--zed\", \"-y\")).run {\n            x shouldBe true\n            y shouldBe true\n            z shouldBe true\n        }\n\n        Args(parserOf()).run {\n            x shouldBe false\n            y shouldBe false\n            z shouldBe false\n        }\n\n        Args(parserOf(\"-y\", \"--ecks\")).run {\n            x shouldBe true\n            y shouldBe true\n        }\n\n        Args(parserOf(\"--zed\")).run {\n            x shouldBe false\n            y shouldBe false\n            z shouldBe true\n        }\n    }\n\n    test(\"Argument no parser\") {\n        class Args(parser: ArgParser) {\n            val x by parser.storing(\"--ecks\", \"-x\",\n                help = TEST_HELP)\n        }\n\n        Args(parserOf(\"-x\", \"foo\")).x shouldBe \"foo\"\n\n        Args(parserOf(\"-x\", \"bar\", \"-x\", \"baz\")).x shouldBe \"baz\"\n\n        Args(parserOf(\"--ecks\", \"long\", \"-x\", \"short\")).x shouldBe \"short\"\n\n        Args(parserOf(\"-x\", \"short\", \"--ecks\", \"long\")).x shouldBe \"long\"\n\n        val args = Args(parserOf())\n        shouldThrow<MissingValueException> {\n            args.x\n        }.run {\n            message shouldBe \"missing ECKS\"\n        }\n    }\n\n    test(\"Argument missing long\") {\n        class Args(parser: ArgParser) {\n            val x by parser.storing(\"--ecks\",\n                help = TEST_HELP)\n        }\n\n        val args = Args(parserOf())\n        shouldThrow<MissingValueException> {\n            args.x\n        }.run {\n            message shouldBe \"missing ECKS\"\n        }\n    }\n\n    test(\"Argument missing short\") {\n        class Args(parser: ArgParser) {\n            val x by parser.storing(\"-x\",\n                help = TEST_HELP)\n        }\n\n        val args = Args(parserOf())\n        shouldThrow<MissingValueException> {\n            args.x\n        }.run {\n            message shouldBe \"missing X\"\n        }\n    }\n\n    test(\"Argument withParser\") {\n        class Args(parser: ArgParser) {\n            val x by parser.storing(\"-x\", \"--ecks\",\n                help = TEST_HELP) { toInt() }\n        }\n\n        val opts1 = Args(parserOf(\"-x\", \"5\"))\n        opts1.x shouldBe 5\n\n        val opts2 = Args(parserOf(\"-x\", \"1\", \"-x\", \"2\"))\n        opts2.x shouldBe 2\n\n        val opts3 = Args(parserOf(\"--ecks\", \"3\", \"-x\", \"4\"))\n        opts3.x shouldBe 4\n\n        val opts4 = Args(parserOf(\"-x\", \"5\", \"--ecks\", \"6\"))\n        opts4.x shouldBe 6\n\n        val opts6 = Args(parserOf())\n        shouldThrow<MissingValueException> {\n            opts6.x\n        }.run {\n            message shouldBe \"missing ECKS\"\n        }\n    }\n\n    test(\"Accumulator noParser\") {\n        class Args(parser: ArgParser) {\n            val x by parser.adding(\"-x\", \"--ecks\",\n                help = TEST_HELP)\n        }\n\n        Args(parserOf()).x shouldBe listOf<String>()\n\n        Args(parserOf(\"-x\", \"foo\")).x shouldBe listOf(\"foo\")\n\n        Args(parserOf(\"-x\", \"bar\", \"-x\", \"baz\")).x shouldBe listOf(\"bar\", \"baz\")\n\n        Args(parserOf(\"--ecks\", \"long\", \"-x\", \"short\")).x shouldBe listOf(\"long\", \"short\")\n\n        Args(parserOf(\"-x\", \"short\", \"--ecks\", \"long\")).x shouldBe listOf(\"short\", \"long\")\n    }\n\n    test(\"Accumulator withParser\") {\n        class Args(parser: ArgParser) {\n            val x by parser.adding(\"-x\", \"--ecks\",\n                help = TEST_HELP) { toInt() }\n        }\n\n        Args(parserOf()).x shouldBe listOf<Int>()\n        Args(parserOf(\"-x\", \"5\")).x shouldBe listOf(5)\n        Args(parserOf(\"-x\", \"1\", \"-x\", \"2\")).x shouldBe listOf(1, 2)\n        Args(parserOf(\"--ecks\", \"3\", \"-x\", \"4\")).x shouldBe listOf(3, 4)\n        Args(parserOf(\"-x\", \"5\", \"--ecks\", \"6\")).x shouldBe listOf(5, 6)\n    }\n\n    class ColorArgs(parser: ArgParser) {\n        val color by parser.mapping(\n            \"--red\" to Color.RED,\n            \"--green\" to Color.GREEN,\n            \"--blue\" to Color.BLUE,\n            help = TEST_HELP)\n    }\n\n    test(\"Mapping\") {\n        ColorArgs(parserOf(\"--red\")).color shouldBe Color.RED\n        ColorArgs(parserOf(\"--green\")).color shouldBe Color.GREEN\n        ColorArgs(parserOf(\"--blue\")).color shouldBe Color.BLUE\n\n        // Last one takes precedence\n        ColorArgs(parserOf(\"--blue\", \"--red\")).color shouldBe Color.RED\n        ColorArgs(parserOf(\"--blue\", \"--green\")).color shouldBe Color.GREEN\n        ColorArgs(parserOf(\"--red\", \"--blue\")).color shouldBe Color.BLUE\n\n        val args = ColorArgs(parserOf())\n        shouldThrow<MissingValueException> {\n            args.color\n        }.run {\n            message shouldBe \"missing --red|--green|--blue\"\n        }\n    }\n\n    class OptionalColorArgs(parser: ArgParser) {\n        val color by parser.mapping(\n            \"--red\" to Color.RED,\n            \"--green\" to Color.GREEN,\n            \"--blue\" to Color.BLUE,\n            help = TEST_HELP)\n            .default(Color.GREEN)\n    }\n\n    test(\"Mapping withDefault\") {\n        OptionalColorArgs(parserOf(\"--red\")).color shouldBe Color.RED\n        OptionalColorArgs(parserOf(\"--green\")).color shouldBe Color.GREEN\n        OptionalColorArgs(parserOf(\"--blue\")).color shouldBe Color.BLUE\n        OptionalColorArgs(parserOf()).color shouldBe Color.GREEN\n    }\n\n    test(\"Unrecognized short opt\") {\n        shouldThrow<UnrecognizedOptionException> {\n            OptionalColorArgs(parserOf(\"-x\")).color\n        }.run {\n            message shouldBe \"unrecognized option '-x'\"\n        }\n    }\n\n    test(\"Unrecognized long opt\") {\n        shouldThrow<UnrecognizedOptionException> {\n            OptionalColorArgs(parserOf(\"--ecks\")).color\n        }.run {\n            message shouldBe \"unrecognized option '--ecks'\"\n        }\n    }\n\n    test(\"Storing no arg\") {\n        class Args(parser: ArgParser) {\n            val x by parser.storing(\"-x\", \"--ecks\",\n                help = TEST_HELP)\n        }\n\n        // Note that name actually used for option is used in message\n        shouldThrow<OptionMissingRequiredArgumentException> {\n            Args(parserOf(\"-x\")).x\n        }.run {\n            message shouldBe \"option '-x' is missing a required argument\"\n        }\n\n        // Note that name actually used for option is used in message\n        shouldThrow<OptionMissingRequiredArgumentException> {\n            Args(parserOf(\"--ecks\")).x\n        }.run {\n            message shouldBe \"option '--ecks' is missing a required argument\"\n        }\n    }\n\n    test(\"Short storing no arg chained\") {\n        class Args(parser: ArgParser) {\n            val y by parser.flagging(\"-y\",\n                help = TEST_HELP)\n            val x by parser.storing(\"-x\",\n                help = TEST_HELP)\n        }\n\n        // Note that despite chaining, hyphen appears in message\n        shouldThrow<OptionMissingRequiredArgumentException> {\n            Args(parserOf(\"-yx\")).x\n        }.run {\n            message shouldBe \"option '-x' is missing a required argument\"\n        }\n    }\n\n    test(\"Init validation\") {\n        class Args(parser: ArgParser) {\n            val yDelegate = parser.storing(\"-y\",\n                help = TEST_HELP) { toInt() }\n            val y by yDelegate\n\n            val xDelegate = parser.storing(\"-x\",\n                help = TEST_HELP) { toInt() }\n            val x by xDelegate\n\n            init {\n                if (y >= x)\n                    throw InvalidArgumentException(\"${yDelegate.errorName} must be less than ${xDelegate.errorName}\")\n\n                // A better way to accomplish validation that only depends on one Delegate is to use\n                // Delegate.addValidator. See testAddValidator for an example of this.\n                if (x.rem(2) != 0)\n                    throw InvalidArgumentException(\"${xDelegate.errorName} must be even, $x is odd\")\n            }\n        }\n\n        // This should pass validation\n        val opts0 = Args(parserOf(\"-y1\", \"-x10\"))\n        opts0.y shouldBe 1\n        opts0.x shouldBe 10\n\n        shouldThrow<InvalidArgumentException> {\n            Args(parserOf(\"-y20\", \"-x10\")).x\n        }.run {\n            message shouldBe \"Y must be less than X\"\n        }\n\n        shouldThrow<InvalidArgumentException> {\n            Args(parserOf(\"-y10\", \"-x15\")).x\n        }.run {\n            message shouldBe \"X must be even, 15 is odd\"\n        }\n\n        shouldThrow<InvalidArgumentException> {\n            Args(parserOf(\"-y10\", \"-x15\")).x\n        }.run {\n            message shouldBe \"X must be even, 15 is odd\"\n        }\n    }\n\n    test(\"Add validator\") {\n        class Args(parser: ArgParser) {\n            val yDelegate = parser.storing(\"-y\",\n                help = TEST_HELP) { toInt() }\n            val y by yDelegate\n\n            val xDelegate = parser.storing(\"-x\",\n                help = TEST_HELP) { toInt() }\n                .addValidator {\n                    if (value.rem(2) != 0)\n                        throw InvalidArgumentException(\"$errorName must be even, $value is odd\")\n                }\n            val x by xDelegate\n\n            init {\n                if (y >= x)\n                    throw InvalidArgumentException(\"${yDelegate.errorName} must be less than ${xDelegate.errorName}\")\n            }\n        }\n\n        // This should pass validation\n        val opts0 = Args(parserOf(\"-y1\", \"-x10\"))\n        opts0.y shouldBe 1\n        opts0.x shouldBe 10\n\n        shouldThrow<InvalidArgumentException> {\n            Args(parserOf(\"-y20\", \"-x10\")).x\n        }.run {\n            message shouldBe \"Y must be less than X\"\n        }\n\n        shouldThrow<InvalidArgumentException> {\n            Args(parserOf(\"-y10\", \"-x15\")).x\n        }.run {\n            message shouldBe \"X must be even, 15 is odd\"\n        }\n    }\n\n    test(\"Unconsumed\") {\n        class Args(parser: ArgParser) {\n            val y by parser.flagging(\"-y\", \"--why\",\n                help = TEST_HELP)\n            val x by parser.flagging(\"-x\", \"--ecks\",\n                help = TEST_HELP)\n        }\n\n        // No problem.\n        Args(parserOf(\"-yx\")).run {\n            x shouldBe true\n            y shouldBe true\n        }\n\n        // Attempting to give -y a parameter, \"z\", is treated as unrecognized option.\n        shouldThrow<UnrecognizedOptionException> {\n            Args(parserOf(\"-yz\")).y\n        }.run {\n            message shouldBe \"unrecognized option '-z'\"\n        }\n\n        // Unconsumed \"z\" again, but note that it triggers even if we don't look at y.\n        shouldThrow<UnrecognizedOptionException> {\n            Args(parserOf(\"-yz\")).x\n        }.run {\n            message shouldBe \"unrecognized option '-z'\"\n        }\n\n        // No problem again, this time with long opts.\n        Args(parserOf(\"--why\", \"--ecks\")).run {\n            x shouldBe true\n            y shouldBe true\n        }\n\n        // Attempting to give --why a parameter, \"z\" causes an error.\n        shouldThrow<UnexpectedOptionArgumentException> {\n            Args(parserOf(\"--why=z\")).y\n        }.run {\n            message shouldBe \"option '--why' doesn't allow an argument\"\n        }\n\n        // Unconsumed \"z\" again, but note that it triggers even if we don't look at y.\n        shouldThrow<UnexpectedOptionArgumentException> {\n            Args(parserOf(\"--why=z\")).x\n        }.run {\n            message shouldBe \"option '--why' doesn't allow an argument\"\n        }\n    }\n\n    test(\"Positional basic\") {\n        class Args(parser: ArgParser) {\n            val flag by parser.flagging(\"-f\", \"--flag\",\n                help = TEST_HELP)\n            val store by parser.storing(\"-s\", \"--store\",\n                help = TEST_HELP).default(\"DEFAULT\")\n            val sources by parser.positionalList(\"SOURCE\",\n                help = TEST_HELP)\n            val destination by parser.positional(\"DEST\",\n                help = TEST_HELP)\n        }\n\n        Args(parserOf(\"foo\", \"bar\", \"baz\", \"quux\")).run {\n            flag shouldBe false\n            store shouldBe \"DEFAULT\"\n            sources shouldBe listOf(\"foo\", \"bar\", \"baz\")\n            destination shouldBe \"quux\"\n        }\n\n        Args(parserOf(\"-f\", \"foo\", \"bar\", \"baz\", \"quux\")).run {\n            flag shouldBe true\n            store shouldBe \"DEFAULT\"\n            sources shouldBe listOf(\"foo\", \"bar\", \"baz\")\n            destination shouldBe \"quux\"\n        }\n\n        Args(parserOf(\"-s\", \"foo\", \"bar\", \"baz\", \"quux\")).run {\n            flag shouldBe false\n            store shouldBe \"foo\"\n            sources shouldBe listOf(\"bar\", \"baz\")\n            destination shouldBe \"quux\"\n        }\n\n        Args(parserOf(\"-s\", \"foo\", \"bar\", \"-f\", \"baz\", \"quux\")).run {\n            flag shouldBe true\n            store shouldBe \"foo\"\n            sources shouldBe listOf(\"bar\", \"baz\")\n            destination shouldBe \"quux\"\n        }\n\n        // \"--\" disables option processing for all further arguments.\n        // Note that \"-f\" is now considered a positional argument.\n        Args(parserOf(\"-s\", \"foo\", \"--\", \"bar\", \"-f\", \"baz\", \"quux\")).run {\n            flag shouldBe false\n            store shouldBe \"foo\"\n            sources shouldBe listOf(\"bar\", \"-f\", \"baz\")\n            destination shouldBe \"quux\"\n        }\n\n        // \"--\" disables option processing for all further arguments.\n        // Note that the second \"--\" is also considered a positional argument.\n        Args(parserOf(\"-s\", \"foo\", \"--\", \"bar\", \"--\", \"-f\", \"baz\", \"quux\")).run {\n            flag shouldBe false\n            store shouldBe \"foo\"\n            sources shouldBe listOf(\"bar\", \"--\", \"-f\", \"baz\")\n            destination shouldBe \"quux\"\n        }\n\n        Args(parserOf(\"-s\", \"foo\", \"bar\", \"-f\", \"baz\", \"quux\", mode = ArgParser.Mode.POSIX)).run {\n            flag shouldBe false\n            store shouldBe \"foo\"\n            sources shouldBe listOf(\"bar\", \"-f\", \"baz\")\n            destination shouldBe \"quux\"\n        }\n    }\n\n    test(\"Positional with parser\") {\n        class Args(parser: ArgParser) {\n            val flag by parser.flagging(\"-f\", \"--flag\",\n                help = TEST_HELP)\n            val store by parser.storing(\"-s\", \"--store\",\n                help = TEST_HELP).default(\"DEFAULT\")\n            val start by parser.positionalList(\"START\", TEST_HELP, 3..4) { toInt() }\n            val end by parser.positionalList(\"END\", TEST_HELP, 3..5) { toInt() }\n        }\n\n        shouldThrow<MissingRequiredPositionalArgumentException> {\n            Args(parserOf(\"1\", \"2\")).flag\n        }.run {\n            message shouldBe \"missing START operand\"\n        }\n\n        shouldThrow<MissingRequiredPositionalArgumentException> {\n            Args(parserOf(\"1\", \"2\", \"3\", \"4\", \"5\")).flag\n        }.run {\n            message shouldBe \"missing END operand\"\n        }\n\n        Args(parserOf(\"1\", \"2\", \"3\", \"4\", \"5\", \"6\")).run {\n            flag shouldBe false\n            store shouldBe \"DEFAULT\"\n\n            // end needs at least 3 args, so start only consumes 3\n            start shouldBe listOf(1, 2, 3)\n            end shouldBe listOf(4, 5, 6)\n        }\n\n        Args(parserOf(\"1\", \"2\", \"3\", \"4\", \"5\", \"6\", \"7\")).run {\n            flag shouldBe false\n            store shouldBe \"DEFAULT\"\n\n            // end only needs at 3 args, so start can consume 4\n            start shouldBe listOf(1, 2, 3, 4)\n            end shouldBe listOf(5, 6, 7)\n        }\n\n        Args(parserOf(\"1\", \"2\", \"3\", \"4\", \"5\", \"6\", \"7\", \"8\")).run {\n            flag shouldBe false\n            store shouldBe \"DEFAULT\"\n\n            // start can't consume more than 4, so end gets the rest.\n            start shouldBe listOf(1, 2, 3, 4)\n            end shouldBe listOf(5, 6, 7, 8)\n        }\n\n        Args(parserOf(\"1\", \"2\", \"3\", \"4\", \"5\", \"6\", \"7\", \"8\", \"9\")).run {\n            flag shouldBe false\n            store shouldBe \"DEFAULT\"\n\n            // once again, start can't consume more than 4, so end gets the rest.\n            start shouldBe listOf(1, 2, 3, 4)\n            end shouldBe listOf(5, 6, 7, 8, 9)\n        }\n\n        shouldThrow<UnexpectedPositionalArgumentException> {\n            Args(parserOf(\"1\", \"2\", \"3\", \"4\", \"5\", \"6\", \"7\", \"8\", \"9\", \"10\")).flag\n        }.run {\n            message shouldBe \"unexpected argument after END\"\n        }\n    }\n\n    test(\"Counting\") {\n        class Args(parser: ArgParser) {\n            val verbosity by parser.counting(\"-v\", \"--verbose\",\n                help = TEST_HELP)\n        }\n\n        Args(parserOf()).run {\n            verbosity shouldBe 0\n        }\n\n        Args(parserOf(\"-v\")).run {\n            verbosity shouldBe 1\n        }\n\n        Args(parserOf(\"-v\", \"-v\")).run {\n            verbosity shouldBe 2\n        }\n    }\n\n    test(\"Help\") {\n        class Args(parser: ArgParser) {\n            val dryRun by parser.flagging(\"-n\", \"--dry-run\",\n                help = \"don't do anything\")\n            val includes by parser.adding(\"-I\", \"--include\",\n                help = \"search in this directory for header files\")\n            val outDir by parser.storing(\"-o\", \"--output\",\n                help = \"directory in which all output should be generated\")\n            val verbosity by parser.counting(\"-v\", \"--verbose\",\n                help = \"increase verbosity\")\n            val sources by parser.positionalList(\"SOURCE\",\n                help = \"source file\")\n            val destination by parser.positional(\"DEST\",\n                help = \"destination file\")\n        }\n\n        shouldThrow<ShowHelpException> {\n            Args(parserOf(\"--help\",\n                helpFormatter = DefaultHelpFormatter(\n                    prologue = \"\"\"\n                            This is the prologue. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam\n                            malesuada maximus eros. Fusce luctus risus eget quam consectetur, eu auctor est ullamcorper.\n                            Maecenas eget suscipit dui, sed sodales erat. Phasellus.\n\n                            This is the second paragraph of the prologue. I don't have anything else to say, but I'd\n                            like there to be enough text that it wraps to the next line.\n                            \"\"\",\n                    epilogue = \"\"\"\n                            This is the epilogue. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec vel tortor nunc. Sed eu massa sed turpis auctor faucibus. Donec vel pellentesque tortor. Ut ultrices tempus lectus fermentum vestibulum. Phasellus.\n                            \"\"\"))).dryRun\n        }.run {\n            val help = StringWriter().apply { printUserMessage(this, \"program_name\", 60) }.toString()\n            help shouldBe \"\"\"\nusage: program_name [-h] [-n] [-I INCLUDE]... -o OUTPUT\n                    [-v]... SOURCE... DEST\n\n\nThis is the prologue. Lorem ipsum dolor sit amet,\nconsectetur adipiscing elit. Aliquam malesuada maximus eros.\nFusce luctus risus eget quam consectetur, eu auctor est\nullamcorper. Maecenas eget suscipit dui, sed sodales erat.\nPhasellus.\n\nThis is the second paragraph of the prologue. I don't have\nanything else to say, but I'd like there to be enough text\nthat it wraps to the next line.\n\n\nrequired arguments:\n  -o OUTPUT,          directory in which all output should\n  --output OUTPUT     be generated\n\n\noptional arguments:\n  -h, --help          show this help message and exit\n\n  -n, --dry-run       don't do anything\n\n  -I INCLUDE,         search in this directory for header\n  --include INCLUDE   files\n\n  -v, --verbose       increase verbosity\n\n\npositional arguments:\n  SOURCE              source file\n\n  DEST                destination file\n\n\nThis is the epilogue. Lorem ipsum dolor sit amet,\nconsectetur adipiscing elit. Donec vel tortor nunc. Sed eu\nmassa sed turpis auctor faucibus. Donec vel pellentesque\ntortor. Ut ultrices tempus lectus fermentum vestibulum.\nPhasellus.\n\"\"\".trimStart()\n\n            val help2 = StringWriter().apply { printUserMessage(this, \"a_really_long_program_name\", 60) }.toString()\n            help2 shouldBe \"\"\"\nusage: a_really_long_program_name\n         [-h] [-n] [-I INCLUDE]... -o OUTPUT [-v]...\n         SOURCE... DEST\n\n\nThis is the prologue. Lorem ipsum dolor sit amet,\nconsectetur adipiscing elit. Aliquam malesuada maximus eros.\nFusce luctus risus eget quam consectetur, eu auctor est\nullamcorper. Maecenas eget suscipit dui, sed sodales erat.\nPhasellus.\n\nThis is the second paragraph of the prologue. I don't have\nanything else to say, but I'd like there to be enough text\nthat it wraps to the next line.\n\n\nrequired arguments:\n  -o OUTPUT,          directory in which all output should\n  --output OUTPUT     be generated\n\n\noptional arguments:\n  -h, --help          show this help message and exit\n\n  -n, --dry-run       don't do anything\n\n  -I INCLUDE,         search in this directory for header\n  --include INCLUDE   files\n\n  -v, --verbose       increase verbosity\n\n\npositional arguments:\n  SOURCE              source file\n\n  DEST                destination file\n\n\nThis is the epilogue. Lorem ipsum dolor sit amet,\nconsectetur adipiscing elit. Donec vel tortor nunc. Sed eu\nmassa sed turpis auctor faucibus. Donec vel pellentesque\ntortor. Ut ultrices tempus lectus fermentum vestibulum.\nPhasellus.\n\"\"\".trimStart()\n\n            // Regression test for issue #17\n            val help_wide = StringWriter().apply { printUserMessage(this, \"program_name\", 0) }.toString()\n            help_wide shouldBe \"\"\"\nusage: program_name [-h] [-n] [-I INCLUDE]... -o OUTPUT [-v]... SOURCE... DEST\n\n\nThis is the prologue. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam malesuada maximus eros. Fusce luctus risus eget quam consectetur, eu auctor est ullamcorper. Maecenas eget suscipit dui, sed sodales erat. Phasellus.\n\nThis is the second paragraph of the prologue. I don't have anything else to say, but I'd like there to be enough text that it wraps to the next line.\n\n\nrequired arguments:\n  -o OUTPUT, --output OUTPUT      directory in which all output should be generated\n\n\noptional arguments:\n  -h, --help                      show this help message and exit\n\n  -n, --dry-run                   don't do anything\n\n  -I INCLUDE, --include INCLUDE   search in this directory for header files\n\n  -v, --verbose                   increase verbosity\n\n\npositional arguments:\n  SOURCE                          source file\n\n  DEST                            destination file\n\n\nThis is the epilogue. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec vel tortor nunc. Sed eu massa sed turpis auctor faucibus. Donec vel pellentesque tortor. Ut ultrices tempus lectus fermentum vestibulum. Phasellus.\n\"\"\".trimStart()\n        }\n    }\n\n    test(\"Implicit long flag name\") {\n        class Args(parser: ArgParser) {\n            val flag1 by parser.flagging(help = TEST_HELP)\n            val flag2 by parser.flagging(help = TEST_HELP)\n            val count by parser.counting(help = TEST_HELP)\n            val store by parser.storing(help = TEST_HELP)\n            val store_int by parser.storing(help = TEST_HELP) { toInt() }\n            val adder by parser.adding(help = TEST_HELP)\n            val int_adder by parser.adding(help = TEST_HELP) { toInt() }\n            val int_set_adder by parser.adding(initialValue = mutableSetOf<Int>(), help = TEST_HELP) { toInt() }\n            val positional by parser.positional(help = TEST_HELP)\n            val positional_int by parser.positional(help = TEST_HELP) { toInt() }\n            val positionalList by parser.positionalList(sizeRange = 2..2, help = TEST_HELP)\n            val positionalList_int by parser.positionalList(sizeRange = 2..2, help = TEST_HELP) { toInt() }\n        }\n\n        Args(parserOf(\n            \"--flag1\", \"--count\", \"--count\", \"--store=hello\", \"--store-int=42\",\n            \"--adder=foo\", \"--adder=bar\",\n            \"--int-adder=2\", \"--int-adder=4\", \"--int-adder=6\",\n            \"--int-set-adder=64\", \"--int-set-adder=128\", \"--int-set-adder=20\",\n            \"1\", \"1\", \"2\", \"3\", \"5\", \"8\"\n        )).run {\n            flag1 shouldBe true\n            flag2 shouldBe false\n            count shouldBe 2\n            store shouldBe \"hello\"\n            store_int shouldBe 42\n            adder shouldBe listOf(\"foo\", \"bar\")\n            int_adder shouldBe listOf(2, 4, 6)\n            int_set_adder shouldBe setOf(20, 64, 128)\n            positional shouldBe \"1\"\n            positional_int shouldBe 1\n            positionalList shouldBe listOf(\"2\", \"3\")\n            positionalList_int shouldBe listOf(5, 8)\n        }\n\n        shouldThrow<MissingRequiredPositionalArgumentException> {\n            Args(parserOf(\n                \"13\", \"21\", \"34\", \"55\", \"89\"\n            )).run {\n                flag1 shouldBe false\n            }\n        }.run {\n            message shouldBe \"missing POSITIONAL-LIST-INT operand\"\n        }\n    }\n\n    fun nullableString(): String? = null\n\n    test(\"Nullable optional\") {\n        class Args(parser: ArgParser) {\n            val path by parser.storing(\"The path\", transform = ::File)\n                .default(nullableString()?.let(::File))\n        }\n    }\n\n    test(\"Nullable optional without transform\") {\n        class Args(parser: ArgParser) {\n            val str by parser.storing(TEST_HELP)\n                .default(nullableString())\n        }\n        Args(parserOf(\"--str=foo\")).run {\n            str shouldBe \"foo\"\n        }\n        Args(parserOf()).run {\n            str shouldBe null\n        }\n    }\n\n    test(\"Default generalization\") {\n        class Args(parser: ArgParser) {\n            val shape by parser.storing(\"The path\", transform = ::Rectangle)\n                .default(Circle())\n            val rect by parser.storing(\"The path\", transform = ::Rectangle)\n        }\n        val args = Args(parserOf(\"--rect=foo\"))\n        staticType(args.shape) shouldBe Shape::class\n        args.shape should beOfType<Circle>()\n        staticType(args.rect) shouldBe Rectangle::class\n\n        val args2 = Args(parserOf())\n        shouldThrow<MissingValueException> {\n            args2.rect\n        }.run {\n            message shouldBe \"missing RECT\"\n        }\n    }\n\n    test(\"Default generalization without transform\") {\n        class Args(parser: ArgParser) {\n            val str by parser.storing(TEST_HELP)\n                .default(5)\n        }\n        Args(parserOf(\"--str=foo\")).run {\n            str shouldBe \"foo\"\n        }\n        Args(parserOf()).run {\n            str shouldBe 5\n        }\n    }\n\n    test(\"Auto named flagging\") {\n        class Args(parser: ArgParser) {\n            val autoFlag by parser.flagging(TEST_HELP)\n        }\n        Args(parserOf()).autoFlag shouldBe false\n        Args(parserOf(\"--auto-flag\")).autoFlag shouldBe true\n    }\n\n    test(\"Auto named counting\") {\n        class Args(parser: ArgParser) {\n            val autoCount by parser.counting(TEST_HELP)\n        }\n        Args(parserOf()).autoCount shouldBe 0\n        Args(parserOf(\"--auto-count\")).autoCount shouldBe 1\n        Args(parserOf(\"--auto-count\", \"--auto-count\")).autoCount shouldBe 2\n    }\n\n    test(\"Auto named storing\") {\n        class Args(parser: ArgParser) {\n            val autoStore by parser.storing(TEST_HELP)\n        }\n\n        shouldThrow<MissingValueException> {\n            Args(parserOf()).autoStore\n        }.run {\n            message shouldBe \"missing AUTO_STORE\"\n        }\n\n        Args(parserOf(\"--auto-store=foo\")).autoStore shouldBe \"foo\"\n        Args(parserOf(\"--auto-store\", \"bar\", \"--auto-store\", \"baz\")).autoStore shouldBe \"baz\"\n    }\n\n    test(\"Auto named storing with transform\") {\n        class Args(parser: ArgParser) {\n            val autoStore by parser.storing(TEST_HELP) { toInt() }\n        }\n\n        shouldThrow<MissingValueException> {\n            Args(parserOf()).autoStore\n        }.run {\n            message shouldBe \"missing AUTO_STORE\"\n        }\n\n        Args(parserOf(\"--auto-store=5\")).autoStore shouldBe 5\n        Args(parserOf(\"--auto-store\", \"11\", \"--auto-store\", \"42\")).autoStore shouldBe 42\n    }\n\n    test(\"Auto named adding\") {\n        class Args(parser: ArgParser) {\n            val autoAccumulator by parser.adding(TEST_HELP)\n        }\n\n        Args(parserOf()).autoAccumulator shouldBe emptyList<String>()\n        Args(parserOf(\"--auto-accumulator=foo\")).autoAccumulator shouldBe listOf(\"foo\")\n        Args(parserOf(\"--auto-accumulator\", \"bar\", \"--auto-accumulator\", \"baz\")).autoAccumulator shouldBe listOf(\"bar\", \"baz\")\n    }\n\n    test(\"Auto named adding with transform\") {\n        class Args(parser: ArgParser) {\n            val autoAccumulator by parser.adding(TEST_HELP) { toInt() }\n        }\n\n        Args(parserOf()).autoAccumulator shouldBe emptyList<Int>()\n        Args(parserOf(\"--auto-accumulator=5\")).autoAccumulator shouldBe listOf(5)\n        Args(parserOf(\"--auto-accumulator\", \"11\", \"--auto-accumulator\", \"42\")).autoAccumulator shouldBe listOf(11, 42)\n    }\n\n    test(\"Auto named adding with transform and initial\") {\n        class Args(parser: ArgParser) {\n            val autoAccumulator by parser.adding(TEST_HELP, initialValue = mutableSetOf<Int>()) { toInt() }\n        }\n\n        Args(parserOf()).autoAccumulator shouldBe emptySet<Int>()\n        Args(parserOf(\"--auto-accumulator=5\")).autoAccumulator shouldBe setOf(5)\n        Args(parserOf(\"--auto-accumulator\", \"11\", \"--auto-accumulator\", \"42\")).autoAccumulator shouldBe setOf(42, 11)\n    }\n\n    test(\"Auto named positional\") {\n        class Args(parser: ArgParser) {\n            val autoPositional by parser.positional(TEST_HELP)\n        }\n\n        shouldThrow<MissingRequiredPositionalArgumentException> {\n            Args(parserOf()).autoPositional\n        }.run {\n            message shouldBe \"missing AUTO-POSITIONAL operand\"\n        }\n        Args(parserOf(\"foo\")).autoPositional shouldBe \"foo\"\n    }\n\n    test(\"Auto named positional with transform\") {\n        class Args(parser: ArgParser) {\n            val autoPositional by parser.positional(TEST_HELP) { toInt() }\n        }\n\n        shouldThrow<MissingRequiredPositionalArgumentException> {\n            Args(parserOf()).autoPositional\n        }.run {\n            message shouldBe \"missing AUTO-POSITIONAL operand\"\n        }\n        Args(parserOf(\"47\")).autoPositional shouldBe 47\n    }\n\n    test(\"Auto named positional list\") {\n        class Args(parser: ArgParser) {\n            val autoPositional by parser.positionalList(TEST_HELP)\n        }\n\n        shouldThrow<MissingRequiredPositionalArgumentException> {\n            Args(parserOf()).autoPositional\n        }.run {\n            message shouldBe \"missing AUTO-POSITIONAL operand\"\n        }\n        Args(parserOf(\"foo\")).autoPositional shouldBe listOf(\"foo\")\n    }\n\n    test(\"Auto named positional list with transform\") {\n        class Args(parser: ArgParser) {\n            val autoPositional by parser.positionalList(TEST_HELP) { toInt() }\n        }\n\n        shouldThrow<MissingRequiredPositionalArgumentException> {\n            Args(parserOf()).autoPositional\n        }.run {\n            message shouldBe \"missing AUTO-POSITIONAL operand\"\n        }\n        Args(parserOf(\"47\")).autoPositional shouldBe listOf(47)\n        Args(parserOf(\"27\", \"38\")).autoPositional shouldBe listOf(27, 38)\n    }\n\n    test(\"Positional default\") {\n        class Args(parser: ArgParser) {\n            val name by parser.positional(\"NAME\", TEST_HELP).default(\"John\")\n        }\n\n        Args(parserOf()).name shouldBe \"John\"\n        Args(parserOf(\"Alfred\")).name shouldBe \"Alfred\"\n    }\n\n    test(\"Positional list default\") {\n        class Args(parser: ArgParser) {\n            val name by parser.positionalList(\"NAME\", TEST_HELP).default(listOf(\"Jack\", \"Jill\"))\n        }\n\n        Args(parserOf()).name shouldBe listOf(\"Jack\", \"Jill\")\n        Args(parserOf(\"Jack\")).name shouldBe listOf(\"Jack\")\n        Args(parserOf(\"John\", \"Jim\", \"Jack\", \"Jason\")).name shouldBe listOf(\"John\", \"Jim\", \"Jack\", \"Jason\")\n    }\n\n    test(\"Auto named long option with multiple args\") {\n        class Args(parser: ArgParser) {\n            val xyz by parser.option<MutableList<String>>(\n                \"--xyz\",\n                argNames = listOf(\"COLOR\", \"SIZE\", \"FLAVOR\"),\n                help = TEST_HELP) {\n                value.orElse { mutableListOf<String>() }.apply { add(\"$optionName:$arguments\")\n                }\n            }\n        }\n\n        // Test with value as separate arg\n        Args(parserOf(\"--xyz\", \"red\", \"5\", \"salty\")).xyz shouldBe listOf(\"--xyz:[red, 5, salty]\")\n\n        Args(parserOf(\"--xyz\", \"green\", \"42\", \"sweet\", \"--xyz\", \"blue\", \"7\", \"bitter\")).xyz shouldBe listOf(\n            \"--xyz:[green, 42, sweet]\", \"--xyz:[blue, 7, bitter]\")\n\n        // Note that something that looks like an option is consumed as an argument if it appears where an argument\n        // should be. This is expected behavior.\n        Args(parserOf(\"--xyz\", \"green\", \"42\", \"--xyz\")).xyz shouldBe listOf(\n            \"--xyz:[green, 42, --xyz]\")\n\n        shouldThrow<OptionMissingRequiredArgumentException> {\n            Args(parserOf(\"--xyz\", \"green\", \"42\", \"sweet\", \"--xyz\", \"blue\", \"7\")).xyz\n        }.run {\n            message shouldBe \"option '--xyz' is missing the required argument FLAVOR\"\n        }\n\n        shouldThrow<OptionMissingRequiredArgumentException> {\n            Args(parserOf(\"--xyz\", \"green\")).xyz\n        }.run {\n            message shouldBe \"option '--xyz' is missing the required argument SIZE\"\n        }\n\n        shouldThrow<OptionMissingRequiredArgumentException> {\n            Args(parserOf(\"--xyz\")).xyz\n        }.run {\n            message shouldBe \"option '--xyz' is missing the required argument COLOR\"\n        }\n    }\n\n    test(\"Positional add validator\") {\n        class Args(parser: ArgParser) {\n            val yDelegate = parser.positional(\"Y\", TEST_HELP) { toInt() }\n            val y by yDelegate\n\n            val xDelegate = parser.positional(\"X\", TEST_HELP) { toInt() }\n                .addValidator {\n                    if (value.rem(2) != 0)\n                        throw InvalidArgumentException(\"$errorName must be even, $value is odd\")\n                }\n            val x by xDelegate\n\n            init {\n                if (y >= x)\n                    throw InvalidArgumentException(\"${yDelegate.errorName} must be less than ${xDelegate.errorName}\")\n            }\n        }\n\n        // This should pass validation\n        val opts0 = Args(parserOf(\"1\", \"10\"))\n        opts0.y shouldBe 1\n        opts0.x shouldBe 10\n\n        shouldThrow<InvalidArgumentException> {\n            Args(parserOf(\"20\", \"10\")).x\n        }.run {\n            message shouldBe \"Y must be less than X\"\n        }\n\n        shouldThrow<InvalidArgumentException> {\n            Args(parserOf(\"10\", \"15\")).x\n        }.run {\n            message shouldBe \"X must be even, 15 is odd\"\n        }\n    }\n\n    test(\"Positional list add validator\") {\n        class Args(parser: ArgParser) {\n            val yDelegate = parser.positionalList(\"Y\", TEST_HELP, 2..2) { toInt() }\n            val y by yDelegate\n\n            val xDelegate = parser.positionalList(\"X\", TEST_HELP, 2..2) { toInt() }\n                .addValidator {\n                    for (i in value) {\n                        if (i.rem(2) != 0)\n                            throw InvalidArgumentException(\"$errorName elements must be even, $i is odd\")\n                    }\n                }\n            val x by xDelegate\n        }\n\n        // This should pass validation\n        val opts0 = Args(parserOf(\"1\", \"10\", \"4\", \"8\"))\n        opts0.y shouldBe listOf(1, 10)\n        opts0.x shouldBe listOf(4, 8)\n\n        shouldThrow<InvalidArgumentException> {\n            Args(parserOf(\"10\", \"15\", \"42\", \"37\")).x\n        }.run {\n            message shouldBe \"X elements must be even, 37 is odd\"\n        }\n    }\n\n    test(\"Parse into\") {\n        class Args(parser: ArgParser) {\n            val str by parser.storing(TEST_HELP)\n        }\n\n        parserOf(\"--str=foo\").parseInto(::Args).run {\n            str shouldBe \"foo\"\n        }\n    }\n\n    test(\"Parse into unrecognized option failure\") {\n        class Args(parser: ArgParser) {\n            val str by parser.storing(TEST_HELP)\n        }\n\n        shouldThrow<UnrecognizedOptionException> {\n            parserOf(\"--str=foo\", \"--eggs=bacon\").parseInto(::Args)\n        }\n    }\n\n    test(\"Parse into missing value failure\") {\n        class Args(parser: ArgParser) {\n            val str by parser.storing(TEST_HELP)\n            val eggs by parser.storing(TEST_HELP)\n        }\n\n        shouldThrow<MissingValueException> {\n            parserOf(\"--str=foo\").parseInto(::Args)\n        }\n    }\n\n    test(\"Parse into illegal state test\") {\n        class Args(parser: ArgParser) {\n            val str by parser.storing(TEST_HELP)\n        }\n\n        shouldThrow<IllegalStateException> {\n            val parser = parserOf(\"--str=foo\")\n            @Suppress(\"unused_variable\")\n            val oops by parser.storing(\"--oops\", help = TEST_HELP).default(\"oops\")\n            parser.parseInto(::Args)\n        }\n    }\n\n    test(\"Issue15\") {\n        class Args(parser: ArgParser) {\n            val manual by parser.storing(\"--named-by-hand\", help = TEST_HELP, argName = \"HANDYS-ARG\")\n            val auto by parser.storing(TEST_HELP, argName = \"OTTOS-ARG\")\n            val foo by parser.adding(help = TEST_HELP, argName = \"BAR\") { toInt() }\n            val bar by parser.adding(\"--baz\", help = TEST_HELP, argName = \"QUUX\")\n        }\n\n        shouldThrow<ShowHelpException> {\n            Args(parserOf(\"--help\")).manual\n        }.run {\n            // TODO: find a way to make this less brittle (ie: don't use help text)\n            StringWriter().apply { printUserMessage(this, null, 10000) }.toString().trim() shouldBe \"\"\"\nusage: [-h] --named-by-hand HANDYS-ARG --auto OTTOS-ARG [--foo BAR]... [--baz QUUX]...\n\nrequired arguments:\n  --named-by-hand HANDYS-ARG   test help message\n\n  --auto OTTOS-ARG             test help message\n\n\noptional arguments:\n  -h, --help                   show this help message and exit\n\n  --foo BAR                    test help message\n\n  --baz QUUX                   test help message\"\"\".trim()\n        }\n    }\n\n    test(\"Issue18 addValidator then default\") {\n        class Args(parser: ArgParser) {\n            val x by parser.storing(\n                \"-x\",\n                help = TEST_HELP,\n                transform = String::toInt\n            ).addValidator {\n                value shouldBe 0\n            }.default(0)\n        }\n        shouldThrow<IllegalStateException> {\n            Args(parserOf())\n        }.message shouldBe \"Cannot add default after adding validators\"\n    }\n\n    test(\"Issue18 default then addValidator\") {\n        class Args(parser: ArgParser) {\n            val x by parser.storing(\n                \"-x\",\n                help = \"\",\n                transform = String::toInt\n            ).default(0).addValidator {\n                value shouldBe 0\n            }\n        }\n        val x = Args(parserOf()).x\n        x shouldBe 0\n    }\n\n    test(\"Issue47\") {\n        class Args(parser: ArgParser) {\n            val caseInsensitive by parser.flagging(\"-c\", \"--case_insensitive\", help = TEST_HELP)\n\n            val includedExtensions by parser.adding(\"-e\", \"--include_ext\", help = TEST_HELP) {\n                extensionCheckCaseInsensitive()\n            }\n\n            private fun String.extensionCheckCaseInsensitive() =\n                if (caseInsensitive) this.toLowerCase() else this\n        }\n\n        val includeExtensions = Args(parserOf(\"-e\", \"Foo\", \"-c\", \"-e\", \"Bar\")).includedExtensions\n        includeExtensions shouldBe listOf(\"Foo\", \"bar\")\n    }\n\n    class DependentArgs(parser: ArgParser) {\n        val suffix by parser.storing(TEST_HELP)\n\n        val x by parser.adding(TEST_HELP) {\n            \"$this:$suffix\"\n        }\n    }\n\n    test(\"Dependent args test order mat\") {\n        val result = DependentArgs(parserOf(\"--suffix\", \"bar\", \"-x\", \"foo\", \"-x\", \"dry\", \"--suffix\", \"fish\", \"-x\", \"cat\")).x\n        result shouldBe listOf(\"foo:bar\", \"dry:bar\", \"cat:fish\")\n    }\n\n    test(\"Dependent args test unset throws missing value excep\") {\n        shouldThrow<MissingValueException> {\n            DependentArgs(parserOf(\"-x\", \"foo\", \"-x\", \"dry\", \"--suffix\", \"fish\", \"-x\", \"cat\")).x\n        }.run {\n            message shouldBe \"missing SUFFIX\"\n        }\n    }\n\n    class DependentArgsWithDefault(parser: ArgParser) {\n        val suffix by parser.storing(TEST_HELP).default(\"\")\n\n        val x by parser.adding(TEST_HELP) {\n            \"$this:$suffix\"\n        }\n    }\n\n    test(\"Dependent args test with default unset\") {\n        DependentArgsWithDefault(parserOf(\"-x\", \"foo\", \"-x\", \"dry\", \"--suffix\", \"fish\", \"-x\", \"cat\")).x shouldBe\n            listOf(\"foo:\", \"dry:\", \"cat:fish\")\n    }\n\n    class DependentArgsWithDependentDefault(parser: ArgParser) {\n        val a by parser.storing(TEST_HELP).default(\"\")\n\n        val b by parser.storing(TEST_HELP).default { \"=$a\" }\n    }\n\n    test(\"Dependent args test with dependent def\") {\n        DependentArgsWithDependentDefault(parserOf()).run {\n            a shouldBe \"\"\n            b shouldBe \"=\"\n        }\n\n        DependentArgsWithDependentDefault(parserOf(\"-aFoo\")).run {\n            a shouldBe \"Foo\"\n            b shouldBe \"=Foo\"\n        }\n\n        DependentArgsWithDependentDefault(parserOf(\"-bBar\")).run {\n            a shouldBe \"\"\n            b shouldBe \"Bar\"\n        }\n\n        DependentArgsWithDependentDefault(parserOf(\"-aFoo\", \"-bBar\")).run {\n            a shouldBe \"Foo\"\n            b shouldBe \"Bar\"\n        }\n\n        DependentArgsWithDependentDefault(parserOf(\"-bBar\", \"-aFoo\")).run {\n            a shouldBe \"Foo\"\n            b shouldBe \"Bar\"\n        }\n    }\n})\n\n/** Used in tests where we need a simple enum */\nenum class Color { RED, GREEN, BLUE }\n\n/** Used in tests where we need a simple class hierarchy */\nopen class Shape\nclass Rectangle(val s: String) : Shape()\nclass Circle : Shape()\n\n/** Creates an ArgParser for the specified (var)args. */\nfun parserOf(\n    vararg args: String,\n    mode: ArgParser.Mode = ArgParser.Mode.GNU,\n    helpFormatter: HelpFormatter? = DefaultHelpFormatter()\n) = ArgParser(args, mode, helpFormatter)\n\n/**\n * Helper function for getting the static (not runtime) type of an expression. This is useful for verifying that the\n * inferred type of an expression is what you think it should be. For example:\n *\n *     staticType(actuallyACircle) shouldBe Shape::class\n */\ninline fun <reified T : Any> staticType(@Suppress(\"UNUSED_PARAMETER\") x: T) = T::class\n\nval oneArgName = listOf(\"ARG_NAME\")\n\nval TEST_HELP = \"test help message\"\n"
  }
]