[
  {
    "path": ".gitattributes",
    "content": "Sources/LinuxBridge/* linguist-vendored\nSources/OpenSSL/* linguist-vendored\nSources/cURL/* linguist-vendored\nXcode/PerfectLib/* linguist-vendored\n"
  },
  {
    "path": ".gitignore",
    "content": "# Xcode\n#\nbuild/\n*.pbxuser\n!default.pbxuser\n*.mode1v3\n!default.mode1v3\n*.mode2v3\n!default.mode2v3\n*.perspectivev3\n!default.perspectivev3\nxcuserdata\n*.xccheckout\n*.moved-aside\nDerivedData\n*.hmap\n*.ipa\n*.xcuserstate\n*.xcscmblueprint\n\n# CocoaPods\n#\n# We recommend against adding the Pods directory to your .gitignore. However\n# you should judge for yourself, the pros and cons are mentioned at:\n# http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control\n#\n# Pods/\n\n# Carthage\n#\n# Add this line if you want to avoid checking in source code from Carthage dependencies.\n# Carthage/Checkouts\n\nCarthage/Build\n\n*.d\n\n*.o\n\n*.swiftdeps\n\n*.swiftdoc\n\n*.swiftmodule\n\n*.so\n\n*.DS_Store\n\n# Perfect binaries\nPerfectServer/perfectserverfcgi\nPerfectServer/perfectserverhttp\n\n# SwiftPM\n.build/\nPackages/\nPerfectLib.xcodeproj/\ndocs/\n"
  },
  {
    "path": ".jazzy.yaml",
    "content": "module: PerfectLib\nauthor: PerfectlySoft\nauthor_url: https://perfect.org\ngithub_url: https://github.com/PerfectlySoft/Perfect\ncopyright: '© 2016 PerfectlySoft Inc. and the Perfect project authors'\ntheme: fullwidth\nxcodebuild_arguments: [-target, PerfectLib, -toolchain, org.swift.3020160620a]\nclean: true\n"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "content": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nIn the interest of fostering an open and welcoming environment, we as\ncontributors and maintainers pledge to making participation in our project and\nour community a harassment-free experience for everyone, regardless of age, body\nsize, disability, ethnicity, gender identity and expression, level of experience,\nnationality, personal appearance, race, religion, or sexual identity and\norientation.\n\n## Our Standards\n\nExamples of behavior that contributes to creating a positive environment\ninclude:\n\n* Using welcoming and inclusive language\n* Being respectful of differing viewpoints and experiences\n* Gracefully accepting constructive criticism\n* Focusing on what is best for the community\n* Showing empathy towards other community members\n\nExamples of unacceptable behavior by participants include:\n\n* The use of sexualized language or imagery and unwelcome sexual attention or\nadvances\n* Trolling, insulting/derogatory comments, and personal or political attacks\n* Public or private harassment\n* Publishing others' private information, such as a physical or electronic\n  address, without explicit permission\n* Other conduct which could reasonably be considered inappropriate in a\n  professional setting\n\n## Our Responsibilities\n\nProject maintainers are responsible for clarifying the standards of acceptable\nbehavior and are expected to take appropriate and fair corrective action in\nresponse to any instances of unacceptable behavior.\n\nProject maintainers have the right and responsibility to remove, edit, or\nreject comments, commits, code, wiki edits, issues, and other contributions\nthat are not aligned to this Code of Conduct, or to ban temporarily or\npermanently any contributor for other behaviors that they deem inappropriate,\nthreatening, offensive, or harmful.\n\n## Scope\n\nThis Code of Conduct applies both within project spaces and in public spaces\nwhen an individual is representing the project or its community. Examples of\nrepresenting a project or community include using an official project e-mail\naddress, posting via an official social media account, or acting as an appointed\nrepresentative at an online or offline event. Representation of a project may be\nfurther defined and clarified by project maintainers.\n\n## Enforcement\n\nInstances of abusive, harassing, or otherwise unacceptable behavior may be\nreported by contacting the project team at [mailto:info@perfect.org]. All\ncomplaints will be reviewed and investigated and will result in a response that\nis deemed necessary and appropriate to the circumstances. The project team is\nobligated to maintain confidentiality with regard to the reporter of an incident.\nFurther details of specific enforcement policies may be posted separately.\n\nProject maintainers who do not follow or enforce the Code of Conduct in good\nfaith may face temporary or permanent repercussions as determined by other\nmembers of the project's leadership.\n\n## Attribution\n\nThis Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,\navailable at [http://contributor-covenant.org/version/1/4][version]\n\n[homepage]: http://contributor-covenant.org\n[version]: http://contributor-covenant.org/version/1/4/\n"
  },
  {
    "path": "CODE_OF_CONDUCT.zh_CN.md",
    "content": "# 贡献者行为规范\n\n## 我们的承诺\n\n为了实现一个开放、和谐的软件开发环境，作为该软件的贡献者和版本维护者，我们保证在社区参与项目的过\n程中，对所有人一视同仁。在社区中，任何人，无论年龄、身材、长相，或者身体是否有缺陷；无论种族、\n性别和学历出身；无论国籍、血统、宗教信仰和任何性取向，我们都承诺避免任何骚扰和歧视。\n\n## 我们的标准\n\n为创造良好的开发环境，我们鼓励：\n\n* 采用友好的语言，秉持包容的态度\n* 充分尊重不同的观点和对问题的不同看法\n* 耐心接纳建设性批评\n* 关注于为社区未来提高产品价值\n* 对其他社区成员保持同情心\n\n无法接受的行为包括：\n\n* 淫秽言语或低级下流的措辞\n* 恶意评论，针对人身和政治观点的言语攻击\n* 公开或私下的言语骚扰\n* 未经许可公布他人隐私，包括实际住址或电子地址\n* 从专业角度考虑的其他不正当行为\n\n## 我们的责任\n\n项目管理维护人员有义务澄清本行为规范，并针对任何不当行为采取必要措施进行纠正。\n\n项目管理维护人员有权并有义务删除、修改、抵制任何不符合本行为规范的评论、代码内容、文字提交和各类\n报告P，也有权因其各种如恐吓、侵犯或者伤害的不当行为暂时或永久屏蔽违规账号。\n\n## 适用范围\n\n本行为规范适用于任何本项目或本项目所在社区空间内的公众行为，如公众邮件账号、公众社交媒体账号，\n或者用于在线和离线活动中的委托代表。项目管理维护人员可以根据需要澄清或委派项目代表。\n\n## 加强措施\n\n任何不当言论、骚扰和其他不可接受的不当行为都可以通过[mailto:info@perfect.org]进行举报。所有\n投诉均会被审理并根据需要进行调查。项目团队有义务为举报者身份保密。更多加强措施会在其他文件中单独\n公开。\n\n对于不遵守本行为规范的项目管理人员，本项目其他领导成员可能会临时或永久取消其管理权。\n\n## 文件归属\n\n本文节选自 [Contributor Covenant][homepage], version 1.4,\n可从以下网址查看： [http://contributor-covenant.org/version/1/4][version]\n\n[homepage]: http://contributor-covenant.org\n[version]: http://contributor-covenant.org/version/1/4/\n"
  },
  {
    "path": "LICENSE",
    "content": "                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"{}\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright {yyyy} {name of copyright owner}\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "LICENSE.zh_CN",
    "content": "Apache许可证\n2.0版 2004年1月\nhttp://www.apache.org/licenses/\n\n关于使用、复制和分发的条款\n\n定义\n\"许可证\"是指根据本文件第1到第9部分关于使用、复制和分发的条款。\n\n\"许可证颁发者\"是指版权所有者或者由版权所有者授权许可证的实体。\n\n\"法律实体\"是指实施实体和进行控制的所有其它实体受该实体控制，或者受该实体集中控制。根据此定义，\"控制\"是指(i)让无论是否签订协议的上述实体，进行指导或管理的直接权利或间接权利，或者(ii)拥有百分之五十(50%)或以上已发行股票的所有者，或者(iii)上述实体的实权所有者。\n\n\"用户\"(或\"用户的\")是指行使本许可证所授予权限的个人或法律实体。\n\n\"源程序\"形式是指对包括但不限于软件源代码、文件源程序和配置文件进行修改的首选形式。\n\n\"目标\"形式是指对源程序形式进行机械转换或翻译的任何形式，包括但不限于对编译的目标代码，生成的文件以及转换为其它媒体类型。\n\n\"作品\"是指根据本许可证所制作的源程序形式或目标形式的著作，在著作中包含的或附加的版权通知(在下面附录中提供了一个示例)。\n\n\"衍生作品\"是指基于作品(或从作品衍生而来)的源程序形式或目标形式的任何作品，以及编辑修订、注释、详细描述或其它修订等构成原创著作作品的整体。根据本许可证，衍生作品不得包括与作品及其衍生作品分离之作品，或仅与作品及其衍生作品的接口相链接(或按名称结合)之作品。\n\n\"贡献\"是指任何著作作品，包括作品的原始版本和对该作品或衍生作品所做的任何修订或补充，意在提交给许可证颁发者以让版权所有者或代表版权所有者的授权个人或法律实体包含在其作品中。根据此定义，\"提交\"一词表示发送给许可证颁发者或其代表人，任何电子的、口头的或书面的交流信息形式，包括但不限于在由许可证颁发者或者代表其管理的电子邮件清单、源代码控制系统、以及发布跟踪系统上为讨论和提高作品的交流，但不包括由版权所有者以书面形式明显标注或指定为\"非贡献\"的交流活动。\n\n\"贡献者\"是指许可证颁发者和代表从许可证颁发者接受之贡献的并随后包含在作品之贡献中的任何个人或法律实体。\n\n版权许可证的授予。根据本许可证的条款，每个贡献者授予用户永久性的、全球性的、非专有性的、免费的、无版权费的、不可撤销的版权许可证以源程序形式或目标形式复制、准备衍生作品、公开显示、公开执行、授予分许可证、以及分发作品和这样的衍生作品。\n专利许可证的授予。根据本许可证的条款，每个贡献者授予用户永久性的、全球性的、非专有性的、免费的、无版权费的、不可撤销的(除在本部分进行说明)专利许可证对作品进行制作、让人制作、使用、提供销售、销售、进口和其它转让，且这样的许可证仅适用于在所递交作品的贡献中因可由单一的或多个这样的贡献者授予而必须侵犯的申请专利。如果用户对任何实体针对作品或作品中所涉及贡献提出因直接性或贡献性专利侵权而提起专利法律诉讼(包括交互诉讼请求或反索赔)，那么根据本许可证，授予用户针对作品的任何专利许可证将在提起上述诉讼之日起终止。\n重新分发。用户可在任何媒介中复制和分发作品或衍生作品之副本，无论是否修订，还是以源程序形式或目标形式，条件是用户需满足下列条款：\n用户必须为作品或衍生作品的任何其他接收者提供本许可证的副本；并且\n用户必须让任何修改过的文件附带明显的通知，声明用户已更改文件；并且\n用户必须从作品的源程序形式中保留衍生作品源程序形式的用户所分发的所有版权、专利、商标和属性通知，但不包括不属于衍生作品任何部分的类似通知；并且\n如果作品将\"通知\"文本文件包括为其分发作品的一部分，那么用户分发的任何衍生作品中须至少在下列地方之一包括，在这样的通知文件中所包含的属性通知的可读副本，但不包括那些不属于衍生作品任何部分的通知：在作为衍生作品一部分而分发的通知文本文件中；如果与衍生作品一起提供则在源程序形式或文件中；或者通常作为第三方通知出现的时候和地方，在衍生作品中产生的画面中。通知文件的内容仅供信息提供，并未对许可证进行修改。用户可在其分发的衍生作品中在作品的通知文本后或作为附录添加自己的属性通知，条件是附加的属性通知不得构成修改本许可证。\n用户可以为自身所做出的修订添加自己的版权声明并可对自身所做出修订内容或为这样的衍生作品作为整体的使用、复制或分发提供附加或不同的条款，条件是用户对作品的使用、复制和分发必须符合本许可证中声明的条款。\n\n贡献的提交。除非用户明确声明，在作品中由用户向许可证颁发者的提交若要包含在贡献中，必须在无任何附加条款下符合本许可证的条款。尽管上面如此规定，执行许可证颁发者有关贡献的条款时，任何情况下均不得替代或修改任何单独许可证协议的条款。\n商标。本许可证并未授予用户使用许可证颁发者的商号、商标、服务标记或产品名称，除非将这些名称用于合理性和惯例性描述作品起源和复制通知文件的内容时。\n保证否认条款。除非因适用法律需要或书面同意，许可证颁发者以\"按原样\"基础提供作品(并且每个贡献者提供其贡献)，无任何明示的或暗示的保证或条件，包括但不限于关于所有权、不侵权、商品适销性、或适用性的保证或条件。用户仅对使用或重新分发作品的正确性负责，并需承担根据本许可证行使权限时的任何风险。\n责任限制条款。在任何情况下并根据任何法律，无论是因侵权(包括过失)或根据合同，还是其它原因，除非根据适用法律需要(例如故意行为和重大过失行为)或经书面同意，即使贡献者事先已被告知发生损害的可能性，任何贡献者不就用户因使用本许可证或不能使用或无法使用作品(包括但不限于商誉损失、停工、计算机失效或故障，或任何商业损坏或损失)而造成的损失，包括直接的、非直接的、特殊的、意外的或间接的字符损坏而负责。\n接受保证或附加责任。重新分发作品或及其衍生作品时，用户可选择提供或为符合本许可证承担之支持、担保、赔偿或其它职责义务和/或权利而收取费用。但是，在承担上述义务时，用户只可代表用户本身和用户本身责任来执行，无需代表任何其它贡献者，并且用户仅可保证、防护并保持每个贡献者不受任何因此而产生的责任或对因用户自身承担这样的保证或附加责任而对这样的贡献者所提出的索赔。\n条款结束\n\n附录：如何向用户作品中应用Apache许可证。\n\n若要向用户作品应用Apache许可证，请附加下列样本通知，将括号\"[]\"中的字段以用户自身的区分信息来替换(但不包括括号)。文本必须以文件格式适当的注释句法包含在其中。另外建议将文件名或类别名以及目的说明包含在相同的\"打印页\"上作为版权通知，以更加容易的区分出第三方档案。\n\n版权所有[yyyy][版权所有者的名称]\n\n根据2.0版本Apache许可证(\"许可证\")授权；\n根据本许可证，用户可以不使用此文件。\n用户可从下列网址获得许可证副本：\n\nhttp://www.apache.org/licenses/LICENSE-2.0\n\n除非因适用法律需要或书面同意，\n根据许可证分发的软件是基于\"按原样\"基础提供，\n无任何明示的或暗示的保证或条件。\n详见根据许可证许可下，特定语言的管辖权限和限制。\n"
  },
  {
    "path": "Package.swift",
    "content": "// swift-tools-version:5.1\n//\n//  Package.swift\n//  PerfectLib\n//\n//  Created by Kyle Jessup on 3/22/16.\n//\tCopyright (C) 2016 PerfectlySoft, Inc.\n//\n//===----------------------------------------------------------------------===//\n//\n// This source file is part of the Perfect.org open source project\n//\n// Copyright (c) 2015 - 2016 PerfectlySoft Inc. and the Perfect project authors\n// Licensed under Apache License v2.0\n//\n// See http://perfect.org/licensing.html for license information\n//\n//===----------------------------------------------------------------------===//\n//\n\nimport PackageDescription\n\n#if os(Linux)\nlet package = Package(\n\tname: \"PerfectLib\",\n\tproducts: [\n\t\t.library(name: \"PerfectLib\", targets: [\"PerfectLib\"])\n\t],\n\tdependencies: [.package(url: \"https://github.com/PerfectlySoft/Perfect-LinuxBridge.git\", from: \"3.0.0\")],\n\ttargets: [\n\t\t.target(name: \"PerfectLib\", dependencies: [\"LinuxBridge\"]),\n\t\t.testTarget(name: \"PerfectLibTests\", dependencies: [\"PerfectLib\"])\n\t]\n)\n#else\nlet package = Package(\n\tname: \"PerfectLib\",\n\tplatforms: [\n\t\t.macOS(.v10_15)\n\t],\n\tproducts: [\n\t\t.library(name: \"PerfectLib\", targets: [\"PerfectLib\"])\n\t],\n\tdependencies: [],\n\ttargets: [\n\t\t.target(name: \"PerfectLib\", dependencies: []),\n\t\t.testTarget(name: \"PerfectLibTests\", dependencies: [\"PerfectLib\"])\n\t]\n)\n#endif\n"
  },
  {
    "path": "README.md",
    "content": "# Perfect: Server-Side Swift [简体中文](README.zh_CN.md)\n<p align=\"center\">\n    <a href=\"http://perfect.org/get-involved.html\" target=\"_blank\">\n        <img src=\"http://perfect.org/assets/github/perfect_github_2_0_0.jpg\" alt=\"Get Involed with Perfect!\" width=\"854\" />\n    </a>\n</p>\n\n<p align=\"center\">\n    <a href=\"https://developer.apple.com/swift/\" target=\"_blank\">\n        <img src=\"https://img.shields.io/badge/Swift-5.2-orange.svg?style=flat\" alt=\"Swift 5.2\">\n    </a>\n    <a href=\"https://developer.apple.com/swift/\" target=\"_blank\">\n        <img src=\"https://img.shields.io/badge/Platforms-OS%20X%20%7C%20Linux%20-lightgray.svg?style=flat\" alt=\"Platforms macOS | Linux\">\n    </a>\n    <a href=\"http://perfect.org/licensing.html\" target=\"_blank\">\n        <img src=\"https://img.shields.io/badge/License-Apache-lightgrey.svg?style=flat\" alt=\"License Apache\">\n    </a>\n</p>\n\n## Perfect: Server-Side Swift\n\nPerfect is a complete and powerful toolbox, framework, and application server for Linux, iOS, and macOS (OS X). It provides everything a Swift engineer needs for developing lightweight, maintainable, and scalable apps and other REST services entirely in the Swift programming language for both client-facing and server-side applications.\n\nPerfect includes a suite of tools that will enhance your productivity as you use only one programming language to build your apps: Swift. The global development community’s most dynamic and popular server-side toolbox and framework available today, Perfect is the backbone for many live web applications and apps available on iTunes.\n\nThis guide is designed for developers at all levels of experience to get Perfect up and running quickly.\n\n## Working with Perfect\n\n### Compatibility with Swift\n\nThe master branch of this project currently compiles with **Xcode 11** or the **Swift 5** toolchain on Ubuntu.\n\n### Getting Started\n\n[Access a tutorial](https://github.com/PerfectlySoft/PerfectDocs/blob/master/guide/gettingStarted.md) to help you get started using Perfect quickly. It includes straightforward examples of how Perfect can be used.\n\n### Documentation\n[Get started working with Perfect](https://github.com/PerfectlySoft/PerfectDocs), deploy your apps, and find more detailed help by consulting our reference library.\n\nWe welcome contributions to Perfect’s documentation. If you spot a typo, bug, or other errata, or have additions or suggestions to recommend, please create a pull request or issue in Github.\n\n### Community\nWe all need a little help now and then. If you do too, don’t be shy, ask us or the friendly and supportive Perfect community:\n\n[Slack](http://perfect.ly/) | [Twitter](https://twitter.com/perfectlysoft)\n\n### Deployment\n\nYour Perfect project can be deployed to any Swift compatible Linux server. We provide a macOS desktop application, [Perfect Assistant](https://www.perfect.org/en/perfect-assistant.html), to help with AWS and Google Cloud deployments. Additional deployment options are in the works.\n\n### Samples, Examples, and Tutorials\n\nOur library continues to grow as members of [the Swift-Perfect development community have shared many samples and examples](https://github.com/PerfectExamples) of their projects in Perfect. Examples include:\n\n- [WebSockets Server](https://github.com/PerfectExamples/PerfectExample-WebSocketsServer)\n- [URL Routing](https://github.com/PerfectExamples/PerfectExample-URLRouting)\n- [Upload Enumerator](https://github.com/PerfectExamples/PerfectExample-UploadEnumerator)\n\nThere are [many more examples](https://github.com/PerfectExamples) you can explore. Please share yours!\n\n## Core Perfect Modules\n\nPerfect project is divided into several repositories to make it easy for you to find, download, and install the components you need:\n\n- [Perfect](https://github.com/PerfectlySoft/Perfect) – This repository contains the core PerfectLib and will continue to be the main landing point for the project\n- [Perfect Docs](https://github.com/PerfectlySoft/PerfectDocs) – Contains all API reference-related material\n\n\n### Examples\n\n- [Perfect Template](https://github.com/PerfectlySoft/PerfectTemplate) - A simple starter project which compiles with the Swift Package Manager into a standalone executable HTTP server. This repository is ideal for starting a Perfect-based project\n- [Perfect Examples](https://github.com/PerfectExamples) - All the Perfect example projects\n\n\n### DataSources\n\n\n- [Perfect Redis](https://github.com/PerfectlySoft/Perfect-Redis) - The Redis database connector\n- [Perfect SQLite](https://github.com/PerfectlySoft/Perfect-SQLite) - SQLite3 database connector\n- [Perfect PostgreSQL](https://github.com/PerfectlySoft/Perfect-PostgreSQL) - PostgreSQL database connector\n- [Perfect MySQL](https://github.com/PerfectlySoft/Perfect-MySQL) - MySQL database connector\n- [Perfect MongoDB](https://github.com/PerfectlySoft/Perfect-MongoDB) - MongoDB database connector\n- [Perfect FileMaker](https://github.com/PerfectlySoft/Perfect-FileMaker) - FileMaker Server database connector\n\n### Utilities\n\n- [Perfect FastCGI Apache 2.4](https://github.com/PerfectlySoft/Perfect-FastCGI-Apache2.4) - Apache 2.4 FastCGI module; required for the Perfect FastCGI server variant\n- [Perfect XML](https://github.com/PerfectlySoft/Perfect-XML) - DOM Core level 2 read-only APIs and XPath support\n- [Perfect HTTP Server](https://github.com/PerfectlySoft/Perfect-HTTPServer) - HTTP 1.1 server for Perfect\n- [Perfect Mustache](https://github.com/PerfectlySoft/Perfect-Mustache) - Mustache template support for Perfect\n- [Perfect CURL](https://github.com/PerfectlySoft/Perfect-CURL) - cURL support for Perfect\n- [Perfect WebSockets](https://github.com/PerfectlySoft/Perfect-WebSockets) - WebSockets support for Perfect\n- [Perfect Zip](https://github.com/PerfectlySoft/Perfect-Zip) - provides simple zip and unzip functionality\n- [Perfect Notifications](https://github.com/PerfectlySoft/Perfect-Notifications) - provides support for Apple Push Notification Service (APNS).\n\n## More about Perfect\n\nPerfect operates using either a standalone [HTTP server](https://github.com/PerfectlySoft/Perfect-HTTP), [HTTPS server](https://github.com/PerfectlySoft/Perfect-HTTPServer), or through [FastCGI server](https://github.com/PerfectlySoft/Perfect-FastCGI). It provides a system for loading your Swift-based modules at startup, for interfacing those modules with its request/response objects, or to the built-in [Mustache template processing system](https://github.com/PerfectlySoft/Perfect-Mustache).\n\nPerfect is built on a completely asynchronous, high-performance networking engine to provide a scalable option for internet services. It supports Secure Sockets Layer (SSL) encryption, and it features a suite of tools commonly required by internet servers such as [WebSockets](https://github.com/PerfectlySoft/Perfect-WebSockets) and [iOS push notifications](https://github.com/PerfectlySoft/Perfect-Notifications), but you are not limited to those options.\n\nFeel free to use your favourite JSON or templating systems, etc.\n\n### Join and Contribute to the Community\n\nThe Swift-Perfect developer community is vital to improving Perfect and supporting one another.  \n\nYou can help other developers by sharing your expertise and tips, as well as learn from others, by joining the [Perfect Slack channel](http://perfect.ly). Contributions of all kinds are welcome: reporting issues, updating documentation, fixing bugs, building examples, sharing projects, and any other tips that may help the Swift-Perfect community.\n\nIf you would like to share your example project, tutorial, or video, please share the URL of your work on GitHub and [Twitter](https://twitter.com/perfectlysoft), and the Perfect team will highlight it to the community.\n\n### Code of Conduct\nThe Perfect team welcomes people of all ethnicities, nationalities, ages, gender, disability, levels of experience, and religious beliefs to use and contribute to the Perfect project. We pledge to foster and enforce a harassment-free environment of openness, respect, and cooperation for everyone in all project and public spaces online or offline.\n\nPlease report any behaviour that violates our [Code of Conduct](https://github.com/PerfectlySoft/Perfect/blob/master/CODE_OF_CONDUCT.md) to [info@perfect.org](mailto:info@perfect.org). The Perfect team is committed to enforcing this Code of Conduct to ensure everyone who wishes to use, contribute to, and comment on the Perfect project may do so freely and openly and without fear of reprisal.\n\nWe will investigate all complaints of unacceptable or abusive behaviour or comments expediently, and we will maintain the confidentiality of the person who reports any perceived infraction or wrongdoing to us. We will not tolerate any form of direct or indirect harassment or discrimination within the Swift-Perfect community, and will take appropriate, fair, and corrective action to any instance of inappropriate behaviour.\n\nThe Perfect team maintains the right to remove, edit, or reject any comments, code, edits, or issues that do not align with our Code of Conduct.\n"
  },
  {
    "path": "README.zh_CN.md",
    "content": "# Perfect：Swift 语言服务器端软件框架 [English](README.md)\n<p align=\"center\">\n    <a href=\"http://perfect.org/get-involved.html\" target=\"_blank\">\n        <img src=\"http://perfect.org/assets/github/perfect_github_2_0_0.jpg\" alt=\"Get Involed with Perfect!\" width=\"854\" />\n    </a>\n</p>\n\n<p align=\"center\">\n    <a href=\"https://developer.apple.com/swift/\" target=\"_blank\">\n        <img src=\"https://img.shields.io/badge/Swift-5.2-orange.svg?style=flat\" alt=\"Swift 5.2\">\n    </a>\n    <a href=\"https://developer.apple.com/swift/\" target=\"_blank\">\n        <img src=\"https://img.shields.io/badge/Platforms-OS%20X%20%7C%20Linux%20-lightgray.svg?style=flat\" alt=\"Platforms OS X | Linux\">\n    </a>\n    <a href=\"http://perfect.org/licensing.html\" target=\"_blank\">\n        <img src=\"https://img.shields.io/badge/License-Apache-lightgrey.svg?style=flat\" alt=\"License Apache\">\n    </a>\n</p>\n\n## Perfect：Swift 语言服务器端软件框架\n\nPerfect是一组完整、强大的工具箱、软件框架体系和Web应用服务器，可以在Linux、iOS和macOS (OS X)上使用。该软件体系为Swift工程师量身定制了一整套用于开发轻量、易维护、规模可扩展的Web应用及其它REST服务的解决方案，这样Swift工程师就可以实现同时在服务器和客户端上采用同一种语言开发软件项目。\n\nPerfect内建整套工具集，因为无论是客户端还是服务器都能够在此基础之上用同一种计算机语言Swift进行程序开发，因此能够为软件工程师大幅提高工作效率。在全球目前众多的服务器端框架体系和工具箱产品之中，Perfect目前已经成为许多iTunes在线应用程序的可靠后台应用。\n\n无论您是资深程序员还是入门级的软件工程师，本文都能够帮助您快速启动Perfect实现服务器项目开发运行。\n\n## 使用Perfect\n\n### 快速上手\n\n[在线教程（简体中文）](https://github.com/PerfectlySoft/PerfectDocs/blob/master/guide.zh_CN/gettingStarted.md) 能够帮助您快速开始使用Perfect。该指南包括了如何使用Perfect的几个典型例子。\n\n### 文档\n[Perfect帮助文档（简体中文）](https://github.com/PerfectlySoft/PerfectDocs) 如何部署应用程序、如何查找详细文档和帮助。\n\n我们欢迎所有贡献以及对Perfect文档提高的宝贵意见。我们欢迎您为Perfect付出宝贵的支持。如果您发现了任何文字或者内容有错误，或者有任何建议，请[提交一个代码上传请求，或在JIRA上报告问题](http://jira.perfect.org:8080/servicedesk/customer/portal/1/user/login?destination=portal%2F1).\n\n### 社区\n我们总会需要您的帮助。如果您真的有想法，不妨加入我们的Perfect支持社区：\n\n\n[Slack](http://perfect.ly/) | [Twitter](https://twitter.com/perfectlysoft)\n\n### 部署\n\n目前，部署Perfect的方式可以选择[Docker](https://hub.docker.com/r/perfectlysoft/ubuntu/)和[Heroku](https://github.com/PerfectlySoft/Perfect-Heroku-Buildpack)。我们强烈推荐使用这种方式进行部署，因为这些部署方式是通过最新Swift 3.0 和 Perfect 2.0编译完成的。\n\n### 教程和案例\n\n我们的资源库一直在随着社区成员的加入而不断增长，[Swift-Perfect开发社区有许多源程序共分享](https://github.com/PerfectExamples)，都是建立在Perfect程序框架之上。典型例子包括：\n\n- [WebSockets 服务器](https://github.com/PerfectlySoft/PerfectExample-WebSocketsServer)\n- [URL 路由](https://github.com/PerfectlySoft/PerfectExample-URLRouting)\n- [文件上传](https://github.com/PerfectlySoft/PerfectExample-UploadEnumerator)\n\n[更多例子敬请关注！](https://github.com/PerfectlySoft/PerfectExamples)\n\n[Perfect 1.0教程](http://perfect.org/tutorials.html) (支持 Swift 2.2) 由Swift-Perfect社区成员贡献。或者[从Perfect 2.0开始](http://perfect.org/downloads.html#download-perfect) (支持 Swift 3.0).\n\n## 核心 Perfect 模块\n\nPerfect 项目由若干代码资源库构成，便于您按需查找、下载和安装必要的组件：\n\n- [Perfect](https://github.com/PerfectlySoft/Perfect)：核心的程序库和基础软件框架\n- [Perfect Docs](https://github.com/PerfectlySoft/PerfectDocs)：所有必要的程序文档和帮助内容\n\n\n### 参考和样例\n\n- [Perfect 模板](https://github.com/PerfectlySoft/PerfectTemplate)：一个使用SPM软件包管理器快速上手的入门项目，能够编译为一个独立运行的HTTP服务器。该代码资源非常适合基于Perfect的项目就此开始开发过程。\n- [Perfect 样例](https://github.com/PerfectExamples)：所有Perfect 项目的典型样例\n\n\n### 数据源\n\n\n- [Perfect Redis](https://github.com/PerfectlySoft/Perfect-Redis)：Redis 数据库连接工具\n- [Perfect SQLite](https://github.com/PerfectlySoft/Perfect-SQLite)：SQLite3 数据库连接工具\n- [Perfect PostgreSQL](https://github.com/PerfectlySoft/Perfect-PostgreSQL)：PostgreSQL 数据库连接工具\n- [Perfect MySQL](https://github.com/PerfectlySoft/Perfect-MySQL)：MySQL 数据库连接工具\n- [Perfect MongoDB](https://github.com/PerfectlySoft/Perfect-MongoDB)：MongoDB 数据库连接工具\n- [Perfect FileMaker](https://github.com/PerfectlySoft/Perfect-FileMaker)：FileMaker 数据库连接工具\n\n### 工具集\n\n- [Perfect FastCGI Apache 2.4](https://github.com/PerfectlySoft/Perfect-FastCGI-Apache2.4) - Apache 2.4 FastCGI 模块。如果您使用FastCGI用于基础Web服务，请使用该模块\n- [Perfect XML](https://github.com/PerfectlySoft/Perfect-XML) - DOM文档对象二级核心只读函数库和XPath路径支持\n- [Perfect HTTP Server](https://github.com/PerfectlySoft/Perfect-HTTPServer) - HTTP 1.1标准的 Perfect服务器\n- [Perfect Mustache](https://github.com/PerfectlySoft/Perfect-Mustache) - Mustache静态模板支持\n- [Perfect CURL](https://github.com/PerfectlySoft/Perfect-CURL) - cURL网页传输支持\n- [Perfect WebSockets](https://github.com/PerfectlySoft/Perfect-WebSockets) - 网络套接字WebSockets支持\n- [Perfect Zip](https://github.com/PerfectlySoft/Perfect-Zip) - 提供简单的zip压缩和解压缩功能\n- [Perfect Notifications](https://github.com/PerfectlySoft/Perfect-Notifications) - 提供苹果消息推送服务支持（APNS）\n\n## 更多内容\n\nPerfect 可以作为一个独立的[HTTP服务器](https://github.com/PerfectlySoft/Perfect-HTTP)或[HTTPS加密服务器](https://github.com/PerfectlySoft/Perfect-HTTPServer)进行运行，或者通过[FastCGI快速网关服务器](https://github.com/PerfectlySoft/Perfect-FastCGI)进行运行。简单来说就是提供一个能够在系统启动是加载的Web服务，从而能够将您自行开发的Swift源码模块根据URL路由要求实现请求/响应，或者根据内建的[Mustache模板](https://github.com/PerfectlySoft/Perfect-Mustache)处理页面。\n\nPerfect是一个完全异步、高性能的网络引擎，并且能够为互联网服务提供大吞吐量控制。该软件体系支持安全套接字（SSL）加密，并且封装了一系列互联网服务器通用的特性，比如[WebSockets](https://github.com/PerfectlySoft/Perfect-WebSockets) 和 [iOS消息推送](https://github.com/PerfectlySoft/Perfect-Notifications)。然而，您的开发可以不必受限于这些选项。\n\n请根据您自己的喜好使用JSON或者其他的模板系统，等等。\n\n### 加入我们的开发社区并贡献自己的力量\n\nSwift-Perfect开发者社区是改进Perfect产品并实现客户支持的关键。\n\n在社区里，您可以通过加入[Perfect Slack 频道](http://perfect.ly)和[Perfect Gitter 频道](https://gitter.im/PerfectlySoft/Perfect)互相帮助、分享技术、互相学习和研究诀窍。任何一种贡献方式我们都非常欢迎：问题汇报、文档更新、补丁修复、编写案例、分享项目或者任何编程窍门，我们相信这些都能够极大地帮助我们的Swift-Perfect社区。\n\n如果您希望分享一下您的项目、教程或者视频，请将URL共享到我们的推特或者GitHub账号：[Perfect 推特](https://twitter.com/perfectlysoft)。之后我们的Perfect团队会继续推广。\n\n### 行为规范\nPerfect团队欢迎所有不同种族、国际、不同年龄、性别、身残志坚、不同学历出身、不同宗教信仰的人为我们的Perfect项目作出贡献。我们承诺为所有项目和公众在线/离线空间提供一个开放、祥和、互相尊重、共同工作的环境。\n\n如果您发现有任何违反上述[行为规范](https://github.com/PerfectlySoft/Perfect/blob/master/CODE_OF_CONDUCT.zh_CN.md)的行为，请[给我们写邮件](mailto:info@perfect.org)。Perfect团队承诺致力于维护上述价值观念以确保所有参与者和用户都能实现对Perfect项目的充分开放的自由使用、自由评论和自由贡献，不需要对任何恐吓而害怕和妥协。\n\n我们会调查任何不当行为与不当言论的投诉，同时我们会对检举人身份保密，便于对各种违法行为进行举报。我们不会容忍在Swift-Perfect社区内的任何直接或间接的骚扰或歧视，并会针对各类不当行为采取适度、公平的纠正措施。\n\nPerfect团队有权删除、修改或拒绝任何不符合我们行为规范的各种言论、代码、版本或问题报告。\n"
  },
  {
    "path": "Sources/PerfectLib/Bytes.swift",
    "content": "//\n//  Bytes.swift\n//  PerfectLib\n//\n//  Created by Kyle Jessup on 7/7/15.\n//\tCopyright (C) 2015 PerfectlySoft, Inc.\n//\n//===----------------------------------------------------------------------===//\n//\n// This source file is part of the Perfect.org open source project\n//\n// Copyright (c) 2015 - 2016 PerfectlySoft Inc. and the Perfect project authors\n// Licensed under Apache License v2.0\n//\n// See http://perfect.org/licensing.html for license information\n//\n//===----------------------------------------------------------------------===//\n//\n\n/// A Bytes object represents an array of UInt8 and provides various utilities for importing and exporting values into and out of that array.\n/// The object maintains a position marker which is used to denote the position from which new export operations proceed.\n/// An export will advance the position by the appropriate amount.\npublic final class Bytes {\n\t\n\t/// The position from which new export operations begin.\n\tpublic var position = 0\n\t/// The underlying UInt8 array\n\tpublic var data: [UInt8]\n\t\n\t/// Indicates the number of bytes which may be successfully exported\n\tpublic var availableExportBytes: Int { return data.count - position }\n\t\n\t/// Create an empty Bytes object\n\tpublic init() {\n\t\tdata = [UInt8]()\n\t}\n\t\n\t/// Initialize with existing bytes\n\tpublic init(existingBytes: [UInt8]) {\n\t\tdata = existingBytes\n\t}\n\t\n\t// -- IMPORT\n\t/// Imports one UInt8 value appending it to the end of the array\n\t/// - returns: The Bytes object\n    @discardableResult\n\tpublic func import8Bits(from frm: UInt8) -> Bytes {\n\t\tdata.append(frm)\n\t\treturn self\n\t}\n\t\n\t/// Imports one UInt16 value appending it to the end of the array\n\t/// - returns: The Bytes object\n    @discardableResult\n\tpublic func import16Bits(from frm: UInt16) -> Bytes {\n\t\tdata.append(UInt8(frm & 0xFF))\n\t\tdata.append(UInt8((frm >> 8) & 0xFF))\n\t\treturn self\n\t}\n\t\n\t/// Imports one UInt32 value appending it to the end of the array\n\t/// - returns: The Bytes object\n    @discardableResult\n\tpublic func import32Bits(from frm: UInt32) -> Bytes {\n\t\tdata.append(UInt8(frm & 0xFF))\n\t\tdata.append(UInt8((frm >> 8) & 0xFF))\n\t\tdata.append(UInt8((frm >> 16) & 0xFF))\n\t\tdata.append(UInt8((frm >> 24) & 0xFF))\n\t\treturn self\n\t}\n\t\n\t/// Imports one UInt64 value appending it to the end of the array\n\t/// - returns: The Bytes object\n    @discardableResult\n\tpublic func import64Bits(from frm: UInt64) -> Bytes {\n\t\tdata.append(UInt8(frm & 0xFF))\n\t\tdata.append(UInt8((frm >> 8) & 0xFF))\n\t\tdata.append(UInt8((frm >> 16) & 0xFF))\n\t\tdata.append(UInt8((frm >> 24) & 0xFF))\n\t\tdata.append(UInt8((frm >> 32) & 0xFF))\n\t\tdata.append(UInt8((frm >> 40) & 0xFF))\n\t\tdata.append(UInt8((frm >> 48) & 0xFF))\n\t\tdata.append(UInt8((frm >> 56) & 0xFF))\n\t\treturn self\n\t}\n\t\n\t/// Imports an array of UInt8 values appending them to the end of the array\n\t/// - returns: The Bytes object\n    @discardableResult\n\tpublic func importBytes(from frm: [UInt8]) -> Bytes {\n\t\tdata.append(contentsOf: frm)\n\t\treturn self\n\t}\n\t\n\t/// Imports the array values of the given Bytes appending them to the end of the array\n\t/// - returns: The Bytes object\n    @discardableResult\n\tpublic func importBytes(from frm: Bytes) -> Bytes {\n\t\tdata.append(contentsOf: frm.data)\n\t\treturn self\n\t}\n\t\n\t/// Imports an `ArraySlice` of UInt8 values appending them to the end of the array\n\t/// - returns: The Bytes object\n    @discardableResult\n\tpublic func importBytes(from frm: ArraySlice<UInt8>) -> Bytes {\n\t\tdata.append(contentsOf: frm)\n\t\treturn self\n\t}\n\t\n\t// -- EXPORT\n\t\n\t/// Exports one UInt8 from the current position. Advances the position marker by 1 byte.\n\t/// - returns: The UInt8 value\n\tpublic func export8Bits() -> UInt8 {\n\t\tlet result = data[position]\n\t\tposition += 1\n\t\treturn result\n\t}\n\t\n\t/// Exports one UInt16 from the current position. Advances the position marker by 2 bytes.\n\t/// - returns: The UInt16 value\n\tpublic func export16Bits() -> UInt16 {\n\n\t\tlet one = UInt16(data[position])\n\t\tposition += 1\n\t\tlet two = UInt16(data[position])\n\t\tposition += 1\n\t\t\n\t\treturn (two << 8) + one\n\t}\n\t\n\t/// Exports one UInt32 from the current position. Advances the position marker by 4 bytes.\n\t/// - returns: The UInt32 value\n\tpublic func export32Bits() -> UInt32 {\n\t\tlet one = UInt32(data[position])\n\t\tposition += 1\n\t\tlet two = UInt32(data[position])\n\t\tposition += 1\n\t\tlet three = UInt32(data[position])\n\t\tposition += 1\n\t\tlet four = UInt32(data[position])\n\t\tposition += 1\n\t\t\n\t\treturn (four << 24) + (three << 16) + (two << 8) + one\n\t}\n\t\n\t/// Exports one UInt64 from the current position. Advances the position marker by 8 bytes.\n\t/// - returns: The UInt64 value\n\tpublic func export64Bits() -> UInt64 {\n\t\tlet one = UInt64(data[position])\n\t\tposition += 1\n\t\tlet two = UInt64(data[position]) << 8\n\t\tposition += 1\n\t\tlet three = UInt64(data[position]) << 16\n\t\tposition += 1\n\t\tlet four = UInt64(data[position]) << 24\n\t\tposition += 1\n\t\tlet five = UInt64(data[position]) << 32\n\t\tposition += 1\n\t\tlet six = UInt64(data[position]) << 40\n\t\tposition += 1\n\t\tlet seven = UInt64(data[position]) << 48\n\t\tposition += 1\n\t\tlet eight = UInt64(data[position]) << 56\n\t\tposition += 1\n\t\t\n\t\treturn (one+two+three+four)+(five+six+seven+eight)\n\t}\n\t\n\t/// Exports the indicated number of bytes\n\tpublic func exportBytes(count cnt: Int) -> [UInt8] {\n\t\tvar sub = [UInt8]()\n\t\tlet end = position + cnt\n\t\twhile position < end {\n\t\t\tsub.append(data[position])\n\t\t\tposition += 1\n\t\t}\n\t\treturn sub\n\t}\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "Sources/PerfectLib/Dir.swift",
    "content": "//\n//  Dir.swift\n//  PerfectLib\n//\n//  Created by Kyle Jessup on 7/7/15.\n//\tCopyright (C) 2015 PerfectlySoft, Inc.\n//\n//===----------------------------------------------------------------------===//\n//\n// This source file is part of the Perfect.org open source project\n//\n// Copyright (c) 2015 - 2016 PerfectlySoft Inc. and the Perfect project authors\n// Licensed under Apache License v2.0\n//\n// See http://perfect.org/licensing.html for license information\n//\n//===----------------------------------------------------------------------===//\n//\n\n#if os(Linux)\nimport LinuxBridge\n#else\nimport Darwin\n#endif\n\n/// This class represents a directory on the file system.\n/// It can be used for creating & inspecting directories and enumerating directory contents.\npublic struct Dir {\n\t/// A typealias for directory permission modes.\n\tpublic typealias PermissionMode = File.PermissionMode\n\n\tvar internalPath = \"\"\n\n\t/// Create a new Dir object with the given path\n\tpublic init(_ path: String) {\n\t\tlet pth = path.ends(with: \"/\") ? path : path + \"/\"\n\t\tinternalPath = File.resolveTilde(inPath: pth)\n\t}\n\n\t/// Returns true if the directory exists\n    public var exists: Bool {\n\t\treturn exists(realPath)\n\t}\n\n\t/// Set this Dir as the process' working directory.\n\tpublic func setAsWorkingDir() throws {\n\t\tlet res = chdir(internalPath)\n\t\tguard res == 0 else {\n\t\t\ttry ThrowFileError()\n\t\t}\n\t}\n\n\t/// Return the process' current working directory.\n\tpublic static var workingDir: Dir {\n\t\tvar buffer = Array(repeating: 0 as UInt8, count: 2049)\n\t\tbuffer.withUnsafeMutableBytes {\n\t\t\t_ = getcwd($0.bindMemory(to: Int8.self).baseAddress, 2048)\n\t\t}\n\t\tlet path = String(cString: buffer)\n\t\treturn Dir(path)\n\t}\n\n\tfunc exists(_ path: String) -> Bool {\n\t\treturn access(path, F_OK) != -1\n\t}\n\n\t/// Creates the directory using the provided permissions. All directories along the path will be created if need be.\n\t/// - parameter perms: The permissions for use for the new directory and preceeding directories which need to be created. Defaults to RWX-GUO\n\t/// - throws: `PerfectError.FileError`\n\tpublic func create(perms: PermissionMode = [.rwxUser, .rxGroup, .rxOther]) throws {\n\t\tlet pth = realPath\n\t\tvar currPath = pth.begins(with: \"/\") ? \"/\" : \"\"\n\t\tfor component in pth.filePathComponents where component != \"/\" {\n            currPath += component\n            defer {\n                currPath += \"/\"\n            }\n            guard !exists(currPath) else {\n                continue\n            }\n            let res = mkdir(currPath, perms.rawValue)\n            guard res != -1 else {\n                try ThrowFileError()\n            }\n        }\n\t}\n\n\t/// Deletes the directory. The directory must be empty in order to be successfully deleted.\n\t/// - throws: `PerfectError.FileError`\n\tpublic func delete() throws {\n\t\tlet res = rmdir(realPath)\n\t\tguard res != -1 else {\n\t\t\ttry ThrowFileError()\n\t\t}\n\t}\n\n\t/// Returns the name of the directory.\n\tpublic var name: String {\n\t\treturn internalPath.lastFilePathComponent\n\t}\n\n\t/// Returns a Dir object representing the current Dir's parent. Returns nil if there is no parent.\n\tpublic var parentDir: Dir? {\n\t\tguard internalPath != \"/\" else {\n\t\t\treturn nil // can not go up\n\t\t}\n\t\treturn Dir(internalPath.deletingLastFilePathComponent)\n\t}\n\n\t/// Returns the path to the current directory.\n\tpublic var path: String {\n\t\treturn internalPath\n\t}\n\n\t/// Returns the UNIX style permissions for the directory.\n\tpublic var perms: PermissionMode {\n\t\tget {\n\t\t\treturn File(internalPath).perms\n\t\t}\n\t\tset {\n\t\t\tFile(internalPath).perms = newValue\n\t\t}\n\t}\n\n\tvar realPath: String {\n\t\treturn internalPath.resolvingSymlinksInFilePath\n\t}\n\n#if os(Linux)\n    func readDir(_ d: OpaquePointer, _ dirEnt: inout dirent, _ endPtr: UnsafeMutablePointer<UnsafeMutablePointer<dirent>?>!) -> Int32 {\n\t\tguard let ent = readdir(d) else {\n\t\t\treturn -1\n\t\t}\n\t\tdirEnt = ent.pointee\n\t\treturn 0\n    }\n#else\n    func readDir(_ d: UnsafeMutablePointer<DIR>, _ dirEnt: inout dirent, _ endPtr: UnsafeMutablePointer<UnsafeMutablePointer<dirent>?>!) -> Int32 {\n        return readdir_r(d, &dirEnt, endPtr)\n    }\n#endif\n\n\t/// Enumerates the contents of the directory passing the name of each contained element to the provided callback.\n\t/// - parameter closure: The callback which will receive each entry's name\n\t/// - throws: `PerfectError.FileError`\n\tpublic func forEachEntry(closure: (String) throws -> ()) throws {\n\t\tguard let dir = opendir(realPath) else {\n\t\t\ttry ThrowFileError()\n\t\t}\n\n\t\tdefer { closedir(dir) }\n\n\t\tvar ent = dirent()\n\t\tlet entPtr = UnsafeMutablePointer<UnsafeMutablePointer<dirent>?>.allocate(capacity:  1)\n\t\tdefer { entPtr.deallocate() }\n\n\t\twhile readDir(dir, &ent, entPtr) == 0 && entPtr.pointee != nil {\n\t\t\tlet name = ent.d_name\n\t\t#if os(Linux)\n\t\t\tlet nameLen = 1024\n\t\t#else\n\t\t\tlet nameLen = ent.d_namlen\n\t\t#endif\n\t\t\tlet type = ent.d_type\n\n\t\t\tvar nameBuf = [CChar]()\n\t\t\tlet mirror = Mirror(reflecting: name)\n\t\t\tlet childGen = mirror.children.makeIterator()\n\t\t\tfor _ in 0..<nameLen {\n                guard let (_, elem) = childGen.next() else {\n                    break\n                }\n\t\t\t\tguard let elemI = elem as? Int8, elemI != 0 else {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tnameBuf.append(elemI)\n\t\t\t}\n\t\t\tnameBuf.append(0)\n\t\t\tif let name = String(validatingUTF8: nameBuf), !(name == \".\" || name == \"..\") {\n                if Int32(type) == Int32(DT_DIR) {\n                    try closure(name + \"/\")\n                } else {\n                    try closure(name)\n                }\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "Sources/PerfectLib/File.swift",
    "content": "//\n//  File.swift\n//  PerfectLib\n//\n//  Created by Kyle Jessup on 7/7/15.\n//\tCopyright (C) 2015 PerfectlySoft, Inc.\n//\n//===----------------------------------------------------------------------===//\n//\n// This source file is part of the Perfect.org open source project\n//\n// Copyright (c) 2015 - 2016 PerfectlySoft Inc. and the Perfect project authors\n// Licensed under Apache License v2.0\n//\n// See http://perfect.org/licensing.html for license information\n//\n//===----------------------------------------------------------------------===//\n//\n\n#if os(Linux)\nimport LinuxBridge\n// !FIX! these are obviously sketchy\n// I hope SwiftGlibc to eventually include these\n// Otherwise, export them from LinuxBridge\n\nimport var Glibc.S_IRUSR\nimport var Glibc.S_IWUSR\nimport var Glibc.S_IXUSR\nimport var Glibc.S_IFMT\nimport var Glibc.S_IFREG\nimport var Glibc.S_IFDIR\nimport var Glibc.S_IFLNK\n\nlet S_IRGRP = (S_IRUSR >> 3)\nlet S_IWGRP\t= (S_IWUSR >> 3)\nlet S_IXGRP\t= (S_IXUSR >> 3)\nlet S_IRWXU = (__S_IREAD|__S_IWRITE|__S_IEXEC)\nlet S_IRWXG = (S_IRWXU >> 3)\nlet S_IRWXO = (S_IRWXG >> 3)\nlet S_IROTH = (S_IRGRP >> 3)\nlet S_IWOTH = (S_IWGRP >> 3)\nlet S_IXOTH = (S_IXGRP >> 3)\n\nlet SEEK_CUR: Int32 = 1\nlet EXDEV = Int32(18)\nlet EACCES = Int32(13)\nlet EAGAIN = Int32(11)\nlet F_OK: Int32 = 0\n\n#else\nimport Darwin\n#endif\n\nlet fileCopyBufferSize = 16384\n\n/// Provides access to a file on the local file system\npublic class File {\n\n\t/// The underlying file system descriptor.\n\tpublic var fd = -1\n\tvar internalPath = \"\"\n\n    /// Checks that the file exists on the file system\n    /// - returns: True if the file exists or false otherwise\n    public var exists: Bool {\n        return access(internalPath, F_OK) != -1\n    }\n\n    /// Returns true if the file has been opened\n    public var isOpen: Bool {\n        return fd != -1\n    }\n\n    /// Returns the file's path\n    public var path: String { return internalPath }\n\n    /// Returns the file path. If the file is a symbolic link, the link will be resolved.\n    public var realPath: String {\n        let maxPath = 2048\n        guard isLink else {\n            return internalPath\n        }\n        var ary = [UInt8](repeating: 0, count: maxPath)\n\t\tlet res: Int = ary.withUnsafeMutableBytes {\n\t\t\tguard let p = $0.bindMemory(to: Int8.self).baseAddress else {\n\t\t\t\treturn -1\n\t\t\t}\n\t\t\treturn readlink(internalPath, p, maxPath)\n\t\t}\n        guard res != -1 else {\n            return internalPath\n        }\n        let trailPath = String(cString: ary)\n        let lastChar = trailPath[trailPath.startIndex]\n        guard lastChar != \"/\" && lastChar != \".\" else {\n            return trailPath\n        }\n        return internalPath.deletingLastFilePathComponent + \"/\" + trailPath\n    }\n\n    /// Returns the modification date for the file in the standard UNIX format of seconds since 1970/01/01 00:00:00 GMT\n    /// - returns: The date as Int\n    public var modificationTime: Int {\n        var st = stat()\n        let res = isOpen ?  fstat(Int32(fd), &st) : stat(internalPath, &st)\n        guard res == 0 else {\n            return Int.max\n        }\n        #if os(Linux)\n            return Int(st.st_mtim.tv_sec)\n        #else\n            return Int(st.st_mtimespec.tv_sec)\n        #endif\n    }\n\n\tstatic func resolveTilde(inPath: String) -> String {\n#if !os(iOS) && !os(tvOS)\n\t\tif !inPath.isEmpty && inPath[inPath.startIndex] == \"~\" {\n\t\t\tvar wexp = wordexp_t()\n\t\t\tguard 0 == wordexp(inPath, &wexp, 0),\n\t\t\t\t\tlet we_wordv = wexp.we_wordv else {\n\t\t\t\treturn inPath\n\t\t\t}\n\t\t\tdefer {\n\t\t\t\twordfree(&wexp)\n\t\t\t}\n\t\t\tif let resolved = we_wordv[0], let pth = String(validatingUTF8: resolved) {\n\t\t\t\treturn pth\n\t\t\t}\n\t\t}\n#endif\n\t\treturn inPath\n\t}\n\n\t/// Create a file object given a path and open mode\n\t/// - parameter path: Path to the file which will be accessed\n    /// - parameter fd: The file descriptor, if any, for an already opened file\n\tpublic init(_ path: String, fd: Int32 = -1) {\n\t\tinternalPath = File.resolveTilde(inPath: path)\n        self.fd = Int(fd)\n\t}\n\n\tdeinit {\n\t\tclose()\n\t}\n\t\n\t/// Closes the file if it had been opened\n\tpublic func close() {\n\t\tif fd != -1 {\n\t\t#if os(Linux)\n\t\t\t_ = SwiftGlibc.close(CInt(fd))\n\t\t#else\n            _ = Darwin.close(CInt(fd))\n\t\t#endif\n\t\t\tfd = -1\n\t\t}\n\t}\n\n\t/// Resets the internal file descriptor, leaving the file opened if it had been.\n\tpublic func abandon() {\n\t\tfd = -1\n\t}\n}\n\npublic extension File {\n    /// The open mode for the file.\n\tenum OpenMode {\n        /// Opens the file for read-only access.\n        case read\n        /// Opens the file for write-only access, creating the file if it did not exist.\n        case write\n        /// Opens the file for read-write access, creating the file if it did not exist.\n        case readWrite\n        /// Opens the file for read-write access, creating the file if it did not exist and moving the file marker to the end.\n        case append\n        /// Opens the file for read-write access, creating the file if it did not exist and setting the file's size to zero.\n        case truncate\n\n        var toMode: Int {\n            switch self {\n            case .read:         return Int(O_RDONLY)\n            case .write:        return Int(O_WRONLY|O_CREAT)\n            case .readWrite:    return Int(O_RDWR|O_CREAT)\n            case .append:       return Int(O_RDWR|O_APPEND|O_CREAT)\n            case .truncate:     return Int(O_RDWR|O_TRUNC|O_CREAT)\n            }\n        }\n    }\n\t/// A file or directory access permission value.\n\tstruct PermissionMode: OptionSet {\n\t\t/// File system mode type.\n\t\tpublic typealias Mode = mode_t\n\t\t/// The raw mode.\n\t\tpublic let rawValue: Mode\n\t\t/// Create a permission mode with a raw value.\n\t\tpublic init(rawValue: Mode) {\n\t\t\tself.rawValue = rawValue\n\t\t}\n\n#if os(Linux)\n\t\tinit(rawValue: Int32) {\n\t\t\tself.init(rawValue: UInt32(rawValue))\n\t\t}\n#endif\n\n\t\t/// Readable by user.\n\t\tpublic static let readUser = PermissionMode(rawValue: S_IRUSR)\n\t\t/// Writable by user.\n\t\tpublic static let writeUser = PermissionMode(rawValue: S_IWUSR)\n\t\t/// Executable by user.\n\t\tpublic static let executeUser = PermissionMode(rawValue: S_IXUSR)\n\t\t/// Readable by group.\n\t\tpublic static let readGroup = PermissionMode(rawValue: S_IRGRP)\n\t\t/// Writable by group.\n\t\tpublic static let writeGroup = PermissionMode(rawValue: S_IWGRP)\n\t\t/// Executable by group.\n\t\tpublic static let executeGroup = PermissionMode(rawValue: S_IXGRP)\n\t\t/// Readable by others.\n\t\tpublic static let readOther = PermissionMode(rawValue: S_IROTH)\n\t\t/// Writable by others.\n\t\tpublic static let writeOther = PermissionMode(rawValue: S_IWOTH)\n\t\t/// Executable by others.\n\t\tpublic static let executeOther = PermissionMode(rawValue: S_IXOTH)\n\n\t\t/// Read, write, execute by user.\n\t\tpublic static let rwxUser: PermissionMode = [.readUser, .writeUser, .executeUser]\n\t\t/// Read, write by user and group.\n\t\tpublic static let rwUserGroup: PermissionMode = [.readUser, .writeUser, .readGroup, .writeGroup]\n\n\t\t/// Read, execute by group.\n\t\tpublic static let rxGroup: PermissionMode = [.readGroup, .executeGroup]\n\t\t/// Read, execute by other.\n\t\tpublic static let rxOther: PermissionMode = [.readOther, .executeOther]\n\n\t}\n\n\t/// Opens the file using the given mode.\n\t/// - throws: `PerfectError.FileError`\n\tfunc open(_ mode: OpenMode = .read, permissions: PermissionMode = .rwUserGroup) throws {\n        if fd != -1 {\n            close()\n        }\n\t#if os(Linux)\n\t\tlet openFd = linux_open(internalPath, CInt(mode.toMode), permissions.rawValue)\n\t#else\n\t\tlet openFd = Darwin.open(internalPath, CInt(mode.toMode), permissions.rawValue)\n\t#endif\n\t\tguard openFd != -1 else {\n\t\t\ttry ThrowFileError()\n\t\t}\n\t\tfd = Int(openFd)\n\t}\n}\n\npublic extension File {\n    /// The current file read/write position.\n\tvar marker: Int {\n        /// Returns the value of the file's current position marker\n        get {\n            if isOpen {\n                return Int(lseek(Int32(fd), 0, SEEK_CUR))\n            }\n            return 0\n        }\n        /// Sets the file's position marker given the value as measured from the begining of the file.\n        set {\n            lseek(Int32(fd), off_t(newValue), SEEK_SET)\n        }\n    }\n}\n\npublic extension File {\n\n    /// Closes and deletes the file\n\tfunc delete() {\n        close()\n        unlink(path)\n    }\n\n    /// Moves the file to the new location, optionally overwriting any existing file\n    /// - parameter path: The path to move the file to\n    /// - parameter overWrite: Indicates that any existing file at the destination path should first be deleted\n    /// - returns: Returns a new file object representing the new location\n    /// - throws: `PerfectError.FileError`\n\tfunc moveTo(path: String, overWrite: Bool = false) throws -> File {\n        let destFile = File(path)\n        if destFile.exists {\n            guard overWrite else {\n                throw PerfectError.fileError(-1, \"Can not overwrite existing file\")\n            }\n            destFile.delete()\n        }\n        close()\n        let res = rename(self.path, path)\n        if res == 0 {\n            return destFile\n        }\n        if errno == EXDEV {\n            _ = try copyTo(path: path, overWrite: overWrite)\n            delete()\n            return destFile\n        }\n        try ThrowFileError()\n    }\n\n    /// Copies the file to the new location, optionally overwriting any existing file\n    /// - parameter path: The path to copy the file to\n    /// - parameter overWrite: Indicates that any existing file at the destination path should first be deleted\n    /// - returns: Returns a new file object representing the new location\n    /// - throws: `PerfectError.FileError`\n    @discardableResult\n\tfunc copyTo(path pth: String, overWrite: Bool = false) throws -> File {\n        let destFile = File(pth)\n        if destFile.exists {\n            guard overWrite else {\n                throw PerfectError.fileError(-1, \"Can not overwrite existing file\")\n            }\n            destFile.delete()\n        }\n        let wasOpen = isOpen\n        let oldMarker = marker\n        if !wasOpen {\n            try open()\n        } else {\n            _ = marker = 0\n        }\n        defer {\n            if !wasOpen {\n                close()\n            } else {\n                _ = marker = oldMarker\n            }\n        }\n\n        try destFile.open(.truncate)\n\n        var bytes = try readSomeBytes(count: fileCopyBufferSize)\n        while bytes.count > 0 {\n            try destFile.write(bytes: bytes)\n            bytes = try readSomeBytes(count: fileCopyBufferSize)\n        }\n\n        destFile.close()\n        return destFile\n    }\n}\n\npublic extension File {\n\n\t/// Returns the size of the file in bytes\n\tvar size: Int {\n\t\tvar st = stat()\n\t\tlet statRes = isOpen ?  fstat(Int32(fd), &st) : stat(internalPath, &st)\n\t\tguard statRes != -1 else {\n\t\t\treturn 0\n\t\t}\n\t\treturn Int(st.st_size)\n\t}\n\n\t/// Returns true if the file is actually a directory\n\tvar isDir: Bool {\n\t\tvar st = stat()\n\t\tlet statRes = isOpen ?  fstat(Int32(fd), &st) : stat(internalPath, &st)\n\t\tguard statRes != -1 else {\n\t\t\treturn false\n\t\t}\n\t\tlet mode = st.st_mode\n\t\treturn (Int32(mode) & Int32(S_IFMT)) == Int32(S_IFDIR)\n\t}\n\n\t/// Returns the UNIX style permissions for the file\n\tvar perms: PermissionMode {\n\t\tget {\n\t\t\tvar st = stat()\n\t\t\tlet statRes = isOpen ?  fstat(Int32(fd), &st) : stat(internalPath, &st)\n\t\t\tguard statRes != -1 else {\n\t\t\t\treturn PermissionMode(rawValue: PermissionMode.Mode(0))\n\t\t\t}\n\t\t\tlet mode = st.st_mode\n\t\t\treturn PermissionMode(rawValue: mode_t(Int32(mode) ^ Int32(S_IFMT)))\n\t\t}\n\t\tset {\n\t\t\t_ = chmod(internalPath, newValue.rawValue)\n\t\t}\n    }\n}\n\npublic extension File {\n\t/// Returns true if the file is a symbolic link\n\tvar isLink: Bool {\n\t\tvar st = stat()\n\t\tlet statRes = lstat(internalPath, &st)\n\t\tguard statRes != -1 else {\n\t\t\treturn false\n\t\t}\n\t\tlet mode = st.st_mode\n\t\treturn (Int32(mode) & Int32(S_IFMT)) == Int32(S_IFLNK)\n\t}\n\t\n\t/// Create a symlink from the target to the destination.\n\t@discardableResult\n\tfunc linkTo(path: String, overWrite: Bool = false) throws -> File {\n\t\tlet destFile = File(path)\n\t\tif destFile.exists {\n\t\t\tguard overWrite else {\n\t\t\t\tthrow PerfectError.fileError(-1, \"Can not overwrite existing file\")\n\t\t\t}\n\t\t\tdestFile.delete()\n\t\t}\n\t\tlet res = symlink(self.path, path)\n\t\tif res == 0 {\n\t\t\treturn File(path)\n\t\t}\n\t\ttry ThrowFileError()\n\t}\n}\n\npublic extension File {\n\n\t/// Reads up to the indicated number of bytes from the file\n\t/// - parameter count: The maximum number of bytes to read\n\t/// - returns: The bytes read as an array of UInt8. May have a count of zero.\n\t/// - throws: `PerfectError.FileError`\n\tfunc readSomeBytes(count: Int) throws -> [UInt8] {\n        if !isOpen {\n            try open()\n        }\n\n        func sizeOr(_ value: Int) -> Int {\n            var st = stat()\n            let statRes = isOpen ?  fstat(Int32(fd), &st) : stat(internalPath, &st)\n            guard statRes != -1 else {\n                return 0\n            }\n            if (Int32(st.st_mode) & Int32(S_IFMT)) == Int32(S_IFREG) {\n                return Int(st.st_size)\n            }\n            return value\n        }\n\n\t\tlet bSize = min(count, sizeOr(count))\n\t\tvar ary = [UInt8](repeating: 0, count: bSize)\n\t\t\n\t\tlet readCount = ary.withUnsafeMutableBytes {\n\t\t   read(CInt(fd), $0.bindMemory(to: Int8.self).baseAddress, bSize)\n\t    }\n\t\tguard readCount >= 0 else {\n\t\t\ttry ThrowFileError()\n\t\t}\n\t\tif readCount < bSize {\n\t\t\tary.removeLast(bSize - readCount)\n\t\t}\n\t\treturn ary\n\t}\n\n\t/// Reads the entire file as a string\n\tfunc readString() throws -> String {\n\t\tlet bytes = try readSomeBytes(count: size)\n\t\treturn UTF8Encoding.encode(bytes: bytes)\n    }\n}\n\npublic extension File {\n\n\t/// Writes the string to the file using UTF-8 encoding\n\t/// - parameter s: The string to write\n\t/// - returns: Returns the number of bytes which were written\n\t/// - throws: `PerfectError.FileError`\n    @discardableResult\n\tfunc write(string: String) throws -> Int {\n\t\treturn try write(bytes: Array(string.utf8))\n\t}\n\n\t/// Write the indicated bytes to the file\n\t/// - parameter bytes: The array of UInt8 to write.\n\t/// - parameter dataPosition: The offset within `bytes` at which to begin writing.\n\t/// - parameter length: The number of bytes to write.\n\t/// - throws: `PerfectError.FileError`\n    @discardableResult\n\tfunc write(bytes: [UInt8], dataPosition: Int = 0, length: Int = Int.max) throws -> Int {\n        let len = min(bytes.count - dataPosition, length)\n    #if os(Linux)\n\t\tlet wrote = bytes.withUnsafeBytes {\n\t\t\tSwiftGlibc.write(Int32(fd), $0.bindMemory(to: Int8.self).baseAddress?.advanced(by: dataPosition), len)\n\t\t}\n\t#else\n\t\tlet wrote = bytes.withUnsafeBytes {\n\t\t\tDarwin.write(Int32(fd), $0.bindMemory(to: Int8.self).baseAddress?.advanced(by: dataPosition), len)\n\t\t}\n\t#endif\n\t\tguard wrote == len else {\n\t\t\ttry ThrowFileError()\n\t\t}\n\t\treturn wrote\n\t}\n}\n\npublic extension File {\n\n\t/// Attempts to place an advisory lock starting from the current position marker up to the indicated byte count. This function will block the current thread until the lock can be performed.\n\t/// - parameter byteCount: The number of bytes to lock\n\t/// - throws: `PerfectError.FileError`\n\tfunc lock(byteCount: Int) throws {\n\t\tif !isOpen {\n\t\t\ttry open(.write)\n\t\t}\n\t\tlet res = lockf(Int32(fd), F_LOCK, off_t(byteCount))\n\t\tguard res == 0 else {\n\t\t\ttry ThrowFileError()\n\t\t}\n\t}\n\n\t/// Unlocks the number of bytes starting from the current position marker up to the indicated byte count.\n\t/// - parameter byteCount: The number of bytes to unlock\n\t/// - throws: `PerfectError.FileError`\n\tfunc unlock(byteCount: Int) throws {\n\t\tif !isOpen {\n\t\t\ttry open(.write)\n\t\t}\n\t\tlet res = lockf(Int32(fd), F_ULOCK, off_t(byteCount))\n\t\tguard res == 0 else {\n\t\t\ttry ThrowFileError()\n\t\t}\n\t}\n\n\t/// Attempts to place an advisory lock starting from the current position marker up to the indicated byte count. This function will throw an exception if the file is already locked, but will not block the current thread.\n\t/// - parameter byteCount: The number of bytes to lock\n\t/// - throws: `PerfectError.FileError`\n\tfunc tryLock(byteCount: Int) throws {\n\t\tif !isOpen {\n\t\t\ttry open(.write)\n\t\t}\n\t\tlet res = lockf(Int32(fd), F_TLOCK, off_t(byteCount))\n\t\tguard res == 0 else {\n\t\t\ttry ThrowFileError()\n\t\t}\n\t}\n\n\t/// Tests if the indicated bytes are locked\n\t/// - parameter byteCount: The number of bytes to test\n\t/// - returns: True if the file is locked\n\t/// - throws: `PerfectError.FileError`\n\tfunc testLock(byteCount: Int) throws -> Bool {\n\t\tif !isOpen {\n\t\t\ttry open(.write)\n\t\t}\n\t\tlet res = Int(lockf(Int32(fd), F_TEST, off_t(byteCount)))\n\t\tguard res == 0 || res == Int(EACCES) || res == Int(EAGAIN) else {\n\t\t\ttry ThrowFileError()\n\t\t}\n\t\treturn res != 0\n\t}\n}\n\n// Subclass to represent a file which can not be closed\nprivate final class UnclosableFile : File {\n    override init(_ path: String, fd: Int32) {\n\t\tsuper.init(path, fd: fd)\n\t}\n\toverride func close() {\n\t\t// nothing\n\t}\n}\n\n/// A temporary, randomly named file.\npublic final class TemporaryFile: File {\n    /// Create a temporary file, usually in the system's /tmp/ directory\n    /// - parameter withPrefix: The prefix for the temporary file's name. Random characters will be appended to the file's eventual name.\n    public convenience init(withPrefix: String) {\n        let template = withPrefix + \"XXXXXX\"\n        let utf8 = template.utf8\n        let name = UnsafeMutablePointer<Int8>.allocate(capacity: utf8.count + 1)\n        var i = utf8.startIndex\n        for index in 0..<utf8.count {\n            name[index] = Int8(utf8[i])\n            i = utf8.index(after: i)\n        }\n        name[utf8.count] = 0\n\n        let fd = mkstemp(name)\n        let tmpFileName = String(validatingUTF8: name)!\n\n        name.deallocate()\n\n        self.init(tmpFileName, fd: fd)\n    }\n}\n\n/// This file can be used to write to standard in\npublic var fileStdin: File {\n    return UnclosableFile(\"/dev/stdin\", fd: STDIN_FILENO)\n}\n\n/// This file can be used to write to standard out\npublic var fileStdout: File {\n\treturn UnclosableFile(\"/dev/stdout\", fd: STDOUT_FILENO)\n}\n\n/// This file can be used to write to standard error\npublic var fileStderr: File {\n\treturn UnclosableFile(\"/dev/stderr\", fd: STDERR_FILENO)\n}\n"
  },
  {
    "path": "Sources/PerfectLib/JSONConvertible.swift",
    "content": "//\n//  JSONConvertible.swift\n//  PerfectLib\n//\n//  Created by Kyle Jessup on 2016-01-21.\n//  Copyright © 2016 Treefrog. All rights reserved.\n//\n//===----------------------------------------------------------------------===//\n//\n// This source file is part of the Perfect.org open source project\n//\n// Copyright (c) 2015 - 2016 PerfectlySoft Inc. and the Perfect project authors\n// Licensed under Apache License v2.0\n//\n// See http://perfect.org/licensing.html for license information\n//\n//===----------------------------------------------------------------------===//\n//\n\n#if os(Linux)\n\timport SwiftGlibc\n#else\n    import Darwin\n#endif\n\n/// This non-instantiable object serves as an access point to a registry for JSONConvertibleObjects\n/// A JSONConvertibleObject is a custom class or struct which can be converted to and from JSON.\npublic class JSONDecoding {\n    private init() {}\n\n    /// The key used in JSON data to indicate the type of custom object which was converted.\n    public static let objectIdentifierKey = \"_jsonobjid\"\n    /// Function which returns a new instance of a custom object which will have its members set based on the JSON data.\n    public typealias JSONConvertibleObjectCreator = () -> JSONConvertibleObject\n\n    static private var jsonDecodableRegistry = [String:JSONConvertibleObjectCreator]()\n\n    /// Register a custom object to be JSON encoded/decoded.\n    static public func registerJSONDecodable(name nam: String, creator: @escaping JSONConvertibleObjectCreator) {\n        JSONDecoding.jsonDecodableRegistry[nam] = creator\n    }\n\n    /// Instantiate a custom object based on the JSON data.\n    /// The system will use the `JSONDecoding.objectIdentifierKey` key to locate the custom object creator.\n    static public func createJSONConvertibleObject(values:[String:Any]) -> JSONConvertibleObject? {\n        guard let objkey = values[JSONDecoding.objectIdentifierKey] as? String else {\n            return nil\n        }\n        return JSONDecoding.createJSONConvertibleObject(name: objkey, values: values)\n    }\n\n    /// Instantiate a custom object based on the JSON data.\n    /// The system will use the `name` parameter to locate the custom object creator.\n    static public func createJSONConvertibleObject(name: String, values:[String:Any]) -> JSONConvertibleObject? {\n        guard let creator = JSONDecoding.jsonDecodableRegistry[name] else {\n            return nil\n        }\n        let jsonObj = creator()\n        jsonObj.setJSONValues(values)\n        return jsonObj\n    }\n}\n\n/// Protocol for an object which can be converted into JSON text.\npublic protocol JSONConvertible {\n    /// Returns the JSON encoded String for any JSONConvertible type.\n    func jsonEncodedString() throws -> String\n}\n\n// !FIX! changed this to be a class due to Linux protocols failing 'as' tests.\n// revisit this\n/// Base for a custom object which can be converted to and from JSON.\nopen class JSONConvertibleObject: JSONConvertible {\n    /// Default initializer.\n\tpublic init() {}\n    /// Get the JSON keys/value.\n    open func setJSONValues(_ values:[String:Any]) {}\n    /// Set the object properties based on the JSON keys/values.\n    open func getJSONValues() -> [String:Any] { return [String:Any]() }\n    /// Encode the object into JSON text\n    open func jsonEncodedString() throws -> String {\n        return try getJSONValues().jsonEncodedString()\n    }\n}\n\n/// Get the JSON keys/values from a custom object.\npublic extension JSONConvertibleObject {\n    /// Get a named value from the Dictionary converting to the given type with a default value.\n    func getJSONValue<T: JSONConvertible>(named namd: String, from:[String:Any], defaultValue: T) -> T {\n        let f = from[namd]\n        if let v = f as? T {\n            return v\n        }\n        return defaultValue\n    }\n}\n\n/// An error occurring during JSON conversion.\npublic enum JSONConversionError: Error {\n    /// The object did not suppport JSON conversion.\n    case notConvertible(Any?)\n    /// A provided key was not a String.\n    case invalidKey(Any)\n    /// The JSON text contained a syntax error.\n    case syntaxError\n}\n\nprivate let jsonBackSlash = UnicodeScalar(UInt32(92))!\nprivate let jsonBackSpace = UnicodeScalar(UInt32(8))!\nprivate let jsonFormFeed = UnicodeScalar(UInt32(12))!\nprivate let jsonLF = UnicodeScalar(UInt32(10))!\nprivate let jsonCR = UnicodeScalar(UInt32(13))!\nprivate let jsonTab = UnicodeScalar(UInt32(9))!\nprivate let jsonQuoteDouble = UnicodeScalar(UInt32(34))!\n\nprivate let jsonOpenObject = UnicodeScalar(UInt32(123))!\nprivate let jsonOpenArray = UnicodeScalar(UInt32(91))!\nprivate let jsonCloseObject = UnicodeScalar(UInt32(125))!\nprivate let jsonCloseArray = UnicodeScalar(UInt32(93))!\nprivate let jsonWhiteSpace = UnicodeScalar(UInt32(32))!\nprivate let jsonColon = UnicodeScalar(UInt32(58))!\nprivate let jsonComma = UnicodeScalar(UInt32(44))!\n\nprivate let highSurrogateLowerBound = UInt32(strtoul(\"d800\", nil, 16))\nprivate let highSurrogateUpperBound = UInt32(strtoul(\"dbff\", nil, 16))\nprivate let lowSurrogateLowerBound = UInt32(strtoul(\"dc00\", nil, 16))\nprivate let lowSurrogateUpperBound = UInt32(strtoul(\"dfff\", nil, 16))\nprivate let surrogateStep = UInt32(strtoul(\"400\", nil, 16))\nprivate let surrogateBase = UInt32(strtoul(\"10000\", nil, 16))\n\n/// This is a stand-in for a JSON null.\n/// May be produced when decoding.\npublic struct JSONConvertibleNull: JSONConvertible {\n    public func jsonEncodedString() throws -> String {\n        return \"null\"\n    }\n}\n\nextension String: JSONConvertible {\n    /// Convert a String into JSON text\n    public func jsonEncodedString() throws -> String {\n        var s = \"\\\"\"\n        for uchar in unicodeScalars {\n            switch(uchar) {\n            case jsonBackSlash:\n                s.append(\"\\\\\\\\\")\n            case jsonQuoteDouble:\n                s.append(\"\\\\\\\"\")\n            case jsonBackSpace:\n                s.append(\"\\\\b\")\n            case jsonFormFeed:\n                s.append(\"\\\\f\")\n            case jsonLF:\n                s.append(\"\\\\n\")\n            case jsonCR:\n                s.append(\"\\\\r\")\n            case jsonTab:\n                s.append(\"\\\\t\")\n            default:\n                s.append(String(uchar))\n            }\n        }\n        s.append(\"\\\"\")\n        return s\n    }\n}\n\nextension Int: JSONConvertible {\n    /// Convert an Int into JSON text.\n    public func jsonEncodedString() throws -> String {\n        return String(self)\n    }\n}\n\nextension UInt: JSONConvertible {\n    /// Convert a UInt into JSON text.\n    public func jsonEncodedString() throws -> String {\n        return String(self)\n    }\n}\n\nextension Int8: JSONConvertible {\n    /// Convert an Int8 into JSON text.\n    public func jsonEncodedString() throws -> String {\n        return String(self)\n    }\n}\n\nextension Int16: JSONConvertible {\n    /// Convert an Int16 into JSON text.\n    public func jsonEncodedString() throws -> String {\n        return String(self)\n    }\n}\n\nextension Int32: JSONConvertible {\n    /// Convert an Int into JSON text.\n    public func jsonEncodedString() throws -> String {\n        return String(self)\n    }\n}\n\nextension Int64: JSONConvertible {\n    /// Convert an Int into JSON text.\n    public func jsonEncodedString() throws -> String {\n        return String(self)\n    }\n}\n\nextension UInt8: JSONConvertible {\n    /// Convert an UInt8 into JSON text.\n    public func jsonEncodedString() throws -> String {\n        return String(self)\n    }\n}\n\nextension UInt16: JSONConvertible {\n    /// Convert an UInt16 into JSON text.\n    public func jsonEncodedString() throws -> String {\n        return String(self)\n    }\n}\n\nextension UInt32: JSONConvertible {\n    /// Convert an Int into JSON text.\n    public func jsonEncodedString() throws -> String {\n        return String(self)\n    }\n}\n\nextension UInt64: JSONConvertible {\n    /// Convert an Int into JSON text.\n    public func jsonEncodedString() throws -> String {\n        return String(self)\n    }\n}\n\nextension Double: JSONConvertible {\n    /// Convert a Double into JSON text.\n    public func jsonEncodedString() throws -> String {\n        return String(self)\n    }\n}\n\nextension Float: JSONConvertible {\n    /// Convert a Float into JSON text.\n    public func jsonEncodedString() throws -> String {\n        return String(self)\n    }\n}\n\nextension Optional: JSONConvertible {\n    /// Convert an Optional into JSON text.\n    public func jsonEncodedString() throws -> String {\n        if self == nil {\n            return \"null\"\n        } else if let v = self! as? JSONConvertible {\n            return try v.jsonEncodedString()\n        }\n        throw JSONConversionError.notConvertible(self)\n    }\n}\n\nextension Bool: JSONConvertible {\n    /// Convert a Bool into JSON text.\n    public func jsonEncodedString() throws -> String {\n        if true == self {\n            return \"true\"\n        }\n        return \"false\"\n    }\n}\n\n// !FIX! Downcasting to protocol does not work on Linux\n// Not sure if this is intentional, or a bug.\nfunc jsonEncodedStringWorkAround(_ o: Any) throws -> String {\n    switch o {\n    case let jsonAble as JSONConvertibleObject: // as part of Linux work around\n        return try jsonAble.jsonEncodedString()\n    case let jsonAble as JSONConvertible:\n        return try jsonAble.jsonEncodedString()\n    case let jsonAble as String:\n        return try jsonAble.jsonEncodedString()\n    case let jsonAble as Int:\n        return try jsonAble.jsonEncodedString()\n    case let jsonAble as Int8:\n        return try jsonAble.jsonEncodedString()\n    case let jsonAble as Int16:\n        return try jsonAble.jsonEncodedString()\n    case let jsonAble as Int32:\n        return try jsonAble.jsonEncodedString()\n    case let jsonAble as Int64:\n        return try jsonAble.jsonEncodedString()\n    case let jsonAble as UInt:\n        return try jsonAble.jsonEncodedString()\n    case let jsonAble as UInt8:\n        return try jsonAble.jsonEncodedString()\n    case let jsonAble as UInt16:\n        return try jsonAble.jsonEncodedString()\n    case let jsonAble as UInt32:\n        return try jsonAble.jsonEncodedString()\n    case let jsonAble as UInt64:\n        return try jsonAble.jsonEncodedString()\n    case let jsonAble as Double:\n        return try jsonAble.jsonEncodedString()\n    case let jsonAble as Float:\n        return try jsonAble.jsonEncodedString()\n    case let jsonAble as Bool:\n        return try jsonAble.jsonEncodedString()\n    case let jsonAble as [Any]:\n        return try jsonAble.jsonEncodedString()\n    case let jsonAble as [[String:Any]]:\n        return try jsonAble.jsonEncodedString()\n    case let jsonAble as [String:Any]:\n        return try jsonAble.jsonEncodedString()\n    default:\n        throw JSONConversionError.notConvertible(o)\n    }\n}\n\nextension Array: JSONConvertible {\n    /// Convert an Array into JSON text.\n    public func jsonEncodedString() throws -> String {\n        var s = \"[\"\n        var first = true\n        for v in self {\n            if !first {\n                s.append(\",\")\n            } else {\n                first = false\n            }\n            s.append(try jsonEncodedStringWorkAround(v))\n        }\n        s.append(\"]\")\n        return s\n    }\n}\n\nextension Dictionary: JSONConvertible {\n    /// Convert a Dictionary into JSON text.\n    public func jsonEncodedString() throws -> String {\n        var s = \"{\"\n        var first = true\n        for (k, v) in self {\n            guard let strKey = k as? String else {\n                throw JSONConversionError.invalidKey(k)\n            }\n            if !first {\n                s.append(\",\")\n            } else {\n                first = false\n            }\n            s.append(try strKey.jsonEncodedString())\n            s.append(\":\")\n            s.append(try jsonEncodedStringWorkAround(v))\n        }\n        s.append(\"}\")\n        return s\n    }\n}\n\nextension String {\n    /// Decode the object represented by the JSON text.\n    public func jsonDecode() throws -> JSONConvertible {\n        let state = JSONDecodeState()\n        state.g = unicodeScalars.makeIterator()\n\n        let o = try state.readObject()\n        if let _ = o as? JSONDecodeState.EOF {\n            throw JSONConversionError.syntaxError\n        }\n        return o\n    }\n}\n\nprivate class JSONDecodeState {\n    struct EOF: JSONConvertible {\n        func jsonEncodedString() throws -> String { return \"\" }\n    }\n\n    var g = String().unicodeScalars.makeIterator()\n    var pushBack: UnicodeScalar?\n\n    func movePastWhite() {\n        while let c = next() {\n            if !c.isWhiteSpace() {\n                pushBack = c\n                break\n            }\n        }\n    }\n\n    func readObject() throws -> JSONConvertible {\n        movePastWhite()\n\n        guard let c = next() else {\n            return EOF()\n        }\n\n        switch(c) {\n        case jsonOpenArray:\n            var a = [Any]()\n            movePastWhite()\n            guard let c = next() else {\n                throw JSONConversionError.syntaxError\n            }\n            if c != jsonCloseArray {\n                pushBack = c\n                while true {\n                    a.append(try readObject())\n                    movePastWhite()\n                    guard let c = next() else {\n                        throw JSONConversionError.syntaxError\n                    }\n                    if c == jsonCloseArray {\n                        break\n                    }\n                    if c != jsonComma {\n                        throw JSONConversionError.syntaxError\n                    }\n                }\n            }\n            return a\n        case jsonOpenObject:\n            var d = [String:Any]()\n            movePastWhite()\n            guard let c = next() else {\n                throw JSONConversionError.syntaxError\n            }\n            if c != jsonCloseObject {\n                pushBack = c\n                while true {\n                    guard let key = try readObject() as? String else {\n                        throw JSONConversionError.syntaxError\n                    }\n                    movePastWhite()\n                    guard let c = next() else {\n                        throw JSONConversionError.syntaxError\n                    }\n                    guard c == jsonColon else {\n                        throw JSONConversionError.syntaxError\n                    }\n                    movePastWhite()\n                    d[key] = try readObject()\n                    do {\n                        movePastWhite()\n                        guard let c = next() else {\n                            throw JSONConversionError.syntaxError\n                        }\n                        if c == jsonCloseObject {\n                            break\n                        }\n                        if c != jsonComma {\n                            throw JSONConversionError.syntaxError\n                        }\n                    }\n                }\n            }\n            if let objid = d[JSONDecoding.objectIdentifierKey] as? String {\n                if let o = JSONDecoding.createJSONConvertibleObject(name: objid, values: d) {\n                    return o\n                }\n            }\n            return d\n        case jsonQuoteDouble:\n            return try readString()\n        default:\n            if c.isWhiteSpace() {\n                // nothing\n            } else if c.isDigit() || c == \"-\" || c == \"+\" {\n                return try readNumber(firstChar: c)\n            } else if c == \"t\" || c == \"T\" {\n                return try readTrue()\n            } else if c == \"f\" || c == \"F\" {\n                return try readFalse()\n            } else if c == \"n\" || c == \"N\" {\n                try readNull()\n                return JSONConvertibleNull()\n            }\n        }\n        throw JSONConversionError.syntaxError\n    }\n\n    func next() -> UnicodeScalar? {\n        if pushBack != nil {\n            let c = pushBack!\n            pushBack = nil\n            return c\n        }\n        return g.next()\n    }\n\n    // the opening quote has been read\n    func readString() throws -> String {\n        var next = self.next()\n        var esc = false\n        var s = \"\"\n        while let c = next {\n\n            if esc {\n                switch(c) {\n                case jsonBackSlash:\n                    s.append(String(jsonBackSlash))\n                case jsonQuoteDouble:\n                    s.append(String(jsonQuoteDouble))\n                case \"b\":\n                    s.append(String(jsonBackSpace))\n                case \"f\":\n                    s.append(String(jsonFormFeed))\n                case \"n\":\n                    s.append(String(jsonLF))\n                case \"r\":\n                    s.append(String(jsonCR))\n                case \"t\":\n                    s.append(String(jsonTab))\n                case \"u\":\n                    var hexStr = \"\"\n                    for _ in 1...4 {\n                        next = self.next()\n                        guard let hexC = next else {\n                            throw JSONConversionError.syntaxError\n                        }\n                        guard hexC.isHexDigit() else {\n                            throw JSONConversionError.syntaxError\n                        }\n                        hexStr.append(String(hexC))\n                    }\n                    var uint32Value = UInt32(strtoul(hexStr, nil, 16))\n                    // if unicode is a high/low surrogate, it can't be converted directly by UnicodeScalar\n                    // if it's a low surrogate (not expected), throw error\n                    if case lowSurrogateLowerBound...lowSurrogateUpperBound = uint32Value {\n                        throw JSONConversionError.syntaxError\n                    }\n                    // if it's a high surrogate, find the low surrogate which the next unicode is supposed to be, then calculate the pair\n                    if case highSurrogateLowerBound...highSurrogateUpperBound = uint32Value {\n                        let highSurrogateValue = uint32Value\n                        guard self.next() == jsonBackSlash else {\n                            throw JSONConversionError.syntaxError\n                        }\n                        guard self.next() == \"u\" else {\n                            throw JSONConversionError.syntaxError\n                        }\n                        var lowSurrogateHexStr = \"\"\n                        for _ in 1...4 {\n                            next = self.next()\n                            guard let hexC = next else {\n                                throw JSONConversionError.syntaxError\n                            }\n                            guard hexC.isHexDigit() else {\n                                throw JSONConversionError.syntaxError\n                            }\n                            lowSurrogateHexStr.append(String(hexC))\n                        }\n                        let lowSurrogateValue = UInt32(strtoul(lowSurrogateHexStr, nil, 16))\n                        uint32Value = ( highSurrogateValue - highSurrogateLowerBound ) * surrogateStep + ( lowSurrogateValue - lowSurrogateLowerBound ) + surrogateBase\n                    }\n\t\t\t\t\tif let result = UnicodeScalar(uint32Value) {\n\t\t\t\t\t\ts.append(String(Character(result)))\n\t\t\t\t\t}\n                default:\n                    s.append(String(c))\n                }\n                esc = false\n            } else if c == jsonBackSlash {\n                esc = true\n            } else if c == jsonQuoteDouble {\n                return s\n            } else {\n                s.append(String(c))\n            }\n\n            next = self.next()\n        }\n        throw JSONConversionError.syntaxError\n    }\n\n    func readNumber(firstChar first: UnicodeScalar) throws -> JSONConvertible {\n        var s = \"\"\n        var needPeriod = true, needExp = true\n        s.append(String(Character(first)))\n\n        if first == \".\" {\n            needPeriod = false\n        }\n\n        var next = self.next()\n        var last = first\n        while let c = next {\n            if c.isDigit() {\n                s.append(String(c))\n            } else if c == \".\" && !needPeriod {\n                break\n            } else if (c == \"e\" || c == \"E\") && !needExp {\n                break\n            } else if c == \".\" {\n                needPeriod = false\n                s.append(String(c))\n            } else if c == \"e\" || c == \"E\" {\n                needExp = false\n                s.append(String(c))\n\n                next = self.next()\n                if next != nil && (next! == \"-\" || next! == \"+\") {\n                    s.append(String(next!))\n                } else {\n                    pushBack = next!\n                }\n\n            } else if last.isDigit() {\n                pushBack = c\n                if needPeriod && needExp {\n                    return Int(s) ?? s\n                }\n                return Double(s)!\n            } else {\n                break\n            }\n            last = c\n            next = self.next()\n        }\n\n        throw JSONConversionError.syntaxError\n    }\n\n    func readTrue() throws -> Bool {\n        var next = self.next()\n        if next != \"r\" && next != \"R\" {\n            throw JSONConversionError.syntaxError\n        }\n        next = self.next()\n        if next != \"u\" && next != \"U\" {\n            throw JSONConversionError.syntaxError\n        }\n        next = self.next()\n        if next != \"e\" && next != \"E\" {\n            throw JSONConversionError.syntaxError\n        }\n        next = self.next()\n        guard next != nil && !next!.isAlphaNum() else {\n            throw JSONConversionError.syntaxError\n        }\n        pushBack = next!\n        return true\n    }\n\n    func readFalse() throws -> Bool {\n        var next = self.next()\n        if next != \"a\" && next != \"A\" {\n            throw JSONConversionError.syntaxError\n        }\n        next = self.next()\n        if next != \"l\" && next != \"L\" {\n            throw JSONConversionError.syntaxError\n        }\n        next = self.next()\n        if next != \"s\" && next != \"S\" {\n            throw JSONConversionError.syntaxError\n        }\n        next = self.next()\n        if next != \"e\" && next != \"E\" {\n            throw JSONConversionError.syntaxError\n        }\n        next = self.next()\n        guard next != nil && !next!.isAlphaNum() else {\n            throw JSONConversionError.syntaxError\n        }\n        pushBack = next!\n        return false\n    }\n\n    func readNull() throws {\n        var next = self.next()\n        if next != \"u\" && next != \"U\" {\n            throw JSONConversionError.syntaxError\n        }\n        next = self.next()\n        if next != \"l\" && next != \"L\" {\n            throw JSONConversionError.syntaxError\n        }\n        next = self.next()\n        if next != \"l\" && next != \"L\" {\n            throw JSONConversionError.syntaxError\n        }\n        next = self.next()\n        guard next != nil && !next!.isAlphaNum() else {\n            throw JSONConversionError.syntaxError\n        }\n        pushBack = next!\n    }\n}\n"
  },
  {
    "path": "Sources/PerfectLib/Log.swift",
    "content": "//\n//  LogManager.swift\n//  PerfectLib\n//\n//  Created by Kyle Jessup on 7/21/15.\n//\tCopyright (C) 2015 PerfectlySoft, Inc.\n//\n//===----------------------------------------------------------------------===//\n//\n// This source file is part of the Perfect.org open source project\n//\n// Copyright (c) 2015 - 2016 PerfectlySoft Inc. and the Perfect project authors\n// Licensed under Apache License v2.0\n//\n// See http://perfect.org/licensing.html for license information\n//\n//===----------------------------------------------------------------------===//\n//\n\n#if os(Linux)\n\timport SwiftGlibc\n\timport LinuxBridge\n#else\n\timport Darwin\n\timport os\n#endif\n\n/// Placeholder functions for logging system\npublic protocol Logger {\n\tfunc debug(message: String, _ even: Bool)\n\tfunc info(message: String, _ even: Bool)\n\tfunc warning(message: String, _ even: Bool)\n\tfunc error(message: String, _ even: Bool)\n\tfunc critical(message: String, _ even: Bool)\n\tfunc terminal(message: String, _ even: Bool)\n}\n\npublic struct ConsoleLogger: Logger {\n\tpublic init(){}\n\n\tpublic func debug(message: String, _ even: Bool) {\n\t\tprint((even ? \"[DBG]  \" : \"[DBG] \") + message)\n\t}\n\n\tpublic func info(message: String, _ even: Bool) {\n\t\tprint((even ? \"[INFO] \" : \"[INFO] \") + message)\n\t}\n\n\tpublic func warning(message: String, _ even: Bool) {\n\t\tprint((even ? \"[WARN] \" : \"[WARN] \") + message)\n\t}\n\n\tpublic func error(message: String, _ even: Bool) {\n\t\tprint((even ? \"[ERR]  \" : \"[ERR] \") + message)\n\t}\n\n\tpublic func critical(message: String, _ even: Bool) {\n\t\tprint((even ? \"[CRIT] \" : \"[CRIT] \") + message)\n\t}\n\n\tpublic func terminal(message: String, _ even: Bool) {\n\t\tprint((even ? \"[TERM] \" : \"[TERM] \") + message)\n\t}\n}\n\npublic struct SysLogger: Logger {\n\tlet consoleEcho = ConsoleLogger()\n\tpublic init(){}\n\n\tfunc syslog(priority: Int32, _ args: CVarArg...) {\n#if os(Linux)// || os(macOS)\n\t\twithVaList(args) {\n\t\t\tvsyslog(priority, \"%s\", $0)\n\t\t}\n#else\n    // nerdo: Using unified logging (https://developer.apple.com/documentation/os/logging)\n    // os_log isn't very well documented... but this seems like a step in the right direction.\n    let osLogType: OSLogType\n    switch priority {\n    case 0, 1, 2:\n        osLogType = .fault\n    case 3:\n        osLogType = .error\n    case 4, 5, 6:\n        osLogType = .info\n    case 7:\n        osLogType = .debug\n    default:\n        osLogType = .default\n    }\n    os_log(\"%s\", log: .default, type: osLogType, args)\n#endif\n\t}\n\n\tpublic func debug(message: String, _ even: Bool) {\n\t\tconsoleEcho.debug(message: message, even)\n\t\tmessage.withCString {\n\t\t\tf in\n\t\t\tsyslog(priority: LOG_DEBUG, f)\n\t\t}\n\t}\n\n\tpublic func info(message: String, _ even: Bool) {\n\t\tconsoleEcho.info(message: message, even)\n\t\tmessage.withCString {\n\t\t\tf in\n\t\t\tsyslog(priority: LOG_INFO, f)\n\t\t}\n\t}\n\n\tpublic func warning(message: String, _ even: Bool) {\n\t\tconsoleEcho.warning(message: message, even)\n\t\tmessage.withCString {\n\t\t\tf in\n\t\t\tsyslog(priority: LOG_WARNING, f)\n\t\t}\n\t}\n\n\tpublic func error(message: String, _ even: Bool) {\n\t\tconsoleEcho.error(message: message, even)\n\t\tmessage.withCString {\n\t\t\tf in\n\t\t\tsyslog(priority: LOG_ERR, f)\n\t\t}\n\t}\n\n\tpublic func critical(message: String, _ even: Bool) {\n\t\tconsoleEcho.critical(message: message, even)\n\t\tmessage.withCString {\n\t\t\tf in\n\t\t\tsyslog(priority: LOG_CRIT, f)\n\t\t}\n\t}\n\n\tpublic func terminal(message: String, _ even: Bool) {\n\t\tconsoleEcho.terminal(message: message, even)\n\t\tmessage.withCString {\n\t\t\tf in\n\t\t\tsyslog(priority: LOG_EMERG, f)\n\t\t}\n\t}\n}\n\n/// Placeholder functions for logging system\npublic struct Log {\n\tprivate init(){}\n\n\tpublic static var logger: Logger = ConsoleLogger()\n\n\t/// Whether or not to even off the log messages\n\t/// If set to true log messages will be inline with each other\n\tpublic static var even = false\n\n\tpublic static func debug(message: @autoclosure () -> String) {\n//\t#if DEBUG\n\t\tLog.logger.debug(message: message(), even)\n//\t#endif\n\t}\n\n\tpublic static func info(message: String, evenIdents: Bool = even) {\n\t\tLog.logger.info(message: message, evenIdents)\n\t}\n\n\tpublic static func warning(message: String, evenIdents: Bool = even) {\n\t\tLog.logger.warning(message: message, evenIdents)\n\t}\n\n\tpublic static func error(message: String, evenIdents: Bool = even) {\n\t\tLog.logger.error(message: message, evenIdents)\n\t}\n\n\tpublic static func critical(message: String, evenIdents: Bool = even) {\n\t\tLog.logger.critical(message: message, evenIdents)\n\t}\n\n\tpublic static func terminal(message: String, evenIdents: Bool = even) -> Never  {\n\t\tLog.logger.terminal(message: message, evenIdents)\n\t\tfatalError(message)\n\t}\n}\n"
  },
  {
    "path": "Sources/PerfectLib/PerfectError.swift",
    "content": "//\n//  PerfectError.swift\n//  PerfectLib\n//\n//  Created by Kyle Jessup on 7/5/15.\n//\tCopyright (C) 2015 PerfectlySoft, Inc.\n//\n//===----------------------------------------------------------------------===//\n//\n// This source file is part of the Perfect.org open source project\n//\n// Copyright (c) 2015 - 2016 PerfectlySoft Inc. and the Perfect project authors\n// Licensed under Apache License v2.0\n//\n// See http://perfect.org/licensing.html for license information\n//\n//===----------------------------------------------------------------------===//\n//\n\n#if os(Linux)\nimport SwiftGlibc\n\nvar errno: Int32 {\n\treturn __errno_location().pointee\n}\n#else\nimport Darwin\n#endif\n\n/// Some but not all of the exception types which may be thrown by the system\npublic enum PerfectError : Error {\n\t/// A network related error code and message.\n\tcase networkError(Int32, String)\n\t/// A file system related error code and message.\n\tcase fileError(Int32, String)\n\t/// A OS level error code and message.\n\tcase systemError(Int32, String)\n\t/// An API exception error message.\n\tcase apiError(String)\n}\n\n\nfunc ThrowFileError(file: String = #file, function: String = #function, line: Int = #line) throws -> Never  {\n\tlet err = errno\n\tlet msg = String(validatingUTF8: strerror(err))!\n\t\n//\tprint(\"FileError: \\(err) \\(msg)\")\n\t\n\tthrow PerfectError.fileError(err, msg + \" \\(file) \\(function) \\(line)\")\n}\n\n\nfunc ThrowSystemError(file: String = #file, function: String = #function, line: Int = #line) throws -> Never  {\n\tlet err = errno\n\tlet msg = String(validatingUTF8: strerror(err))!\n\t\n//\tprint(\"SystemError: \\(err) \\(msg)\")\n\t\n\tthrow PerfectError.systemError(err, msg + \" \\(file) \\(function) \\(line)\")\n}\n\n\nfunc ThrowNetworkError(file: String = #file, function: String = #function, line: Int = #line) throws -> Never  {\n\tlet err = errno\n\tlet msg = String(validatingUTF8: strerror(err))!\n\t\n//\tprint(\"NetworkError: \\(err) \\(msg)\")\n\t\n\tthrow PerfectError.networkError(err, msg + \" \\(file) \\(function) \\(line)\")\n}\n"
  },
  {
    "path": "Sources/PerfectLib/PerfectServer.swift",
    "content": "//\n//  Perfect.swift\n//  PerfectLib\n//\n//  Created by Kyle Jessup on 7/5/15.\n//\tCopyright (C) 2015 PerfectlySoft, Inc.\n//\n//===----------------------------------------------------------------------===//\n//\n// This source file is part of the Perfect.org open source project\n//\n// Copyright (c) 2015 - 2016 PerfectlySoft Inc. and the Perfect project authors\n// Licensed under Apache License v2.0\n//\n// See http://perfect.org/licensing.html for license information\n//\n//===----------------------------------------------------------------------===//\n//\n\n#if os(Linux)\n    import SwiftGlibc\n#else\n    import Darwin\n#endif\n\n/// Provides access to various system level features for the process.\n/// A static instance of this class is created at startup and all access to this object go through the `PerfectServer.staticPerfectServer` static property.\npublic struct PerfectServer {\n\t\n\t@available(*, deprecated, message: \"No longer required to call this\")\n\tpublic static func initializeServices() {\n\t\n\t}\n\t\n    /// Switch the current process to run with the permissions of the indicated user\n    public static func switchTo(userName unam: String) throws {\n        guard let pw = getpwnam(unam) else {\n            try ThrowSystemError()\n        }\n        let gid = pw.pointee.pw_gid\n        let uid = pw.pointee.pw_uid\n        guard 0 == setgid(gid) else {\n            try ThrowSystemError()\n        }\n        guard 0 == setuid(uid) else {\n            try ThrowSystemError()\n        }\n    }\n}\n\n"
  },
  {
    "path": "Sources/PerfectLib/SysProcess.swift",
    "content": "//\n//  SysProcess.swift\n//  PerfectLib\n//\n//  Created by Kyle Jessup on 7/20/15.\n//  Copyright (C) 2015 PerfectlySoft, Inc.\n//\n//===----------------------------------------------------------------------===//\n//\n// This source file is part of the Perfect.org open source project\n//\n// Copyright (c) 2015 - 2016 PerfectlySoft Inc. and the Perfect project authors\n// Licensed under Apache License v2.0\n//\n// See http://perfect.org/licensing.html for license information\n//\n//===----------------------------------------------------------------------===//\n//\n\n#if os(Linux)\n\timport SwiftGlibc\n\tlet WUNTRACED = Int32(2)\n\tlet WNOHANG = Int32(1)\n\tpublic let SIGTERM = Int32(15)\n#else\n\timport Darwin\n#endif\n\n/// This class permits an external process to be launched given a set of command line arguments and environment variables.\n/// The standard in, out and err file streams are made available. The process can be terminated or permitted to be run to completion.\npublic class SysProcess {\n\n\t/// The standard in file stream.\n\tpublic var stdin: File?\n\t/// The standard out file stream.\n\tpublic var stdout: File?\n\t/// The standard err file stream.\n\tpublic var stderr: File?\n\t/// The process identifier.\n\tpublic var pid = pid_t(-1)\n\t/// The process group identifier.\n\tpublic var gid = pid_t(-1)\n\n\t/// Initialize the object and launch the process.\n\t/// - parameter cmd: The path to the process which will be launched.\n\t/// - parameter args: An optional array of String arguments which will be given to the process.\n\t/// - parameter env: An optional array of environment variable name and value pairs.\n\t/// - parameter newGroup: Create a new process group for this and all sub-processes. Default is no.\n\t/// - throws: `PerfectError.SystemError`\n\tpublic init(_ cmd: String, args: [String]?, env: [(String,String)]?, newGroup: Bool = false) throws {\n\t\ttypealias maybeCChar = UnsafeMutablePointer<CChar>?\n\t\t\n\t\tlet cArgsCount = args?.count ?? 0\n\t\tlet cArgs = UnsafeMutablePointer<maybeCChar>.allocate(capacity: cArgsCount + 2)\n\n\t\tdefer {\n\t\t\tcArgs.deinitialize(count: cArgsCount + 2)\n\t\t\tcArgs.deallocate()\n\t\t}\n\n\t\tcArgs[0] = strdup(cmd)\n\t\tcArgs[cArgsCount + 1] = nil\n\t\t\n\t\tfor idx in 0..<cArgsCount {\n\t\t\tcArgs[idx+1] = strdup(args![idx])\n\t\t}\n\n\t\tlet cEnvCount = env?.count ?? 0\n\t\tlet cEnv = UnsafeMutablePointer<maybeCChar>.allocate(capacity: cEnvCount + 1)\n\n\t\tdefer {\n            cEnv.deinitialize(count: cEnvCount + 1)\n            cEnv.deallocate()\n        }\n\n\t\tcEnv[cEnvCount] = nil\n\t\tfor idx in 0..<cEnvCount {\n\t\t\tcEnv[idx] = strdup(env![idx].0 + \"=\" + env![idx].1)\n\t\t}\n\n\t\tvar fSTDIN: [Int32] = [0, 0]\n\t\tvar fSTDOUT: [Int32] = [0, 0]\n\t\tvar fSTDERR: [Int32] = [0, 0]\n\n\t\tfSTDIN.withUnsafeMutableBytes {\n\t\t\t_ = pipe($0.bindMemory(to: Int32.self).baseAddress)\n\t\t}\n\t\tfSTDOUT.withUnsafeMutableBytes {\n\t\t\t_ = pipe($0.bindMemory(to: Int32.self).baseAddress)\n\t\t}\n\t\tfSTDERR.withUnsafeMutableBytes {\n\t\t\t_ = pipe($0.bindMemory(to: Int32.self).baseAddress)\n\t\t}\n    #if os(Linux)\n\t\tvar action = posix_spawn_file_actions_t()\n\t\tvar attr = posix_spawnattr_t()\n    #else\n\t\tvar action = posix_spawn_file_actions_t(nil as OpaquePointer?)\n\t\tvar attr = posix_spawnattr_t(nil as OpaquePointer?)\n    #endif\n\n        // nerdo: This probably causes SysProcess to fail on tvOS, but it doesn't seem to be called in any of the\n        // basic, core Perfect libraries, so this is probably a non-issue unless it is used directly\n    #if os(tvOS)\n        var procPid = pid_t()\n        var spawnRes = 0\n    #else\n\t\tposix_spawn_file_actions_init(&action);\n\t\tposix_spawn_file_actions_adddup2(&action, fSTDOUT[1], STDOUT_FILENO);\n\t\tposix_spawn_file_actions_adddup2(&action, fSTDIN[0], STDIN_FILENO);\n\t\tposix_spawn_file_actions_adddup2(&action, fSTDERR[1], STDERR_FILENO);\n\n\t\tposix_spawn_file_actions_addclose(&action, fSTDOUT[0]);\n\t\tposix_spawn_file_actions_addclose(&action, fSTDIN[0]);\n\t\tposix_spawn_file_actions_addclose(&action, fSTDERR[0]);\n\t\tposix_spawn_file_actions_addclose(&action, fSTDOUT[1]);\n\t\tposix_spawn_file_actions_addclose(&action, fSTDIN[1]);\n\t\tposix_spawn_file_actions_addclose(&action, fSTDERR[1]);\n\t\t\n\t\tposix_spawnattr_init(&attr)\n\t\t\n\t\tif newGroup {\n\t\t\t// By default, all flags are unset after the init call\n\t\t\t// so no need to OR in the existing flags.\n\t\t\tposix_spawnattr_setflags(&attr, Int16(POSIX_SPAWN_SETPGROUP))\n\t\t}\n\n\t\tvar procPid = pid_t()\n\t\tlet spawnRes = posix_spawnp(&procPid, cmd, &action, &attr, cArgs, cEnv)\n\t\tposix_spawn_file_actions_destroy(&action)\n\t\tposix_spawnattr_destroy(&attr)\n\n\t\tfor idx in 0..<cArgsCount {\n\t\t\tfree(cArgs[idx])\n\t\t}\n\n\t\tfor idx in 0..<cEnvCount {\n\t\t\tfree(cEnv[idx])\n\t\t}\n    #endif\n\n\t#if os(Linux)\n\t\t// On Ubuntu the getpgid(pid_t) call does not seem to work.\n\t\t// However, the Posix standard says that the pgid is the same\n\t\t// as the pid of the first process spawned, so we can just use that.\n\t\tgid = procPid\n\t\t_ = SwiftGlibc.close(fSTDIN[0])\n\t\t_ = SwiftGlibc.close(fSTDOUT[1])\n\t\t_ = SwiftGlibc.close(fSTDERR[1])\n\t\tif spawnRes != 0 {\n\t\t\t_ = SwiftGlibc.close(fSTDIN[1])\n\t\t\t_ = SwiftGlibc.close(fSTDOUT[0])\n\t\t\t_ = SwiftGlibc.close(fSTDERR[0])\n\t\t\ttry ThrowSystemError()\n\t\t}\n\t#else\n\t\tgid = Darwin.getpgid(procPid)\n\t\t_ = Darwin.close(fSTDIN[0])\n\t\t_ = Darwin.close(fSTDOUT[1])\n\t\t_ = Darwin.close(fSTDERR[1])\n\t\tif spawnRes != 0 {\n\t\t\t_ = Darwin.close(fSTDIN[1])\n\t\t\t_ = Darwin.close(fSTDOUT[0])\n\t\t\t_ = Darwin.close(fSTDERR[0])\n\t\t\ttry ThrowSystemError()\n\t\t}\n\t#endif\n\t\tpid = procPid\n\t\tstdin = File(\"stdin\", fd: fSTDIN[1])\n\t\tstdout = File(\"stdout\", fd: fSTDOUT[0])\n\t\tstderr = File(\"stderr\", fd: fSTDERR[0])\n\t}\n\n\tdeinit {\n\t\tclose()\n\t}\n\n\t/// Returns true if the process was opened and was running at some point.\n\t/// Note that the process may not be currently running. Use `wait(false)` to check if the process is currently running.\n\tpublic func isOpen() -> Bool {\n\t\treturn pid != -1\n\t}\n\n\t/// Terminate the process and clean up.\n\tpublic func close() {\n\t\tif stdin != nil {\n\t\t\tstdin!.close()\n\t\t}\n\t\tif stdout != nil {\n\t\t\tstdout!.close()\n\t\t}\n\t\tif stderr != nil {\n\t\t\tstderr!.close()\n\t\t}\n\t\tif pid != -1 {\n\t\t\tdo {\n\t\t\t\tlet _ = try kill()\n\t\t\t} catch {\n\n\t\t\t}\n\t\t}\n\t\tstdin = nil\n\t\tstdout = nil\n\t\tstderr = nil\n\t\tpid = -1\n\t\tgid = -1\n\t}\n\n\t/// Detach from the process such that it will not be manually terminated when this object is deinitialized.\n\tpublic func detach() {\n\t\tpid = -1\n\t}\n\n\t/// Determine if the process has completed running and retrieve its result code.\n\tpublic func wait(hang: Bool = true) throws -> Int32 {\n\t\tvar code = Int32(0)\n\t\twhile true {\n\t\t\tlet status = waitpid(pid, &code, WUNTRACED | (hang ? 0 : WNOHANG))\n\t\t\tif status == -1 && errno == EINTR {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tguard status != -1 else {\n\t\t\t\ttry ThrowSystemError()\n\t\t\t}\n\t\t\tif status == 0 && !hang {\n\t\t\t\treturn 0\n\t\t\t}\n\t\t\tbreak\n\t\t}\n\t\tpid = -1\n\t\treturn (((code) & 0xff00) >> 8)\n\t}\n\n\t/// Terminate the process and return its result code.\n\tpublic func kill(signal: Int32 = SIGTERM) throws -> Int32 {\n\t#if os(Linux)\n\t\tlet status = SwiftGlibc.kill(pid, signal)\n\t#else\n\t\tlet status = Darwin.kill(pid, signal)\n\t#endif\n\t\tguard status != -1 else {\n\t\t\ttry ThrowSystemError()\n\t\t}\n\t\treturn try wait()\n\t}\n\t\n\t/// Terminate the process group and return the root process result code.\n\tpublic func killGroup(signal: Int32 = SIGTERM) throws -> Int32 {\n\t\t#if os(Linux)\n\t\t\tlet status = SwiftGlibc.killpg(gid, signal)\n\t\t#else\n\t\t\tlet status = Darwin.killpg(gid, signal)\n\t\t#endif\n\t\tguard status != -1 else {\n\t\t\ttry ThrowSystemError()\n\t\t}\n\t\treturn try wait()\n\t}\n}\n"
  },
  {
    "path": "Sources/PerfectLib/Utilities.swift",
    "content": "//\n//  Utilities.swift\n//  PerfectLib\n//\n//  Created by Kyle Jessup on 7/17/15.\n//\tCopyright (C) 2015 PerfectlySoft, Inc.\n//\n//===----------------------------------------------------------------------===//\n//\n// This source file is part of the Perfect.org open source project\n//\n// Copyright (c) 2015 - 2016 PerfectlySoft Inc. and the Perfect project authors\n// Licensed under Apache License v2.0\n//\n// See http://perfect.org/licensing.html for license information\n//\n//===----------------------------------------------------------------------===//\n//\n\n#if os(Linux)\n\timport LinuxBridge\n#else\n\timport Darwin\n#endif\nimport Foundation\n\n/// This class permits an UnsafeMutablePointer to be used as a GeneratorType\npublic struct GenerateFromPointer<T> : IteratorProtocol {\n\t\n\tpublic typealias Element = T\n\t\n\tvar count = 0\n\tvar pos = 0\n\tvar from: UnsafeMutablePointer<T>\n\t\n\t/// Initialize given an UnsafeMutablePointer and the number of elements pointed to.\n\tpublic init(from: UnsafeMutablePointer<T>, count: Int) {\n\t\tself.from = from\n\t\tself.count = count\n\t}\n\t\n\t/// Return the next element or nil if the sequence has been exhausted.\n\tmutating public func next() -> Element? {\n\t\tguard count > 0 else {\n\t\t\treturn nil\n\t\t}\n\t\tcount -= 1\n\t\tlet result = from[pos]\n\t\tpos += 1\n\t\treturn result\n\t}\n}\n\n/// A generalized wrapper around the Unicode codec operations.\npublic struct Encoding {\n\t\n\t/// Return a String given a character generator.\n\tpublic static func encode<D : UnicodeCodec, G : IteratorProtocol>(codec inCodec: D, generator: G) -> String where G.Element == D.CodeUnit {\n\t\tvar encodedString = \"\"\n\t\tvar finished: Bool = false\n\t\tvar mutableDecoder = inCodec\n\t\tvar mutableGenerator = generator\n\t\trepeat {\n\t\t\tlet decodingResult = mutableDecoder.decode(&mutableGenerator)\n\t\t\tswitch decodingResult {\n\t\t\tcase .scalarValue(let char):\n\t\t\t\tencodedString.append(String(char))\n\t\t\tcase .emptyInput:\n\t\t\t\tfinished = true\n\t\t\t\t/* ignore errors and unexpected values */\n\t\t\tcase .error:\n\t\t\t\tfinished = true\n\t\t\t}\n\t\t} while !finished\n\t\treturn encodedString\n\t}\n}\n\n/// Utility wrapper permitting a UTF-8 character generator to encode a String. Also permits a String to be converted into a UTF-8 byte array.\npublic struct UTF8Encoding {\n\t\n\t/// Use a character generator to create a String.\n\tpublic static func encode<G : IteratorProtocol>(generator gen: G) -> String where G.Element == UTF8.CodeUnit {\n\t\treturn Encoding.encode(codec: UTF8(), generator: gen)\n\t}\n\t\n\t/// Use a character sequence to create a String.\n\tpublic static func encode<S : Sequence>(bytes byts: S) -> String where S.Iterator.Element == UTF8.CodeUnit {\n\t\treturn encode(generator: byts.makeIterator())\n\t}\n\t\n\t/// Use a character sequence to create a String.\n\tpublic static func encode(bytes byts: [UTF8.CodeUnit]) -> String {\n\t\treturn encode(generator: byts.makeIterator())\n\t}\n\t\n\t/// Decode a String into an array of UInt8.\n\tpublic static func decode(string str: String) -> Array<UInt8> {\n\t\treturn [UInt8](str.utf8)\n\t}\n}\n\nextension UInt8 {\n\tvar shouldURLEncode: Bool {\n\t\tlet cc = self\n\t\treturn ( ( cc >= 128 )\n\t\t\t|| ( cc < 33 )\n\t\t\t|| ( cc >= 34  && cc < 38 )\n\t\t\t|| ( ( cc > 59  && cc < 61) || cc == 62 || cc == 58)\n\t\t\t|| ( ( cc >= 91  && cc < 95 ) || cc == 96 )\n\t\t\t|| ( cc >= 123 && cc <= 126 )\n\t\t\t|| self == 43 )\n\t}\n\t\n\t// same as String(self, radix: 16)\n\t// but outputs two characters. i.e. 0 padded\n\tvar hexString: String {\n\t\tvar s = \"\"\n\t\tlet b = self >> 4\n\t\ts.append(String(Character(UnicodeScalar(b > 9 ? b - 10 + 65 : b + 48))))\n\t\tlet b2 = self & 0x0F\n\t\ts.append(String(Character(UnicodeScalar(b2 > 9 ? b2 - 10 + 65 : b2 + 48))))\n\t\treturn s\n\t}\n}\n\nextension String {\n\t/// Returns the String with all special HTML characters encoded.\n\tpublic var stringByEncodingHTML: String {\n\t\tvar ret = \"\"\n\t\tvar g = unicodeScalars.makeIterator()\n\t\tvar lastWasCR = false\n\t\twhile let c = g.next() {\n\t\t\tif c == UnicodeScalar(10) {\n\t\t\t\tif lastWasCR {\n\t\t\t\t\tlastWasCR = false\n\t\t\t\t\tret.append(\"\\n\")\n\t\t\t\t} else {\n\t\t\t\t\tret.append(\"<br>\\n\")\n\t\t\t\t}\n\t\t\t\tcontinue\n\t\t\t} else if c == UnicodeScalar(13) {\n\t\t\t\tlastWasCR = true\n\t\t\t\tret.append(\"<br>\\r\")\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tlastWasCR = false\n\t\t\tif c < UnicodeScalar(0x0009) {\n\t\t\t\tif let scale = UnicodeScalar(0x0030 + UInt32(c)) {\n\t\t\t\t\tret.append(\"&#x\")\n\t\t\t\t\tret.append(String(Character(scale)))\n\t\t\t\t\tret.append(\";\")\n\t\t\t\t}\n\t\t\t} else if c == UnicodeScalar(0x0022) {\n\t\t\t\tret.append(\"&quot;\")\n\t\t\t} else if c == UnicodeScalar(0x0026) {\n\t\t\t\tret.append(\"&amp;\")\n\t\t\t} else if c == UnicodeScalar(0x0027) {\n\t\t\t\tret.append(\"&#39;\")\n\t\t\t} else if c == UnicodeScalar(0x003C) {\n\t\t\t\tret.append(\"&lt;\")\n\t\t\t} else if c == UnicodeScalar(0x003E) {\n\t\t\t\tret.append(\"&gt;\")\n\t\t\t} else if c > UnicodeScalar(126) {\n\t\t\t\tret.append(\"&#\\(UInt32(c));\")\n\t\t\t} else {\n\t\t\t\tret.append(String(Character(c)))\n\t\t\t}\n\t\t}\n\t\treturn ret\n\t}\n\t\n\t/// Returns the String with all special URL characters encoded.\n\tpublic var stringByEncodingURL: String {\n\t\tvar ret = \"\"\n\t\tvar g = utf8.makeIterator()\n\t\twhile let c = g.next() {\n\t\t\tif c.shouldURLEncode {\n\t\t\t\tret.append(String(Character(UnicodeScalar(37))))\n\t\t\t\tret.append(c.hexString)\n\t\t\t} else {\n\t\t\t\tret.append(String(Character(UnicodeScalar(c))))\n\t\t\t}\n\t\t}\n\t\treturn ret\n\t}\n\t\n\t// Utility - not sure if it makes the most sense to have here or outside or elsewhere\n\tstatic func byteFromHexDigits(one c1v: UInt8, two c2v: UInt8) -> UInt8? {\n\t\t\n\t\tlet capA: UInt8 = 65\n\t\tlet capF: UInt8 = 70\n\t\tlet lowA: UInt8 = 97\n\t\tlet lowF: UInt8 = 102\n\t\tlet zero: UInt8 = 48\n\t\tlet nine: UInt8 = 57\n\t\t\n\t\tvar newChar = UInt8(0)\n\t\t\n\t\tif c1v >= capA && c1v <= capF {\n\t\t\tnewChar = c1v - capA + 10\n\t\t} else if c1v >= lowA && c1v <= lowF {\n\t\t\tnewChar = c1v - lowA + 10\n\t\t} else if c1v >= zero && c1v <= nine {\n\t\t\tnewChar = c1v - zero\n\t\t} else {\n\t\t\treturn nil\n\t\t}\n\t\t\n\t\tnewChar *= 16\n\t\t\n\t\tif c2v >= capA && c2v <= capF {\n\t\t\tnewChar += c2v - capA + 10\n\t\t} else if c2v >= lowA && c2v <= lowF {\n\t\t\tnewChar += c2v - lowA + 10\n\t\t} else if c2v >= zero && c2v <= nine {\n\t\t\tnewChar += c2v - zero\n\t\t} else {\n\t\t\treturn nil\n\t\t}\n\t\treturn newChar\n\t}\n\t\n\t/// Decode the % encoded characters in a URL and return result\n\tpublic var stringByDecodingURL: String? {\n\t\tlet percent: UInt8 = 37\n\t\tlet plus: UInt8 = 43\n\t\tlet space: UInt8 = 32\n\t\tvar bytesArray = [UInt8]()\n\t\tvar g = utf8.makeIterator()\n\t\twhile let c = g.next() {\n\t\t\tif c == percent {\n\t\t\t\tguard let c1v = g.next() else {\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\t\t\t\tguard let c2v = g.next() else {\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\t\t\t\tguard let newChar = String.byteFromHexDigits(one: c1v, two: c2v) else {\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\t\t\t\tbytesArray.append(newChar)\n\t\t\t} else if c == plus {\n\t\t\t\tbytesArray.append(space)\n\t\t\t} else {\n\t\t\t\tbytesArray.append(c)\n\t\t\t}\n\t\t}\n\t\tbytesArray.append(0)\n\t\treturn bytesArray.withUnsafeBytes {\n\t\t\tguard let p = $0.bindMemory(to: Int8.self).baseAddress else {\n\t\t\t\treturn nil\n\t\t\t}\n\t\t\treturn String(validatingUTF8: p)\n\t\t}\n\t}\n\t\n\t/// Decode a hex string into resulting byte array\n\tpublic var decodeHex: [UInt8]? {\n\t\t\n\t\tvar bytesArray = [UInt8]()\n\t\tvar g = utf8.makeIterator()\n\t\twhile let c1v = g.next() {\n\t\t\t\n\t\t\tguard let c2v = g.next() else {\n\t\t\t\treturn nil\n\t\t\t}\n\t\t\t\n\t\t\tguard let newChar = String.byteFromHexDigits(one: c1v, two: c2v) else {\n\t\t\t\treturn nil\n\t\t\t}\n\t\t\t\n\t\t\tbytesArray.append(newChar)\n\t\t}\n\t\treturn bytesArray\n\t}\n}\n\n@available(*, deprecated, message: \"Use Foundation.UUID\")\npublic struct UUID {\n\tlet uuid: uuid_t\n\t\n\tpublic init() {\n\t\tlet u = UnsafeMutablePointer<UInt8>.allocate(capacity:  MemoryLayout<uuid_t>.size)\n\t\tdefer {\n\t\t\tu.deallocate()\n\t\t}\n\t\tuuid_generate_random(u)\n\t\tuuid = UUID.uuidFromPointer(u)\n\t}\n\t\n\tpublic init(_ string: String) {\n\t\tlet u = UnsafeMutablePointer<UInt8>.allocate(capacity:  MemoryLayout<uuid_t>.size)\n\t\tdefer {\n\t\t\tu.deallocate()\n\t\t}\n\t\tuuid_parse(string, u)\n\t\tuuid = UUID.uuidFromPointer(u)\n\t}\n\t\n\tinit(_ uuid: uuid_t) {\n\t\tself.uuid = uuid\n\t}\n\t\n\tprivate static func uuidFromPointer(_ u: UnsafeMutablePointer<UInt8>) -> uuid_t {\n\t\t// is there a better way?\n\t\treturn uuid_t(u[0], u[1], u[2], u[3], u[4], u[5], u[6], u[7], u[8], u[9], u[10], u[11], u[12], u[13], u[14], u[15])\n\t}\n\t\n\tpublic var string: String {\n\t\tlet u = UnsafeMutablePointer<UInt8>.allocate(capacity:  MemoryLayout<uuid_t>.size)\n\t\tlet unu = UnsafeMutablePointer<Int8>.allocate(capacity:  37) // as per spec. 36 + null\n\t\tdefer {\n\t\t\tu.deallocate()\n\t\t\tunu.deallocate()\n\t\t}\n\t\tvar uu = uuid\n\t\tmemcpy(u, &uu, MemoryLayout<uuid_t>.size)\n\t\tuuid_unparse_lower(u, unu)\n\t\treturn String(validatingUTF8: unu)!\n\t}\n}\n\nextension String {\n\t\n\t/// Parse an HTTP Digest authentication header returning a Dictionary containing each part.\n\tpublic func parseAuthentication() -> [String:String] {\n\t\tvar ret = [String:String]()\n\t\tif let _ = range(of: \"Digest \") {\n\t\t\tret[\"type\"] = \"Digest\"\n\t\t\tlet wantFields = [\"username\", \"nonce\", \"nc\", \"cnonce\", \"response\", \"uri\", \"realm\", \"qop\", \"algorithm\"]\n\t\t\tfor field in wantFields {\n\t\t\t\tif let foundField = String.extractField(from: self, named: field) {\n\t\t\t\t\tret[field] = foundField\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn ret\n\t}\n\t\n\tprivate static func extractField(from frm: String, named: String) -> String? {\n\t\tguard let range = frm.range(of: named + \"=\") else {\n\t\t\treturn nil\n\t\t}\n\t\t\n\t\tvar currPos = range.upperBound\n\t\tvar ret = \"\"\n\t\tlet quoted = frm[currPos] == \"\\\"\"\n\t\tif quoted {\n\t\t\tcurrPos = frm.index(after: currPos)\n\t\t\tlet tooFar = frm.endIndex\n\t\t\twhile currPos != tooFar {\n\t\t\t\tif frm[currPos] == \"\\\"\" {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tret.append(frm[currPos])\n\t\t\t\tcurrPos = frm.index(after: currPos)\n\t\t\t}\n\t\t} else {\n\t\t\tlet tooFar = frm.endIndex\n\t\t\twhile currPos != tooFar {\n\t\t\t\tif frm[currPos] == \",\" {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tret.append(frm[currPos])\n\t\t\t\tcurrPos = frm.index(after: currPos)\n\t\t\t}\n\t\t}\n\t\treturn ret\n\t}\n}\n\nextension String {\n\t\n\t/// Replace all occurrences of `string` with `withString`.\n\tpublic func stringByReplacing(string strng: String, withString: String) -> String {\n\t\t\n\t\tguard !strng.isEmpty else {\n\t\t\treturn self\n\t\t}\n\t\tguard !isEmpty else {\n\t\t\treturn self\n\t\t}\n\t\t\n\t\tvar ret = \"\"\n\t\tvar idx = startIndex\n\t\tlet endIdx = endIndex\n\t\t\n\t\twhile idx != endIdx {\n\t\t\tif self[idx] == strng[strng.startIndex] {\n\t\t\t\tvar newIdx = index(after: idx)\n\t\t\t\tvar findIdx = strng.index(after: strng.startIndex)\n\t\t\t\tlet findEndIdx = strng.endIndex\n\t\t\t\t\n\t\t\t\twhile newIdx != endIndex && findIdx != findEndIdx && self[newIdx] == strng[findIdx] {\n\t\t\t\t\tnewIdx = index(after: newIdx)\n\t\t\t\t\tfindIdx = strng.index(after: findIdx)\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif findIdx == findEndIdx { // match\n\t\t\t\t\tret.append(withString)\n\t\t\t\t\tidx = newIdx\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t}\n\t\t\tret.append(self[idx])\n\t\t\tidx = index(after: idx)\n\t\t}\n\t\t\n\t\treturn ret\n\t}\n\t\n\t// For compatibility due to shifting swift\n\tpublic func contains(string: String) -> Bool {\n\t\treturn nil != range(of: string)\n\t}\n}\n\nextension String {\n\tfunc begins(with str: String) -> Bool {\n\t\treturn starts(with: str)\n\t}\n\t\n\tfunc ends(with str: String) -> Bool {\n\t\tguard count >= str.count else {\n\t\t\treturn false\n\t\t}\n\t\treturn str.begins(with: String(self[index(endIndex, offsetBy: -str.count)..<endIndex]))\n\t}\n}\n\n/// Returns the current time according to ICU\n/// ICU dates are the number of milliseconds since the reference date of Thu, 01-Jan-1970 00:00:00 GMT\npublic func getNow() -> Double {\n\t\n\tvar posixTime = timeval()\n\tgettimeofday(&posixTime, nil)\n\treturn Double((posixTime.tv_sec * 1000) + (Int(posixTime.tv_usec)/1000))\n}\n/// Converts the milliseconds based ICU date to seconds since the epoch\npublic func icuDateToSeconds(_ icuDate: Double) -> Int {\n\treturn Int(icuDate / 1000)\n}\n/// Converts the seconds since the epoch into the milliseconds based ICU date\npublic func secondsToICUDate(_ seconds: Int) -> Double {\n\treturn Double(seconds * 1000)\n}\n\n/// Format a date value according to the indicated format string and return a date string.\n/// - parameter date: The date value\n/// - parameter format: The format by which the date will be formatted. Use a valid strftime style format string.\n/// - parameter timezone: The optional timezone in which the date is expected to be based. Default is the local timezone.\n/// - parameter locale: The optional locale which will be used when parsing the date. Default is the current global locale.\n/// - returns: The resulting date string\n/// - throws: `PerfectError.systemError`\npublic func formatDate(_ date: Double, format: String, timezone inTimezone: String? = nil, locale inLocale: String? = nil) throws -> String {\n\t\n\tvar t = tm()\n\tvar time = time_t(date / 1000.0)\n\tgmtime_r(&time, &t)\n\tlet maxResults = 1024\n\tlet results = UnsafeMutablePointer<Int8>.allocate(capacity:  maxResults)\n\tdefer {\n\t\tresults.deallocate()\n\t}\n\tlet res = strftime(results, maxResults, format, &t)\n\tif res > 0 {\n\t\tlet formatted = String(validatingUTF8: results)\n\t\treturn formatted!\n\t}\n\ttry ThrowSystemError()\n}\n\nextension UnicodeScalar {\n\t\n\t/// Returns true if the UnicodeScalar is a white space character\n\tpublic func isWhiteSpace() -> Bool {\n\t\treturn isspace(Int32(value)) != 0\n\t}\n\t/// Returns true if the UnicodeScalar is a digit character\n\tpublic func isDigit() -> Bool {\n\t\treturn isdigit(Int32(value)) != 0\n\t}\n\t/// Returns true if the UnicodeScalar is an alpha-numeric character\n\tpublic func isAlphaNum() -> Bool {\n\t\treturn isalnum(Int32(value)) != 0\n\t}\n\t/// Returns true if the UnicodeScalar is a hexadecimal character\n\tpublic func isHexDigit() -> Bool {\n\t\tif isDigit() {\n\t\t\treturn true\n\t\t}\n\t\tswitch self {\n\t\tcase \"A\", \"B\", \"C\", \"D\", \"E\", \"F\", \"a\", \"b\", \"c\", \"d\", \"e\", \"f\":\n\t\t\treturn true\n\t\tdefault:\n\t\t\treturn false\n\t\t}\n\t}\n}\n\nextension String {\n\t\n\tvar filePathSeparator: UnicodeScalar {\n\t\treturn UnicodeScalar(47)\n\t}\n\t\n\tvar fileExtensionSeparator: UnicodeScalar {\n\t\treturn UnicodeScalar(46)\n\t}\n\t\n\tpublic var beginsWithFilePathSeparator: Bool {\n\t\tguard count > 0 else {\n\t\t\treturn false\n\t\t}\n\t\treturn self[startIndex] == Character(filePathSeparator)\n\t}\n\t\n\tpublic var endsWithFilePathSeparator: Bool {\n\t\tguard count > 0 else {\n\t\t\treturn false\n\t\t}\n\t\treturn self[index(before: endIndex)] == Character(filePathSeparator)\n\t}\n\t\n\tprivate func filePathComponents(addFirstLast addfl: Bool) -> [String] {\n\t\tvar r = [String]()\n\t\tguard count > 0 else {\n\t\t\treturn r\n\t\t}\n\t\tlet fsc = Character(filePathSeparator)\n\t\tlet beginSlash = self[startIndex] == fsc\n\t\tif addfl && beginSlash {\n\t\t\tr.append(String(filePathSeparator))\n\t\t}\n\t\t\n\t\tr.append(contentsOf: split(separator: fsc).map { String($0) })\n\t\t\n\t\tif addfl && self[index(before: endIndex)] == fsc {\n\t\t\tif !beginSlash || r.count > 1 {\n\t\t\t\tr.append(String(filePathSeparator))\n\t\t\t}\n\t\t}\n\t\treturn r\n\t}\n\t\n\tpublic var filePathComponents: [String] {\n\t\treturn filePathComponents(addFirstLast: true)\n\t}\n\t\n\tpublic var lastFilePathComponent: String {\n\t\tlet last = filePathComponents(addFirstLast: false).last ?? \"\"\n\t\tif last.isEmpty && first == Character(filePathSeparator) {\n\t\t\treturn String(filePathSeparator)\n\t\t}\n\t\treturn last\n\t}\n\t\n\tpublic var deletingLastFilePathComponent: String {\n\t\tvar comps = filePathComponents(addFirstLast: false)\n\t\tguard comps.count > 1 else {\n\t\t\tif beginsWithFilePathSeparator {\n\t\t\t\treturn String(filePathSeparator)\n\t\t\t}\n\t\t\treturn \"\"\n\t\t}\n\t\tcomps.removeLast()\n\t\tlet joined = comps.joined(separator: String(filePathSeparator))\n\t\tif beginsWithFilePathSeparator {\n\t\t\treturn String(filePathSeparator) + joined\n\t\t}\n\t\treturn joined\n\t}\n\t\n\tprivate func lastPathSeparator(in unis: String) -> String.Index {\n\t\tlet startIndex = unis.startIndex\n\t\tvar endIndex = unis.endIndex\n\t\twhile endIndex != startIndex {\n\t\t\tif unis[unis.index(before: endIndex)] != Character(filePathSeparator) {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tendIndex = unis.index(before: endIndex)\n\t\t}\n\t\treturn endIndex\n\t}\n\t\n\tprivate func lastExtensionSeparator(in unis: String, endIndex: String.Index) -> String.Index {\n\t\tvar endIndex = endIndex\n\t\twhile endIndex != startIndex {\n\t\t\tendIndex = unis.index(before: endIndex)\n\t\t\tif unis[endIndex] == Character(fileExtensionSeparator) {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\treturn endIndex\n\t}\n\t\n\tpublic var deletingFileExtension: String {\n\t\tvar endIndex = lastPathSeparator(in: self)\n\t\tlet noTrailsIndex = endIndex\n\t\tendIndex = lastExtensionSeparator(in: self, endIndex: endIndex)\n\t\tguard endIndex != startIndex else {\n\t\t\tif noTrailsIndex == startIndex {\n\t\t\t\treturn self\n\t\t\t}\n\t\t\treturn String(self[startIndex..<noTrailsIndex])\n\t\t}\n\t\treturn String(self[startIndex..<endIndex])\n\t}\n\t\n\tpublic var filePathExtension: String {\n\t\tvar endIndex = lastPathSeparator(in: self)\n\t\tlet noTrailsIndex = endIndex\n\t\tendIndex = lastExtensionSeparator(in: self, endIndex: endIndex)\n\t\tguard endIndex != startIndex else {\n\t\t\treturn \"\"\n\t\t}\n\t\treturn String(self[index(after: endIndex)..<noTrailsIndex])\n\t}\n\t\n\tpublic var resolvingSymlinksInFilePath: String {\n\t\treturn File(self).realPath\n\t}\n}\n"
  },
  {
    "path": "Tests/LinuxMain.swift",
    "content": "import XCTest\n@testable import PerfectLibTests\n\nXCTMain([\n\ttestCase(PerfectLibTests.allTests),\n])\n"
  },
  {
    "path": "Tests/PerfectLibTests/PerfectLibTests.swift",
    "content": "//\n//  PerfectLibTests.swift\n//  PerfectLibTests\n//\n//  Created by Kyle Jessup on 2015-10-19.\n//  Copyright © 2015 PerfectlySoft. All rights reserved.\n//\n//===----------------------------------------------------------------------===//\n//\n// This source file is part of the Perfect.org open source project\n//\n// Copyright (c) 2015 - 2016 PerfectlySoft Inc. and the Perfect project authors\n// Licensed under Apache License v2.0\n//\n// See http://perfect.org/licensing.html for license information\n//\n//===----------------------------------------------------------------------===//\n//\n\n\nimport XCTest\n@testable import PerfectLib\n\n#if os(Linux)\nimport SwiftGlibc\nimport Foundation\n#endif\n\nclass PerfectLibTests: XCTestCase {\n\n\toverride func setUp() {\n\t\tsuper.setUp()\n\t#if os(Linux)\n\t\tSwiftGlibc.srand(UInt32(time(nil)))\n\t#endif\n\t}\n\n\toverride func tearDown() {\n\t\t// Put teardown code here. This method is called after the invocation of each test method in the class.\n\t\tsuper.tearDown()\n\t}\n\n\tfunc testJSONConvertibleObject1() {\n\n\t\tclass Test: JSONConvertibleObject {\n\n\t\t\tstatic let registerName = \"test\"\n\n\t\t\tvar one = 0\n\t\t\toverride func setJSONValues(_ values: [String : Any]) {\n\t\t\t\tself.one = getJSONValue(named: \"One\", from: values, defaultValue: 42)\n\t\t\t}\n\t\t\toverride func getJSONValues() -> [String : Any] {\n\t\t\t\treturn [JSONDecoding.objectIdentifierKey:Test.registerName, \"One\":1]\n\t\t\t}\n\t\t}\n\n\t\tJSONDecoding.registerJSONDecodable(name: Test.registerName, creator: { return Test() })\n\n\t\tdo {\n\t\t\tlet encoded = try Test().jsonEncodedString()\n\t\t\tlet decoded = try encoded.jsonDecode() as? Test\n\n\t\t\tXCTAssert(decoded != nil)\n\n\t\t\tXCTAssert(decoded!.one == 1)\n\t\t} catch {\n\t\t\tXCTAssert(false, \"Exception \\(error)\")\n\t\t}\n\t}\n\t\n\tfunc testJSONConvertibleObject2() {\n\t\t\n\t\tclass User: JSONConvertibleObject {\n\t\t\tstatic let registerName = \"user\"\n\t\t\tvar firstName = \"\"\n\t\t\tvar lastName = \"\"\n\t\t\tvar age = 0\n\t\t\toverride func setJSONValues(_ values: [String : Any]) {\n\t\t\t\tself.firstName = getJSONValue(named: \"firstName\", from: values, defaultValue: \"\")\n\t\t\t\tself.lastName = getJSONValue(named: \"lastName\", from: values, defaultValue: \"\")\n\t\t\t\tself.age = getJSONValue(named: \"age\", from: values, defaultValue: 0)\n\t\t\t}\n\t\t\toverride func getJSONValues() -> [String : Any] {\n\t\t\t\treturn [\n\t\t\t\t\tJSONDecoding.objectIdentifierKey:User.registerName,\n\t\t\t\t\t\"firstName\":firstName,\n\t\t\t\t\t\"lastName\":lastName,\n\t\t\t\t\t\"age\":age\n\t\t\t\t]\n\t\t\t}\n\t\t}\n\t\t\n\t\t// register the class. do this once\n\t\tJSONDecoding.registerJSONDecodable(name: User.registerName, creator: { return User() })\n\t\t\n\t\t// encode and decode the object\n\t\tlet user = User()\n\t\tuser.firstName = \"Donnie\"\n\t\tuser.lastName = \"Darko\"\n\t\tuser.age = 17\n\t\t\n\t\tdo {\n\t\t\tlet encoded = try user.jsonEncodedString()\n\t\t\tguard let user2 = try encoded.jsonDecode() as? User else {\n\t\t\t\treturn XCTAssert(false, \"Invalid object \\(encoded)\")\n\t\t\t}\t\t\t\n\t\t\tXCTAssert(user.firstName == user2.firstName)\n\t\t\tXCTAssert(user.lastName == user2.lastName)\n\t\t\tXCTAssert(user.age == user2.age)\n\t\t} catch {}\n\t}\n\n\tfunc testJSONEncodeDecode() {\n\n\t\tlet srcAry: [[String:Any]] = [[\"i\": -41451, \"i2\": 41451, \"d\": -42E+2, \"t\": true, \"f\": false, \"n\": nil as String? as Any, \"a\":[1, 2, 3, 4]], [\"another\":\"one\"]]\n\t\tvar encoded = \"\"\n\t\tvar decoded: [Any]?\n\t\tdo {\n\n\t\t\tencoded = try srcAry.jsonEncodedString()\n\n\t\t} catch let e {\n\t\t\tXCTAssert(false, \"Exception while encoding JSON \\(e)\")\n\t\t\treturn\n\t\t}\n\n\t\tdo {\n\n\t\t\tdecoded = try encoded.jsonDecode() as? [Any]\n\n\t\t} catch let e {\n\t\t\tXCTAssert(false, \"Exception while decoding JSON \\(e)\")\n\t\t\treturn\n\t\t}\n\n\t\tXCTAssert(decoded != nil)\n\n\t\tlet resAry = decoded!\n\n\t\tXCTAssert(srcAry.count == resAry.count)\n\n\t\tfor index in 0..<srcAry.count {\n\n\t\t\tlet d1 = srcAry[index]\n\t\t\tlet d2 = resAry[index] as? [String:Any]\n\n\t\t\tfor (key, value) in d1 {\n\n\t\t\t\tlet value2 = d2![key]\n\n\t\t\t\tXCTAssert(value2 != nil)\n\n\t\t\t\tswitch value {\n\t\t\t\tcase let i as Int:\n\t\t\t\t\tXCTAssert(i == value2 as! Int)\n\t\t\t\tcase let d as Double:\n\t\t\t\t\tXCTAssert(d == value2 as! Double)\n\t\t\t\tcase let s as String:\n\t\t\t\t\tXCTAssert(s == value2 as! String)\n\t\t\t\tcase let s as Bool:\n\t\t\t\t\tXCTAssert(s == value2 as! Bool)\n\n\t\t\t\tdefault:\n\t\t\t\t\t()\n\t\t\t\t\t// does not go on to test sub-sub-elements\n\t\t\t\t}\n\t\t\t}\n\n\t\t}\n\t}\n    func testIntegerTypesEncode(){\n        let i8:Int8 = -12\n        let i16:Int16 = -1234\n        let i32:Int32 = -1234567890\n        let i64:Int64 = -123456789012345678\n\n        let u8:UInt8 = 12\n        let u16:UInt16 = 1234\n        let u32:UInt32 = 1234567890\n        let u64:UInt64 = 123456789012345678\n        \n        var srcDict:[String:Any] = [String:Any]()\n        var destDict:[String:Any]?\n        \n        srcDict[\"i8\"] = i8\n        srcDict[\"i16\"] = i8\n        srcDict[\"i32\"] = i8\n        srcDict[\"i64\"] = i8\n        srcDict[\"u8\"] = i8\n        srcDict[\"u16\"] = i8\n        srcDict[\"u32\"] = i8\n        srcDict[\"u64\"] = i8\n        \n        \n        var encoded = \"\"\n        \n        \n        do {\n            \n            encoded = try i8.jsonEncodedString()\n            XCTAssert(encoded == String(i8), \"Invalid result\")\n            \n        } catch let e {\n            XCTAssert(false, \"Exception while encoding i8 \\(e)\")\n            return\n        }\n\n        do {\n            \n            encoded = try i16.jsonEncodedString()\n            XCTAssert(encoded == String(i16), \"Invalid result\")\n\n        } catch let e {\n            XCTAssert(false, \"Exception while encoding i16 \\(e)\")\n            return\n        }\n\n        do {\n            \n            encoded = try i32.jsonEncodedString()\n            XCTAssert(encoded == String(i32), \"Invalid result\")\n\n        } catch let e {\n            XCTAssert(false, \"Exception while encoding i32 \\(e)\")\n            return\n        }\n\n        do {\n            \n            encoded = try i64.jsonEncodedString()\n            XCTAssert(encoded == String(i64), \"Invalid result\")\n\n        } catch let e {\n            XCTAssert(false, \"Exception while encoding i64 \\(e)\")\n            return\n        }\n\n        do {\n            \n            encoded = try u8.jsonEncodedString()\n            XCTAssert(encoded == String(u8), \"Invalid result\")\n\n        } catch let e {\n            XCTAssert(false, \"Exception while encoding u8 \\(e)\")\n            return\n        }\n        \n        do {\n            \n            encoded = try u16.jsonEncodedString()\n            XCTAssert(encoded == String(u16), \"Invalid result\")\n\n        } catch let e {\n            XCTAssert(false, \"Exception while encoding u16 \\(e)\")\n            return\n        }\n        \n        do {\n            \n            encoded = try u32.jsonEncodedString()\n            XCTAssert(encoded == String(u32), \"Invalid result\")\n\n        } catch let e {\n            XCTAssert(false, \"Exception while encoding u32 \\(e)\")\n            return\n        }\n        \n        do {\n            \n            encoded = try u64.jsonEncodedString()\n            XCTAssert(encoded == String(u64), \"Invalid result\")\n\n        } catch let e {\n            XCTAssert(false, \"Exception while encoding u64 \\(e)\")\n            return\n        }\n        \n        do {\n            encoded = \"\"\n            encoded = try srcDict.jsonEncodedString()\n            XCTAssert(encoded != \"\", \"Invalid result\")\n        } catch let e {\n            XCTAssert(false, \"Exception while encoding srcDict \\(e)\")\n        }\n\n        do {\n            destDict = try encoded.jsonDecode() as? [String:Any]\n            \n        } catch let e {\n            XCTAssert(false, \"Exception while decoding into destDict \\(e)\" )\n        }\n        \n        for (key, value) in destDict! {\n            \n            let value2 = srcDict[key]\n            XCTAssert(value2 != nil)\n            switch value2 {\n            case let i as Int8:\n                XCTAssert(value as! Int == Int(i))\n            case let i as Int16:\n                XCTAssert(value as! Int == Int(i))\n            case let i as Int32:\n                XCTAssert(value as! Int == Int(i))\n            case let i as Int64:\n                XCTAssert(value as! Int == Int(i))\n            case let i as UInt8:\n                XCTAssert(value as! Int == Int(i))\n            case let i as UInt16:\n                XCTAssert(value as! Int == Int(i))\n            case let i as UInt32:\n                XCTAssert(value as! Int == Int(i))\n            case let i as UInt64:\n                XCTAssert(value as! Int == Int(i))\n            default:\n                ()\n            }\n            \n        }\n    }\n    \n\tfunc testJSONDecodeUnicode() {\n\t\tvar decoded: [String: Any]?\n\t\tlet jsonStr = \"{\\\"emoji\\\": \\\"\\\\ud83d\\\\ude33\\\"}\"     // {\"emoji\": \"\\ud83d\\ude33\"}\n\t\tdo {\n\t\t\tdecoded = try jsonStr.jsonDecode() as? [String: Any]\n\t\t} catch let e {\n\n\t\t\tXCTAssert(false, \"Exception while decoding JSON \\(e)\")\n\t\t\treturn\n\t\t}\n\n\t\tXCTAssert(decoded != nil)\n\t\tlet value = decoded![\"emoji\"]\n\t\tXCTAssert(value != nil)\n\t\tlet emojiStr = decoded![\"emoji\"] as! String\n\t\tXCTAssert(emojiStr == \"😳\")\n\t}\n\n\tfunc testSysProcess() {\n\t\tdo {\n\t\t\tlet proc = try SysProcess(\"ls\", args:[\"-l\", \"/\"], env:[(\"PATH\", \"/usr/bin:/bin\")])\n\n\t\t\tXCTAssertTrue(proc.isOpen())\n\t\t\tXCTAssertNotNil(proc.stdin)\n\n\t\t\tlet fileOut = proc.stdout!\n\t\t\tlet data = try fileOut.readSomeBytes(count: 4096)\n\n\t\t\tXCTAssertTrue(data.count > 0)\n\n\t\t\tlet waitRes = try proc.wait()\n\n\t\t\tXCTAssert(0 == waitRes, \"\\(waitRes) \\(UTF8Encoding.encode(bytes: data))\")\n\n\t\t\tproc.close()\n\t\t} catch {\n\t\t\tXCTAssert(false, \"Exception running SysProcess test: \\(error)\")\n\t\t}\n\t}\n\t\n\tfunc testSysProcessGroup() {\n\t\tdo {\n\t\t\tlet proc = try SysProcess(\"sh\", args: [\"-c\", \"(sleep 10s &) ; (sleep 10s &) ; sleep 10s\"], env: [(\"PATH\", \"/usr/bin:/bin\")], newGroup: true)\n\t\t\t\n\t\t\tXCTAssert(proc.isOpen())\n\t\t\tXCTAssertNotEqual(-1, proc.pid)\n\t\t\tXCTAssertNotEqual(-1, proc.gid)\n\t\t\t\n\t\t\t// Ensure that the process group is different from the test process\n\t\t\t#if os(Linux)\n\t\t\t\tlet testGid = SwiftGlibc.getpgrp()\n\t\t\t#else\n\t\t\t\tlet testGid = Darwin.getpgrp()\n\t\t\t#endif\n\t\t\tXCTAssertNotEqual(testGid, proc.gid)\n\t\t\t\n\t\t\tlet savedGid = proc.gid\n\t\t\t\n\t\t\tXCTAssertTrue(try hasChildProcesses(gid: savedGid))\n\t\t\t_ = try proc.killGroup()\n\t\t\tXCTAssertFalse(try hasChildProcesses(gid: savedGid))\n\t\t} catch {\n\t\t\tXCTAssert(false, \"Exception running SysProcess group test: \\(error)\")\n\t\t}\n\t}\n\t\n\tprivate func hasChildProcesses(gid: pid_t) throws -> Bool {\n\t\tlet proc = try SysProcess(\"sh\", args: [\"-c\", \"ps -e -o pgid,comm | grep \\(gid)\"], env: [(\"PATH\", \"/usr/bin:/bin\")])\n\t\t\n\t\t_ = try proc.wait()\n\t\t\n\t\tif let bytes = try proc.stdout?.readSomeBytes(count: 4096) {\n\t\t\treturn bytes.count > 0\n\t\t} else {\n\t\t\treturn false\n\t\t}\n\t}\n\n\tfunc testStringByEncodingHTML() {\n\t\tlet src = \"<b>\\\"quoted\\\" '& ☃\"\n\t\tlet res = src.stringByEncodingHTML\n\t\tXCTAssertEqual(res, \"&lt;b&gt;&quot;quoted&quot; &#39;&amp; &#9731;\")\n\t}\n\n\tfunc testStringByEncodingURL() {\n\t\tlet src = \"This has \\\"weird\\\" characters & ßtuff\"\n\t\tlet res = src.stringByEncodingURL\n\t\tXCTAssertEqual(res, \"This%20has%20%22weird%22%20characters%20&%20%C3%9Ftuff\")\n\t}\n\n\tfunc testStringByDecodingURL() {\n\t\tlet src = \"This has \\\"weird\\\" characters & ßtuff\"\n\t\tlet mid = src.stringByEncodingURL\n\t\tguard let res = mid.stringByDecodingURL else {\n\t\t\tXCTAssert(false, \"Got nil String\")\n\t\t\treturn\n\t\t}\n\t\tXCTAssert(res == src, \"Bad URL decoding\")\n\t}\n\n\tfunc testStringByDecodingURL2() {\n\t\tlet src = \"This is badly%PWencoded\"\n\t\tlet res = src.stringByDecodingURL\n\n\t\tXCTAssert(res == nil, \"Bad URL decoding\")\n\t}\n\n\tfunc testStringByReplacingString() {\n\n\t\tlet src = \"ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ\"\n\t\tlet test = \"ABCFEDGHIJKLMNOPQRSTUVWXYZABCFEDGHIJKLMNOPQRSTUVWXYZABCFEDGHIJKLMNOPQRSTUVWXYZ\"\n\t\tlet find = \"DEF\"\n\t\tlet rep = \"FED\"\n\n\t\tlet res = src.stringByReplacing(string: find, withString: rep)\n\n\t\tXCTAssert(res == test)\n\t}\n\n\tfunc testStringByReplacingString2() {\n\n\t\tlet src = \"\"\n\t\tlet find = \"DEF\"\n\t\tlet rep = \"FED\"\n\n\t\tlet res = src.stringByReplacing(string: find, withString: rep)\n\n\t\tXCTAssert(res == src)\n\t}\n\n\tfunc testStringByReplacingString3() {\n\n\t\tlet src = \"ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ\"\n\t\tlet find = \"\"\n\t\tlet rep = \"FED\"\n\n\t\tlet res = src.stringByReplacing(string: find, withString: rep)\n\n\t\tXCTAssert(res == src)\n\t}\n\n\tfunc testStringBeginsWith() {\n\t\tlet a = \"123456\"\n\n\t\tXCTAssert(a.begins(with: \"123\"))\n\t\tXCTAssert(!a.begins(with: \"abc\"))\n\t}\n\n\tfunc testStringEndsWith() {\n\t\tlet a = \"123456\"\n\n\t\tXCTAssert(a.ends(with: \"456\"))\n\t\tXCTAssert(!a.ends(with: \"abc\"))\n\t}\n\n\tfunc testDeletingPathExtension() {\n\t\tlet path = \"/a/b/c.txt\"\n\t\tlet del = path.deletingFileExtension\n\t\tXCTAssert(\"/a/b/c\" == del)\n\t}\n\n\tfunc testGetPathExtension() {\n\t\tlet path = \"/a/b/c.txt\"\n\t\tlet ext = path.filePathExtension\n\t\tXCTAssert(\"txt\" == ext)\n\t}\n\n\tfunc testDirCreate() {\n\t\tlet path = \"/tmp/a/b/c/d/e/f/g\"\n\t\tdo {\n\t\t\ttry Dir(path).create()\n\n\t\t\tXCTAssert(Dir(path).exists)\n\n\t\t\tvar unPath = path\n\n\t\t\twhile unPath != \"/tmp\" {\n\t\t\t\ttry Dir(unPath).delete()\n\t\t\t\tunPath = unPath.deletingLastFilePathComponent\n\t\t\t}\n\t\t} catch {\n\t\t\tXCTAssert(false, \"Error while creating dirs: \\(error)\")\n\t\t}\n\t}\n\n\tfunc testDirCreateRel() {\n\t\tlet path = \"a/b/c/d/e/f/g\"\n\t\tdo {\n\t\t\ttry Dir(path).create()\n\t\t\tXCTAssert(Dir(path).exists)\n\t\t\tvar unPath = path\n\t\t\trepeat {\n\t\t\t\ttry Dir(unPath).delete()\n\n\t\t\t\t\t\t\t\t// this was killing linux on the final path component\n\t\t\t\t\t\t\t\t//unPath = unPath.stringByDeletingLastPathComponent\n\n\t\t\t\t\t\t\t\tvar splt = unPath.split(separator: \"/\").map(String.init)\n\t\t\t\t\t\t\t\tsplt.removeLast()\n\t\t\t\t\t\t\t\tunPath = splt.joined(separator: \"/\")\n\n\t\t\t} while !unPath.isEmpty\n\t\t} catch {\n\t\t\tXCTAssert(false, \"Error while creating dirs: \\(error)\")\n\t\t}\n\t}\n\n\tfunc testDirForEach() {\n\t\tlet dirs = [\"a/\", \"b/\", \"c/\"]\n\t\tdo {\n\t\t\ttry Dir(\"/tmp/a\").create()\n\t\t\tfor d in dirs {\n\t\t\t\ttry Dir(\"/tmp/a/\\(d)\").create()\n\t\t\t}\n\t\t\tvar ta = [String]()\n\t\t\ttry Dir(\"/tmp/a\").forEachEntry {\n\t\t\t\tname in\n\t\t\t\tta.append(name)\n\t\t\t}\n\t\t\tta.sort()\n\t\t\tXCTAssert(ta == dirs, \"\\(ta) == \\(dirs)\")\n\t\t\tfor d in dirs {\n\t\t\t\ttry Dir(\"/tmp/a/\\(d)\").delete()\n\t\t\t}\n\t\t\ttry Dir(\"/tmp/a\").delete()\n\t\t} catch {\n\t\t\tXCTAssert(false, \"Error while creating dirs: \\(error)\")\n\t\t}\n\t}\n\t\n\tfunc testFilePerms() {\n\t\tlet fileName = \"/tmp/\\(UUID().uuidString)\"\n\t\tlet file = File(fileName)\n\t\tdo {\n\t\t\ttry file.open(.readWrite, permissions: [.readUser, .writeUser])\n\t\t\tdefer {\n\t\t\t\tfile.delete()\n\t\t\t}\n\t\t\t\n\t\t\tlet res = file.perms.contains([.readUser, .writeUser])\n\t\t\tXCTAssert(res, \"\\(file.perms) != \\([File.PermissionMode.readUser, File.PermissionMode.writeUser])\")\n\t\t\t\n\t\t} catch {\n\t\t\tXCTAssert(false, \"Error testing file perms: \\(error)\")\n\t\t}\n\t}\n\t\n\tfunc testDirPerms() {\n\t\tlet fileName = \"/tmp/\\(UUID().uuidString)\"\n\t\tlet file = Dir(fileName)\n\t\tdo {\n\t\t\ttry file.create(perms: [.readUser, .writeUser])\n\t\t\t\n\t\t\tlet res = file.perms.contains([.readUser, .writeUser])\n\t\t\tXCTAssert(res, \"\\(file.perms) != \\([File.PermissionMode.readUser, File.PermissionMode.writeUser])\")\n\t\t\t\n\t\t\ttry file.delete()\n\t\t} catch {\n\t\t\tXCTAssert(false, \"Error testing file perms: \\(error)\")\n\t\t}\n\t}\n\t\n\tfunc testDirWorkDir() {\n\t\tlet workDir = File(\"/tmp\").realPath.replacingOccurrences(of: \"//\", with: \"/\") + \"/\"\n\t\tlet dir = Dir(workDir)\n\t\tdo {\n\t\t\ttry dir.setAsWorkingDir()\n\t\t\tlet fetch = Dir.workingDir.path\n\t\t\tXCTAssertEqual(workDir, fetch)\n\t\t} catch {\n\t\t\tXCTAssert(false, \"Error testing file perms: \\(error)\")\n\t\t}\n\t}\n\t\n\tfunc testBytesIO() {\n\t\tlet i8 = 254 as UInt8\n\t\tlet i16 = 54045 as UInt16\n\t\tlet i32 = 4160745471 as UInt32\n\t\tlet i64 = 17293541094125989887 as UInt64\n\t\t\n\t\tlet bytes = Bytes()\n\t\t\n\t\tbytes.import64Bits(from: i64)\n\t\t\t.import32Bits(from: i32)\n\t\t\t.import16Bits(from: i16)\n\t\t\t.import8Bits(from: i8)\n\t\t\n\t\tlet bytes2 = Bytes()\n\t\tbytes2.importBytes(from: bytes)\n\t\t\n\t\tXCTAssert(i64 == bytes2.export64Bits())\n\t\tXCTAssert(i32 == bytes2.export32Bits())\n\t\tXCTAssert(i16 == bytes2.export16Bits())\n\t\tbytes2.position -= MemoryLayout<UInt16>.size\n\t\tXCTAssert(i16 == bytes2.export16Bits())\n\t\tXCTAssert(bytes2.availableExportBytes == 1)\n\t\tXCTAssert(i8 == bytes2.export8Bits())\n\t}\n\t\n\tfunc testSymlink() {\n\t\tlet f1 = File(\"./foo\")\n\t\tlet f2 = File(\"./foo2\")\n\t\tdo {\n\t\t\tf2.delete()\n\t\t\ttry f1.open(.truncate)\n\t\t\ttry f1.write(string: \"test\")\n\t\t\tf1.close()\n\t\t\tdefer {\n\t\t\t\tf1.delete()\n\t\t\t\tf2.delete()\n\t\t\t}\n\t\t\t\n\t\t\tlet newF2 = try f1.linkTo(path: f2.path)\n\t\t\t\n\t\t\tXCTAssert(try newF2.readString() == \"test\")\n\t\t\tXCTAssert(newF2.isLink)\n\t\t} catch {\n\t\t\tXCTAssert(false, \"\\(error)\")\n\t\t}\n\t}\n}\n\nextension PerfectLibTests {\n\tstatic var allTests : [(String, (PerfectLibTests) -> () throws -> Void)] {\n\t\treturn [\n\t\t\t(\"testJSONConvertibleObject1\", testJSONConvertibleObject1),\n\t\t\t(\"testJSONConvertibleObject2\", testJSONConvertibleObject2),\n\t\t\t(\"testJSONEncodeDecode\", testJSONEncodeDecode),\n\t\t\t(\"testJSONDecodeUnicode\", testJSONDecodeUnicode),\n\t\t\t(\"testSysProcess\", testSysProcess),\n\t\t\t(\"testSysProcessGroup\", testSysProcessGroup),\n\t\t\t(\"testStringByEncodingHTML\", testStringByEncodingHTML),\n\t\t\t(\"testStringByEncodingURL\", testStringByEncodingURL),\n\t\t\t(\"testStringByDecodingURL\", testStringByDecodingURL),\n\t\t\t(\"testStringByDecodingURL2\", testStringByDecodingURL2),\n\t\t\t(\"testStringByReplacingString\", testStringByReplacingString),\n\t\t\t(\"testStringByReplacingString2\", testStringByReplacingString2),\n\t\t\t(\"testStringByReplacingString3\", testStringByReplacingString3),\n\n\t\t\t(\"testDeletingPathExtension\", testDeletingPathExtension),\n\t\t\t(\"testGetPathExtension\", testGetPathExtension),\n\n\t\t\t(\"testDirCreate\", testDirCreate),\n\t\t\t(\"testDirCreateRel\", testDirCreateRel),\n\t\t\t(\"testDirForEach\", testDirForEach),\n\t\t\t\n\t\t\t(\"testFilePerms\", testFilePerms),\n\t\t\t(\"testDirPerms\", testDirPerms),\n\t\t\t\n\t\t\t(\"testBytesIO\", testBytesIO),\n            (\"testIntegerTypesEncode\", testIntegerTypesEncode)\n\t\t]\n\t}\n}\n"
  },
  {
    "path": "Tests/PerfectLibTests/XCTestManifests.swift",
    "content": "//\n//  XCTestManifests.swift\n//\n//  Created by Kyle Jessup on 2015-10-19.\n//  Copyright © 2015 PerfectlySoft. All rights reserved.\n//\n//===----------------------------------------------------------------------===//\n//\n// This source file is part of the Perfect.org open source project\n//\n// Copyright (c) 2015 - 2016 PerfectlySoft Inc. and the Perfect project authors\n// Licensed under Apache License v2.0\n//\n// See http://perfect.org/licensing.html for license information\n//\n//===----------------------------------------------------------------------===//\n//\n\nimport XCTest\n\n#if !os(OSX)\npublic func allTests() -> [XCTestCaseEntry] {\n\treturn [\n\t\t\ttestCase(PerfectLibTests.allTests)\n\t]\n}\n#endif\n"
  }
]