Full Code of PerfectlySoft/Perfect for AI

master 859e696457fa cached
22 files
134.9 KB
37.3k tokens
1 requests
Download .txt
Repository: PerfectlySoft/Perfect
Branch: master
Commit: 859e696457fa
Files: 22
Total size: 134.9 KB

Directory structure:
gitextract_dd4e6amv/

├── .gitattributes
├── .gitignore
├── .jazzy.yaml
├── CODE_OF_CONDUCT.md
├── CODE_OF_CONDUCT.zh_CN.md
├── LICENSE
├── LICENSE.zh_CN
├── Package.swift
├── README.md
├── README.zh_CN.md
├── Sources/
│   └── PerfectLib/
│       ├── Bytes.swift
│       ├── Dir.swift
│       ├── File.swift
│       ├── JSONConvertible.swift
│       ├── Log.swift
│       ├── PerfectError.swift
│       ├── PerfectServer.swift
│       ├── SysProcess.swift
│       └── Utilities.swift
└── Tests/
    ├── LinuxMain.swift
    └── PerfectLibTests/
        ├── PerfectLibTests.swift
        └── XCTestManifests.swift

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitattributes
================================================
Sources/LinuxBridge/* linguist-vendored
Sources/OpenSSL/* linguist-vendored
Sources/cURL/* linguist-vendored
Xcode/PerfectLib/* linguist-vendored


================================================
FILE: .gitignore
================================================
# Xcode
#
build/
*.pbxuser
!default.pbxuser
*.mode1v3
!default.mode1v3
*.mode2v3
!default.mode2v3
*.perspectivev3
!default.perspectivev3
xcuserdata
*.xccheckout
*.moved-aside
DerivedData
*.hmap
*.ipa
*.xcuserstate
*.xcscmblueprint

# CocoaPods
#
# We recommend against adding the Pods directory to your .gitignore. However
# you should judge for yourself, the pros and cons are mentioned at:
# http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control
#
# Pods/

# Carthage
#
# Add this line if you want to avoid checking in source code from Carthage dependencies.
# Carthage/Checkouts

Carthage/Build

*.d

*.o

*.swiftdeps

*.swiftdoc

*.swiftmodule

*.so

*.DS_Store

# Perfect binaries
PerfectServer/perfectserverfcgi
PerfectServer/perfectserverhttp

# SwiftPM
.build/
Packages/
PerfectLib.xcodeproj/
docs/


================================================
FILE: .jazzy.yaml
================================================
module: PerfectLib
author: PerfectlySoft
author_url: https://perfect.org
github_url: https://github.com/PerfectlySoft/Perfect
copyright: '© 2016 PerfectlySoft Inc. and the Perfect project authors'
theme: fullwidth
xcodebuild_arguments: [-target, PerfectLib, -toolchain, org.swift.3020160620a]
clean: true


================================================
FILE: CODE_OF_CONDUCT.md
================================================
# Contributor Covenant Code of Conduct

## Our Pledge

In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to making participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, gender identity and expression, level of experience,
nationality, personal appearance, race, religion, or sexual identity and
orientation.

## Our Standards

Examples of behavior that contributes to creating a positive environment
include:

* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members

Examples of unacceptable behavior by participants include:

* The use of sexualized language or imagery and unwelcome sexual attention or
advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic
  address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a
  professional setting

## Our Responsibilities

Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.

Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.

## Scope

This Code of Conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community. Examples of
representing a project or community include using an official project e-mail
address, posting via an official social media account, or acting as an appointed
representative at an online or offline event. Representation of a project may be
further defined and clarified by project maintainers.

## Enforcement

Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the project team at [mailto:info@perfect.org]. All
complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. The project team is
obligated to maintain confidentiality with regard to the reporter of an incident.
Further details of specific enforcement policies may be posted separately.

Project maintainers who do not follow or enforce the Code of Conduct in good
faith may face temporary or permanent repercussions as determined by other
members of the project's leadership.

## Attribution

This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
available at [http://contributor-covenant.org/version/1/4][version]

[homepage]: http://contributor-covenant.org
[version]: http://contributor-covenant.org/version/1/4/


================================================
FILE: CODE_OF_CONDUCT.zh_CN.md
================================================
# 贡献者行为规范

## 我们的承诺

为了实现一个开放、和谐的软件开发环境,作为该软件的贡献者和版本维护者,我们保证在社区参与项目的过
程中,对所有人一视同仁。在社区中,任何人,无论年龄、身材、长相,或者身体是否有缺陷;无论种族、
性别和学历出身;无论国籍、血统、宗教信仰和任何性取向,我们都承诺避免任何骚扰和歧视。

## 我们的标准

为创造良好的开发环境,我们鼓励:

* 采用友好的语言,秉持包容的态度
* 充分尊重不同的观点和对问题的不同看法
* 耐心接纳建设性批评
* 关注于为社区未来提高产品价值
* 对其他社区成员保持同情心

无法接受的行为包括:

* 淫秽言语或低级下流的措辞
* 恶意评论,针对人身和政治观点的言语攻击
* 公开或私下的言语骚扰
* 未经许可公布他人隐私,包括实际住址或电子地址
* 从专业角度考虑的其他不正当行为

## 我们的责任

项目管理维护人员有义务澄清本行为规范,并针对任何不当行为采取必要措施进行纠正。

项目管理维护人员有权并有义务删除、修改、抵制任何不符合本行为规范的评论、代码内容、文字提交和各类
报告P,也有权因其各种如恐吓、侵犯或者伤害的不当行为暂时或永久屏蔽违规账号。

## 适用范围

本行为规范适用于任何本项目或本项目所在社区空间内的公众行为,如公众邮件账号、公众社交媒体账号,
或者用于在线和离线活动中的委托代表。项目管理维护人员可以根据需要澄清或委派项目代表。

## 加强措施

任何不当言论、骚扰和其他不可接受的不当行为都可以通过[mailto:info@perfect.org]进行举报。所有
投诉均会被审理并根据需要进行调查。项目团队有义务为举报者身份保密。更多加强措施会在其他文件中单独
公开。

对于不遵守本行为规范的项目管理人员,本项目其他领导成员可能会临时或永久取消其管理权。

## 文件归属

本文节选自 [Contributor Covenant][homepage], version 1.4,
可从以下网址查看: [http://contributor-covenant.org/version/1/4][version]

[homepage]: http://contributor-covenant.org
[version]: http://contributor-covenant.org/version/1/4/


================================================
FILE: LICENSE
================================================
                                 Apache License
                           Version 2.0, January 2004
                        http://www.apache.org/licenses/

   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

   1. Definitions.

      "License" shall mean the terms and conditions for use, reproduction,
      and distribution as defined by Sections 1 through 9 of this document.

      "Licensor" shall mean the copyright owner or entity authorized by
      the copyright owner that is granting the License.

      "Legal Entity" shall mean the union of the acting entity and all
      other entities that control, are controlled by, or are under common
      control with that entity. For the purposes of this definition,
      "control" means (i) the power, direct or indirect, to cause the
      direction or management of such entity, whether by contract or
      otherwise, or (ii) ownership of fifty percent (50%) or more of the
      outstanding shares, or (iii) beneficial ownership of such entity.

      "You" (or "Your") shall mean an individual or Legal Entity
      exercising permissions granted by this License.

      "Source" form shall mean the preferred form for making modifications,
      including but not limited to software source code, documentation
      source, and configuration files.

      "Object" form shall mean any form resulting from mechanical
      transformation or translation of a Source form, including but
      not limited to compiled object code, generated documentation,
      and conversions to other media types.

      "Work" shall mean the work of authorship, whether in Source or
      Object form, made available under the License, as indicated by a
      copyright notice that is included in or attached to the work
      (an example is provided in the Appendix below).

      "Derivative Works" shall mean any work, whether in Source or Object
      form, that is based on (or derived from) the Work and for which the
      editorial revisions, annotations, elaborations, or other modifications
      represent, as a whole, an original work of authorship. For the purposes
      of this License, Derivative Works shall not include works that remain
      separable from, or merely link (or bind by name) to the interfaces of,
      the Work and Derivative Works thereof.

      "Contribution" shall mean any work of authorship, including
      the original version of the Work and any modifications or additions
      to that Work or Derivative Works thereof, that is intentionally
      submitted to Licensor for inclusion in the Work by the copyright owner
      or by an individual or Legal Entity authorized to submit on behalf of
      the copyright owner. For the purposes of this definition, "submitted"
      means any form of electronic, verbal, or written communication sent
      to the Licensor or its representatives, including but not limited to
      communication on electronic mailing lists, source code control systems,
      and issue tracking systems that are managed by, or on behalf of, the
      Licensor for the purpose of discussing and improving the Work, but
      excluding communication that is conspicuously marked or otherwise
      designated in writing by the copyright owner as "Not a Contribution."

      "Contributor" shall mean Licensor and any individual or Legal Entity
      on behalf of whom a Contribution has been received by Licensor and
      subsequently incorporated within the Work.

   2. Grant of Copyright License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      copyright license to reproduce, prepare Derivative Works of,
      publicly display, publicly perform, sublicense, and distribute the
      Work and such Derivative Works in Source or Object form.

   3. Grant of Patent License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      (except as stated in this section) patent license to make, have made,
      use, offer to sell, sell, import, and otherwise transfer the Work,
      where such license applies only to those patent claims licensable
      by such Contributor that are necessarily infringed by their
      Contribution(s) alone or by combination of their Contribution(s)
      with the Work to which such Contribution(s) was submitted. If You
      institute patent litigation against any entity (including a
      cross-claim or counterclaim in a lawsuit) alleging that the Work
      or a Contribution incorporated within the Work constitutes direct
      or contributory patent infringement, then any patent licenses
      granted to You under this License for that Work shall terminate
      as of the date such litigation is filed.

   4. Redistribution. You may reproduce and distribute copies of the
      Work or Derivative Works thereof in any medium, with or without
      modifications, and in Source or Object form, provided that You
      meet the following conditions:

      (a) You must give any other recipients of the Work or
          Derivative Works a copy of this License; and

      (b) You must cause any modified files to carry prominent notices
          stating that You changed the files; and

      (c) You must retain, in the Source form of any Derivative Works
          that You distribute, all copyright, patent, trademark, and
          attribution notices from the Source form of the Work,
          excluding those notices that do not pertain to any part of
          the Derivative Works; and

      (d) If the Work includes a "NOTICE" text file as part of its
          distribution, then any Derivative Works that You distribute must
          include a readable copy of the attribution notices contained
          within such NOTICE file, excluding those notices that do not
          pertain to any part of the Derivative Works, in at least one
          of the following places: within a NOTICE text file distributed
          as part of the Derivative Works; within the Source form or
          documentation, if provided along with the Derivative Works; or,
          within a display generated by the Derivative Works, if and
          wherever such third-party notices normally appear. The contents
          of the NOTICE file are for informational purposes only and
          do not modify the License. You may add Your own attribution
          notices within Derivative Works that You distribute, alongside
          or as an addendum to the NOTICE text from the Work, provided
          that such additional attribution notices cannot be construed
          as modifying the License.

      You may add Your own copyright statement to Your modifications and
      may provide additional or different license terms and conditions
      for use, reproduction, or distribution of Your modifications, or
      for any such Derivative Works as a whole, provided Your use,
      reproduction, and distribution of the Work otherwise complies with
      the conditions stated in this License.

   5. Submission of Contributions. Unless You explicitly state otherwise,
      any Contribution intentionally submitted for inclusion in the Work
      by You to the Licensor shall be under the terms and conditions of
      this License, without any additional terms or conditions.
      Notwithstanding the above, nothing herein shall supersede or modify
      the terms of any separate license agreement you may have executed
      with Licensor regarding such Contributions.

   6. Trademarks. This License does not grant permission to use the trade
      names, trademarks, service marks, or product names of the Licensor,
      except as required for reasonable and customary use in describing the
      origin of the Work and reproducing the content of the NOTICE file.

   7. Disclaimer of Warranty. Unless required by applicable law or
      agreed to in writing, Licensor provides the Work (and each
      Contributor provides its Contributions) on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
      implied, including, without limitation, any warranties or conditions
      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
      PARTICULAR PURPOSE. You are solely responsible for determining the
      appropriateness of using or redistributing the Work and assume any
      risks associated with Your exercise of permissions under this License.

   8. Limitation of Liability. In no event and under no legal theory,
      whether in tort (including negligence), contract, or otherwise,
      unless required by applicable law (such as deliberate and grossly
      negligent acts) or agreed to in writing, shall any Contributor be
      liable to You for damages, including any direct, indirect, special,
      incidental, or consequential damages of any character arising as a
      result of this License or out of the use or inability to use the
      Work (including but not limited to damages for loss of goodwill,
      work stoppage, computer failure or malfunction, or any and all
      other commercial damages or losses), even if such Contributor
      has been advised of the possibility of such damages.

   9. Accepting Warranty or Additional Liability. While redistributing
      the Work or Derivative Works thereof, You may choose to offer,
      and charge a fee for, acceptance of support, warranty, indemnity,
      or other liability obligations and/or rights consistent with this
      License. However, in accepting such obligations, You may act only
      on Your own behalf and on Your sole responsibility, not on behalf
      of any other Contributor, and only if You agree to indemnify,
      defend, and hold each Contributor harmless for any liability
      incurred by, or claims asserted against, such Contributor by reason
      of your accepting any such warranty or additional liability.

   END OF TERMS AND CONDITIONS

   APPENDIX: How to apply the Apache License to your work.

      To apply the Apache License to your work, attach the following
      boilerplate notice, with the fields enclosed by brackets "{}"
      replaced with your own identifying information. (Don't include
      the brackets!)  The text should be enclosed in the appropriate
      comment syntax for the file format. We also recommend that a
      file or class name and description of purpose be included on the
      same "printed page" as the copyright notice for easier
      identification within third-party archives.

   Copyright {yyyy} {name of copyright owner}

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.


================================================
FILE: LICENSE.zh_CN
================================================
Apache许可证
2.0版 2004年1月
http://www.apache.org/licenses/

关于使用、复制和分发的条款

定义
"许可证"是指根据本文件第1到第9部分关于使用、复制和分发的条款。

"许可证颁发者"是指版权所有者或者由版权所有者授权许可证的实体。

"法律实体"是指实施实体和进行控制的所有其它实体受该实体控制,或者受该实体集中控制。根据此定义,"控制"是指(i)让无论是否签订协议的上述实体,进行指导或管理的直接权利或间接权利,或者(ii)拥有百分之五十(50%)或以上已发行股票的所有者,或者(iii)上述实体的实权所有者。

"用户"(或"用户的")是指行使本许可证所授予权限的个人或法律实体。

"源程序"形式是指对包括但不限于软件源代码、文件源程序和配置文件进行修改的首选形式。

"目标"形式是指对源程序形式进行机械转换或翻译的任何形式,包括但不限于对编译的目标代码,生成的文件以及转换为其它媒体类型。

"作品"是指根据本许可证所制作的源程序形式或目标形式的著作,在著作中包含的或附加的版权通知(在下面附录中提供了一个示例)。

"衍生作品"是指基于作品(或从作品衍生而来)的源程序形式或目标形式的任何作品,以及编辑修订、注释、详细描述或其它修订等构成原创著作作品的整体。根据本许可证,衍生作品不得包括与作品及其衍生作品分离之作品,或仅与作品及其衍生作品的接口相链接(或按名称结合)之作品。

"贡献"是指任何著作作品,包括作品的原始版本和对该作品或衍生作品所做的任何修订或补充,意在提交给许可证颁发者以让版权所有者或代表版权所有者的授权个人或法律实体包含在其作品中。根据此定义,"提交"一词表示发送给许可证颁发者或其代表人,任何电子的、口头的或书面的交流信息形式,包括但不限于在由许可证颁发者或者代表其管理的电子邮件清单、源代码控制系统、以及发布跟踪系统上为讨论和提高作品的交流,但不包括由版权所有者以书面形式明显标注或指定为"非贡献"的交流活动。

"贡献者"是指许可证颁发者和代表从许可证颁发者接受之贡献的并随后包含在作品之贡献中的任何个人或法律实体。

版权许可证的授予。根据本许可证的条款,每个贡献者授予用户永久性的、全球性的、非专有性的、免费的、无版权费的、不可撤销的版权许可证以源程序形式或目标形式复制、准备衍生作品、公开显示、公开执行、授予分许可证、以及分发作品和这样的衍生作品。
专利许可证的授予。根据本许可证的条款,每个贡献者授予用户永久性的、全球性的、非专有性的、免费的、无版权费的、不可撤销的(除在本部分进行说明)专利许可证对作品进行制作、让人制作、使用、提供销售、销售、进口和其它转让,且这样的许可证仅适用于在所递交作品的贡献中因可由单一的或多个这样的贡献者授予而必须侵犯的申请专利。如果用户对任何实体针对作品或作品中所涉及贡献提出因直接性或贡献性专利侵权而提起专利法律诉讼(包括交互诉讼请求或反索赔),那么根据本许可证,授予用户针对作品的任何专利许可证将在提起上述诉讼之日起终止。
重新分发。用户可在任何媒介中复制和分发作品或衍生作品之副本,无论是否修订,还是以源程序形式或目标形式,条件是用户需满足下列条款:
用户必须为作品或衍生作品的任何其他接收者提供本许可证的副本;并且
用户必须让任何修改过的文件附带明显的通知,声明用户已更改文件;并且
用户必须从作品的源程序形式中保留衍生作品源程序形式的用户所分发的所有版权、专利、商标和属性通知,但不包括不属于衍生作品任何部分的类似通知;并且
如果作品将"通知"文本文件包括为其分发作品的一部分,那么用户分发的任何衍生作品中须至少在下列地方之一包括,在这样的通知文件中所包含的属性通知的可读副本,但不包括那些不属于衍生作品任何部分的通知:在作为衍生作品一部分而分发的通知文本文件中;如果与衍生作品一起提供则在源程序形式或文件中;或者通常作为第三方通知出现的时候和地方,在衍生作品中产生的画面中。通知文件的内容仅供信息提供,并未对许可证进行修改。用户可在其分发的衍生作品中在作品的通知文本后或作为附录添加自己的属性通知,条件是附加的属性通知不得构成修改本许可证。
用户可以为自身所做出的修订添加自己的版权声明并可对自身所做出修订内容或为这样的衍生作品作为整体的使用、复制或分发提供附加或不同的条款,条件是用户对作品的使用、复制和分发必须符合本许可证中声明的条款。

贡献的提交。除非用户明确声明,在作品中由用户向许可证颁发者的提交若要包含在贡献中,必须在无任何附加条款下符合本许可证的条款。尽管上面如此规定,执行许可证颁发者有关贡献的条款时,任何情况下均不得替代或修改任何单独许可证协议的条款。
商标。本许可证并未授予用户使用许可证颁发者的商号、商标、服务标记或产品名称,除非将这些名称用于合理性和惯例性描述作品起源和复制通知文件的内容时。
保证否认条款。除非因适用法律需要或书面同意,许可证颁发者以"按原样"基础提供作品(并且每个贡献者提供其贡献),无任何明示的或暗示的保证或条件,包括但不限于关于所有权、不侵权、商品适销性、或适用性的保证或条件。用户仅对使用或重新分发作品的正确性负责,并需承担根据本许可证行使权限时的任何风险。
责任限制条款。在任何情况下并根据任何法律,无论是因侵权(包括过失)或根据合同,还是其它原因,除非根据适用法律需要(例如故意行为和重大过失行为)或经书面同意,即使贡献者事先已被告知发生损害的可能性,任何贡献者不就用户因使用本许可证或不能使用或无法使用作品(包括但不限于商誉损失、停工、计算机失效或故障,或任何商业损坏或损失)而造成的损失,包括直接的、非直接的、特殊的、意外的或间接的字符损坏而负责。
接受保证或附加责任。重新分发作品或及其衍生作品时,用户可选择提供或为符合本许可证承担之支持、担保、赔偿或其它职责义务和/或权利而收取费用。但是,在承担上述义务时,用户只可代表用户本身和用户本身责任来执行,无需代表任何其它贡献者,并且用户仅可保证、防护并保持每个贡献者不受任何因此而产生的责任或对因用户自身承担这样的保证或附加责任而对这样的贡献者所提出的索赔。
条款结束

附录:如何向用户作品中应用Apache许可证。

若要向用户作品应用Apache许可证,请附加下列样本通知,将括号"[]"中的字段以用户自身的区分信息来替换(但不包括括号)。文本必须以文件格式适当的注释句法包含在其中。另外建议将文件名或类别名以及目的说明包含在相同的"打印页"上作为版权通知,以更加容易的区分出第三方档案。

版权所有[yyyy][版权所有者的名称]

根据2.0版本Apache许可证("许可证")授权;
根据本许可证,用户可以不使用此文件。
用户可从下列网址获得许可证副本:

http://www.apache.org/licenses/LICENSE-2.0

除非因适用法律需要或书面同意,
根据许可证分发的软件是基于"按原样"基础提供,
无任何明示的或暗示的保证或条件。
详见根据许可证许可下,特定语言的管辖权限和限制。


================================================
FILE: Package.swift
================================================
// swift-tools-version:5.1
//
//  Package.swift
//  PerfectLib
//
//  Created by Kyle Jessup on 3/22/16.
//	Copyright (C) 2016 PerfectlySoft, Inc.
//
//===----------------------------------------------------------------------===//
//
// This source file is part of the Perfect.org open source project
//
// Copyright (c) 2015 - 2016 PerfectlySoft Inc. and the Perfect project authors
// Licensed under Apache License v2.0
//
// See http://perfect.org/licensing.html for license information
//
//===----------------------------------------------------------------------===//
//

import PackageDescription

#if os(Linux)
let package = Package(
	name: "PerfectLib",
	products: [
		.library(name: "PerfectLib", targets: ["PerfectLib"])
	],
	dependencies: [.package(url: "https://github.com/PerfectlySoft/Perfect-LinuxBridge.git", from: "3.0.0")],
	targets: [
		.target(name: "PerfectLib", dependencies: ["LinuxBridge"]),
		.testTarget(name: "PerfectLibTests", dependencies: ["PerfectLib"])
	]
)
#else
let package = Package(
	name: "PerfectLib",
	platforms: [
		.macOS(.v10_15)
	],
	products: [
		.library(name: "PerfectLib", targets: ["PerfectLib"])
	],
	dependencies: [],
	targets: [
		.target(name: "PerfectLib", dependencies: []),
		.testTarget(name: "PerfectLibTests", dependencies: ["PerfectLib"])
	]
)
#endif


================================================
FILE: README.md
================================================
# Perfect: Server-Side Swift [简体中文](README.zh_CN.md)
<p align="center">
    <a href="http://perfect.org/get-involved.html" target="_blank">
        <img src="http://perfect.org/assets/github/perfect_github_2_0_0.jpg" alt="Get Involed with Perfect!" width="854" />
    </a>
</p>

<p align="center">
    <a href="https://developer.apple.com/swift/" target="_blank">
        <img src="https://img.shields.io/badge/Swift-5.2-orange.svg?style=flat" alt="Swift 5.2">
    </a>
    <a href="https://developer.apple.com/swift/" target="_blank">
        <img src="https://img.shields.io/badge/Platforms-OS%20X%20%7C%20Linux%20-lightgray.svg?style=flat" alt="Platforms macOS | Linux">
    </a>
    <a href="http://perfect.org/licensing.html" target="_blank">
        <img src="https://img.shields.io/badge/License-Apache-lightgrey.svg?style=flat" alt="License Apache">
    </a>
</p>

## Perfect: Server-Side Swift

Perfect 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.

Perfect 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.

This guide is designed for developers at all levels of experience to get Perfect up and running quickly.

## Working with Perfect

### Compatibility with Swift

The master branch of this project currently compiles with **Xcode 11** or the **Swift 5** toolchain on Ubuntu.

### Getting Started

[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.

### Documentation
[Get started working with Perfect](https://github.com/PerfectlySoft/PerfectDocs), deploy your apps, and find more detailed help by consulting our reference library.

We 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.

### Community
We 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:

[Slack](http://perfect.ly/) | [Twitter](https://twitter.com/perfectlysoft)

### Deployment

Your 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.

### Samples, Examples, and Tutorials

Our 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:

- [WebSockets Server](https://github.com/PerfectExamples/PerfectExample-WebSocketsServer)
- [URL Routing](https://github.com/PerfectExamples/PerfectExample-URLRouting)
- [Upload Enumerator](https://github.com/PerfectExamples/PerfectExample-UploadEnumerator)

There are [many more examples](https://github.com/PerfectExamples) you can explore. Please share yours!

## Core Perfect Modules

Perfect project is divided into several repositories to make it easy for you to find, download, and install the components you need:

- [Perfect](https://github.com/PerfectlySoft/Perfect) – This repository contains the core PerfectLib and will continue to be the main landing point for the project
- [Perfect Docs](https://github.com/PerfectlySoft/PerfectDocs) – Contains all API reference-related material


### Examples

- [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
- [Perfect Examples](https://github.com/PerfectExamples) - All the Perfect example projects


### DataSources


- [Perfect Redis](https://github.com/PerfectlySoft/Perfect-Redis) - The Redis database connector
- [Perfect SQLite](https://github.com/PerfectlySoft/Perfect-SQLite) - SQLite3 database connector
- [Perfect PostgreSQL](https://github.com/PerfectlySoft/Perfect-PostgreSQL) - PostgreSQL database connector
- [Perfect MySQL](https://github.com/PerfectlySoft/Perfect-MySQL) - MySQL database connector
- [Perfect MongoDB](https://github.com/PerfectlySoft/Perfect-MongoDB) - MongoDB database connector
- [Perfect FileMaker](https://github.com/PerfectlySoft/Perfect-FileMaker) - FileMaker Server database connector

### Utilities

- [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
- [Perfect XML](https://github.com/PerfectlySoft/Perfect-XML) - DOM Core level 2 read-only APIs and XPath support
- [Perfect HTTP Server](https://github.com/PerfectlySoft/Perfect-HTTPServer) - HTTP 1.1 server for Perfect
- [Perfect Mustache](https://github.com/PerfectlySoft/Perfect-Mustache) - Mustache template support for Perfect
- [Perfect CURL](https://github.com/PerfectlySoft/Perfect-CURL) - cURL support for Perfect
- [Perfect WebSockets](https://github.com/PerfectlySoft/Perfect-WebSockets) - WebSockets support for Perfect
- [Perfect Zip](https://github.com/PerfectlySoft/Perfect-Zip) - provides simple zip and unzip functionality
- [Perfect Notifications](https://github.com/PerfectlySoft/Perfect-Notifications) - provides support for Apple Push Notification Service (APNS).

## More about Perfect

Perfect 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).

Perfect 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.

Feel free to use your favourite JSON or templating systems, etc.

### Join and Contribute to the Community

The Swift-Perfect developer community is vital to improving Perfect and supporting one another.  

You 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.

If 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.

### Code of Conduct
The 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.

Please 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.

We 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.

The 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.


================================================
FILE: README.zh_CN.md
================================================
# Perfect:Swift 语言服务器端软件框架 [English](README.md)
<p align="center">
    <a href="http://perfect.org/get-involved.html" target="_blank">
        <img src="http://perfect.org/assets/github/perfect_github_2_0_0.jpg" alt="Get Involed with Perfect!" width="854" />
    </a>
</p>

<p align="center">
    <a href="https://developer.apple.com/swift/" target="_blank">
        <img src="https://img.shields.io/badge/Swift-5.2-orange.svg?style=flat" alt="Swift 5.2">
    </a>
    <a href="https://developer.apple.com/swift/" target="_blank">
        <img src="https://img.shields.io/badge/Platforms-OS%20X%20%7C%20Linux%20-lightgray.svg?style=flat" alt="Platforms OS X | Linux">
    </a>
    <a href="http://perfect.org/licensing.html" target="_blank">
        <img src="https://img.shields.io/badge/License-Apache-lightgrey.svg?style=flat" alt="License Apache">
    </a>
</p>

## Perfect:Swift 语言服务器端软件框架

Perfect是一组完整、强大的工具箱、软件框架体系和Web应用服务器,可以在Linux、iOS和macOS (OS X)上使用。该软件体系为Swift工程师量身定制了一整套用于开发轻量、易维护、规模可扩展的Web应用及其它REST服务的解决方案,这样Swift工程师就可以实现同时在服务器和客户端上采用同一种语言开发软件项目。

Perfect内建整套工具集,因为无论是客户端还是服务器都能够在此基础之上用同一种计算机语言Swift进行程序开发,因此能够为软件工程师大幅提高工作效率。在全球目前众多的服务器端框架体系和工具箱产品之中,Perfect目前已经成为许多iTunes在线应用程序的可靠后台应用。

无论您是资深程序员还是入门级的软件工程师,本文都能够帮助您快速启动Perfect实现服务器项目开发运行。

## 使用Perfect

### 快速上手

[在线教程(简体中文)](https://github.com/PerfectlySoft/PerfectDocs/blob/master/guide.zh_CN/gettingStarted.md) 能够帮助您快速开始使用Perfect。该指南包括了如何使用Perfect的几个典型例子。

### 文档
[Perfect帮助文档(简体中文)](https://github.com/PerfectlySoft/PerfectDocs) 如何部署应用程序、如何查找详细文档和帮助。

我们欢迎所有贡献以及对Perfect文档提高的宝贵意见。我们欢迎您为Perfect付出宝贵的支持。如果您发现了任何文字或者内容有错误,或者有任何建议,请[提交一个代码上传请求,或在JIRA上报告问题](http://jira.perfect.org:8080/servicedesk/customer/portal/1/user/login?destination=portal%2F1).

### 社区
我们总会需要您的帮助。如果您真的有想法,不妨加入我们的Perfect支持社区:


[Slack](http://perfect.ly/) | [Twitter](https://twitter.com/perfectlysoft)

### 部署

目前,部署Perfect的方式可以选择[Docker](https://hub.docker.com/r/perfectlysoft/ubuntu/)和[Heroku](https://github.com/PerfectlySoft/Perfect-Heroku-Buildpack)。我们强烈推荐使用这种方式进行部署,因为这些部署方式是通过最新Swift 3.0 和 Perfect 2.0编译完成的。

### 教程和案例

我们的资源库一直在随着社区成员的加入而不断增长,[Swift-Perfect开发社区有许多源程序共分享](https://github.com/PerfectExamples),都是建立在Perfect程序框架之上。典型例子包括:

- [WebSockets 服务器](https://github.com/PerfectlySoft/PerfectExample-WebSocketsServer)
- [URL 路由](https://github.com/PerfectlySoft/PerfectExample-URLRouting)
- [文件上传](https://github.com/PerfectlySoft/PerfectExample-UploadEnumerator)

[更多例子敬请关注!](https://github.com/PerfectlySoft/PerfectExamples)

[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).

## 核心 Perfect 模块

Perfect 项目由若干代码资源库构成,便于您按需查找、下载和安装必要的组件:

- [Perfect](https://github.com/PerfectlySoft/Perfect):核心的程序库和基础软件框架
- [Perfect Docs](https://github.com/PerfectlySoft/PerfectDocs):所有必要的程序文档和帮助内容


### 参考和样例

- [Perfect 模板](https://github.com/PerfectlySoft/PerfectTemplate):一个使用SPM软件包管理器快速上手的入门项目,能够编译为一个独立运行的HTTP服务器。该代码资源非常适合基于Perfect的项目就此开始开发过程。
- [Perfect 样例](https://github.com/PerfectExamples):所有Perfect 项目的典型样例


### 数据源


- [Perfect Redis](https://github.com/PerfectlySoft/Perfect-Redis):Redis 数据库连接工具
- [Perfect SQLite](https://github.com/PerfectlySoft/Perfect-SQLite):SQLite3 数据库连接工具
- [Perfect PostgreSQL](https://github.com/PerfectlySoft/Perfect-PostgreSQL):PostgreSQL 数据库连接工具
- [Perfect MySQL](https://github.com/PerfectlySoft/Perfect-MySQL):MySQL 数据库连接工具
- [Perfect MongoDB](https://github.com/PerfectlySoft/Perfect-MongoDB):MongoDB 数据库连接工具
- [Perfect FileMaker](https://github.com/PerfectlySoft/Perfect-FileMaker):FileMaker 数据库连接工具

### 工具集

- [Perfect FastCGI Apache 2.4](https://github.com/PerfectlySoft/Perfect-FastCGI-Apache2.4) - Apache 2.4 FastCGI 模块。如果您使用FastCGI用于基础Web服务,请使用该模块
- [Perfect XML](https://github.com/PerfectlySoft/Perfect-XML) - DOM文档对象二级核心只读函数库和XPath路径支持
- [Perfect HTTP Server](https://github.com/PerfectlySoft/Perfect-HTTPServer) - HTTP 1.1标准的 Perfect服务器
- [Perfect Mustache](https://github.com/PerfectlySoft/Perfect-Mustache) - Mustache静态模板支持
- [Perfect CURL](https://github.com/PerfectlySoft/Perfect-CURL) - cURL网页传输支持
- [Perfect WebSockets](https://github.com/PerfectlySoft/Perfect-WebSockets) - 网络套接字WebSockets支持
- [Perfect Zip](https://github.com/PerfectlySoft/Perfect-Zip) - 提供简单的zip压缩和解压缩功能
- [Perfect Notifications](https://github.com/PerfectlySoft/Perfect-Notifications) - 提供苹果消息推送服务支持(APNS)

## 更多内容

Perfect 可以作为一个独立的[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)处理页面。

Perfect是一个完全异步、高性能的网络引擎,并且能够为互联网服务提供大吞吐量控制。该软件体系支持安全套接字(SSL)加密,并且封装了一系列互联网服务器通用的特性,比如[WebSockets](https://github.com/PerfectlySoft/Perfect-WebSockets) 和 [iOS消息推送](https://github.com/PerfectlySoft/Perfect-Notifications)。然而,您的开发可以不必受限于这些选项。

请根据您自己的喜好使用JSON或者其他的模板系统,等等。

### 加入我们的开发社区并贡献自己的力量

Swift-Perfect开发者社区是改进Perfect产品并实现客户支持的关键。

在社区里,您可以通过加入[Perfect Slack 频道](http://perfect.ly)和[Perfect Gitter 频道](https://gitter.im/PerfectlySoft/Perfect)互相帮助、分享技术、互相学习和研究诀窍。任何一种贡献方式我们都非常欢迎:问题汇报、文档更新、补丁修复、编写案例、分享项目或者任何编程窍门,我们相信这些都能够极大地帮助我们的Swift-Perfect社区。

如果您希望分享一下您的项目、教程或者视频,请将URL共享到我们的推特或者GitHub账号:[Perfect 推特](https://twitter.com/perfectlysoft)。之后我们的Perfect团队会继续推广。

### 行为规范
Perfect团队欢迎所有不同种族、国际、不同年龄、性别、身残志坚、不同学历出身、不同宗教信仰的人为我们的Perfect项目作出贡献。我们承诺为所有项目和公众在线/离线空间提供一个开放、祥和、互相尊重、共同工作的环境。

如果您发现有任何违反上述[行为规范](https://github.com/PerfectlySoft/Perfect/blob/master/CODE_OF_CONDUCT.zh_CN.md)的行为,请[给我们写邮件](mailto:info@perfect.org)。Perfect团队承诺致力于维护上述价值观念以确保所有参与者和用户都能实现对Perfect项目的充分开放的自由使用、自由评论和自由贡献,不需要对任何恐吓而害怕和妥协。

我们会调查任何不当行为与不当言论的投诉,同时我们会对检举人身份保密,便于对各种违法行为进行举报。我们不会容忍在Swift-Perfect社区内的任何直接或间接的骚扰或歧视,并会针对各类不当行为采取适度、公平的纠正措施。

Perfect团队有权删除、修改或拒绝任何不符合我们行为规范的各种言论、代码、版本或问题报告。


================================================
FILE: Sources/PerfectLib/Bytes.swift
================================================
//
//  Bytes.swift
//  PerfectLib
//
//  Created by Kyle Jessup on 7/7/15.
//	Copyright (C) 2015 PerfectlySoft, Inc.
//
//===----------------------------------------------------------------------===//
//
// This source file is part of the Perfect.org open source project
//
// Copyright (c) 2015 - 2016 PerfectlySoft Inc. and the Perfect project authors
// Licensed under Apache License v2.0
//
// See http://perfect.org/licensing.html for license information
//
//===----------------------------------------------------------------------===//
//

/// A Bytes object represents an array of UInt8 and provides various utilities for importing and exporting values into and out of that array.
/// The object maintains a position marker which is used to denote the position from which new export operations proceed.
/// An export will advance the position by the appropriate amount.
public final class Bytes {
	
	/// The position from which new export operations begin.
	public var position = 0
	/// The underlying UInt8 array
	public var data: [UInt8]
	
	/// Indicates the number of bytes which may be successfully exported
	public var availableExportBytes: Int { return data.count - position }
	
	/// Create an empty Bytes object
	public init() {
		data = [UInt8]()
	}
	
	/// Initialize with existing bytes
	public init(existingBytes: [UInt8]) {
		data = existingBytes
	}
	
	// -- IMPORT
	/// Imports one UInt8 value appending it to the end of the array
	/// - returns: The Bytes object
    @discardableResult
	public func import8Bits(from frm: UInt8) -> Bytes {
		data.append(frm)
		return self
	}
	
	/// Imports one UInt16 value appending it to the end of the array
	/// - returns: The Bytes object
    @discardableResult
	public func import16Bits(from frm: UInt16) -> Bytes {
		data.append(UInt8(frm & 0xFF))
		data.append(UInt8((frm >> 8) & 0xFF))
		return self
	}
	
	/// Imports one UInt32 value appending it to the end of the array
	/// - returns: The Bytes object
    @discardableResult
	public func import32Bits(from frm: UInt32) -> Bytes {
		data.append(UInt8(frm & 0xFF))
		data.append(UInt8((frm >> 8) & 0xFF))
		data.append(UInt8((frm >> 16) & 0xFF))
		data.append(UInt8((frm >> 24) & 0xFF))
		return self
	}
	
	/// Imports one UInt64 value appending it to the end of the array
	/// - returns: The Bytes object
    @discardableResult
	public func import64Bits(from frm: UInt64) -> Bytes {
		data.append(UInt8(frm & 0xFF))
		data.append(UInt8((frm >> 8) & 0xFF))
		data.append(UInt8((frm >> 16) & 0xFF))
		data.append(UInt8((frm >> 24) & 0xFF))
		data.append(UInt8((frm >> 32) & 0xFF))
		data.append(UInt8((frm >> 40) & 0xFF))
		data.append(UInt8((frm >> 48) & 0xFF))
		data.append(UInt8((frm >> 56) & 0xFF))
		return self
	}
	
	/// Imports an array of UInt8 values appending them to the end of the array
	/// - returns: The Bytes object
    @discardableResult
	public func importBytes(from frm: [UInt8]) -> Bytes {
		data.append(contentsOf: frm)
		return self
	}
	
	/// Imports the array values of the given Bytes appending them to the end of the array
	/// - returns: The Bytes object
    @discardableResult
	public func importBytes(from frm: Bytes) -> Bytes {
		data.append(contentsOf: frm.data)
		return self
	}
	
	/// Imports an `ArraySlice` of UInt8 values appending them to the end of the array
	/// - returns: The Bytes object
    @discardableResult
	public func importBytes(from frm: ArraySlice<UInt8>) -> Bytes {
		data.append(contentsOf: frm)
		return self
	}
	
	// -- EXPORT
	
	/// Exports one UInt8 from the current position. Advances the position marker by 1 byte.
	/// - returns: The UInt8 value
	public func export8Bits() -> UInt8 {
		let result = data[position]
		position += 1
		return result
	}
	
	/// Exports one UInt16 from the current position. Advances the position marker by 2 bytes.
	/// - returns: The UInt16 value
	public func export16Bits() -> UInt16 {

		let one = UInt16(data[position])
		position += 1
		let two = UInt16(data[position])
		position += 1
		
		return (two << 8) + one
	}
	
	/// Exports one UInt32 from the current position. Advances the position marker by 4 bytes.
	/// - returns: The UInt32 value
	public func export32Bits() -> UInt32 {
		let one = UInt32(data[position])
		position += 1
		let two = UInt32(data[position])
		position += 1
		let three = UInt32(data[position])
		position += 1
		let four = UInt32(data[position])
		position += 1
		
		return (four << 24) + (three << 16) + (two << 8) + one
	}
	
	/// Exports one UInt64 from the current position. Advances the position marker by 8 bytes.
	/// - returns: The UInt64 value
	public func export64Bits() -> UInt64 {
		let one = UInt64(data[position])
		position += 1
		let two = UInt64(data[position]) << 8
		position += 1
		let three = UInt64(data[position]) << 16
		position += 1
		let four = UInt64(data[position]) << 24
		position += 1
		let five = UInt64(data[position]) << 32
		position += 1
		let six = UInt64(data[position]) << 40
		position += 1
		let seven = UInt64(data[position]) << 48
		position += 1
		let eight = UInt64(data[position]) << 56
		position += 1
		
		return (one+two+three+four)+(five+six+seven+eight)
	}
	
	/// Exports the indicated number of bytes
	public func exportBytes(count cnt: Int) -> [UInt8] {
		var sub = [UInt8]()
		let end = position + cnt
		while position < end {
			sub.append(data[position])
			position += 1
		}
		return sub
	}
}


















================================================
FILE: Sources/PerfectLib/Dir.swift
================================================
//
//  Dir.swift
//  PerfectLib
//
//  Created by Kyle Jessup on 7/7/15.
//	Copyright (C) 2015 PerfectlySoft, Inc.
//
//===----------------------------------------------------------------------===//
//
// This source file is part of the Perfect.org open source project
//
// Copyright (c) 2015 - 2016 PerfectlySoft Inc. and the Perfect project authors
// Licensed under Apache License v2.0
//
// See http://perfect.org/licensing.html for license information
//
//===----------------------------------------------------------------------===//
//

#if os(Linux)
import LinuxBridge
#else
import Darwin
#endif

/// This class represents a directory on the file system.
/// It can be used for creating & inspecting directories and enumerating directory contents.
public struct Dir {
	/// A typealias for directory permission modes.
	public typealias PermissionMode = File.PermissionMode

	var internalPath = ""

	/// Create a new Dir object with the given path
	public init(_ path: String) {
		let pth = path.ends(with: "/") ? path : path + "/"
		internalPath = File.resolveTilde(inPath: pth)
	}

	/// Returns true if the directory exists
    public var exists: Bool {
		return exists(realPath)
	}

	/// Set this Dir as the process' working directory.
	public func setAsWorkingDir() throws {
		let res = chdir(internalPath)
		guard res == 0 else {
			try ThrowFileError()
		}
	}

	/// Return the process' current working directory.
	public static var workingDir: Dir {
		var buffer = Array(repeating: 0 as UInt8, count: 2049)
		buffer.withUnsafeMutableBytes {
			_ = getcwd($0.bindMemory(to: Int8.self).baseAddress, 2048)
		}
		let path = String(cString: buffer)
		return Dir(path)
	}

	func exists(_ path: String) -> Bool {
		return access(path, F_OK) != -1
	}

	/// Creates the directory using the provided permissions. All directories along the path will be created if need be.
	/// - parameter perms: The permissions for use for the new directory and preceeding directories which need to be created. Defaults to RWX-GUO
	/// - throws: `PerfectError.FileError`
	public func create(perms: PermissionMode = [.rwxUser, .rxGroup, .rxOther]) throws {
		let pth = realPath
		var currPath = pth.begins(with: "/") ? "/" : ""
		for component in pth.filePathComponents where component != "/" {
            currPath += component
            defer {
                currPath += "/"
            }
            guard !exists(currPath) else {
                continue
            }
            let res = mkdir(currPath, perms.rawValue)
            guard res != -1 else {
                try ThrowFileError()
            }
        }
	}

	/// Deletes the directory. The directory must be empty in order to be successfully deleted.
	/// - throws: `PerfectError.FileError`
	public func delete() throws {
		let res = rmdir(realPath)
		guard res != -1 else {
			try ThrowFileError()
		}
	}

	/// Returns the name of the directory.
	public var name: String {
		return internalPath.lastFilePathComponent
	}

	/// Returns a Dir object representing the current Dir's parent. Returns nil if there is no parent.
	public var parentDir: Dir? {
		guard internalPath != "/" else {
			return nil // can not go up
		}
		return Dir(internalPath.deletingLastFilePathComponent)
	}

	/// Returns the path to the current directory.
	public var path: String {
		return internalPath
	}

	/// Returns the UNIX style permissions for the directory.
	public var perms: PermissionMode {
		get {
			return File(internalPath).perms
		}
		set {
			File(internalPath).perms = newValue
		}
	}

	var realPath: String {
		return internalPath.resolvingSymlinksInFilePath
	}

#if os(Linux)
    func readDir(_ d: OpaquePointer, _ dirEnt: inout dirent, _ endPtr: UnsafeMutablePointer<UnsafeMutablePointer<dirent>?>!) -> Int32 {
		guard let ent = readdir(d) else {
			return -1
		}
		dirEnt = ent.pointee
		return 0
    }
#else
    func readDir(_ d: UnsafeMutablePointer<DIR>, _ dirEnt: inout dirent, _ endPtr: UnsafeMutablePointer<UnsafeMutablePointer<dirent>?>!) -> Int32 {
        return readdir_r(d, &dirEnt, endPtr)
    }
#endif

	/// Enumerates the contents of the directory passing the name of each contained element to the provided callback.
	/// - parameter closure: The callback which will receive each entry's name
	/// - throws: `PerfectError.FileError`
	public func forEachEntry(closure: (String) throws -> ()) throws {
		guard let dir = opendir(realPath) else {
			try ThrowFileError()
		}

		defer { closedir(dir) }

		var ent = dirent()
		let entPtr = UnsafeMutablePointer<UnsafeMutablePointer<dirent>?>.allocate(capacity:  1)
		defer { entPtr.deallocate() }

		while readDir(dir, &ent, entPtr) == 0 && entPtr.pointee != nil {
			let name = ent.d_name
		#if os(Linux)
			let nameLen = 1024
		#else
			let nameLen = ent.d_namlen
		#endif
			let type = ent.d_type

			var nameBuf = [CChar]()
			let mirror = Mirror(reflecting: name)
			let childGen = mirror.children.makeIterator()
			for _ in 0..<nameLen {
                guard let (_, elem) = childGen.next() else {
                    break
                }
				guard let elemI = elem as? Int8, elemI != 0 else {
					break
				}
				nameBuf.append(elemI)
			}
			nameBuf.append(0)
			if let name = String(validatingUTF8: nameBuf), !(name == "." || name == "..") {
                if Int32(type) == Int32(DT_DIR) {
                    try closure(name + "/")
                } else {
                    try closure(name)
                }
			}
		}
	}
}


================================================
FILE: Sources/PerfectLib/File.swift
================================================
//
//  File.swift
//  PerfectLib
//
//  Created by Kyle Jessup on 7/7/15.
//	Copyright (C) 2015 PerfectlySoft, Inc.
//
//===----------------------------------------------------------------------===//
//
// This source file is part of the Perfect.org open source project
//
// Copyright (c) 2015 - 2016 PerfectlySoft Inc. and the Perfect project authors
// Licensed under Apache License v2.0
//
// See http://perfect.org/licensing.html for license information
//
//===----------------------------------------------------------------------===//
//

#if os(Linux)
import LinuxBridge
// !FIX! these are obviously sketchy
// I hope SwiftGlibc to eventually include these
// Otherwise, export them from LinuxBridge

import var Glibc.S_IRUSR
import var Glibc.S_IWUSR
import var Glibc.S_IXUSR
import var Glibc.S_IFMT
import var Glibc.S_IFREG
import var Glibc.S_IFDIR
import var Glibc.S_IFLNK

let S_IRGRP = (S_IRUSR >> 3)
let S_IWGRP	= (S_IWUSR >> 3)
let S_IXGRP	= (S_IXUSR >> 3)
let S_IRWXU = (__S_IREAD|__S_IWRITE|__S_IEXEC)
let S_IRWXG = (S_IRWXU >> 3)
let S_IRWXO = (S_IRWXG >> 3)
let S_IROTH = (S_IRGRP >> 3)
let S_IWOTH = (S_IWGRP >> 3)
let S_IXOTH = (S_IXGRP >> 3)

let SEEK_CUR: Int32 = 1
let EXDEV = Int32(18)
let EACCES = Int32(13)
let EAGAIN = Int32(11)
let F_OK: Int32 = 0

#else
import Darwin
#endif

let fileCopyBufferSize = 16384

/// Provides access to a file on the local file system
public class File {

	/// The underlying file system descriptor.
	public var fd = -1
	var internalPath = ""

    /// Checks that the file exists on the file system
    /// - returns: True if the file exists or false otherwise
    public var exists: Bool {
        return access(internalPath, F_OK) != -1
    }

    /// Returns true if the file has been opened
    public var isOpen: Bool {
        return fd != -1
    }

    /// Returns the file's path
    public var path: String { return internalPath }

    /// Returns the file path. If the file is a symbolic link, the link will be resolved.
    public var realPath: String {
        let maxPath = 2048
        guard isLink else {
            return internalPath
        }
        var ary = [UInt8](repeating: 0, count: maxPath)
		let res: Int = ary.withUnsafeMutableBytes {
			guard let p = $0.bindMemory(to: Int8.self).baseAddress else {
				return -1
			}
			return readlink(internalPath, p, maxPath)
		}
        guard res != -1 else {
            return internalPath
        }
        let trailPath = String(cString: ary)
        let lastChar = trailPath[trailPath.startIndex]
        guard lastChar != "/" && lastChar != "." else {
            return trailPath
        }
        return internalPath.deletingLastFilePathComponent + "/" + trailPath
    }

    /// Returns the modification date for the file in the standard UNIX format of seconds since 1970/01/01 00:00:00 GMT
    /// - returns: The date as Int
    public var modificationTime: Int {
        var st = stat()
        let res = isOpen ?  fstat(Int32(fd), &st) : stat(internalPath, &st)
        guard res == 0 else {
            return Int.max
        }
        #if os(Linux)
            return Int(st.st_mtim.tv_sec)
        #else
            return Int(st.st_mtimespec.tv_sec)
        #endif
    }

	static func resolveTilde(inPath: String) -> String {
#if !os(iOS) && !os(tvOS)
		if !inPath.isEmpty && inPath[inPath.startIndex] == "~" {
			var wexp = wordexp_t()
			guard 0 == wordexp(inPath, &wexp, 0),
					let we_wordv = wexp.we_wordv else {
				return inPath
			}
			defer {
				wordfree(&wexp)
			}
			if let resolved = we_wordv[0], let pth = String(validatingUTF8: resolved) {
				return pth
			}
		}
#endif
		return inPath
	}

	/// Create a file object given a path and open mode
	/// - parameter path: Path to the file which will be accessed
    /// - parameter fd: The file descriptor, if any, for an already opened file
	public init(_ path: String, fd: Int32 = -1) {
		internalPath = File.resolveTilde(inPath: path)
        self.fd = Int(fd)
	}

	deinit {
		close()
	}
	
	/// Closes the file if it had been opened
	public func close() {
		if fd != -1 {
		#if os(Linux)
			_ = SwiftGlibc.close(CInt(fd))
		#else
            _ = Darwin.close(CInt(fd))
		#endif
			fd = -1
		}
	}

	/// Resets the internal file descriptor, leaving the file opened if it had been.
	public func abandon() {
		fd = -1
	}
}

public extension File {
    /// The open mode for the file.
	enum OpenMode {
        /// Opens the file for read-only access.
        case read
        /// Opens the file for write-only access, creating the file if it did not exist.
        case write
        /// Opens the file for read-write access, creating the file if it did not exist.
        case readWrite
        /// Opens the file for read-write access, creating the file if it did not exist and moving the file marker to the end.
        case append
        /// Opens the file for read-write access, creating the file if it did not exist and setting the file's size to zero.
        case truncate

        var toMode: Int {
            switch self {
            case .read:         return Int(O_RDONLY)
            case .write:        return Int(O_WRONLY|O_CREAT)
            case .readWrite:    return Int(O_RDWR|O_CREAT)
            case .append:       return Int(O_RDWR|O_APPEND|O_CREAT)
            case .truncate:     return Int(O_RDWR|O_TRUNC|O_CREAT)
            }
        }
    }
	/// A file or directory access permission value.
	struct PermissionMode: OptionSet {
		/// File system mode type.
		public typealias Mode = mode_t
		/// The raw mode.
		public let rawValue: Mode
		/// Create a permission mode with a raw value.
		public init(rawValue: Mode) {
			self.rawValue = rawValue
		}

#if os(Linux)
		init(rawValue: Int32) {
			self.init(rawValue: UInt32(rawValue))
		}
#endif

		/// Readable by user.
		public static let readUser = PermissionMode(rawValue: S_IRUSR)
		/// Writable by user.
		public static let writeUser = PermissionMode(rawValue: S_IWUSR)
		/// Executable by user.
		public static let executeUser = PermissionMode(rawValue: S_IXUSR)
		/// Readable by group.
		public static let readGroup = PermissionMode(rawValue: S_IRGRP)
		/// Writable by group.
		public static let writeGroup = PermissionMode(rawValue: S_IWGRP)
		/// Executable by group.
		public static let executeGroup = PermissionMode(rawValue: S_IXGRP)
		/// Readable by others.
		public static let readOther = PermissionMode(rawValue: S_IROTH)
		/// Writable by others.
		public static let writeOther = PermissionMode(rawValue: S_IWOTH)
		/// Executable by others.
		public static let executeOther = PermissionMode(rawValue: S_IXOTH)

		/// Read, write, execute by user.
		public static let rwxUser: PermissionMode = [.readUser, .writeUser, .executeUser]
		/// Read, write by user and group.
		public static let rwUserGroup: PermissionMode = [.readUser, .writeUser, .readGroup, .writeGroup]

		/// Read, execute by group.
		public static let rxGroup: PermissionMode = [.readGroup, .executeGroup]
		/// Read, execute by other.
		public static let rxOther: PermissionMode = [.readOther, .executeOther]

	}

	/// Opens the file using the given mode.
	/// - throws: `PerfectError.FileError`
	func open(_ mode: OpenMode = .read, permissions: PermissionMode = .rwUserGroup) throws {
        if fd != -1 {
            close()
        }
	#if os(Linux)
		let openFd = linux_open(internalPath, CInt(mode.toMode), permissions.rawValue)
	#else
		let openFd = Darwin.open(internalPath, CInt(mode.toMode), permissions.rawValue)
	#endif
		guard openFd != -1 else {
			try ThrowFileError()
		}
		fd = Int(openFd)
	}
}

public extension File {
    /// The current file read/write position.
	var marker: Int {
        /// Returns the value of the file's current position marker
        get {
            if isOpen {
                return Int(lseek(Int32(fd), 0, SEEK_CUR))
            }
            return 0
        }
        /// Sets the file's position marker given the value as measured from the begining of the file.
        set {
            lseek(Int32(fd), off_t(newValue), SEEK_SET)
        }
    }
}

public extension File {

    /// Closes and deletes the file
	func delete() {
        close()
        unlink(path)
    }

    /// Moves the file to the new location, optionally overwriting any existing file
    /// - parameter path: The path to move the file to
    /// - parameter overWrite: Indicates that any existing file at the destination path should first be deleted
    /// - returns: Returns a new file object representing the new location
    /// - throws: `PerfectError.FileError`
	func moveTo(path: String, overWrite: Bool = false) throws -> File {
        let destFile = File(path)
        if destFile.exists {
            guard overWrite else {
                throw PerfectError.fileError(-1, "Can not overwrite existing file")
            }
            destFile.delete()
        }
        close()
        let res = rename(self.path, path)
        if res == 0 {
            return destFile
        }
        if errno == EXDEV {
            _ = try copyTo(path: path, overWrite: overWrite)
            delete()
            return destFile
        }
        try ThrowFileError()
    }

    /// Copies the file to the new location, optionally overwriting any existing file
    /// - parameter path: The path to copy the file to
    /// - parameter overWrite: Indicates that any existing file at the destination path should first be deleted
    /// - returns: Returns a new file object representing the new location
    /// - throws: `PerfectError.FileError`
    @discardableResult
	func copyTo(path pth: String, overWrite: Bool = false) throws -> File {
        let destFile = File(pth)
        if destFile.exists {
            guard overWrite else {
                throw PerfectError.fileError(-1, "Can not overwrite existing file")
            }
            destFile.delete()
        }
        let wasOpen = isOpen
        let oldMarker = marker
        if !wasOpen {
            try open()
        } else {
            _ = marker = 0
        }
        defer {
            if !wasOpen {
                close()
            } else {
                _ = marker = oldMarker
            }
        }

        try destFile.open(.truncate)

        var bytes = try readSomeBytes(count: fileCopyBufferSize)
        while bytes.count > 0 {
            try destFile.write(bytes: bytes)
            bytes = try readSomeBytes(count: fileCopyBufferSize)
        }

        destFile.close()
        return destFile
    }
}

public extension File {

	/// Returns the size of the file in bytes
	var size: Int {
		var st = stat()
		let statRes = isOpen ?  fstat(Int32(fd), &st) : stat(internalPath, &st)
		guard statRes != -1 else {
			return 0
		}
		return Int(st.st_size)
	}

	/// Returns true if the file is actually a directory
	var isDir: Bool {
		var st = stat()
		let statRes = isOpen ?  fstat(Int32(fd), &st) : stat(internalPath, &st)
		guard statRes != -1 else {
			return false
		}
		let mode = st.st_mode
		return (Int32(mode) & Int32(S_IFMT)) == Int32(S_IFDIR)
	}

	/// Returns the UNIX style permissions for the file
	var perms: PermissionMode {
		get {
			var st = stat()
			let statRes = isOpen ?  fstat(Int32(fd), &st) : stat(internalPath, &st)
			guard statRes != -1 else {
				return PermissionMode(rawValue: PermissionMode.Mode(0))
			}
			let mode = st.st_mode
			return PermissionMode(rawValue: mode_t(Int32(mode) ^ Int32(S_IFMT)))
		}
		set {
			_ = chmod(internalPath, newValue.rawValue)
		}
    }
}

public extension File {
	/// Returns true if the file is a symbolic link
	var isLink: Bool {
		var st = stat()
		let statRes = lstat(internalPath, &st)
		guard statRes != -1 else {
			return false
		}
		let mode = st.st_mode
		return (Int32(mode) & Int32(S_IFMT)) == Int32(S_IFLNK)
	}
	
	/// Create a symlink from the target to the destination.
	@discardableResult
	func linkTo(path: String, overWrite: Bool = false) throws -> File {
		let destFile = File(path)
		if destFile.exists {
			guard overWrite else {
				throw PerfectError.fileError(-1, "Can not overwrite existing file")
			}
			destFile.delete()
		}
		let res = symlink(self.path, path)
		if res == 0 {
			return File(path)
		}
		try ThrowFileError()
	}
}

public extension File {

	/// Reads up to the indicated number of bytes from the file
	/// - parameter count: The maximum number of bytes to read
	/// - returns: The bytes read as an array of UInt8. May have a count of zero.
	/// - throws: `PerfectError.FileError`
	func readSomeBytes(count: Int) throws -> [UInt8] {
        if !isOpen {
            try open()
        }

        func sizeOr(_ value: Int) -> Int {
            var st = stat()
            let statRes = isOpen ?  fstat(Int32(fd), &st) : stat(internalPath, &st)
            guard statRes != -1 else {
                return 0
            }
            if (Int32(st.st_mode) & Int32(S_IFMT)) == Int32(S_IFREG) {
                return Int(st.st_size)
            }
            return value
        }

		let bSize = min(count, sizeOr(count))
		var ary = [UInt8](repeating: 0, count: bSize)
		
		let readCount = ary.withUnsafeMutableBytes {
		   read(CInt(fd), $0.bindMemory(to: Int8.self).baseAddress, bSize)
	    }
		guard readCount >= 0 else {
			try ThrowFileError()
		}
		if readCount < bSize {
			ary.removeLast(bSize - readCount)
		}
		return ary
	}

	/// Reads the entire file as a string
	func readString() throws -> String {
		let bytes = try readSomeBytes(count: size)
		return UTF8Encoding.encode(bytes: bytes)
    }
}

public extension File {

	/// Writes the string to the file using UTF-8 encoding
	/// - parameter s: The string to write
	/// - returns: Returns the number of bytes which were written
	/// - throws: `PerfectError.FileError`
    @discardableResult
	func write(string: String) throws -> Int {
		return try write(bytes: Array(string.utf8))
	}

	/// Write the indicated bytes to the file
	/// - parameter bytes: The array of UInt8 to write.
	/// - parameter dataPosition: The offset within `bytes` at which to begin writing.
	/// - parameter length: The number of bytes to write.
	/// - throws: `PerfectError.FileError`
    @discardableResult
	func write(bytes: [UInt8], dataPosition: Int = 0, length: Int = Int.max) throws -> Int {
        let len = min(bytes.count - dataPosition, length)
    #if os(Linux)
		let wrote = bytes.withUnsafeBytes {
			SwiftGlibc.write(Int32(fd), $0.bindMemory(to: Int8.self).baseAddress?.advanced(by: dataPosition), len)
		}
	#else
		let wrote = bytes.withUnsafeBytes {
			Darwin.write(Int32(fd), $0.bindMemory(to: Int8.self).baseAddress?.advanced(by: dataPosition), len)
		}
	#endif
		guard wrote == len else {
			try ThrowFileError()
		}
		return wrote
	}
}

public extension File {

	/// 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.
	/// - parameter byteCount: The number of bytes to lock
	/// - throws: `PerfectError.FileError`
	func lock(byteCount: Int) throws {
		if !isOpen {
			try open(.write)
		}
		let res = lockf(Int32(fd), F_LOCK, off_t(byteCount))
		guard res == 0 else {
			try ThrowFileError()
		}
	}

	/// Unlocks the number of bytes starting from the current position marker up to the indicated byte count.
	/// - parameter byteCount: The number of bytes to unlock
	/// - throws: `PerfectError.FileError`
	func unlock(byteCount: Int) throws {
		if !isOpen {
			try open(.write)
		}
		let res = lockf(Int32(fd), F_ULOCK, off_t(byteCount))
		guard res == 0 else {
			try ThrowFileError()
		}
	}

	/// 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.
	/// - parameter byteCount: The number of bytes to lock
	/// - throws: `PerfectError.FileError`
	func tryLock(byteCount: Int) throws {
		if !isOpen {
			try open(.write)
		}
		let res = lockf(Int32(fd), F_TLOCK, off_t(byteCount))
		guard res == 0 else {
			try ThrowFileError()
		}
	}

	/// Tests if the indicated bytes are locked
	/// - parameter byteCount: The number of bytes to test
	/// - returns: True if the file is locked
	/// - throws: `PerfectError.FileError`
	func testLock(byteCount: Int) throws -> Bool {
		if !isOpen {
			try open(.write)
		}
		let res = Int(lockf(Int32(fd), F_TEST, off_t(byteCount)))
		guard res == 0 || res == Int(EACCES) || res == Int(EAGAIN) else {
			try ThrowFileError()
		}
		return res != 0
	}
}

// Subclass to represent a file which can not be closed
private final class UnclosableFile : File {
    override init(_ path: String, fd: Int32) {
		super.init(path, fd: fd)
	}
	override func close() {
		// nothing
	}
}

/// A temporary, randomly named file.
public final class TemporaryFile: File {
    /// Create a temporary file, usually in the system's /tmp/ directory
    /// - parameter withPrefix: The prefix for the temporary file's name. Random characters will be appended to the file's eventual name.
    public convenience init(withPrefix: String) {
        let template = withPrefix + "XXXXXX"
        let utf8 = template.utf8
        let name = UnsafeMutablePointer<Int8>.allocate(capacity: utf8.count + 1)
        var i = utf8.startIndex
        for index in 0..<utf8.count {
            name[index] = Int8(utf8[i])
            i = utf8.index(after: i)
        }
        name[utf8.count] = 0

        let fd = mkstemp(name)
        let tmpFileName = String(validatingUTF8: name)!

        name.deallocate()

        self.init(tmpFileName, fd: fd)
    }
}

/// This file can be used to write to standard in
public var fileStdin: File {
    return UnclosableFile("/dev/stdin", fd: STDIN_FILENO)
}

/// This file can be used to write to standard out
public var fileStdout: File {
	return UnclosableFile("/dev/stdout", fd: STDOUT_FILENO)
}

/// This file can be used to write to standard error
public var fileStderr: File {
	return UnclosableFile("/dev/stderr", fd: STDERR_FILENO)
}


================================================
FILE: Sources/PerfectLib/JSONConvertible.swift
================================================
//
//  JSONConvertible.swift
//  PerfectLib
//
//  Created by Kyle Jessup on 2016-01-21.
//  Copyright © 2016 Treefrog. All rights reserved.
//
//===----------------------------------------------------------------------===//
//
// This source file is part of the Perfect.org open source project
//
// Copyright (c) 2015 - 2016 PerfectlySoft Inc. and the Perfect project authors
// Licensed under Apache License v2.0
//
// See http://perfect.org/licensing.html for license information
//
//===----------------------------------------------------------------------===//
//

#if os(Linux)
	import SwiftGlibc
#else
    import Darwin
#endif

/// This non-instantiable object serves as an access point to a registry for JSONConvertibleObjects
/// A JSONConvertibleObject is a custom class or struct which can be converted to and from JSON.
public class JSONDecoding {
    private init() {}

    /// The key used in JSON data to indicate the type of custom object which was converted.
    public static let objectIdentifierKey = "_jsonobjid"
    /// Function which returns a new instance of a custom object which will have its members set based on the JSON data.
    public typealias JSONConvertibleObjectCreator = () -> JSONConvertibleObject

    static private var jsonDecodableRegistry = [String:JSONConvertibleObjectCreator]()

    /// Register a custom object to be JSON encoded/decoded.
    static public func registerJSONDecodable(name nam: String, creator: @escaping JSONConvertibleObjectCreator) {
        JSONDecoding.jsonDecodableRegistry[nam] = creator
    }

    /// Instantiate a custom object based on the JSON data.
    /// The system will use the `JSONDecoding.objectIdentifierKey` key to locate the custom object creator.
    static public func createJSONConvertibleObject(values:[String:Any]) -> JSONConvertibleObject? {
        guard let objkey = values[JSONDecoding.objectIdentifierKey] as? String else {
            return nil
        }
        return JSONDecoding.createJSONConvertibleObject(name: objkey, values: values)
    }

    /// Instantiate a custom object based on the JSON data.
    /// The system will use the `name` parameter to locate the custom object creator.
    static public func createJSONConvertibleObject(name: String, values:[String:Any]) -> JSONConvertibleObject? {
        guard let creator = JSONDecoding.jsonDecodableRegistry[name] else {
            return nil
        }
        let jsonObj = creator()
        jsonObj.setJSONValues(values)
        return jsonObj
    }
}

/// Protocol for an object which can be converted into JSON text.
public protocol JSONConvertible {
    /// Returns the JSON encoded String for any JSONConvertible type.
    func jsonEncodedString() throws -> String
}

// !FIX! changed this to be a class due to Linux protocols failing 'as' tests.
// revisit this
/// Base for a custom object which can be converted to and from JSON.
open class JSONConvertibleObject: JSONConvertible {
    /// Default initializer.
	public init() {}
    /// Get the JSON keys/value.
    open func setJSONValues(_ values:[String:Any]) {}
    /// Set the object properties based on the JSON keys/values.
    open func getJSONValues() -> [String:Any] { return [String:Any]() }
    /// Encode the object into JSON text
    open func jsonEncodedString() throws -> String {
        return try getJSONValues().jsonEncodedString()
    }
}

/// Get the JSON keys/values from a custom object.
public extension JSONConvertibleObject {
    /// Get a named value from the Dictionary converting to the given type with a default value.
    func getJSONValue<T: JSONConvertible>(named namd: String, from:[String:Any], defaultValue: T) -> T {
        let f = from[namd]
        if let v = f as? T {
            return v
        }
        return defaultValue
    }
}

/// An error occurring during JSON conversion.
public enum JSONConversionError: Error {
    /// The object did not suppport JSON conversion.
    case notConvertible(Any?)
    /// A provided key was not a String.
    case invalidKey(Any)
    /// The JSON text contained a syntax error.
    case syntaxError
}

private let jsonBackSlash = UnicodeScalar(UInt32(92))!
private let jsonBackSpace = UnicodeScalar(UInt32(8))!
private let jsonFormFeed = UnicodeScalar(UInt32(12))!
private let jsonLF = UnicodeScalar(UInt32(10))!
private let jsonCR = UnicodeScalar(UInt32(13))!
private let jsonTab = UnicodeScalar(UInt32(9))!
private let jsonQuoteDouble = UnicodeScalar(UInt32(34))!

private let jsonOpenObject = UnicodeScalar(UInt32(123))!
private let jsonOpenArray = UnicodeScalar(UInt32(91))!
private let jsonCloseObject = UnicodeScalar(UInt32(125))!
private let jsonCloseArray = UnicodeScalar(UInt32(93))!
private let jsonWhiteSpace = UnicodeScalar(UInt32(32))!
private let jsonColon = UnicodeScalar(UInt32(58))!
private let jsonComma = UnicodeScalar(UInt32(44))!

private let highSurrogateLowerBound = UInt32(strtoul("d800", nil, 16))
private let highSurrogateUpperBound = UInt32(strtoul("dbff", nil, 16))
private let lowSurrogateLowerBound = UInt32(strtoul("dc00", nil, 16))
private let lowSurrogateUpperBound = UInt32(strtoul("dfff", nil, 16))
private let surrogateStep = UInt32(strtoul("400", nil, 16))
private let surrogateBase = UInt32(strtoul("10000", nil, 16))

/// This is a stand-in for a JSON null.
/// May be produced when decoding.
public struct JSONConvertibleNull: JSONConvertible {
    public func jsonEncodedString() throws -> String {
        return "null"
    }
}

extension String: JSONConvertible {
    /// Convert a String into JSON text
    public func jsonEncodedString() throws -> String {
        var s = "\""
        for uchar in unicodeScalars {
            switch(uchar) {
            case jsonBackSlash:
                s.append("\\\\")
            case jsonQuoteDouble:
                s.append("\\\"")
            case jsonBackSpace:
                s.append("\\b")
            case jsonFormFeed:
                s.append("\\f")
            case jsonLF:
                s.append("\\n")
            case jsonCR:
                s.append("\\r")
            case jsonTab:
                s.append("\\t")
            default:
                s.append(String(uchar))
            }
        }
        s.append("\"")
        return s
    }
}

extension Int: JSONConvertible {
    /// Convert an Int into JSON text.
    public func jsonEncodedString() throws -> String {
        return String(self)
    }
}

extension UInt: JSONConvertible {
    /// Convert a UInt into JSON text.
    public func jsonEncodedString() throws -> String {
        return String(self)
    }
}

extension Int8: JSONConvertible {
    /// Convert an Int8 into JSON text.
    public func jsonEncodedString() throws -> String {
        return String(self)
    }
}

extension Int16: JSONConvertible {
    /// Convert an Int16 into JSON text.
    public func jsonEncodedString() throws -> String {
        return String(self)
    }
}

extension Int32: JSONConvertible {
    /// Convert an Int into JSON text.
    public func jsonEncodedString() throws -> String {
        return String(self)
    }
}

extension Int64: JSONConvertible {
    /// Convert an Int into JSON text.
    public func jsonEncodedString() throws -> String {
        return String(self)
    }
}

extension UInt8: JSONConvertible {
    /// Convert an UInt8 into JSON text.
    public func jsonEncodedString() throws -> String {
        return String(self)
    }
}

extension UInt16: JSONConvertible {
    /// Convert an UInt16 into JSON text.
    public func jsonEncodedString() throws -> String {
        return String(self)
    }
}

extension UInt32: JSONConvertible {
    /// Convert an Int into JSON text.
    public func jsonEncodedString() throws -> String {
        return String(self)
    }
}

extension UInt64: JSONConvertible {
    /// Convert an Int into JSON text.
    public func jsonEncodedString() throws -> String {
        return String(self)
    }
}

extension Double: JSONConvertible {
    /// Convert a Double into JSON text.
    public func jsonEncodedString() throws -> String {
        return String(self)
    }
}

extension Float: JSONConvertible {
    /// Convert a Float into JSON text.
    public func jsonEncodedString() throws -> String {
        return String(self)
    }
}

extension Optional: JSONConvertible {
    /// Convert an Optional into JSON text.
    public func jsonEncodedString() throws -> String {
        if self == nil {
            return "null"
        } else if let v = self! as? JSONConvertible {
            return try v.jsonEncodedString()
        }
        throw JSONConversionError.notConvertible(self)
    }
}

extension Bool: JSONConvertible {
    /// Convert a Bool into JSON text.
    public func jsonEncodedString() throws -> String {
        if true == self {
            return "true"
        }
        return "false"
    }
}

// !FIX! Downcasting to protocol does not work on Linux
// Not sure if this is intentional, or a bug.
func jsonEncodedStringWorkAround(_ o: Any) throws -> String {
    switch o {
    case let jsonAble as JSONConvertibleObject: // as part of Linux work around
        return try jsonAble.jsonEncodedString()
    case let jsonAble as JSONConvertible:
        return try jsonAble.jsonEncodedString()
    case let jsonAble as String:
        return try jsonAble.jsonEncodedString()
    case let jsonAble as Int:
        return try jsonAble.jsonEncodedString()
    case let jsonAble as Int8:
        return try jsonAble.jsonEncodedString()
    case let jsonAble as Int16:
        return try jsonAble.jsonEncodedString()
    case let jsonAble as Int32:
        return try jsonAble.jsonEncodedString()
    case let jsonAble as Int64:
        return try jsonAble.jsonEncodedString()
    case let jsonAble as UInt:
        return try jsonAble.jsonEncodedString()
    case let jsonAble as UInt8:
        return try jsonAble.jsonEncodedString()
    case let jsonAble as UInt16:
        return try jsonAble.jsonEncodedString()
    case let jsonAble as UInt32:
        return try jsonAble.jsonEncodedString()
    case let jsonAble as UInt64:
        return try jsonAble.jsonEncodedString()
    case let jsonAble as Double:
        return try jsonAble.jsonEncodedString()
    case let jsonAble as Float:
        return try jsonAble.jsonEncodedString()
    case let jsonAble as Bool:
        return try jsonAble.jsonEncodedString()
    case let jsonAble as [Any]:
        return try jsonAble.jsonEncodedString()
    case let jsonAble as [[String:Any]]:
        return try jsonAble.jsonEncodedString()
    case let jsonAble as [String:Any]:
        return try jsonAble.jsonEncodedString()
    default:
        throw JSONConversionError.notConvertible(o)
    }
}

extension Array: JSONConvertible {
    /// Convert an Array into JSON text.
    public func jsonEncodedString() throws -> String {
        var s = "["
        var first = true
        for v in self {
            if !first {
                s.append(",")
            } else {
                first = false
            }
            s.append(try jsonEncodedStringWorkAround(v))
        }
        s.append("]")
        return s
    }
}

extension Dictionary: JSONConvertible {
    /// Convert a Dictionary into JSON text.
    public func jsonEncodedString() throws -> String {
        var s = "{"
        var first = true
        for (k, v) in self {
            guard let strKey = k as? String else {
                throw JSONConversionError.invalidKey(k)
            }
            if !first {
                s.append(",")
            } else {
                first = false
            }
            s.append(try strKey.jsonEncodedString())
            s.append(":")
            s.append(try jsonEncodedStringWorkAround(v))
        }
        s.append("}")
        return s
    }
}

extension String {
    /// Decode the object represented by the JSON text.
    public func jsonDecode() throws -> JSONConvertible {
        let state = JSONDecodeState()
        state.g = unicodeScalars.makeIterator()

        let o = try state.readObject()
        if let _ = o as? JSONDecodeState.EOF {
            throw JSONConversionError.syntaxError
        }
        return o
    }
}

private class JSONDecodeState {
    struct EOF: JSONConvertible {
        func jsonEncodedString() throws -> String { return "" }
    }

    var g = String().unicodeScalars.makeIterator()
    var pushBack: UnicodeScalar?

    func movePastWhite() {
        while let c = next() {
            if !c.isWhiteSpace() {
                pushBack = c
                break
            }
        }
    }

    func readObject() throws -> JSONConvertible {
        movePastWhite()

        guard let c = next() else {
            return EOF()
        }

        switch(c) {
        case jsonOpenArray:
            var a = [Any]()
            movePastWhite()
            guard let c = next() else {
                throw JSONConversionError.syntaxError
            }
            if c != jsonCloseArray {
                pushBack = c
                while true {
                    a.append(try readObject())
                    movePastWhite()
                    guard let c = next() else {
                        throw JSONConversionError.syntaxError
                    }
                    if c == jsonCloseArray {
                        break
                    }
                    if c != jsonComma {
                        throw JSONConversionError.syntaxError
                    }
                }
            }
            return a
        case jsonOpenObject:
            var d = [String:Any]()
            movePastWhite()
            guard let c = next() else {
                throw JSONConversionError.syntaxError
            }
            if c != jsonCloseObject {
                pushBack = c
                while true {
                    guard let key = try readObject() as? String else {
                        throw JSONConversionError.syntaxError
                    }
                    movePastWhite()
                    guard let c = next() else {
                        throw JSONConversionError.syntaxError
                    }
                    guard c == jsonColon else {
                        throw JSONConversionError.syntaxError
                    }
                    movePastWhite()
                    d[key] = try readObject()
                    do {
                        movePastWhite()
                        guard let c = next() else {
                            throw JSONConversionError.syntaxError
                        }
                        if c == jsonCloseObject {
                            break
                        }
                        if c != jsonComma {
                            throw JSONConversionError.syntaxError
                        }
                    }
                }
            }
            if let objid = d[JSONDecoding.objectIdentifierKey] as? String {
                if let o = JSONDecoding.createJSONConvertibleObject(name: objid, values: d) {
                    return o
                }
            }
            return d
        case jsonQuoteDouble:
            return try readString()
        default:
            if c.isWhiteSpace() {
                // nothing
            } else if c.isDigit() || c == "-" || c == "+" {
                return try readNumber(firstChar: c)
            } else if c == "t" || c == "T" {
                return try readTrue()
            } else if c == "f" || c == "F" {
                return try readFalse()
            } else if c == "n" || c == "N" {
                try readNull()
                return JSONConvertibleNull()
            }
        }
        throw JSONConversionError.syntaxError
    }

    func next() -> UnicodeScalar? {
        if pushBack != nil {
            let c = pushBack!
            pushBack = nil
            return c
        }
        return g.next()
    }

    // the opening quote has been read
    func readString() throws -> String {
        var next = self.next()
        var esc = false
        var s = ""
        while let c = next {

            if esc {
                switch(c) {
                case jsonBackSlash:
                    s.append(String(jsonBackSlash))
                case jsonQuoteDouble:
                    s.append(String(jsonQuoteDouble))
                case "b":
                    s.append(String(jsonBackSpace))
                case "f":
                    s.append(String(jsonFormFeed))
                case "n":
                    s.append(String(jsonLF))
                case "r":
                    s.append(String(jsonCR))
                case "t":
                    s.append(String(jsonTab))
                case "u":
                    var hexStr = ""
                    for _ in 1...4 {
                        next = self.next()
                        guard let hexC = next else {
                            throw JSONConversionError.syntaxError
                        }
                        guard hexC.isHexDigit() else {
                            throw JSONConversionError.syntaxError
                        }
                        hexStr.append(String(hexC))
                    }
                    var uint32Value = UInt32(strtoul(hexStr, nil, 16))
                    // if unicode is a high/low surrogate, it can't be converted directly by UnicodeScalar
                    // if it's a low surrogate (not expected), throw error
                    if case lowSurrogateLowerBound...lowSurrogateUpperBound = uint32Value {
                        throw JSONConversionError.syntaxError
                    }
                    // if it's a high surrogate, find the low surrogate which the next unicode is supposed to be, then calculate the pair
                    if case highSurrogateLowerBound...highSurrogateUpperBound = uint32Value {
                        let highSurrogateValue = uint32Value
                        guard self.next() == jsonBackSlash else {
                            throw JSONConversionError.syntaxError
                        }
                        guard self.next() == "u" else {
                            throw JSONConversionError.syntaxError
                        }
                        var lowSurrogateHexStr = ""
                        for _ in 1...4 {
                            next = self.next()
                            guard let hexC = next else {
                                throw JSONConversionError.syntaxError
                            }
                            guard hexC.isHexDigit() else {
                                throw JSONConversionError.syntaxError
                            }
                            lowSurrogateHexStr.append(String(hexC))
                        }
                        let lowSurrogateValue = UInt32(strtoul(lowSurrogateHexStr, nil, 16))
                        uint32Value = ( highSurrogateValue - highSurrogateLowerBound ) * surrogateStep + ( lowSurrogateValue - lowSurrogateLowerBound ) + surrogateBase
                    }
					if let result = UnicodeScalar(uint32Value) {
						s.append(String(Character(result)))
					}
                default:
                    s.append(String(c))
                }
                esc = false
            } else if c == jsonBackSlash {
                esc = true
            } else if c == jsonQuoteDouble {
                return s
            } else {
                s.append(String(c))
            }

            next = self.next()
        }
        throw JSONConversionError.syntaxError
    }

    func readNumber(firstChar first: UnicodeScalar) throws -> JSONConvertible {
        var s = ""
        var needPeriod = true, needExp = true
        s.append(String(Character(first)))

        if first == "." {
            needPeriod = false
        }

        var next = self.next()
        var last = first
        while let c = next {
            if c.isDigit() {
                s.append(String(c))
            } else if c == "." && !needPeriod {
                break
            } else if (c == "e" || c == "E") && !needExp {
                break
            } else if c == "." {
                needPeriod = false
                s.append(String(c))
            } else if c == "e" || c == "E" {
                needExp = false
                s.append(String(c))

                next = self.next()
                if next != nil && (next! == "-" || next! == "+") {
                    s.append(String(next!))
                } else {
                    pushBack = next!
                }

            } else if last.isDigit() {
                pushBack = c
                if needPeriod && needExp {
                    return Int(s) ?? s
                }
                return Double(s)!
            } else {
                break
            }
            last = c
            next = self.next()
        }

        throw JSONConversionError.syntaxError
    }

    func readTrue() throws -> Bool {
        var next = self.next()
        if next != "r" && next != "R" {
            throw JSONConversionError.syntaxError
        }
        next = self.next()
        if next != "u" && next != "U" {
            throw JSONConversionError.syntaxError
        }
        next = self.next()
        if next != "e" && next != "E" {
            throw JSONConversionError.syntaxError
        }
        next = self.next()
        guard next != nil && !next!.isAlphaNum() else {
            throw JSONConversionError.syntaxError
        }
        pushBack = next!
        return true
    }

    func readFalse() throws -> Bool {
        var next = self.next()
        if next != "a" && next != "A" {
            throw JSONConversionError.syntaxError
        }
        next = self.next()
        if next != "l" && next != "L" {
            throw JSONConversionError.syntaxError
        }
        next = self.next()
        if next != "s" && next != "S" {
            throw JSONConversionError.syntaxError
        }
        next = self.next()
        if next != "e" && next != "E" {
            throw JSONConversionError.syntaxError
        }
        next = self.next()
        guard next != nil && !next!.isAlphaNum() else {
            throw JSONConversionError.syntaxError
        }
        pushBack = next!
        return false
    }

    func readNull() throws {
        var next = self.next()
        if next != "u" && next != "U" {
            throw JSONConversionError.syntaxError
        }
        next = self.next()
        if next != "l" && next != "L" {
            throw JSONConversionError.syntaxError
        }
        next = self.next()
        if next != "l" && next != "L" {
            throw JSONConversionError.syntaxError
        }
        next = self.next()
        guard next != nil && !next!.isAlphaNum() else {
            throw JSONConversionError.syntaxError
        }
        pushBack = next!
    }
}


================================================
FILE: Sources/PerfectLib/Log.swift
================================================
//
//  LogManager.swift
//  PerfectLib
//
//  Created by Kyle Jessup on 7/21/15.
//	Copyright (C) 2015 PerfectlySoft, Inc.
//
//===----------------------------------------------------------------------===//
//
// This source file is part of the Perfect.org open source project
//
// Copyright (c) 2015 - 2016 PerfectlySoft Inc. and the Perfect project authors
// Licensed under Apache License v2.0
//
// See http://perfect.org/licensing.html for license information
//
//===----------------------------------------------------------------------===//
//

#if os(Linux)
	import SwiftGlibc
	import LinuxBridge
#else
	import Darwin
	import os
#endif

/// Placeholder functions for logging system
public protocol Logger {
	func debug(message: String, _ even: Bool)
	func info(message: String, _ even: Bool)
	func warning(message: String, _ even: Bool)
	func error(message: String, _ even: Bool)
	func critical(message: String, _ even: Bool)
	func terminal(message: String, _ even: Bool)
}

public struct ConsoleLogger: Logger {
	public init(){}

	public func debug(message: String, _ even: Bool) {
		print((even ? "[DBG]  " : "[DBG] ") + message)
	}

	public func info(message: String, _ even: Bool) {
		print((even ? "[INFO] " : "[INFO] ") + message)
	}

	public func warning(message: String, _ even: Bool) {
		print((even ? "[WARN] " : "[WARN] ") + message)
	}

	public func error(message: String, _ even: Bool) {
		print((even ? "[ERR]  " : "[ERR] ") + message)
	}

	public func critical(message: String, _ even: Bool) {
		print((even ? "[CRIT] " : "[CRIT] ") + message)
	}

	public func terminal(message: String, _ even: Bool) {
		print((even ? "[TERM] " : "[TERM] ") + message)
	}
}

public struct SysLogger: Logger {
	let consoleEcho = ConsoleLogger()
	public init(){}

	func syslog(priority: Int32, _ args: CVarArg...) {
#if os(Linux)// || os(macOS)
		withVaList(args) {
			vsyslog(priority, "%s", $0)
		}
#else
    // nerdo: Using unified logging (https://developer.apple.com/documentation/os/logging)
    // os_log isn't very well documented... but this seems like a step in the right direction.
    let osLogType: OSLogType
    switch priority {
    case 0, 1, 2:
        osLogType = .fault
    case 3:
        osLogType = .error
    case 4, 5, 6:
        osLogType = .info
    case 7:
        osLogType = .debug
    default:
        osLogType = .default
    }
    os_log("%s", log: .default, type: osLogType, args)
#endif
	}

	public func debug(message: String, _ even: Bool) {
		consoleEcho.debug(message: message, even)
		message.withCString {
			f in
			syslog(priority: LOG_DEBUG, f)
		}
	}

	public func info(message: String, _ even: Bool) {
		consoleEcho.info(message: message, even)
		message.withCString {
			f in
			syslog(priority: LOG_INFO, f)
		}
	}

	public func warning(message: String, _ even: Bool) {
		consoleEcho.warning(message: message, even)
		message.withCString {
			f in
			syslog(priority: LOG_WARNING, f)
		}
	}

	public func error(message: String, _ even: Bool) {
		consoleEcho.error(message: message, even)
		message.withCString {
			f in
			syslog(priority: LOG_ERR, f)
		}
	}

	public func critical(message: String, _ even: Bool) {
		consoleEcho.critical(message: message, even)
		message.withCString {
			f in
			syslog(priority: LOG_CRIT, f)
		}
	}

	public func terminal(message: String, _ even: Bool) {
		consoleEcho.terminal(message: message, even)
		message.withCString {
			f in
			syslog(priority: LOG_EMERG, f)
		}
	}
}

/// Placeholder functions for logging system
public struct Log {
	private init(){}

	public static var logger: Logger = ConsoleLogger()

	/// Whether or not to even off the log messages
	/// If set to true log messages will be inline with each other
	public static var even = false

	public static func debug(message: @autoclosure () -> String) {
//	#if DEBUG
		Log.logger.debug(message: message(), even)
//	#endif
	}

	public static func info(message: String, evenIdents: Bool = even) {
		Log.logger.info(message: message, evenIdents)
	}

	public static func warning(message: String, evenIdents: Bool = even) {
		Log.logger.warning(message: message, evenIdents)
	}

	public static func error(message: String, evenIdents: Bool = even) {
		Log.logger.error(message: message, evenIdents)
	}

	public static func critical(message: String, evenIdents: Bool = even) {
		Log.logger.critical(message: message, evenIdents)
	}

	public static func terminal(message: String, evenIdents: Bool = even) -> Never  {
		Log.logger.terminal(message: message, evenIdents)
		fatalError(message)
	}
}


================================================
FILE: Sources/PerfectLib/PerfectError.swift
================================================
//
//  PerfectError.swift
//  PerfectLib
//
//  Created by Kyle Jessup on 7/5/15.
//	Copyright (C) 2015 PerfectlySoft, Inc.
//
//===----------------------------------------------------------------------===//
//
// This source file is part of the Perfect.org open source project
//
// Copyright (c) 2015 - 2016 PerfectlySoft Inc. and the Perfect project authors
// Licensed under Apache License v2.0
//
// See http://perfect.org/licensing.html for license information
//
//===----------------------------------------------------------------------===//
//

#if os(Linux)
import SwiftGlibc

var errno: Int32 {
	return __errno_location().pointee
}
#else
import Darwin
#endif

/// Some but not all of the exception types which may be thrown by the system
public enum PerfectError : Error {
	/// A network related error code and message.
	case networkError(Int32, String)
	/// A file system related error code and message.
	case fileError(Int32, String)
	/// A OS level error code and message.
	case systemError(Int32, String)
	/// An API exception error message.
	case apiError(String)
}


func ThrowFileError(file: String = #file, function: String = #function, line: Int = #line) throws -> Never  {
	let err = errno
	let msg = String(validatingUTF8: strerror(err))!
	
//	print("FileError: \(err) \(msg)")
	
	throw PerfectError.fileError(err, msg + " \(file) \(function) \(line)")
}


func ThrowSystemError(file: String = #file, function: String = #function, line: Int = #line) throws -> Never  {
	let err = errno
	let msg = String(validatingUTF8: strerror(err))!
	
//	print("SystemError: \(err) \(msg)")
	
	throw PerfectError.systemError(err, msg + " \(file) \(function) \(line)")
}


func ThrowNetworkError(file: String = #file, function: String = #function, line: Int = #line) throws -> Never  {
	let err = errno
	let msg = String(validatingUTF8: strerror(err))!
	
//	print("NetworkError: \(err) \(msg)")
	
	throw PerfectError.networkError(err, msg + " \(file) \(function) \(line)")
}


================================================
FILE: Sources/PerfectLib/PerfectServer.swift
================================================
//
//  Perfect.swift
//  PerfectLib
//
//  Created by Kyle Jessup on 7/5/15.
//	Copyright (C) 2015 PerfectlySoft, Inc.
//
//===----------------------------------------------------------------------===//
//
// This source file is part of the Perfect.org open source project
//
// Copyright (c) 2015 - 2016 PerfectlySoft Inc. and the Perfect project authors
// Licensed under Apache License v2.0
//
// See http://perfect.org/licensing.html for license information
//
//===----------------------------------------------------------------------===//
//

#if os(Linux)
    import SwiftGlibc
#else
    import Darwin
#endif

/// Provides access to various system level features for the process.
/// A static instance of this class is created at startup and all access to this object go through the `PerfectServer.staticPerfectServer` static property.
public struct PerfectServer {
	
	@available(*, deprecated, message: "No longer required to call this")
	public static func initializeServices() {
	
	}
	
    /// Switch the current process to run with the permissions of the indicated user
    public static func switchTo(userName unam: String) throws {
        guard let pw = getpwnam(unam) else {
            try ThrowSystemError()
        }
        let gid = pw.pointee.pw_gid
        let uid = pw.pointee.pw_uid
        guard 0 == setgid(gid) else {
            try ThrowSystemError()
        }
        guard 0 == setuid(uid) else {
            try ThrowSystemError()
        }
    }
}



================================================
FILE: Sources/PerfectLib/SysProcess.swift
================================================
//
//  SysProcess.swift
//  PerfectLib
//
//  Created by Kyle Jessup on 7/20/15.
//  Copyright (C) 2015 PerfectlySoft, Inc.
//
//===----------------------------------------------------------------------===//
//
// This source file is part of the Perfect.org open source project
//
// Copyright (c) 2015 - 2016 PerfectlySoft Inc. and the Perfect project authors
// Licensed under Apache License v2.0
//
// See http://perfect.org/licensing.html for license information
//
//===----------------------------------------------------------------------===//
//

#if os(Linux)
	import SwiftGlibc
	let WUNTRACED = Int32(2)
	let WNOHANG = Int32(1)
	public let SIGTERM = Int32(15)
#else
	import Darwin
#endif

/// This class permits an external process to be launched given a set of command line arguments and environment variables.
/// The standard in, out and err file streams are made available. The process can be terminated or permitted to be run to completion.
public class SysProcess {

	/// The standard in file stream.
	public var stdin: File?
	/// The standard out file stream.
	public var stdout: File?
	/// The standard err file stream.
	public var stderr: File?
	/// The process identifier.
	public var pid = pid_t(-1)
	/// The process group identifier.
	public var gid = pid_t(-1)

	/// Initialize the object and launch the process.
	/// - parameter cmd: The path to the process which will be launched.
	/// - parameter args: An optional array of String arguments which will be given to the process.
	/// - parameter env: An optional array of environment variable name and value pairs.
	/// - parameter newGroup: Create a new process group for this and all sub-processes. Default is no.
	/// - throws: `PerfectError.SystemError`
	public init(_ cmd: String, args: [String]?, env: [(String,String)]?, newGroup: Bool = false) throws {
		typealias maybeCChar = UnsafeMutablePointer<CChar>?
		
		let cArgsCount = args?.count ?? 0
		let cArgs = UnsafeMutablePointer<maybeCChar>.allocate(capacity: cArgsCount + 2)

		defer {
			cArgs.deinitialize(count: cArgsCount + 2)
			cArgs.deallocate()
		}

		cArgs[0] = strdup(cmd)
		cArgs[cArgsCount + 1] = nil
		
		for idx in 0..<cArgsCount {
			cArgs[idx+1] = strdup(args![idx])
		}

		let cEnvCount = env?.count ?? 0
		let cEnv = UnsafeMutablePointer<maybeCChar>.allocate(capacity: cEnvCount + 1)

		defer {
            cEnv.deinitialize(count: cEnvCount + 1)
            cEnv.deallocate()
        }

		cEnv[cEnvCount] = nil
		for idx in 0..<cEnvCount {
			cEnv[idx] = strdup(env![idx].0 + "=" + env![idx].1)
		}

		var fSTDIN: [Int32] = [0, 0]
		var fSTDOUT: [Int32] = [0, 0]
		var fSTDERR: [Int32] = [0, 0]

		fSTDIN.withUnsafeMutableBytes {
			_ = pipe($0.bindMemory(to: Int32.self).baseAddress)
		}
		fSTDOUT.withUnsafeMutableBytes {
			_ = pipe($0.bindMemory(to: Int32.self).baseAddress)
		}
		fSTDERR.withUnsafeMutableBytes {
			_ = pipe($0.bindMemory(to: Int32.self).baseAddress)
		}
    #if os(Linux)
		var action = posix_spawn_file_actions_t()
		var attr = posix_spawnattr_t()
    #else
		var action = posix_spawn_file_actions_t(nil as OpaquePointer?)
		var attr = posix_spawnattr_t(nil as OpaquePointer?)
    #endif

        // nerdo: This probably causes SysProcess to fail on tvOS, but it doesn't seem to be called in any of the
        // basic, core Perfect libraries, so this is probably a non-issue unless it is used directly
    #if os(tvOS)
        var procPid = pid_t()
        var spawnRes = 0
    #else
		posix_spawn_file_actions_init(&action);
		posix_spawn_file_actions_adddup2(&action, fSTDOUT[1], STDOUT_FILENO);
		posix_spawn_file_actions_adddup2(&action, fSTDIN[0], STDIN_FILENO);
		posix_spawn_file_actions_adddup2(&action, fSTDERR[1], STDERR_FILENO);

		posix_spawn_file_actions_addclose(&action, fSTDOUT[0]);
		posix_spawn_file_actions_addclose(&action, fSTDIN[0]);
		posix_spawn_file_actions_addclose(&action, fSTDERR[0]);
		posix_spawn_file_actions_addclose(&action, fSTDOUT[1]);
		posix_spawn_file_actions_addclose(&action, fSTDIN[1]);
		posix_spawn_file_actions_addclose(&action, fSTDERR[1]);
		
		posix_spawnattr_init(&attr)
		
		if newGroup {
			// By default, all flags are unset after the init call
			// so no need to OR in the existing flags.
			posix_spawnattr_setflags(&attr, Int16(POSIX_SPAWN_SETPGROUP))
		}

		var procPid = pid_t()
		let spawnRes = posix_spawnp(&procPid, cmd, &action, &attr, cArgs, cEnv)
		posix_spawn_file_actions_destroy(&action)
		posix_spawnattr_destroy(&attr)

		for idx in 0..<cArgsCount {
			free(cArgs[idx])
		}

		for idx in 0..<cEnvCount {
			free(cEnv[idx])
		}
    #endif

	#if os(Linux)
		// On Ubuntu the getpgid(pid_t) call does not seem to work.
		// However, the Posix standard says that the pgid is the same
		// as the pid of the first process spawned, so we can just use that.
		gid = procPid
		_ = SwiftGlibc.close(fSTDIN[0])
		_ = SwiftGlibc.close(fSTDOUT[1])
		_ = SwiftGlibc.close(fSTDERR[1])
		if spawnRes != 0 {
			_ = SwiftGlibc.close(fSTDIN[1])
			_ = SwiftGlibc.close(fSTDOUT[0])
			_ = SwiftGlibc.close(fSTDERR[0])
			try ThrowSystemError()
		}
	#else
		gid = Darwin.getpgid(procPid)
		_ = Darwin.close(fSTDIN[0])
		_ = Darwin.close(fSTDOUT[1])
		_ = Darwin.close(fSTDERR[1])
		if spawnRes != 0 {
			_ = Darwin.close(fSTDIN[1])
			_ = Darwin.close(fSTDOUT[0])
			_ = Darwin.close(fSTDERR[0])
			try ThrowSystemError()
		}
	#endif
		pid = procPid
		stdin = File("stdin", fd: fSTDIN[1])
		stdout = File("stdout", fd: fSTDOUT[0])
		stderr = File("stderr", fd: fSTDERR[0])
	}

	deinit {
		close()
	}

	/// Returns true if the process was opened and was running at some point.
	/// Note that the process may not be currently running. Use `wait(false)` to check if the process is currently running.
	public func isOpen() -> Bool {
		return pid != -1
	}

	/// Terminate the process and clean up.
	public func close() {
		if stdin != nil {
			stdin!.close()
		}
		if stdout != nil {
			stdout!.close()
		}
		if stderr != nil {
			stderr!.close()
		}
		if pid != -1 {
			do {
				let _ = try kill()
			} catch {

			}
		}
		stdin = nil
		stdout = nil
		stderr = nil
		pid = -1
		gid = -1
	}

	/// Detach from the process such that it will not be manually terminated when this object is deinitialized.
	public func detach() {
		pid = -1
	}

	/// Determine if the process has completed running and retrieve its result code.
	public func wait(hang: Bool = true) throws -> Int32 {
		var code = Int32(0)
		while true {
			let status = waitpid(pid, &code, WUNTRACED | (hang ? 0 : WNOHANG))
			if status == -1 && errno == EINTR {
				continue
			}
			guard status != -1 else {
				try ThrowSystemError()
			}
			if status == 0 && !hang {
				return 0
			}
			break
		}
		pid = -1
		return (((code) & 0xff00) >> 8)
	}

	/// Terminate the process and return its result code.
	public func kill(signal: Int32 = SIGTERM) throws -> Int32 {
	#if os(Linux)
		let status = SwiftGlibc.kill(pid, signal)
	#else
		let status = Darwin.kill(pid, signal)
	#endif
		guard status != -1 else {
			try ThrowSystemError()
		}
		return try wait()
	}
	
	/// Terminate the process group and return the root process result code.
	public func killGroup(signal: Int32 = SIGTERM) throws -> Int32 {
		#if os(Linux)
			let status = SwiftGlibc.killpg(gid, signal)
		#else
			let status = Darwin.killpg(gid, signal)
		#endif
		guard status != -1 else {
			try ThrowSystemError()
		}
		return try wait()
	}
}


================================================
FILE: Sources/PerfectLib/Utilities.swift
================================================
//
//  Utilities.swift
//  PerfectLib
//
//  Created by Kyle Jessup on 7/17/15.
//	Copyright (C) 2015 PerfectlySoft, Inc.
//
//===----------------------------------------------------------------------===//
//
// This source file is part of the Perfect.org open source project
//
// Copyright (c) 2015 - 2016 PerfectlySoft Inc. and the Perfect project authors
// Licensed under Apache License v2.0
//
// See http://perfect.org/licensing.html for license information
//
//===----------------------------------------------------------------------===//
//

#if os(Linux)
	import LinuxBridge
#else
	import Darwin
#endif
import Foundation

/// This class permits an UnsafeMutablePointer to be used as a GeneratorType
public struct GenerateFromPointer<T> : IteratorProtocol {
	
	public typealias Element = T
	
	var count = 0
	var pos = 0
	var from: UnsafeMutablePointer<T>
	
	/// Initialize given an UnsafeMutablePointer and the number of elements pointed to.
	public init(from: UnsafeMutablePointer<T>, count: Int) {
		self.from = from
		self.count = count
	}
	
	/// Return the next element or nil if the sequence has been exhausted.
	mutating public func next() -> Element? {
		guard count > 0 else {
			return nil
		}
		count -= 1
		let result = from[pos]
		pos += 1
		return result
	}
}

/// A generalized wrapper around the Unicode codec operations.
public struct Encoding {
	
	/// Return a String given a character generator.
	public static func encode<D : UnicodeCodec, G : IteratorProtocol>(codec inCodec: D, generator: G) -> String where G.Element == D.CodeUnit {
		var encodedString = ""
		var finished: Bool = false
		var mutableDecoder = inCodec
		var mutableGenerator = generator
		repeat {
			let decodingResult = mutableDecoder.decode(&mutableGenerator)
			switch decodingResult {
			case .scalarValue(let char):
				encodedString.append(String(char))
			case .emptyInput:
				finished = true
				/* ignore errors and unexpected values */
			case .error:
				finished = true
			}
		} while !finished
		return encodedString
	}
}

/// 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.
public struct UTF8Encoding {
	
	/// Use a character generator to create a String.
	public static func encode<G : IteratorProtocol>(generator gen: G) -> String where G.Element == UTF8.CodeUnit {
		return Encoding.encode(codec: UTF8(), generator: gen)
	}
	
	/// Use a character sequence to create a String.
	public static func encode<S : Sequence>(bytes byts: S) -> String where S.Iterator.Element == UTF8.CodeUnit {
		return encode(generator: byts.makeIterator())
	}
	
	/// Use a character sequence to create a String.
	public static func encode(bytes byts: [UTF8.CodeUnit]) -> String {
		return encode(generator: byts.makeIterator())
	}
	
	/// Decode a String into an array of UInt8.
	public static func decode(string str: String) -> Array<UInt8> {
		return [UInt8](str.utf8)
	}
}

extension UInt8 {
	var shouldURLEncode: Bool {
		let cc = self
		return ( ( cc >= 128 )
			|| ( cc < 33 )
			|| ( cc >= 34  && cc < 38 )
			|| ( ( cc > 59  && cc < 61) || cc == 62 || cc == 58)
			|| ( ( cc >= 91  && cc < 95 ) || cc == 96 )
			|| ( cc >= 123 && cc <= 126 )
			|| self == 43 )
	}
	
	// same as String(self, radix: 16)
	// but outputs two characters. i.e. 0 padded
	var hexString: String {
		var s = ""
		let b = self >> 4
		s.append(String(Character(UnicodeScalar(b > 9 ? b - 10 + 65 : b + 48))))
		let b2 = self & 0x0F
		s.append(String(Character(UnicodeScalar(b2 > 9 ? b2 - 10 + 65 : b2 + 48))))
		return s
	}
}

extension String {
	/// Returns the String with all special HTML characters encoded.
	public var stringByEncodingHTML: String {
		var ret = ""
		var g = unicodeScalars.makeIterator()
		var lastWasCR = false
		while let c = g.next() {
			if c == UnicodeScalar(10) {
				if lastWasCR {
					lastWasCR = false
					ret.append("\n")
				} else {
					ret.append("<br>\n")
				}
				continue
			} else if c == UnicodeScalar(13) {
				lastWasCR = true
				ret.append("<br>\r")
				continue
			}
			lastWasCR = false
			if c < UnicodeScalar(0x0009) {
				if let scale = UnicodeScalar(0x0030 + UInt32(c)) {
					ret.append("&#x")
					ret.append(String(Character(scale)))
					ret.append(";")
				}
			} else if c == UnicodeScalar(0x0022) {
				ret.append("&quot;")
			} else if c == UnicodeScalar(0x0026) {
				ret.append("&amp;")
			} else if c == UnicodeScalar(0x0027) {
				ret.append("&#39;")
			} else if c == UnicodeScalar(0x003C) {
				ret.append("&lt;")
			} else if c == UnicodeScalar(0x003E) {
				ret.append("&gt;")
			} else if c > UnicodeScalar(126) {
				ret.append("&#\(UInt32(c));")
			} else {
				ret.append(String(Character(c)))
			}
		}
		return ret
	}
	
	/// Returns the String with all special URL characters encoded.
	public var stringByEncodingURL: String {
		var ret = ""
		var g = utf8.makeIterator()
		while let c = g.next() {
			if c.shouldURLEncode {
				ret.append(String(Character(UnicodeScalar(37))))
				ret.append(c.hexString)
			} else {
				ret.append(String(Character(UnicodeScalar(c))))
			}
		}
		return ret
	}
	
	// Utility - not sure if it makes the most sense to have here or outside or elsewhere
	static func byteFromHexDigits(one c1v: UInt8, two c2v: UInt8) -> UInt8? {
		
		let capA: UInt8 = 65
		let capF: UInt8 = 70
		let lowA: UInt8 = 97
		let lowF: UInt8 = 102
		let zero: UInt8 = 48
		let nine: UInt8 = 57
		
		var newChar = UInt8(0)
		
		if c1v >= capA && c1v <= capF {
			newChar = c1v - capA + 10
		} else if c1v >= lowA && c1v <= lowF {
			newChar = c1v - lowA + 10
		} else if c1v >= zero && c1v <= nine {
			newChar = c1v - zero
		} else {
			return nil
		}
		
		newChar *= 16
		
		if c2v >= capA && c2v <= capF {
			newChar += c2v - capA + 10
		} else if c2v >= lowA && c2v <= lowF {
			newChar += c2v - lowA + 10
		} else if c2v >= zero && c2v <= nine {
			newChar += c2v - zero
		} else {
			return nil
		}
		return newChar
	}
	
	/// Decode the % encoded characters in a URL and return result
	public var stringByDecodingURL: String? {
		let percent: UInt8 = 37
		let plus: UInt8 = 43
		let space: UInt8 = 32
		var bytesArray = [UInt8]()
		var g = utf8.makeIterator()
		while let c = g.next() {
			if c == percent {
				guard let c1v = g.next() else {
					return nil
				}
				guard let c2v = g.next() else {
					return nil
				}
				guard let newChar = String.byteFromHexDigits(one: c1v, two: c2v) else {
					return nil
				}
				bytesArray.append(newChar)
			} else if c == plus {
				bytesArray.append(space)
			} else {
				bytesArray.append(c)
			}
		}
		bytesArray.append(0)
		return bytesArray.withUnsafeBytes {
			guard let p = $0.bindMemory(to: Int8.self).baseAddress else {
				return nil
			}
			return String(validatingUTF8: p)
		}
	}
	
	/// Decode a hex string into resulting byte array
	public var decodeHex: [UInt8]? {
		
		var bytesArray = [UInt8]()
		var g = utf8.makeIterator()
		while let c1v = g.next() {
			
			guard let c2v = g.next() else {
				return nil
			}
			
			guard let newChar = String.byteFromHexDigits(one: c1v, two: c2v) else {
				return nil
			}
			
			bytesArray.append(newChar)
		}
		return bytesArray
	}
}

@available(*, deprecated, message: "Use Foundation.UUID")
public struct UUID {
	let uuid: uuid_t
	
	public init() {
		let u = UnsafeMutablePointer<UInt8>.allocate(capacity:  MemoryLayout<uuid_t>.size)
		defer {
			u.deallocate()
		}
		uuid_generate_random(u)
		uuid = UUID.uuidFromPointer(u)
	}
	
	public init(_ string: String) {
		let u = UnsafeMutablePointer<UInt8>.allocate(capacity:  MemoryLayout<uuid_t>.size)
		defer {
			u.deallocate()
		}
		uuid_parse(string, u)
		uuid = UUID.uuidFromPointer(u)
	}
	
	init(_ uuid: uuid_t) {
		self.uuid = uuid
	}
	
	private static func uuidFromPointer(_ u: UnsafeMutablePointer<UInt8>) -> uuid_t {
		// is there a better way?
		return 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])
	}
	
	public var string: String {
		let u = UnsafeMutablePointer<UInt8>.allocate(capacity:  MemoryLayout<uuid_t>.size)
		let unu = UnsafeMutablePointer<Int8>.allocate(capacity:  37) // as per spec. 36 + null
		defer {
			u.deallocate()
			unu.deallocate()
		}
		var uu = uuid
		memcpy(u, &uu, MemoryLayout<uuid_t>.size)
		uuid_unparse_lower(u, unu)
		return String(validatingUTF8: unu)!
	}
}

extension String {
	
	/// Parse an HTTP Digest authentication header returning a Dictionary containing each part.
	public func parseAuthentication() -> [String:String] {
		var ret = [String:String]()
		if let _ = range(of: "Digest ") {
			ret["type"] = "Digest"
			let wantFields = ["username", "nonce", "nc", "cnonce", "response", "uri", "realm", "qop", "algorithm"]
			for field in wantFields {
				if let foundField = String.extractField(from: self, named: field) {
					ret[field] = foundField
				}
			}
		}
		return ret
	}
	
	private static func extractField(from frm: String, named: String) -> String? {
		guard let range = frm.range(of: named + "=") else {
			return nil
		}
		
		var currPos = range.upperBound
		var ret = ""
		let quoted = frm[currPos] == "\""
		if quoted {
			currPos = frm.index(after: currPos)
			let tooFar = frm.endIndex
			while currPos != tooFar {
				if frm[currPos] == "\"" {
					break
				}
				ret.append(frm[currPos])
				currPos = frm.index(after: currPos)
			}
		} else {
			let tooFar = frm.endIndex
			while currPos != tooFar {
				if frm[currPos] == "," {
					break
				}
				ret.append(frm[currPos])
				currPos = frm.index(after: currPos)
			}
		}
		return ret
	}
}

extension String {
	
	/// Replace all occurrences of `string` with `withString`.
	public func stringByReplacing(string strng: String, withString: String) -> String {
		
		guard !strng.isEmpty else {
			return self
		}
		guard !isEmpty else {
			return self
		}
		
		var ret = ""
		var idx = startIndex
		let endIdx = endIndex
		
		while idx != endIdx {
			if self[idx] == strng[strng.startIndex] {
				var newIdx = index(after: idx)
				var findIdx = strng.index(after: strng.startIndex)
				let findEndIdx = strng.endIndex
				
				while newIdx != endIndex && findIdx != findEndIdx && self[newIdx] == strng[findIdx] {
					newIdx = index(after: newIdx)
					findIdx = strng.index(after: findIdx)
				}
				
				if findIdx == findEndIdx { // match
					ret.append(withString)
					idx = newIdx
					continue
				}
			}
			ret.append(self[idx])
			idx = index(after: idx)
		}
		
		return ret
	}
	
	// For compatibility due to shifting swift
	public func contains(string: String) -> Bool {
		return nil != range(of: string)
	}
}

extension String {
	func begins(with str: String) -> Bool {
		return starts(with: str)
	}
	
	func ends(with str: String) -> Bool {
		guard count >= str.count else {
			return false
		}
		return str.begins(with: String(self[index(endIndex, offsetBy: -str.count)..<endIndex]))
	}
}

/// Returns the current time according to ICU
/// ICU dates are the number of milliseconds since the reference date of Thu, 01-Jan-1970 00:00:00 GMT
public func getNow() -> Double {
	
	var posixTime = timeval()
	gettimeofday(&posixTime, nil)
	return Double((posixTime.tv_sec * 1000) + (Int(posixTime.tv_usec)/1000))
}
/// Converts the milliseconds based ICU date to seconds since the epoch
public func icuDateToSeconds(_ icuDate: Double) -> Int {
	return Int(icuDate / 1000)
}
/// Converts the seconds since the epoch into the milliseconds based ICU date
public func secondsToICUDate(_ seconds: Int) -> Double {
	return Double(seconds * 1000)
}

/// Format a date value according to the indicated format string and return a date string.
/// - parameter date: The date value
/// - parameter format: The format by which the date will be formatted. Use a valid strftime style format string.
/// - parameter timezone: The optional timezone in which the date is expected to be based. Default is the local timezone.
/// - parameter locale: The optional locale which will be used when parsing the date. Default is the current global locale.
/// - returns: The resulting date string
/// - throws: `PerfectError.systemError`
public func formatDate(_ date: Double, format: String, timezone inTimezone: String? = nil, locale inLocale: String? = nil) throws -> String {
	
	var t = tm()
	var time = time_t(date / 1000.0)
	gmtime_r(&time, &t)
	let maxResults = 1024
	let results = UnsafeMutablePointer<Int8>.allocate(capacity:  maxResults)
	defer {
		results.deallocate()
	}
	let res = strftime(results, maxResults, format, &t)
	if res > 0 {
		let formatted = String(validatingUTF8: results)
		return formatted!
	}
	try ThrowSystemError()
}

extension UnicodeScalar {
	
	/// Returns true if the UnicodeScalar is a white space character
	public func isWhiteSpace() -> Bool {
		return isspace(Int32(value)) != 0
	}
	/// Returns true if the UnicodeScalar is a digit character
	public func isDigit() -> Bool {
		return isdigit(Int32(value)) != 0
	}
	/// Returns true if the UnicodeScalar is an alpha-numeric character
	public func isAlphaNum() -> Bool {
		return isalnum(Int32(value)) != 0
	}
	/// Returns true if the UnicodeScalar is a hexadecimal character
	public func isHexDigit() -> Bool {
		if isDigit() {
			return true
		}
		switch self {
		case "A", "B", "C", "D", "E", "F", "a", "b", "c", "d", "e", "f":
			return true
		default:
			return false
		}
	}
}

extension String {
	
	var filePathSeparator: UnicodeScalar {
		return UnicodeScalar(47)
	}
	
	var fileExtensionSeparator: UnicodeScalar {
		return UnicodeScalar(46)
	}
	
	public var beginsWithFilePathSeparator: Bool {
		guard count > 0 else {
			return false
		}
		return self[startIndex] == Character(filePathSeparator)
	}
	
	public var endsWithFilePathSeparator: Bool {
		guard count > 0 else {
			return false
		}
		return self[index(before: endIndex)] == Character(filePathSeparator)
	}
	
	private func filePathComponents(addFirstLast addfl: Bool) -> [String] {
		var r = [String]()
		guard count > 0 else {
			return r
		}
		let fsc = Character(filePathSeparator)
		let beginSlash = self[startIndex] == fsc
		if addfl && beginSlash {
			r.append(String(filePathSeparator))
		}
		
		r.append(contentsOf: split(separator: fsc).map { String($0) })
		
		if addfl && self[index(before: endIndex)] == fsc {
			if !beginSlash || r.count > 1 {
				r.append(String(filePathSeparator))
			}
		}
		return r
	}
	
	public var filePathComponents: [String] {
		return filePathComponents(addFirstLast: true)
	}
	
	public var lastFilePathComponent: String {
		let last = filePathComponents(addFirstLast: false).last ?? ""
		if last.isEmpty && first == Character(filePathSeparator) {
			return String(filePathSeparator)
		}
		return last
	}
	
	public var deletingLastFilePathComponent: String {
		var comps = filePathComponents(addFirstLast: false)
		guard comps.count > 1 else {
			if beginsWithFilePathSeparator {
				return String(filePathSeparator)
			}
			return ""
		}
		comps.removeLast()
		let joined = comps.joined(separator: String(filePathSeparator))
		if beginsWithFilePathSeparator {
			return String(filePathSeparator) + joined
		}
		return joined
	}
	
	private func lastPathSeparator(in unis: String) -> String.Index {
		let startIndex = unis.startIndex
		var endIndex = unis.endIndex
		while endIndex != startIndex {
			if unis[unis.index(before: endIndex)] != Character(filePathSeparator) {
				break
			}
			endIndex = unis.index(before: endIndex)
		}
		return endIndex
	}
	
	private func lastExtensionSeparator(in unis: String, endIndex: String.Index) -> String.Index {
		var endIndex = endIndex
		while endIndex != startIndex {
			endIndex = unis.index(before: endIndex)
			if unis[endIndex] == Character(fileExtensionSeparator) {
				break
			}
		}
		return endIndex
	}
	
	public var deletingFileExtension: String {
		var endIndex = lastPathSeparator(in: self)
		let noTrailsIndex = endIndex
		endIndex = lastExtensionSeparator(in: self, endIndex: endIndex)
		guard endIndex != startIndex else {
			if noTrailsIndex == startIndex {
				return self
			}
			return String(self[startIndex..<noTrailsIndex])
		}
		return String(self[startIndex..<endIndex])
	}
	
	public var filePathExtension: String {
		var endIndex = lastPathSeparator(in: self)
		let noTrailsIndex = endIndex
		endIndex = lastExtensionSeparator(in: self, endIndex: endIndex)
		guard endIndex != startIndex else {
			return ""
		}
		return String(self[index(after: endIndex)..<noTrailsIndex])
	}
	
	public var resolvingSymlinksInFilePath: String {
		return File(self).realPath
	}
}


================================================
FILE: Tests/LinuxMain.swift
================================================
import XCTest
@testable import PerfectLibTests

XCTMain([
	testCase(PerfectLibTests.allTests),
])


================================================
FILE: Tests/PerfectLibTests/PerfectLibTests.swift
================================================
//
//  PerfectLibTests.swift
//  PerfectLibTests
//
//  Created by Kyle Jessup on 2015-10-19.
//  Copyright © 2015 PerfectlySoft. All rights reserved.
//
//===----------------------------------------------------------------------===//
//
// This source file is part of the Perfect.org open source project
//
// Copyright (c) 2015 - 2016 PerfectlySoft Inc. and the Perfect project authors
// Licensed under Apache License v2.0
//
// See http://perfect.org/licensing.html for license information
//
//===----------------------------------------------------------------------===//
//


import XCTest
@testable import PerfectLib

#if os(Linux)
import SwiftGlibc
import Foundation
#endif

class PerfectLibTests: XCTestCase {

	override func setUp() {
		super.setUp()
	#if os(Linux)
		SwiftGlibc.srand(UInt32(time(nil)))
	#endif
	}

	override func tearDown() {
		// Put teardown code here. This method is called after the invocation of each test method in the class.
		super.tearDown()
	}

	func testJSONConvertibleObject1() {

		class Test: JSONConvertibleObject {

			static let registerName = "test"

			var one = 0
			override func setJSONValues(_ values: [String : Any]) {
				self.one = getJSONValue(named: "One", from: values, defaultValue: 42)
			}
			override func getJSONValues() -> [String : Any] {
				return [JSONDecoding.objectIdentifierKey:Test.registerName, "One":1]
			}
		}

		JSONDecoding.registerJSONDecodable(name: Test.registerName, creator: { return Test() })

		do {
			let encoded = try Test().jsonEncodedString()
			let decoded = try encoded.jsonDecode() as? Test

			XCTAssert(decoded != nil)

			XCTAssert(decoded!.one == 1)
		} catch {
			XCTAssert(false, "Exception \(error)")
		}
	}
	
	func testJSONConvertibleObject2() {
		
		class User: JSONConvertibleObject {
			static let registerName = "user"
			var firstName = ""
			var lastName = ""
			var age = 0
			override func setJSONValues(_ values: [String : Any]) {
				self.firstName = getJSONValue(named: "firstName", from: values, defaultValue: "")
				self.lastName = getJSONValue(named: "lastName", from: values, defaultValue: "")
				self.age = getJSONValue(named: "age", from: values, defaultValue: 0)
			}
			override func getJSONValues() -> [String : Any] {
				return [
					JSONDecoding.objectIdentifierKey:User.registerName,
					"firstName":firstName,
					"lastName":lastName,
					"age":age
				]
			}
		}
		
		// register the class. do this once
		JSONDecoding.registerJSONDecodable(name: User.registerName, creator: { return User() })
		
		// encode and decode the object
		let user = User()
		user.firstName = "Donnie"
		user.lastName = "Darko"
		user.age = 17
		
		do {
			let encoded = try user.jsonEncodedString()
			guard let user2 = try encoded.jsonDecode() as? User else {
				return XCTAssert(false, "Invalid object \(encoded)")
			}			
			XCTAssert(user.firstName == user2.firstName)
			XCTAssert(user.lastName == user2.lastName)
			XCTAssert(user.age == user2.age)
		} catch {}
	}

	func testJSONEncodeDecode() {

		let 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"]]
		var encoded = ""
		var decoded: [Any]?
		do {

			encoded = try srcAry.jsonEncodedString()

		} catch let e {
			XCTAssert(false, "Exception while encoding JSON \(e)")
			return
		}

		do {

			decoded = try encoded.jsonDecode() as? [Any]

		} catch let e {
			XCTAssert(false, "Exception while decoding JSON \(e)")
			return
		}

		XCTAssert(decoded != nil)

		let resAry = decoded!

		XCTAssert(srcAry.count == resAry.count)

		for index in 0..<srcAry.count {

			let d1 = srcAry[index]
			let d2 = resAry[index] as? [String:Any]

			for (key, value) in d1 {

				let value2 = d2![key]

				XCTAssert(value2 != nil)

				switch value {
				case let i as Int:
					XCTAssert(i == value2 as! Int)
				case let d as Double:
					XCTAssert(d == value2 as! Double)
				case let s as String:
					XCTAssert(s == value2 as! String)
				case let s as Bool:
					XCTAssert(s == value2 as! Bool)

				default:
					()
					// does not go on to test sub-sub-elements
				}
			}

		}
	}
    func testIntegerTypesEncode(){
        let i8:Int8 = -12
        let i16:Int16 = -1234
        let i32:Int32 = -1234567890
        let i64:Int64 = -123456789012345678

        let u8:UInt8 = 12
        let u16:UInt16 = 1234
        let u32:UInt32 = 1234567890
        let u64:UInt64 = 123456789012345678
        
        var srcDict:[String:Any] = [String:Any]()
        var destDict:[String:Any]?
        
        srcDict["i8"] = i8
        srcDict["i16"] = i8
        srcDict["i32"] = i8
        srcDict["i64"] = i8
        srcDict["u8"] = i8
        srcDict["u16"] = i8
        srcDict["u32"] = i8
        srcDict["u64"] = i8
        
        
        var encoded = ""
        
        
        do {
            
            encoded = try i8.jsonEncodedString()
            XCTAssert(encoded == String(i8), "Invalid result")
            
        } catch let e {
            XCTAssert(false, "Exception while encoding i8 \(e)")
            return
        }

        do {
            
            encoded = try i16.jsonEncodedString()
            XCTAssert(encoded == String(i16), "Invalid result")

        } catch let e {
            XCTAssert(false, "Exception while encoding i16 \(e)")
            return
        }

        do {
            
            encoded = try i32.jsonEncodedString()
            XCTAssert(encoded == String(i32), "Invalid result")

        } catch let e {
            XCTAssert(false, "Exception while encoding i32 \(e)")
            return
        }

        do {
            
            encoded = try i64.jsonEncodedString()
            XCTAssert(encoded == String(i64), "Invalid result")

        } catch let e {
            XCTAssert(false, "Exception while encoding i64 \(e)")
            return
        }

        do {
            
            encoded = try u8.jsonEncodedString()
            XCTAssert(encoded == String(u8), "Invalid result")

        } catch let e {
            XCTAssert(false, "Exception while encoding u8 \(e)")
            return
        }
        
        do {
            
            encoded = try u16.jsonEncodedString()
            XCTAssert(encoded == String(u16), "Invalid result")

        } catch let e {
            XCTAssert(false, "Exception while encoding u16 \(e)")
            return
        }
        
        do {
            
            encoded = try u32.jsonEncodedString()
            XCTAssert(encoded == String(u32), "Invalid result")

        } catch let e {
            XCTAssert(false, "Exception while encoding u32 \(e)")
            return
        }
        
        do {
            
            encoded = try u64.jsonEncodedString()
            XCTAssert(encoded == String(u64), "Invalid result")

        } catch let e {
            XCTAssert(false, "Exception while encoding u64 \(e)")
            return
        }
        
        do {
            encoded = ""
            encoded = try srcDict.jsonEncodedString()
            XCTAssert(encoded != "", "Invalid result")
        } catch let e {
            XCTAssert(false, "Exception while encoding srcDict \(e)")
        }

        do {
            destDict = try encoded.jsonDecode() as? [String:Any]
            
        } catch let e {
            XCTAssert(false, "Exception while decoding into destDict \(e)" )
        }
        
        for (key, value) in destDict! {
            
            let value2 = srcDict[key]
            XCTAssert(value2 != nil)
            switch value2 {
            case let i as Int8:
                XCTAssert(value as! Int == Int(i))
            case let i as Int16:
                XCTAssert(value as! Int == Int(i))
            case let i as Int32:
                XCTAssert(value as! Int == Int(i))
            case let i as Int64:
                XCTAssert(value as! Int == Int(i))
            case let i as UInt8:
                XCTAssert(value as! Int == Int(i))
            case let i as UInt16:
                XCTAssert(value as! Int == Int(i))
            case let i as UInt32:
                XCTAssert(value as! Int == Int(i))
            case let i as UInt64:
                XCTAssert(value as! Int == Int(i))
            default:
                ()
            }
            
        }
    }
    
	func testJSONDecodeUnicode() {
		var decoded: [String: Any]?
		let jsonStr = "{\"emoji\": \"\\ud83d\\ude33\"}"     // {"emoji": "\ud83d\ude33"}
		do {
			decoded = try jsonStr.jsonDecode() as? [String: Any]
		} catch let e {

			XCTAssert(false, "Exception while decoding JSON \(e)")
			return
		}

		XCTAssert(decoded != nil)
		let value = decoded!["emoji"]
		XCTAssert(value != nil)
		let emojiStr = decoded!["emoji"] as! String
		XCTAssert(emojiStr == "😳")
	}

	func testSysProcess() {
		do {
			let proc = try SysProcess("ls", args:["-l", "/"], env:[("PATH", "/usr/bin:/bin")])

			XCTAssertTrue(proc.isOpen())
			XCTAssertNotNil(proc.stdin)

			let fileOut = proc.stdout!
			let data = try fileOut.readSomeBytes(count: 4096)

			XCTAssertTrue(data.count > 0)

			let waitRes = try proc.wait()

			XCTAssert(0 == waitRes, "\(waitRes) \(UTF8Encoding.encode(bytes: data))")

			proc.close()
		} catch {
			XCTAssert(false, "Exception running SysProcess test: \(error)")
		}
	}
	
	func testSysProcessGroup() {
		do {
			let proc = try SysProcess("sh", args: ["-c", "(sleep 10s &) ; (sleep 10s &) ; sleep 10s"], env: [("PATH", "/usr/bin:/bin")], newGroup: true)
			
			XCTAssert(proc.isOpen())
			XCTAssertNotEqual(-1, proc.pid)
			XCTAssertNotEqual(-1, proc.gid)
			
			// Ensure that the process group is different from the test process
			#if os(Linux)
				let testGid = SwiftGlibc.getpgrp()
			#else
				let testGid = Darwin.getpgrp()
			#endif
			XCTAssertNotEqual(testGid, proc.gid)
			
			let savedGid = proc.gid
			
			XCTAssertTrue(try hasChildProcesses(gid: savedGid))
			_ = try proc.killGroup()
			XCTAssertFalse(try hasChildProcesses(gid: savedGid))
		} catch {
			XCTAssert(false, "Exception running SysProcess group test: \(error)")
		}
	}
	
	private func hasChildProcesses(gid: pid_t) throws -> Bool {
		let proc = try SysProcess("sh", args: ["-c", "ps -e -o pgid,comm | grep \(gid)"], env: [("PATH", "/usr/bin:/bin")])
		
		_ = try proc.wait()
		
		if let bytes = try proc.stdout?.readSomeBytes(count: 4096) {
			return bytes.count > 0
		} else {
			return false
		}
	}

	func testStringByEncodingHTML() {
		let src = "<b>\"quoted\" '& ☃"
		let res = src.stringByEncodingHTML
		XCTAssertEqual(res, "&lt;b&gt;&quot;quoted&quot; &#39;&amp; &#9731;")
	}

	func testStringByEncodingURL() {
		let src = "This has \"weird\" characters & ßtuff"
		let res = src.stringByEncodingURL
		XCTAssertEqual(res, "This%20has%20%22weird%22%20characters%20&%20%C3%9Ftuff")
	}

	func testStringByDecodingURL() {
		let src = "This has \"weird\" characters & ßtuff"
		let mid = src.stringByEncodingURL
		guard let res = mid.stringByDecodingURL else {
			XCTAssert(false, "Got nil String")
			return
		}
		XCTAssert(res == src, "Bad URL decoding")
	}

	func testStringByDecodingURL2() {
		let src = "This is badly%PWencoded"
		let res = src.stringByDecodingURL

		XCTAssert(res == nil, "Bad URL decoding")
	}

	func testStringByReplacingString() {

		let src = "ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ"
		let test = "ABCFEDGHIJKLMNOPQRSTUVWXYZABCFEDGHIJKLMNOPQRSTUVWXYZABCFEDGHIJKLMNOPQRSTUVWXYZ"
		let find = "DEF"
		let rep = "FED"

		let res = src.stringByReplacing(string: find, withString: rep)

		XCTAssert(res == test)
	}

	func testStringByReplacingString2() {

		let src = ""
		let find = "DEF"
		let rep = "FED"

		let res = src.stringByReplacing(string: find, withString: rep)

		XCTAssert(res == src)
	}

	func testStringByReplacingString3() {

		let src = "ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ"
		let find = ""
		let rep = "FED"

		let res = src.stringByReplacing(string: find, withString: rep)

		XCTAssert(res == src)
	}

	func testStringBeginsWith() {
		let a = "123456"

		XCTAssert(a.begins(with: "123"))
		XCTAssert(!a.begins(with: "abc"))
	}

	func testStringEndsWith() {
		let a = "123456"

		XCTAssert(a.ends(with: "456"))
		XCTAssert(!a.ends(with: "abc"))
	}

	func testDeletingPathExtension() {
		let path = "/a/b/c.txt"
		let del = path.deletingFileExtension
		XCTAssert("/a/b/c" == del)
	}

	func testGetPathExtension() {
		let path = "/a/b/c.txt"
		let ext = path.filePathExtension
		XCTAssert("txt" == ext)
	}

	func testDirCreate() {
		let path = "/tmp/a/b/c/d/e/f/g"
		do {
			try Dir(path).create()

			XCTAssert(Dir(path).exists)

			var unPath = path

			while unPath != "/tmp" {
				try Dir(unPath).delete()
				unPath = unPath.deletingLastFilePathComponent
			}
		} catch {
			XCTAssert(false, "Error while creating dirs: \(error)")
		}
	}

	func testDirCreateRel() {
		let path = "a/b/c/d/e/f/g"
		do {
			try Dir(path).create()
			XCTAssert(Dir(path).exists)
			var unPath = path
			repeat {
				try Dir(unPath).delete()

								// this was killing linux on the final path component
								//unPath = unPath.stringByDeletingLastPathComponent

								var splt = unPath.split(separator: "/").map(String.init)
								splt.removeLast()
								unPath = splt.joined(separator: "/")

			} while !unPath.isEmpty
		} catch {
			XCTAssert(false, "Error while creating dirs: \(error)")
		}
	}

	func testDirForEach() {
		let dirs = ["a/", "b/", "c/"]
		do {
			try Dir("/tmp/a").create()
			for d in dirs {
				try Dir("/tmp/a/\(d)").create()
			}
			var ta = [String]()
			try Dir("/tmp/a").forEachEntry {
				name in
				ta.append(name)
			}
			ta.sort()
			XCTAssert(ta == dirs, "\(ta) == \(dirs)")
			for d in dirs {
				try Dir("/tmp/a/\(d)").delete()
			}
			try Dir("/tmp/a").delete()
		} catch {
			XCTAssert(false, "Error while creating dirs: \(error)")
		}
	}
	
	func testFilePerms() {
		let fileName = "/tmp/\(UUID().uuidString)"
		let file = File(fileName)
		do {
			try file.open(.readWrite, permissions: [.readUser, .writeUser])
			defer {
				file.delete()
			}
			
			let res = file.perms.contains([.readUser, .writeUser])
			XCTAssert(res, "\(file.perms) != \([File.PermissionMode.readUser, File.PermissionMode.writeUser])")
			
		} catch {
			XCTAssert(false, "Error testing file perms: \(error)")
		}
	}
	
	func testDirPerms() {
		let fileName = "/tmp/\(UUID().uuidString)"
		let file = Dir(fileName)
		do {
			try file.create(perms: [.readUser, .writeUser])
			
			let res = file.perms.contains([.readUser, .writeUser])
			XCTAssert(res, "\(file.perms) != \([File.PermissionMode.readUser, File.PermissionMode.writeUser])")
			
			try file.delete()
		} catch {
			XCTAssert(false, "Error testing file perms: \(error)")
		}
	}
	
	func testDirWorkDir() {
		let workDir = File("/tmp").realPath.replacingOccurrences(of: "//", with: "/") + "/"
		let dir = Dir(workDir)
		do {
			try dir.setAsWorkingDir()
			let fetch = Dir.workingDir.path
			XCTAssertEqual(workDir, fetch)
		} catch {
			XCTAssert(false, "Error testing file perms: \(error)")
		}
	}
	
	func testBytesIO() {
		let i8 = 254 as UInt8
		let i16 = 54045 as UInt16
		let i32 = 4160745471 as UInt32
		let i64 = 17293541094125989887 as UInt64
		
		let bytes = Bytes()
		
		bytes.import64Bits(from: i64)
			.import32Bits(from: i32)
			.import16Bits(from: i16)
			.import8Bits(from: i8)
		
		let bytes2 = Bytes()
		bytes2.importBytes(from: bytes)
		
		XCTAssert(i64 == bytes2.export64Bits())
		XCTAssert(i32 == bytes2.export32Bits())
		XCTAssert(i16 == bytes2.export16Bits())
		bytes2.position -= MemoryLayout<UInt16>.size
		XCTAssert(i16 == bytes2.export16Bits())
		XCTAssert(bytes2.availableExportBytes == 1)
		XCTAssert(i8 == bytes2.export8Bits())
	}
	
	func testSymlink() {
		let f1 = File("./foo")
		let f2 = File("./foo2")
		do {
			f2.delete()
			try f1.open(.truncate)
			try f1.write(string: "test")
			f1.close()
			defer {
				f1.delete()
				f2.delete()
			}
			
			let newF2 = try f1.linkTo(path: f2.path)
			
			XCTAssert(try newF2.readString() == "test")
			XCTAssert(newF2.isLink)
		} catch {
			XCTAssert(false, "\(error)")
		}
	}
}

extension PerfectLibTests {
	static var allTests : [(String, (PerfectLibTests) -> () throws -> Void)] {
		return [
			("testJSONConvertibleObject1", testJSONConvertibleObject1),
			("testJSONConvertibleObject2", testJSONConvertibleObject2),
			("testJSONEncodeDecode", testJSONEncodeDecode),
			("testJSONDecodeUnicode", testJSONDecodeUnicode),
			("testSysProcess", testSysProcess),
			("testSysProcessGroup", testSysProcessGroup),
			("testStringByEncodingHTML", testStringByEncodingHTML),
			("testStringByEncodingURL", testStringByEncodingURL),
			("testStringByDecodingURL", testStringByDecodingURL),
			("testStringByDecodingURL2", testStringByDecodingURL2),
			("testStringByReplacingString", testStringByReplacingString),
			("testStringByReplacingString2", testStringByReplacingString2),
			("testStringByReplacingString3", testStringByReplacingString3),

			("testDeletingPathExtension", testDeletingPathExtension),
			("testGetPathExtension", testGetPathExtension),

			("testDirCreate", testDirCreate),
			("testDirCreateRel", testDirCreateRel),
			("testDirForEach", testDirForEach),
			
			("testFilePerms", testFilePerms),
			("testDirPerms", testDirPerms),
			
			("testBytesIO", testBytesIO),
            ("testIntegerTypesEncode", testIntegerTypesEncode)
		]
	}
}


================================================
FILE: Tests/PerfectLibTests/XCTestManifests.swift
================================================
//
//  XCTestManifests.swift
//
//  Created by Kyle Jessup on 2015-10-19.
//  Copyright © 2015 PerfectlySoft. All rights reserved.
//
//===----------------------------------------------------------------------===//
//
// This source file is part of the Perfect.org open source project
//
// Copyright (c) 2015 - 2016 PerfectlySoft Inc. and the Perfect project authors
// Licensed under Apache License v2.0
//
// See http://perfect.org/licensing.html for license information
//
//===----------------------------------------------------------------------===//
//

import XCTest

#if !os(OSX)
public func allTests() -> [XCTestCaseEntry] {
	return [
			testCase(PerfectLibTests.allTests)
	]
}
#endif
Download .txt
gitextract_dd4e6amv/

├── .gitattributes
├── .gitignore
├── .jazzy.yaml
├── CODE_OF_CONDUCT.md
├── CODE_OF_CONDUCT.zh_CN.md
├── LICENSE
├── LICENSE.zh_CN
├── Package.swift
├── README.md
├── README.zh_CN.md
├── Sources/
│   └── PerfectLib/
│       ├── Bytes.swift
│       ├── Dir.swift
│       ├── File.swift
│       ├── JSONConvertible.swift
│       ├── Log.swift
│       ├── PerfectError.swift
│       ├── PerfectServer.swift
│       ├── SysProcess.swift
│       └── Utilities.swift
└── Tests/
    ├── LinuxMain.swift
    └── PerfectLibTests/
        ├── PerfectLibTests.swift
        └── XCTestManifests.swift
Condensed preview — 22 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (148K chars).
[
  {
    "path": ".gitattributes",
    "chars": 146,
    "preview": "Sources/LinuxBridge/* linguist-vendored\nSources/OpenSSL/* linguist-vendored\nSources/cURL/* linguist-vendored\nXcode/Perfe"
  },
  {
    "path": ".gitignore",
    "chars": 861,
    "preview": "# Xcode\n#\nbuild/\n*.pbxuser\n!default.pbxuser\n*.mode1v3\n!default.mode1v3\n*.mode2v3\n!default.mode2v3\n*.perspectivev3\n!defau"
  },
  {
    "path": ".jazzy.yaml",
    "chars": 305,
    "preview": "module: PerfectLib\nauthor: PerfectlySoft\nauthor_url: https://perfect.org\ngithub_url: https://github.com/PerfectlySoft/Pe"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "chars": 3233,
    "preview": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nIn the interest of fostering an open and welcoming environment, w"
  },
  {
    "path": "CODE_OF_CONDUCT.zh_CN.md",
    "chars": 1015,
    "preview": "# 贡献者行为规范\n\n## 我们的承诺\n\n为了实现一个开放、和谐的软件开发环境,作为该软件的贡献者和版本维护者,我们保证在社区参与项目的过\n程中,对所有人一视同仁。在社区中,任何人,无论年龄、身材、长相,或者身体是否有缺陷;无论种族、\n性别"
  },
  {
    "path": "LICENSE",
    "chars": 11357,
    "preview": "                                 Apache License\n                           Version 2.0, January 2004\n                   "
  },
  {
    "path": "LICENSE.zh_CN",
    "chars": 2938,
    "preview": "Apache许可证\n2.0版 2004年1月\nhttp://www.apache.org/licenses/\n\n关于使用、复制和分发的条款\n\n定义\n\"许可证\"是指根据本文件第1到第9部分关于使用、复制和分发的条款。\n\n\"许可证颁发者\"是指版"
  },
  {
    "path": "Package.swift",
    "chars": 1311,
    "preview": "// swift-tools-version:5.1\n//\n//  Package.swift\n//  PerfectLib\n//\n//  Created by Kyle Jessup on 3/22/16.\n//\tCopyright (C"
  },
  {
    "path": "README.md",
    "chars": 9071,
    "preview": "# Perfect: Server-Side Swift [简体中文](README.zh_CN.md)\n<p align=\"center\">\n    <a href=\"http://perfect.org/get-involved.htm"
  },
  {
    "path": "README.zh_CN.md",
    "chars": 5939,
    "preview": "# Perfect:Swift 语言服务器端软件框架 [English](README.md)\n<p align=\"center\">\n    <a href=\"http://perfect.org/get-involved.html\" ta"
  },
  {
    "path": "Sources/PerfectLib/Bytes.swift",
    "chars": 5403,
    "preview": "//\n//  Bytes.swift\n//  PerfectLib\n//\n//  Created by Kyle Jessup on 7/7/15.\n//\tCopyright (C) 2015 PerfectlySoft, Inc.\n//\n"
  },
  {
    "path": "Sources/PerfectLib/Dir.swift",
    "chars": 5463,
    "preview": "//\n//  Dir.swift\n//  PerfectLib\n//\n//  Created by Kyle Jessup on 7/7/15.\n//\tCopyright (C) 2015 PerfectlySoft, Inc.\n//\n//"
  },
  {
    "path": "Sources/PerfectLib/File.swift",
    "chars": 18041,
    "preview": "//\n//  File.swift\n//  PerfectLib\n//\n//  Created by Kyle Jessup on 7/7/15.\n//\tCopyright (C) 2015 PerfectlySoft, Inc.\n//\n/"
  },
  {
    "path": "Sources/PerfectLib/JSONConvertible.swift",
    "chars": 22903,
    "preview": "//\n//  JSONConvertible.swift\n//  PerfectLib\n//\n//  Created by Kyle Jessup on 2016-01-21.\n//  Copyright © 2016 Treefrog. "
  },
  {
    "path": "Sources/PerfectLib/Log.swift",
    "chars": 4547,
    "preview": "//\n//  LogManager.swift\n//  PerfectLib\n//\n//  Created by Kyle Jessup on 7/21/15.\n//\tCopyright (C) 2015 PerfectlySoft, In"
  },
  {
    "path": "Sources/PerfectLib/PerfectError.swift",
    "chars": 1983,
    "preview": "//\n//  PerfectError.swift\n//  PerfectLib\n//\n//  Created by Kyle Jessup on 7/5/15.\n//\tCopyright (C) 2015 PerfectlySoft, I"
  },
  {
    "path": "Sources/PerfectLib/PerfectServer.swift",
    "chars": 1483,
    "preview": "//\n//  Perfect.swift\n//  PerfectLib\n//\n//  Created by Kyle Jessup on 7/5/15.\n//\tCopyright (C) 2015 PerfectlySoft, Inc.\n/"
  },
  {
    "path": "Sources/PerfectLib/SysProcess.swift",
    "chars": 7394,
    "preview": "//\n//  SysProcess.swift\n//  PerfectLib\n//\n//  Created by Kyle Jessup on 7/20/15.\n//  Copyright (C) 2015 PerfectlySoft, I"
  },
  {
    "path": "Sources/PerfectLib/Utilities.swift",
    "chars": 16497,
    "preview": "//\n//  Utilities.swift\n//  PerfectLib\n//\n//  Created by Kyle Jessup on 7/17/15.\n//\tCopyright (C) 2015 PerfectlySoft, Inc"
  },
  {
    "path": "Tests/LinuxMain.swift",
    "chars": 98,
    "preview": "import XCTest\n@testable import PerfectLibTests\n\nXCTMain([\n\ttestCase(PerfectLibTests.allTests),\n])\n"
  },
  {
    "path": "Tests/PerfectLibTests/PerfectLibTests.swift",
    "chars": 17469,
    "preview": "//\n//  PerfectLibTests.swift\n//  PerfectLibTests\n//\n//  Created by Kyle Jessup on 2015-10-19.\n//  Copyright © 2015 Perfe"
  },
  {
    "path": "Tests/PerfectLibTests/XCTestManifests.swift",
    "chars": 696,
    "preview": "//\n//  XCTestManifests.swift\n//\n//  Created by Kyle Jessup on 2015-10-19.\n//  Copyright © 2015 PerfectlySoft. All rights"
  }
]

About this extraction

This page contains the full source code of the PerfectlySoft/Perfect GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 22 files (134.9 KB), approximately 37.3k tokens. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!