[
  {
    "path": ".github/CONTRIBUTING.md",
    "content": "## How to contribute\n\n1. Fork it\n2. Clone your project\n3. Create your feature branch (`git checkout -b my-feature`)\n4. Commit your changes (`git commit -am 'Add some feature'`)\n5. Push to the branch (`git push origin my-feature`)\n6. Create new Pull Request\n\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE.md",
    "content": "### 提出问题前请先确认完成了下列几项步骤 New Issue Checklist\n\n* [ ] 我已经阅读过 [贡献指南](CONTRIBUTING.md) I have read and understood the [CONTRIBUTING guide](CONTRIBUTING.md)\n* [ ] 我已经阅读过 [程序文档]((http://cocoadocs.org/docsets/YTKNetwork)) I have read the [Documentation](http://cocoadocs.org/docsets/YTKNetwork)\n* [ ] 我已经证实这个问题来源于 YTKNetwork 本身，而不是其所依赖的 [AFNetworking](https://github.com/AFNetworking/AFNetworking) I have confirmed that this issue is caused by YTKNetwork, not [AFNetworking](https://github.com/AFNetworking/AFNetworking)\n* [ ] 我已经在项目的 [问题列表](https://github.com/yuantiku/YTKNetwork/issues) 中搜索过并且没有找到类似问题 I have searched for a similar issue in the [project](https://github.com/yuantiku/YTKNetwork/issues) and found none\n\n### 问题描述 Issue Description\n\n请给出所提出问题的详尽描述，包括具体的错误信息，打印的堆栈等等，以及重现此问题的具体步骤。\n\nPlease fill in the detailed description of the issue (full output of any stack trace, compiler error, ...) and the steps to reproduce the issue."
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE.md",
    "content": "### 提出 Pull Request 前请先确认完成了下列几项步骤 New Pull Request Checklist\n\n* [ ] 我已经阅读过 [贡献指南](CONTRIBUTING.md) I have read and understood the [CONTRIBUTING guide](CONTRIBUTING.md)\n* [ ] 我已经阅读过 [程序文档]((http://cocoadocs.org/docsets/YTKNetwork)) I have read the [Documentation](http://cocoadocs.org/docsets/YTKNetwork)\n* [ ] 我已经在项目的 [Pull Request 列表](https://github.com/yuantiku/YTKNetwork/pulls) 中搜索过并且没有找到类似的 Pull Request I have searched for a similar pull request in the [project](https://github.com/yuantiku/YTKNetwork/pulls) and found none\n* [ ] 我已经添加了必要的测试以证明我的改动是正确的 I have added the required tests to prove the fix/feature I am adding\n* [ ] 我已经更新了有关文档（如必要）I have updated the documentation (if necesarry)\n\n### Pull Request 说明 Pull Request Description\n\n这个 Pull Request 解决了如下问题/加入了如下功能：···\n\nThis pull request fixes / reffers to the following issues: ...\n\n"
  },
  {
    "path": ".gitignore",
    "content": "# Xcode\n#\n# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore\n\n## Build generated\nbuild/\nDerivedData\n\n## Various settings\n*.pbxuser\n!default.pbxuser\n*.mode1v3\n!default.mode1v3\n*.mode2v3\n!default.mode2v3\n*.perspectivev3\n!default.perspectivev3\nxcuserdata\nxcbaselines\n\n## Other\n*.xccheckout\n*.moved-aside\n*.xcuserstate\n*.xcscmblueprint\n\n## Obj-C/Swift specific\n*.hmap\n*.ipa\n\n# CocoaPods\n#\n# We recommend against adding the Pods directory to your .gitignore. However\n# you should judge for yourself, the pros and cons are mentioned at:\n# http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control\n#\nPods/\n\n# Carthage\n#\n# Add this line if you want to avoid checking in source code from Carthage dependencies.\nCarthage/Checkouts\nCarthage/Build\nCartfile.resolved\n\n.DS_Store\n\n"
  },
  {
    "path": ".travis.yml",
    "content": "language: objective-c\nosx_image: xcode8\ncache:\n  - cocoapods\n  - bundler\nenv:\n  matrix:\n    - TEST_TYPE=iOS\n    - TEST_TYPE=macOS\n    - TEST_TYPE=tvOS\nbefore_install:\n- |\n  brew update\n  brew install carthage\n  carthage bootstrap\n  if [ \"$TEST_TYPE\" = iOS ] || [ \"$TEST_TYPE\" = macOS ] || [ \"$TEST_TYPE\" = tvOS ]; then\n    gem install xcpretty --no-ri --no-rdoc --no-document --quiet\n  elif [ \"$TEST_TYPE\" = CocoaPods ]; then\n    gem install cocoapods --no-ri --no-rdoc --no-document --quiet\n  fi\nscript:\n- |\n  if [ \"$TEST_TYPE\" = iOS ]; then\n    set -o pipefail\n    xcodebuild test -scheme \"YTKNetwork iOS\" -sdk iphonesimulator -destination \"platform=iOS Simulator,name=iPhone 6\" -skip-testing:\"YTKNetwork iOSTests\"/YTKPerformanceTests -skip-testing:\"YTKNetwork iOSTests\"/YTKResumableDownloadTests | xcpretty -c\n  elif [ \"$TEST_TYPE\" = macOS ]; then\n    set -o pipefail\n    xcodebuild test -scheme \"YTKNetwork macOS\" -sdk macosx -skip-testing:\"YTKNetwork macOSTests\"/YTKPerformanceTests -skip-testing:\"YTKNetwork macOSTests\"/YTKResumableDownloadTests | xcpretty -c\n  elif [ \"$TEST_TYPE\" = tvOS ]; then\n    set -o pipefail\n    xcodebuild test -scheme \"YTKNetwork tvOS\" -sdk appletvsimulator -destination \"platform=tvOS Simulator,name=Apple TV 1080p\" -skip-testing:\"YTKNetwork tvOSTests\"/YTKPerformanceTests -skip-testing:\"YTKNetwork tvOSTests\"/YTKResumableDownloadTests | xcpretty -c\n  fi\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "# Changelog\n\n---\n\n## 2.0.2 (link here)\n\n#### Added\n\n* New `debugLogEnabled` option in `YTKNetworkConfig` to enable/disable logging ([f0ee0b4](https://github.com/yuantiku/YTKNetwork/commit/f0ee0b4f49c1a38c6d89cec59b7e736a26fef1f8)).\n* Exposed more errors when constructing `YTKBaseRequest` ([f210739](https://github.com/yuantiku/YTKNetwork/commit/f21073998eeff8a558aad73d61c87a2482824319)).\n\n#### Updated\n\n* Documentation is now organized and updated to reflect the latest code ([#236](https://github.com/yuantiku/YTKNetwork/pull/236) & [#230](https://github.com/yuantiku/YTKNetwork/pull/230)). \n\n#### Fixed\n\n* When put inside `YTKBatchRequest` or `YTKChainRequest`, a single `YTKRequest` will have its completion blocks(delegates) cleared to prevent further confusing behaviour ([55d88ae](https://github.com/yuantiku/YTKNetwork/commit/55d88ae20a6401fad176b31203fee8cb2fe749b4)).\n"
  },
  {
    "path": "Cartfile",
    "content": "github \"AFNetworking/AFNetworking\" ~> 3.0\n\n"
  },
  {
    "path": "Docs/2.0_MigrationGuide_cn.md",
    "content": "YTKNetwork 2.0 迁移指南\n======================\n\nYTKNetwork 2.0 所依赖的 AFNetworking 版本从 2.X 变为 3.X 版本，抛弃了旧有的以 `AFHTTPRequestOperation` 为核心的 API，采用新的基于 `NSURLSession` 的 API。本指南的目的在于帮助使用 YTKNetwork 1.X 版本的应用迁移到新的 API。\n\n## AFHTTPRequestOperation 完全被移除\n\n在 iOS 7 上苹果引入了 `NSURLSession` 系列 API，旨在替代 `NSURLConnection` 系列 API。在 Xcode 7 中，`NSURLConnection` API 已经正式标记为废弃的（deprecated）。AFNetworking 3 当中也放弃了基于 `NSOperation` 的请求方式，转而采用基于 `NSURLSessionTask`。因此 `YTKRequest` 中的下列属性发生了变化：\n\n#### YTKNetwork 1.X\n\n```objectivec\n@property (nonatomic, strong) AFHTTPRequestOperation *requestOperation;\n@property (nonatomic, strong, readonly, nullable) NSError *requestOperationError;\n```\n\n#### YTKNetwork 2.X\n\n```objectivec\n@property (nonatomic, strong, readonly) NSURLSessionTask *requestTask;\n@property (nonatomic, strong, readonly, nullable) NSError *error;\n```\n\n同时，原来依赖于 `AFHTTPRequestOperation` 的这些属性，需要使用新加入的替代 API 获取：\n\n* `request.requestOperation.response` --> `request.response`\n* `request.requestOperation.request` --> `request.currentRequest` & `request.originalRequest`\n\n由于失去了 Operation 封装类，`request.currentRequest` 和 `request.originalRequest` 属性需要在 request 进行 `start` 之后才能获取，否则为 nil。\n\n## 响应序列化选项\n\nYTKNetwork 2.0 中加入了新的响应序列化选项，以及对应的 `responseObject` 属性，不同的序列化选项会导致响应返回不同类型的 `responseObject`，具体对应如下：\n\n```objectivec\ntypedef NS_ENUM(NSInteger, YTKResponseSerializerType) {\n    YTKResponseSerializerTypeHTTP = 0,  /// NSData\n    YTKResponseSerializerTypeJSON,      /// JSON object\n    YTKResponseSerializerTypeXMLParser  /// NSXMLParser\n};\n```\n\n默认的序列化选项是 `YTKResponseSerializerTypeJSON`。\n\n需要注意的是，YTKNetwork 1.0 没有对响应序列化进行控制，并且主动忽略了 AFN 返回的响应序列化错误。AFN 默认进行的是 JSON 序列化，而在 YTKNetwork 1.0 中即使序列化结果是错误的（例如 Content-Type 不正确，或者返回的是二进制数据），仍然会认为请求是成功的，并且调用 YTKRequest 的成功回调。这一行为在 YTKNetwork 2.0 当中被修正了。如果发现在升级 YTKNetwork 2.0 之后某些之前正常的请求报错，请检查是否是由于响应的类型不正确。\n\n## URL 拼接\n\nYTKNetwork 2.0 中 `baseUrl` 和 `requestUrl` 的拼接实现发生了变化。在 1.X 中这两个 URL 是作为字符串直接拼接起来的，而在 2.0 中改为使用 `[NSURL URLWithString:relativeToURL]` 方法进行拼接，以提升可靠性和兼容性。\n\n这一实现可能导致和之前不同的 URL 拼接结果。当 `requestUrl` 带有 `/` 前缀，同时 `baseUrl` 包含除 Host 之外的内容， `requestUrl` 仍然会被拼接到最顶级，这一差距来源于 `NSURL` 本身的实现：\n\n```objectivec\nNSURL *baseURL = [NSURL URLWithString:@\"http://example.com/v1/\"];\nNSURL *resultURL = [NSURL URLWithString:@\"/foo\" relativeToURL:baseURL:];\n// resultURL : http://example.com/foo\n```\n\n因此请注意如果 `baseUrl` 包含 Path 那么 `requestUrl` 的前缀不要在加入 `/` ，以免产生错误的的拼接结果。\n\n## 下载请求\n\n原来基于 `AFDownloadRequestOperation` 的下载请求改为使用系统自己的 `NSURLSessionDownloadTask`。当 `YTKRequest` 的 `resumableDownloadPath` 属性不为 nil 的情况下，会调用 `NSURLSessionDownloadTask` 进行下载，下载完成后文件会自动保存到给出的路径，无需再进行存储操作。\n\n对于下载请求来说，响应属性的获取行为如下：\n\n* `responseData`：不能获取\n* `responseString`：不能获取\n* `responseObject`：为 NSURL，是下载文件在本地所存储的路径。\n\n如果在使用 YTKNetwork 1.X 的情况下，采用存储 `responseData` 的方式进行下载，那么无需进行改动。不过对于下载完整文件的情况，建议迁移到新的采用 `NSURLSessionDownloadTask` 的 API。\n\n同时，获取下载进度的 API 也发生了变化，旧的 block 类型被抛弃，新的 block 类型取自 AFN 3.X：\n\n```objectivec\ntypedef void (^AFURLSessionTaskProgressBlock)(NSProgress *);\n```\n\n可以通过 `NSProgress` 的 `totalUnitCount` 和 `completedUnitCount` 获取下载进度有关的信息。\n\n## YTKNetworkPrivate 不再暴露\n\n`YTKNetworkPrivate.h` 将会成为私有头文件，所有依赖于此头文件的方法将不再可用。\n\n## Cache API 更新\n\n`YTKRequest` 类当中的 Cache 有关接口发生改变，不发送请求的情况下获取 Cache 的下列接口被去除：\n\n* `- (id)cacheJson`\n* `- (BOOL)isCacheVersionExpired;`\n\n新的替代接口为：\n\n* `- (BOOL)loadCacheWithError:(NSError **)error`\n\n这个接口可以用于在不发送请求的情况下，直接读取磁盘缓存，返回值表示获取成功与否，如果获取失败，error 会返回错误的具体信息。读取缓存成功后，可以直接通过 `responseObject`，`responseData` 等属性获取数据。\n\n用于将一个请求的响应写到另一个请求的缓存中的接口，也发生了变化：\n\n#### YTKNetwork 1.X\n\n`- (void)saveJsonResponseToCacheFile:(id)jsonResponse`\n\n#### YTKNetwork 2.X\n\n`- (void)saveResponseDataToCacheFile:(NSData *)data`\n\nYTKNetwork 2.0 中加入了用于控制是否进行异步写缓存的接口：\n\n`- (BOOL)writeCacheAsynchronously`\n\n默认返回 `YES`，即使用异步方式写缓存，以提高性能。如果需要关闭此功能，可以在子类中覆盖这个方法并返回 `NO`。\n\n## 响应前向处理\n\n与 `- (void)requestCompleteFilter` 和 `- (void)requestFailedFilter` 对应， YTKNetwork 2.0 中加入了用于在响应结束，但是切换回主线程之前执行操作的函数 `- (void)requestCompletePreprocessor` 和 `- (void)requestFailedPreprocessor`，在这里执行的操作，可以避免阻塞主线程。\n\n## 命名变更\n\nYTKNetwork 2.0 中部分函数命名发生了变更：\n\n* `[YTKNetworkAgent sharedInstance]` -> `[YTKNetworkAgent sharedAgent]`\n* `[YTKChainRequestAgent sharedInstance]` -> `[YTKChainRequestAgent sharedAgent]`\n* `[YTKBatchRequestAgent sharedInstance]` -> `[YTKBatchRequestAgent sharedAgent]`\n* `[YTKNetworkConfig sharedInstance]` -> `[YTKNetworkConfig sharedConfig]`\n\n部分枚举的命名也发生了变化：\n\n* `YTKRequestMethodGet` -> `YTKRequestMethodGET`\n* `YTKRequestMethodPost` -> `YTKRequestMethodPOST`\n* ...\n\n同时 `ChainCallback` 类型被重命名为 `YTKChainCallback`：\n\n```typedef void (^YTKChainCallback)(YTKChainRequest *chainRequest, YTKBaseRequest *baseRequest);```\n\n"
  },
  {
    "path": "Docs/BasicGuide_cn.md",
    "content": "YTKNetwork 使用基础教程\n=====================\n\n本教程将讲解 YTKNetwork 的基本功能的使用。\n\n\n## YTKNetwork 基本组成\n\nYTKNetwork 包括以下几个基本的类：\n\n * YTKNetworkConfig 类：用于统一设置网络请求的服务器和 CDN 的地址。\n * YTKRequest 类：所有的网络请求类需要继承于 `YTKRequest` 类，每一个 `YTKRequest` 类的子类代表一种专门的网络请求。\n\n接下来我们详细地来解释这些类以及它们的用法。\n\n### YTKNetworkConfig 类\n\nYTKNetworkConfig 类有两个作用：\n\n 1. 统一设置网络请求的服务器和 CDN 的地址。\n 2. 管理网络请求的 YTKUrlFilterProtocol 实例（在[高级功能教程](ProGuide_cn.md) 中有介绍）。\n\n我们为什么需要统一设置服务器地址呢？因为：\n\n 1. 按照设计模式里的 `Do Not Repeat Yourself` 原则，我们应该把服务器地址统一写在一个地方。\n 2. 在实际业务中，我们的测试人员需要切换不同的服务器地址来测试。统一设置服务器地址到 YTKNetworkConfig 类中，也便于我们统一切换服务器地址。\n \n具体的用法是，在程序刚启动的回调中，设置好 YTKNetworkConfig 的信息，如下所示：\n\n```objectivec\n- (BOOL)application:(UIApplication *)application \n   didFinishLaunchingWithOptions:(NSDictionary *)launchOptions\n{\n   YTKNetworkConfig *config = [YTKNetworkConfig sharedConfig];\n   config.baseUrl = @\"http://yuantiku.com\";\n   config.cdnUrl = @\"http://fen.bi\";\n}\n```\n\n设置好之后，所有的网络请求都会默认使用 YTKNetworkConfig 中 `baseUrl` 参数指定的地址。\n\n大部分企业应用都需要对一些静态资源（例如图片、js、css）使用 CDN。YTKNetworkConfig 的 `cdnUrl` 参数用于统一设置这一部分网络请求的地址。\n\n当我们需要切换服务器地址时，只需要修改 YTKNetworkConfig 中的 `baseUrl` 和 `cdnUrl` 参数即可。\n\n### YTKRequest 类\n\nYTKNetwork 的基本的思想是把每一个网络请求封装成对象。所以使用 YTKNetwork，你的每一种请求都需要继承 YTKRequest 类，通过覆盖父类的一些方法来构造指定的网络请求。把每一个网络请求封装成对象其实是使用了设计模式中的 Command 模式。\n\n每一种网络请求继承 YTKRequest 类后，需要用方法覆盖（overwrite）的方式，来指定网络请求的具体信息。如下是一个示例：\n\n假如我们要向网址 `http://www.yuantiku.com/iphone/register` 发送一个 `POST` 请求，请求参数是 username 和 password。那么，这个类应该如下所示：\n\n```objectivec\n// RegisterApi.h\n#import \"YTKRequest.h\"\n\n@interface RegisterApi : YTKRequest\n\n- (id)initWithUsername:(NSString *)username password:(NSString *)password;\n\n@end\n\n\n// RegisterApi.m\n\n#import \"RegisterApi.h\"\n\n@implementation RegisterApi {\n    NSString *_username;\n    NSString *_password;\n}\n\n- (id)initWithUsername:(NSString *)username password:(NSString *)password {\n    self = [super init];\n    if (self) {\n        _username = username;\n        _password = password;\n    }\n    return self;\n}\n\n- (NSString *)requestUrl {\n    // “ http://www.yuantiku.com ” 在 YTKNetworkConfig 中设置，这里只填除去域名剩余的网址信息\n    return @\"/iphone/register\";\n}\n\n- (YTKRequestMethod)requestMethod {\n    return YTKRequestMethodPOST;\n}\n\n- (id)requestArgument {\n    return @{\n        @\"username\": _username,\n        @\"password\": _password\n    };\n}\n\n@end\n\n```\n\n在上面这个示例中，我们可以看到：\n\n * 我们通过覆盖 YTKRequest 类的 `requestUrl` 方法，实现了指定网址信息。并且我们只需要指定除去域名剩余的网址信息，因为域名信息在 YTKNetworkConfig 中已经设置过了。\n * 我们通过覆盖 YTKRequest 类的 `requestMethod` 方法，实现了指定 POST 方法来传递参数。\n * 我们通过覆盖 YTKRequest 类的 `requestArgument` 方法，提供了 POST 的信息。这里面的参数 `username` 和 `password` 如果有一些特殊字符（如中文或空格），也会被自动编码。\n \n## 调用 RegisterApi\n\n在构造完成 RegisterApi 之后，具体如何使用呢？我们可以在登录的 ViewController 中，调用 RegisterApi，并用 block 的方式来取得网络请求结果：\n\n```objectivec\n- (void)loginButtonPressed:(id)sender {\n    NSString *username = self.UserNameTextField.text;\n    NSString *password = self.PasswordTextField.text;\n    if (username.length > 0 && password.length > 0) {\n        RegisterApi *api = [[RegisterApi alloc] initWithUsername:username password:password];\n        [api startWithCompletionBlockWithSuccess:^(YTKBaseRequest *request) {\n            // 你可以直接在这里使用 self\n            NSLog(@\"succeed\");\n        } failure:^(YTKBaseRequest *request) {\n            // 你可以直接在这里使用 self\n            NSLog(@\"failed\");\n        }];\n    }\n}\n\n```\n\n注意：你可以直接在 block 回调中使用 `self`，不用担心循环引用。因为 YTKRequest 会在执行完 block 回调之后，将相应的 block 设置成 nil。从而打破循环引用。\n\n除了 block 的回调方式外，YTKRequest 也支持 delegate 方式的回调：\n\n```objectivec\n- (void)loginButtonPressed:(id)sender {\n    NSString *username = self.UserNameTextField.text;\n    NSString *password = self.PasswordTextField.text;\n    if (username.length > 0 && password.length > 0) {\n        RegisterApi *api = [[RegisterApi alloc] initWithUsername:username password:password];\n        api.delegate = self;\n        [api start];\n    }\n}\n\n- (void)requestFinished:(YTKBaseRequest *)request {\n    NSLog(@\"succeed\");\n}\n\n- (void)requestFailed:(YTKBaseRequest *)request {\n    NSLog(@\"failed\");\n}\n```\n\n## 验证服务器返回内容\n\n有些时候，由于服务器的 Bug，会造成服务器返回一些不合法的数据，如果盲目地信任这些数据，可能会造成客户端 Crash。如果加入大量的验证代码，又使得编程体力活增加，费时费力。\n\n使用 YTKRequest 的验证服务器返回值功能，可以很大程度上节省验证代码的编写时间。\n\n例如，我们要向网址 `http://www.yuantiku.com/iphone/users` 发送一个 `GET` 请求，请求参数是 `userId` 。我们想获得某一个用户的信息，包括他的昵称和等级，我们需要服务器必须返回昵称（字符串类型）和等级信息（数值类型），则可以覆盖 `jsonValidator` 方法，实现简单的验证。\n\n```objectivec\n- (id)jsonValidator {\n    return @{\n        @\"nick\": [NSString class],\n        @\"level\": [NSNumber class]\n    };\n}\n```\n\n完整的代码如下：\n\n```objectivec\n// GetUserInfoApi.h\n#import \"YTKRequest.h\"\n\n@interface GetUserInfoApi : YTKRequest\n\n- (id)initWithUserId:(NSString *)userId;\n\n@end\n\n\n// GetUserInfoApi.m\n#import \"GetUserInfoApi.h\"\n\n@implementation GetUserInfoApi {\n    NSString *_userId;\n}\n\n- (id)initWithUserId:(NSString *)userId {\n    self = [super init];\n    if (self) {\n        _userId = userId;\n    }\n    return self;\n}\n\n- (NSString *)requestUrl {\n    return @\"/iphone/users\";\n}\n\n- (id)requestArgument {\n    return @{ @\"id\": _userId };\n}\n\n- (id)jsonValidator {\n    return @{\n        @\"nick\": [NSString class],\n        @\"level\": [NSNumber class]\n    };\n}\n\n@end\n```\n\n以下是更多的 jsonValidator 的示例：\n\n * 要求返回 String 数组：\n\n```objectivec\n- (id)jsonValidator {\n    return @[ [NSString class] ];\n}\n```\n\n * 来自猿题库线上环境的一个复杂的例子：\n \n```objectivec\n- (id)jsonValidator {\n    return @[@{\n        @\"id\": [NSNumber class],\n        @\"imageId\": [NSString class],\n        @\"time\": [NSNumber class],\n        @\"status\": [NSNumber class],\n        @\"question\": @{\n            @\"id\": [NSNumber class],\n            @\"content\": [NSString class],\n            @\"contentType\": [NSNumber class]\n        }\n    }];\n} \n```\n\n\n## 使用 CDN 地址\n\n如果要使用 CDN 地址，只需要覆盖 YTKRequest 类的 `- (BOOL)useCDN;` 方法。\n\n例如我们有一个取图片的接口，地址是 `http://fen.bi/image/imageId` ，则我们可以这么写代码 :\n\n```objectivec\n// GetImageApi.h\n#import \"YTKRequest.h\"\n\n@interface GetImageApi : YTKRequest\n- (id)initWithImageId:(NSString *)imageId;\n@end\n\n// GetImageApi.m\n#import \"GetImageApi.h\"\n\n@implementation GetImageApi {\n    NSString *_imageId;\n}\n\n- (id)initWithImageId:(NSString *)imageId {\n    self = [super init];\n    if (self) {\n        _imageId = imageId;\n    }\n    return self;\n}\n\n- (NSString *)requestUrl {\n    return [NSString stringWithFormat:@\"/iphone/images/%@\", _imageId];\n}\n\n- (BOOL)useCDN {\n    return YES;\n}\n@end\n```\n\n## 断点续传\n\n要启动断点续传功能，只需要覆盖 `resumableDownloadPath` 方法，指定断点续传时文件的存储路径即可，文件会被自动保存到此路径。如下代码将刚刚的取图片的接口改造成了支持断点续传：\n\n```objectivec\n@implementation GetImageApi {\n    NSString *_imageId;\n}\n\n- (id)initWithImageId:(NSString *)imageId {\n    self = [super init];\n    if (self) {\n        _imageId = imageId;\n    }\n    return self;\n}\n\n- (NSString *)requestUrl {\n    return [NSString stringWithFormat:@\"/iphone/images/%@\", _imageId];\n}\n\n- (BOOL)useCDN {\n    return YES;\n}\n\n- (NSString *)resumableDownloadPath {\n    NSString *libPath = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) objectAtIndex:0];\n    NSString *cachePath = [libPath stringByAppendingPathComponent:@\"Caches\"];\n    NSString *filePath = [cachePath stringByAppendingPathComponent:_imageId];\n    return filePath;\n}\n\n@end\n```\n\n## 按时间缓存内容\n\n刚刚我们写了一个 GetUserInfoApi ，这个网络请求是获得用户的一些资料。\n\n我们想像这样一个场景，假设你在完成一个类似微博的客户端，GetUserInfoApi 用于获得你的某一个好友的资料，因为好友并不会那么频繁地更改昵称，那么短时间内频繁地调用这个接口很可能每次都返回同样的内容，所以我们可以给这个接口加一个缓存。\n\n在如下示例中，我们通过覆盖 `cacheTimeInSeconds` 方法，给 GetUserInfoApi 增加了一个 3 分钟的缓存，3 分钟内调用调 Api 的 start 方法，实际上并不会发送真正的请求。\n\n```objectivec\n@implementation GetUserInfoApi {\n    NSString *_userId;\n}\n\n- (id)initWithUserId:(NSString *)userId {\n    self = [super init];\n    if (self) {\n        _userId = userId;\n    }\n    return self;\n}\n\n- (NSString *)requestUrl {\n    return @\"/iphone/users\";\n}\n\n- (id)requestArgument {\n    return @{ @\"id\": _userId };\n}\n\n- (id)jsonValidator {\n    return @{\n        @\"nick\": [NSString class],\n        @\"level\": [NSNumber class]\n    };\n}\n\n- (NSInteger)cacheTimeInSeconds {\n    // 3 分钟 = 180 秒\n    return 60 * 3;\n}\n\n@end\n```\n\n该缓存逻辑对上层是透明的，所以上层可以不用考虑缓存逻辑，每次调用 GetUserInfoApi 的 start 方法即可。GetUserInfoApi 只有在缓存过期时，才会真正地发送网络请求。\n\n以上几个示例代码在 Demo 工程中也可获得。\n"
  },
  {
    "path": "Docs/BasicGuide_en.md",
    "content": "YTKNetwork Basic Guide \n======================\n\nIn the article, we will introduce the basic usage of YTKNetwork.\n\n## YTKNetwork's basic composition\n\nYTKNetwork mainly contains the following classes:\n\n * YTKNetworkConfig ：it's used for setting global network host address and CDN address.\n * YTKRequest ：it's the parent of all the detailed network request classes. All network request classes should inherit it. Every subclass of `YTKRequest` represents a specific network request.\n\nWe will explain the above 2 classes' detailed usage below.\n\n### YTKNetworkConfig class\n\nYTKNetworkConfig class has 2 usages:\n\n 1. Set global network host address and CDN address.\n 2. Manage the filters which implemented `YTKUrlFilterProtocol` protocol（we will discuss it in pro usage guide）。\n\nWe use YTKNetworkConfig to set global network host address because:\n\n 1. According to the `Do Not Repeat Yourself` principle，we should write the host address only once.\n 2. In practise, our testers need to switch host addresses at runtime. YTKNetworkConfig can satisfy such requirement.\n \nWe should set YTKNetworkConfig's property at the beggining of app launching, the sample is below:\n\n```objectivec\n- (BOOL)application:(UIApplication *)application \n   didFinishLaunchingWithOptions:(NSDictionary *)launchOptions\n{\n   YTKNetworkConfig *config = [YTKNetworkConfig sharedConfig];\n   config.baseUrl = @\"http://yuantiku.com\";\n   config.cdnUrl = @\"http://fen.bi\";\n}\n```\n\nAfter setting, all network requests will use YTKNetworkConfig's `baseUrl` property as their host addresses, and they will use the `cdnUrl` property of YTKNetworkConfig as their CDN addresses.\n\nIf we want to switch server address, we can just change YTKNetworkConfig's `baseUrl` property.\n\n### YTKRequest class\n\nThe design idea of YTKNetwork is that every specific network request should be a object. So after using YTKNetwork, all your request classes should inherit YTKNetwork. Through overwriting the methods of super class, you can build your own specific and distinguished request. The key idea behind this is somewhat like the Command pattern.\n\nFor example, if we want to send a POST request to `http://www.yuantiku.com/iphone/register`，with username and password as arguments, then the class should be as following:：\n\n```objectivec\n// RegisterApi.h\n#import \"YTKRequest.h\"\n\n@interface RegisterApi : YTKRequest\n\n- (id)initWithUsername:(NSString *)username password:(NSString *)password;\n\n@end\n\n\n// RegisterApi.m\n\n\n#import \"RegisterApi.h\"\n\n@implementation RegisterApi {\n    NSString *_username;\n    NSString *_password;\n}\n\n- (id)initWithUsername:(NSString *)username password:(NSString *)password {\n    self = [super init];\n    if (self) {\n        _username = username;\n        _password = password;\n    }\n    return self;\n}\n\n- (NSString *)requestUrl {\n    // “http://www.yuantiku.com” is set in YTKNetworkConfig, so we ignore it\n    return @\"/iphone/register\";\n}\n\n- (YTKRequestMethod)requestMethod {\n    return YTKRequestMethodPOST;\n}\n\n- (id)requestArgument {\n    return @{\n        @\"username\": _username,\n        @\"password\": _password\n    };\n}\n\n@end\n```\n\nIn above example:\n\n * Through overwriting `requestUrl` method, we've indicated the detailed url. Bacause host address has been set in `YTKNetworkConfig`, we should not write the host address in `requestUrl` method.\n * Through overwriting `requestMethod` method, we've indicated the use of the `POST` method.\n * Through overwriting `requestArgument` method, we've provided the `POST` data. If arguments `username` and `password` contain any charaters which should be escaped, the library will do it automatically.\n \n## Call RegisterApi\n\nOK, how can we use the `RegisterApi`? We can call it in the login view controller. After initializing the instance, we can call its `start` or `startWithCompletionBlockWithSuccess` method to send the request to the network request queue.\n\nThen we can get network response by `block` or `delegate` mechanism.\n\n```objectivec\n- (void)loginButtonPressed:(id)sender {\n    NSString *username = self.UserNameTextField.text;\n    NSString *password = self.PasswordTextField.text;\n    if (username.length > 0 && password.length > 0) {\n        RegisterApi *api = [[RegisterApi alloc] initWithUsername:username password:password];\n        [api startWithCompletionBlockWithSuccess:^(YTKBaseRequest *request) {\n            // you can use self here, retain cycle won't happen\n            NSLog(@\"succeed\");\n            \n        } failure:^(YTKBaseRequest *request) {\n            // you can use self here, retain cycle won't happen\n            NSLog(@\"failed\");\n        }];\n    }\n}\n```\n\nKindly be noted that you can use `self` directly in the block where the retain cycle won't happen. Because YTKRequest will set callback block to nil, so the block will be released right after the network request completed.\n\nBesides the `block` callback, YTKRequest also support `delegate` callback method. The example is below:\n\n```objectivec\n- (void)loginButtonPressed:(id)sender {\n    NSString *username = self.UserNameTextField.text;\n    NSString *password = self.PasswordTextField.text;\n    if (username.length > 0 && password.length > 0) {\n        RegisterApi *api = [[RegisterApi alloc] initWithUsername:username password:password];\n        api.delegate = self;\n        [api start];\n    }\n}\n\n- (void)requestFinished:(YTKBaseRequest *)request {\n    NSLog(@\"succeed\");\n}\n\n- (void)requestFailed:(YTKBaseRequest *)request {\n    NSLog(@\"failed\");\n}\n```\n\n## Verify response JSON\n\nThe response JSON from the server cannnot be always trusted. Client may crash if the data is returned in faulty format from the server. \n\nYTKRequest provides a simple way to verity the respose JSON.\n\nFor example, let's say we need to send a `GET` request to `http://www.yuantiku.com/iphone/users` address with a argument named `userId`. The server will return the target user's information, including nickname and level. We shall guarantee that the response type of nickname is string and the type of level is number. To ensure this, we can overwrite the `jsonValidator` as following:\n\n```objectivec\n- (id)jsonValidator {\n    return @{\n        @\"nick\": [NSString class],\n        @\"level\": [NSNumber class]\n    };\n}\n```\n\nThe whole code sample is below:\n\n```objectivec\n// GetUserInfoApi.h\n#import \"YTKRequest.h\"\n\n@interface GetUserInfoApi : YTKRequest\n\n- (id)initWithUserId:(NSString *)userId;\n\n@end\n\n\n// GetUserInfoApi.m\n#import \"GetUserInfoApi.h\"\n\n@implementation GetUserInfoApi {\n    NSString *_userId;\n}\n\n- (id)initWithUserId:(NSString *)userId {\n    self = [super init];\n    if (self) {\n        _userId = userId;\n    }\n    return self;\n}\n\n- (NSString *)requestUrl {\n    return @\"/iphone/users\";\n}\n\n- (id)requestArgument {\n    return @{ @\"id\": _userId };\n}\n\n- (id)jsonValidator {\n    return @{\n        @\"nick\": [NSString class],\n        @\"level\": [NSNumber class]\n    };\n}\n\n@end\n```\n\nHere is some other samples：\n\n * Require return String array:\n\n```objectivec\n- (id)jsonValidator {\n    return @[ [NSString class] ];\n}\n```\n\n * Here is one complex sample from our company:\n \n```objectivec\n- (id)jsonValidator {\n    return @[@{\n        @\"id\": [NSNumber class],\n        @\"imageId\": [NSString class],\n        @\"time\": [NSNumber class],\n        @\"status\": [NSNumber class],\n        @\"question\": @{\n            @\"id\": [NSNumber class],\n            @\"content\": [NSString class],\n            @\"contentType\": [NSNumber class]\n        }\n    }];\n} \n```\n\n## Use CDN address\n\nIf you need to use CDN address in some of your requests, just overwrite the `- (BOOL)useCDN;` method, and return `YES` in the method.\n\nFor example, if we have a interface for image downloading, and the address is `http://fen.bi/image/imageId` with the host `http://fen.bi` as the CDN address. Then the code should be below:\n\n```objectivec\n// GetImageApi.h\n#import \"YTKRequest.h\"\n\n@interface GetImageApi : YTKRequest\n- (id)initWithImageId:(NSString *)imageId;\n@end\n\n// GetImageApi.m\n#import \"GetImageApi.h\"\n\n@implementation GetImageApi {\n    NSString *_imageId;\n}\n\n- (id)initWithImageId:(NSString *)imageId {\n    self = [super init];\n    if (self) {\n        _imageId = imageId;\n    }\n    return self;\n}\n\n- (NSString *)requestUrl {\n    return [NSString stringWithFormat:@\"/iphone/images/%@\", _imageId];\n}\n\n- (BOOL)useCDN {\n    return YES;\n}\n\n@end\n```\n\n## Resumable Downloading\n\nIf you want to enable resumable downloading, you just need to overwrite the  `resumableDownloadPath` method and provide a the path you want to save the downloaded file. The file will be automatically saved to that path.\n\nWe can modify above example to support resumable downloading.\n\n```objectivec\n@implementation GetImageApi {\n    NSString *_imageId;\n}\n\n- (id)initWithImageId:(NSString *)imageId {\n    self = [super init];\n    if (self) {\n        _imageId = imageId;\n    }\n    return self;\n}\n\n- (NSString *)requestUrl {\n    return [NSString stringWithFormat:@\"/iphone/images/%@\", _imageId];\n}\n\n- (BOOL)useCDN {\n    return YES;\n}\n\n- (NSString *)resumableDownloadPath {\n    NSString *libPath = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) objectAtIndex:0];\n    NSString *cachePath = [libPath stringByAppendingPathComponent:@\"Caches\"];\n    NSString *filePath = [cachePath stringByAppendingPathComponent:_imageId];\n    return filePath;\n}\n\n@end\n```\n\n## Cache response data\n \nWe've implemented the `GetUserInfoApi` before, which is used for getting user information. \n\nWe may want to cache the response. In the following example, we overwrite  the `cacheTimeInSeconds` method, then our API will automatically cache data for specified amount of time. If the cached data is not expired, the api's `start` and `startWithCompletionBlockWithSuccess` will return cached data as a result directly.\n\n```objectivec\n@implementation GetUserInfoApi {\n    NSString *_userId;\n}\n\n- (id)initWithUserId:(NSString *)userId {\n    self = [super init];\n    if (self) {\n        _userId = userId;\n    }\n    return self;\n}\n\n- (NSString *)requestUrl {\n    return @\"/iphone/users\";\n}\n\n- (id)requestArgument {\n    return @{ @\"id\": _userId };\n}\n\n- (id)jsonValidator {\n    return @{\n        @\"nick\": [NSString class],\n        @\"level\": [NSNumber class]\n    };\n}\n\n- (NSInteger)cacheTimeInSeconds {\n    // cache 3 minutes, which is 60 * 3 = 180 seconds\n    return 60 * 3;\n}\n\n@end\n```\n\nThe cache mechanism is transparent to the controller, which means the request caller may get the result right after invoking the request without casuing any real network traffic as long as its cached data remains valid.\n\nThe above code samples are available in the YTKNetworkDemo project.\n"
  },
  {
    "path": "Docs/ProGuide_cn.md",
    "content": "YTKNetwork 使用高级教程\n=====================\n\n本教程将讲解 YTKNetwork 的高级功能的使用。\n\n## YTKUrlFilterProtocol 接口\n\nYTKUrlFilterProtocol 接口用于实现对网络请求 URL 或参数的重写，例如可以统一为网络请求加上一些参数，或者修改一些路径。\n\n例如：在猿题库中，我们需要为每个网络请求加上客户端的版本号作为参数。所以我们实现了如下一个 `YTKUrlArgumentsFilter` 类，实现了 `YTKUrlFilterProtocol` 接口 :\n\n```objectivec\n// YTKUrlArgumentsFilter.h\n// 实现自己的 URL 拼接工具类\n@interface YTKUrlArgumentsFilter : NSObject <YTKUrlFilterProtocol>\n\n+ (YTKUrlArgumentsFilter *)filterWithArguments:(NSDictionary *)arguments;\n\n- (NSString *)filterUrl:(NSString *)originUrl withRequest:(YTKBaseRequest *)request;\n\n@end\n\n\n// YTKUrlArgumentsFilter.m\n@implementation YTKUrlArgumentsFilter {\n    NSDictionary *_arguments;\n}\n\n+ (YTKUrlArgumentsFilter *)filterWithArguments:(NSDictionary *)arguments {\n    return [[self alloc] initWithArguments:arguments];\n}\n\n- (id)initWithArguments:(NSDictionary *)arguments {\n    self = [super init];\n    if (self) {\n        _arguments = arguments;\n    }\n    return self;\n}\n\n- (NSString *)filterUrl:(NSString *)originUrl withRequest:(YTKBaseRequest *)request {\n    return [YTKUrlArgumentsFilter urlStringWithOriginUrlString:originUrl appendParameters:_arguments];\n}\n\n@end\n```\n\n通过以上 `YTKUrlArgumentsFilter` 类，我们就可以用以下代码方便地为网络请求增加统一的参数，如增加当前客户端的版本号：\n\n```objectivec\n- (BOOL)application:(UIApplication *)application \n         didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {\n    [self setupRequestFilters];\n    return YES;\n}\n\n- (void)setupRequestFilters {\n    NSString *appVersion = [[[NSBundle mainBundle] infoDictionary] objectForKey:@\"CFBundleShortVersionString\"];\n    YTKNetworkConfig *config = [YTKNetworkConfig sharedConfig];\n    YTKUrlArgumentsFilter *urlFilter = [YTKUrlArgumentsFilter filterWithArguments:@{@\"version\": appVersion}];\n    [config addUrlFilter:urlFilter];\n}\n```\n\n## YTKBatchRequest 类\n\nYTKBatchRequest 类：用于方便地发送批量的网络请求，YTKBatchRequest 是一个容器类，它可以放置多个 `YTKRequest` 子类，并统一处理这多个网络请求的成功和失败。\n\n在如下的示例中，我们发送了 4 个批量的请求，并统一处理这 4 个请求同时成功的回调。\n\n```objectivec\n#import \"YTKBatchRequest.h\"\n#import \"GetImageApi.h\"\n#import \"GetUserInfoApi.h\"\n\n- (void)sendBatchRequest {\n    GetImageApi *a = [[GetImageApi alloc] initWithImageId:@\"1.jpg\"];\n    GetImageApi *b = [[GetImageApi alloc] initWithImageId:@\"2.jpg\"];\n    GetImageApi *c = [[GetImageApi alloc] initWithImageId:@\"3.jpg\"];\n    GetUserInfoApi *d = [[GetUserInfoApi alloc] initWithUserId:@\"123\"];\n    YTKBatchRequest *batchRequest = [[YTKBatchRequest alloc] initWithRequestArray:@[a, b, c, d]];\n    [batchRequest startWithCompletionBlockWithSuccess:^(YTKBatchRequest *batchRequest) {\n        NSLog(@\"succeed\");\n        NSArray *requests = batchRequest.requestArray;\n        GetImageApi *a = (GetImageApi *)requests[0];\n        GetImageApi *b = (GetImageApi *)requests[1];\n        GetImageApi *c = (GetImageApi *)requests[2];\n        GetUserInfoApi *user = (GetUserInfoApi *)requests[3];\n        // deal with requests result ...\n    } failure:^(YTKBatchRequest *batchRequest) {\n        NSLog(@\"failed\");\n    }];\n}\n```\n\n## YTKChainRequest 类\n\n用于管理有相互依赖的网络请求，它实际上最终可以用来管理多个拓扑排序后的网络请求。\n\n例如，我们有一个需求，需要用户在注册时，先发送注册的 Api，然后 :\n * 如果注册成功，再发送读取用户信息的 Api。并且，读取用户信息的 Api 需要使用注册成功返回的用户 id 号。\n * 如果注册失败，则不发送读取用户信息的 Api 了。\n\n以下是具体的代码示例，在示例中，我们在 `sendChainRequest` 方法中设置好了 Api 相互的依赖，然后。\n我们就可以通过 `chainRequestFinished` 回调来处理所有网络请求都发送成功的逻辑了。如果有任何其中一个网络请求失败了，则会触发 `chainRequestFailed` 回调。\n\n```objectivec\n- (void)sendChainRequest {\n    RegisterApi *reg = [[RegisterApi alloc] initWithUsername:@\"username\" password:@\"password\"];\n    YTKChainRequest *chainReq = [[YTKChainRequest alloc] init];\n    [chainReq addRequest:reg callback:^(YTKChainRequest *chainRequest, YTKBaseRequest *baseRequest) {\n        RegisterApi *result = (RegisterApi *)baseRequest;\n        NSString *userId = [result userId];\n        GetUserInfoApi *api = [[GetUserInfoApi alloc] initWithUserId:userId];\n        [chainRequest addRequest:api callback:nil];\n        \n    }];\n    chainReq.delegate = self;\n    // start to send request\n    [chainReq start];\n}\n\n- (void)chainRequestFinished:(YTKChainRequest *)chainRequest {\n    // all requests are done\n}\n\n- (void)chainRequestFailed:(YTKChainRequest *)chainRequest failedBaseRequest:(YTKBaseRequest*)request {\n    // some one of request is failed\n}\n```\n\n## 显示上次缓存的内容\n\n在实际开发中，有一些内容可能会加载很慢，我们想先显示上次的内容，等加载成功后，再用最新的内容替换上次的内容。也有时候，由于网络处于断开状态，为了更加友好，我们想显示上次缓存中的内容。这个时候，可以使用 YTKReqeust 的直接加载缓存的高级用法。\n\n具体的方法是直接使用 `YTKRequest` 的 `- (BOOL)loadCacheWithError:` 方法，即可获得上次缓存的内容。当然，你需要把 `- (NSInteger)cacheTimeInSeconds` 覆盖，返回一个大于等于 0 的值，这样才能开启 YTKRequest 的缓存功能，否则默认情况下，缓存功能是关闭的。\n\n以下是一个示例，我们在加载用户信息前，先取得上次加载的内容，然后再发送请求，请求成功后再更新界面：\n\n```objectivec\n- (void)loadCacheData {\n    NSString *userId = @\"1\";\n    GetUserInfoApi *api = [[GetUserInfoApi alloc] initWithUserId:userId];\n    if ([api loadCacheWithError:nil]) {\n        NSDictionary *json = [api responseJSONObject];\n        NSLog(@\"json = %@\", json);\n        // show cached data\n    }\n    [api startWithCompletionBlockWithSuccess:^(YTKBaseRequest *request) {\n        NSLog(@\"update ui\");\n    } failure:^(YTKBaseRequest *request) {\n        NSLog(@\"failed\");\n    }];\n}\n\n```\n\n## 上传文件\n\n我们可以通过覆盖 `constructingBodyBlock` 方法，来方便地上传图片等附件，如下是一个示例：\n\n```objectivec\n// YTKRequest.h\n#import \"YTKRequest.h\"\n\n@interface UploadImageApi : YTKRequest\n\n- (id)initWithImage:(UIImage *)image;\n- (NSString *)responseImageId;\n\n@end\n\n// YTKRequest.m\n@implementation UploadImageApi {\n    UIImage *_image;\n}\n\n- (id)initWithImage:(UIImage *)image {\n    self = [super init];\n    if (self) {\n        _image = image;\n    }\n    return self;\n}\n\n- (YTKRequestMethod)requestMethod {\n    return YTKRequestMethodPOST;\n}\n\n- (NSString *)requestUrl {\n    return @\"/iphone/image/upload\";\n}\n\n- (AFConstructingBlock)constructingBodyBlock {\n    return ^(id<AFMultipartFormData> formData) {\n        NSData *data = UIImageJPEGRepresentation(_image, 0.9);\n        NSString *name = @\"image\";\n        NSString *formKey = @\"image\";\n        NSString *type = @\"image/jpeg\";\n        [formData appendPartWithFileData:data name:formKey fileName:name mimeType:type];\n    };\n}\n\n- (id)jsonValidator {\n    return @{ @\"imageId\": [NSString class] };\n}\n\n- (NSString *)responseImageId {\n    NSDictionary *dict = self.responseJSONObject;\n    return dict[@\"imageId\"];\n}\n\n@end\n```\n\n通过如上代码，我们创建了一个上传图片，然后获得服务器返回的 imageId 的网络请求 Api。\n\n## 定制网络请求的 HeaderField\n\n通过覆盖 `requestHeaderFieldValueDictionary` 方法返回一个 dictionary 对象来自定义请求的 HeaderField，返回的 dictionary，其 key 即为 HeaderField 的 key，value 为 HeaderField 的 Value，需要注意的是 key 和 value 都必须为 string 对象。\n\n## 定制 `buildCustomUrlRequest`\n\n通过覆盖 `buildCustomUrlRequest` 方法，返回一个 `NSURLRequest` 对象来达到完全自定义请求的需求。该方法定义在 `YTKBaseRequest` 类，如下：\n\n```objectivec\n// 构建自定义的 UrlRequest，\n// 若这个方法返回非 nil 对象，会忽略 requestUrl, requestArgument, requestMethod, requestSerializerType,requestHeaderFieldValueDictionary\n- (NSURLRequest *)buildCustomUrlRequest;\n```\n\n如注释所言，如果构建自定义的 request，会忽略其他的一切自定义 request 的方法，例如 `requestUrl`, `requestArgument`, `requestMethod`, `requestSerializerType`,`requestHeaderFieldValueDictionary` 等等。一个上传 gzippingData 的示例如下：\n\n```objectivec\n- (NSURLRequest *)buildCustomUrlRequest {\n    NSData *rawData = [[_events jsonString] dataUsingEncoding:NSUTF8StringEncoding];\n    NSData *gzippingData = [NSData gtm_dataByGzippingData:rawData];\n    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:self.requestUrl]];\n    [request setHTTPMethod:@\"POST\"];\n    [request addValue:@\"application/json;charset=UTF-8\" forHTTPHeaderField:@\"Content-Type\"];\n    [request addValue:@\"gzip\" forHTTPHeaderField:@\"Content-Encoding\"];\n    [request setHTTPBody:gzippingData];\n    return request;\n}\n```\n\n\n\n"
  },
  {
    "path": "Docs/README_cn.md",
    "content": "## YTKNetwork 是什么\n\nYTKNetwork 是猿题库 iOS 研发团队基于 [AFNetworking][AFNetworking] 封装的 iOS 网络库，其实现了一套 High Level 的 API，提供了更高层次的网络访问抽象。YTKNetwork 现在同时被使用在猿题库公司的所有产品的 iOS 端，包括：[猿题库][YuanTiKu]、[小猿搜题][YuanSoTi]、[猿辅导][YuanFuDao]、[粉笔直播课][FenBiZhiBoKe] 。\n\n## YTKNetwork 提供了哪些功能\n\n相比 AFNetworking，YTKNetwork 提供了以下更高级的功能：\n\n * 支持按时间缓存网络请求内容\n * 支持按版本号缓存网络请求内容\n * 支持统一设置服务器和 CDN 的地址\n * 支持检查返回 JSON 内容的合法性\n * 支持文件的断点续传\n * 支持 `block` 和 `delegate` 两种模式的回调方式\n * 支持批量的网络请求发送，并统一设置它们的回调（实现在 `YTKBatchRequest` 类中）\n * 支持方便地设置有相互依赖的网络请求的发送，例如：发送请求 A，根据请求 A 的结果，选择性的发送请求 B 和 C，再根据 B 和 C 的结果，选择性的发送请求 D。（实现在 `YTKChainRequest` 类中）\n * 支持网络请求 URL 的 filter，可以统一为网络请求加上一些参数，或者修改一些路径。\n * 定义了一套插件机制，可以很方便地为 YTKNetwork 增加功能。猿题库官方现在提供了一个插件，可以在某些网络请求发起时，在界面上显示“正在加载”的 HUD。\n\n## 哪些项目适合使用 YTKNetwork\n\nYTKNetwork 适合稍微复杂一些的项目，不适合个人的小项目。\n\n如果你的项目中需要缓存网络请求、管理多个网络请求之间的依赖、希望检查服务器返回的 JSON 是否合法，那么 YTKNetwork 能给你带来很大的帮助。如果你缓存的网络请求内容需要依赖特定版本号过期，那么 YTKNetwork 就能发挥出它最大的优势。\n\n## YTKNetwork 的基本思想\n\nYTKNetwork 的基本的思想是把每一个网络请求封装成对象。所以使用 YTKNetwork，你的每一个请求都需要继承 `YTKRequest` 类，通过覆盖父类的一些方法来构造指定的网络请求。\n\n把每一个网络请求封装成对象其实是使用了设计模式中的 Command 模式，它有以下好处：\n\n * 将网络请求与具体的第三方库依赖隔离，方便以后更换底层的网络库。实际上 YTKNetwork 最初是基于 ASIHttpRequest 的，我们只花了两天，就很轻松地切换到了 AFNetworking。\n * 方便在基类中处理公共逻辑，例如猿题库的数据版本号信息就统一在基类中处理。\n * 方便在基类中处理缓存逻辑，以及其它一些公共逻辑。\n * 方便做对象的持久化。\n\n当然，如果说它有什么不好，那就是如果你的工程非常简单，这么写会显得没有直接用 AFNetworking 将请求逻辑写在 Controller 中方便，所以 YTKNetwork 并不适合特别简单的项目。\n\n## 安装\n\n你可以在 Podfile 中加入下面一行代码来使用 YTKNetwork\n\n    pod 'YTKNetwork'\n\n在 Cartfile 中加入下面的代码以使用 YTKNetwork\n\n    github \"yuantiku/YTKNetwork\" ~> 2.0\n\n## 安装要求\n\n| YTKNetwork 版本 | AFNetworking 版本 |  最低 iOS Target | 注意 |\n|:----------------:|:----------------:|:----------------:|:-----|\n| 2.x | 3.x | iOS 7 | 要求 Xcode 7 以上  |\n| 1.x | 2.x | iOS 6 | n/a |\n\n\nYTKNetwork 依赖于 AFNetworking，可以在 [AFNetworking README](https://github.com/AFNetworking/AFNetworking) 中找到更多关于依赖版本有关的信息。\n\n## 相关的使用教程和 Demo\n\n * [基础使用教程](BasicGuide_cn.md)\n * [高级使用教程](ProGuide_cn.md)\n * [YTKNetwork 2 迁移指南](2.0_MigrationGuide_cn.md)\n\n## 作者\n\nYTKNetwork 的主要作者是：\n\n* [lancy][lancyGithub]\n* [maojj][maojjGithub]\n* [veecci][veecciGithub]\n* [tangqiaoboy][tangqiaoboyGithub]\n* [skyline75489][skyline75489Github]\n\n## 感谢\n\nYTKNetwork 基于 [AFNetworking][AFNetworking] 和 [AFDownloadRequestOperation][AFDownloadRequestOperation] 进行开发，感谢他们对开源社区做出的贡献。\n\n## 协议\n\nYTKNetwork 被许可在 MIT 协议下使用。查阅 LICENSE 文件来获得更多信息。\n\n\n<!-- external links -->\n[AFNetworking]:https://github.com/AFNetworking/AFNetworking\n[AFDownloadRequestOperation]:https://github.com/steipete/AFDownloadRequestOperation\n\n[YuanTiKu]:http://www.yuantiku.com\n[YuanSoTi]:http://www.yuansouti.com/\n[YuanFuDao]:http://www.yuanfudao.com\n[FenBiZhiBoKe]:http://ke.fenbi.com/\n[tangqiaoboyGithub]:https://github.com/tangqiaoboy\n[lancyGithub]:https://github.com/lancy\n[maojjGithub]:https://github.com/maojj\n[veecciGithub]:https://github.com/veecci\n[skyline75489Github]:https://github.com/skyline75489\n"
  },
  {
    "path": "Framework/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>en</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>FMWK</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>2.0.3</string>\n\t<key>CFBundleSignature</key>\n\t<string>????</string>\n\t<key>CFBundleVersion</key>\n\t<string>$(CURRENT_PROJECT_VERSION)</string>\n\t<key>NSPrincipalClass</key>\n\t<string></string>\n</dict>\n</plist>\n"
  },
  {
    "path": "LICENSE",
    "content": "Copyright (c) 2012-2016 YTKNetwork https://github.com/yuantiku\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n\n"
  },
  {
    "path": "README.md",
    "content": "YTKNetwork\n==========\n\n![License MIT](https://img.shields.io/github/license/mashape/apistatus.svg?maxAge=2592000)\n![Pod version](https://img.shields.io/cocoapods/v/YTKNetwork.svg?style=flat)\n[![Carthage Compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage)\n[![Platform info](https://img.shields.io/cocoapods/p/YTKNetwork.svg?style=flat)](http://cocoadocs.org/docsets/YTKNetwork)\n[![Build Status](https://api.travis-ci.org/yuantiku/YTKNetwork.svg?branch=master)](https://travis-ci.org/yuantiku/YTKNetwork)\n\n## What\n\nYTKNetwork is a high level request util based on [AFNetworking][AFNetworking]. It's developed by the iOS Team of YuanTiKu. It provides a High Level API for network request.\n\nYTKNetwork is used in all products of YuanTiKu, including: [YuanTiKu][YuanTiKu], [YuanSoTi][YuanSoTi], [YuanFuDao][YuanFuDao], [FenBiZhiBoKe][FenBiZhiBoKe].\n\n[**中文说明**](Docs/README_cn.md)\n\n## Features\n\n* Response can be cached by expiration time\n* Response can be cached by version number\n* Set common base URL and CDN URL\n* Validate JSON response\n* Resume download\n* `block` and `delegate` callback\n* Batch requests (see `YTKBatchRequest`)\n* Chain requests (see `YTKChainRequest`)\n* URL filter, replace part of URL, or append common parameter \n* Plugin mechanism, handle request start and finish. A plugin for show \"Loading\" HUD is provided\n\n## Who\n\nYTKNetowrk is suitable for a slightly more complex project, not for a simple personal project.\n\nYTKNetwork is helpful if you want to cache requests, manage the dependences of requests, or validate the JSON response. And if you want to cache requests based on request version, this is one of the greatest advantages of YTKNetwork.\n\n## Why \n\nYTKNetwork provides YTKRequest to handle every network request. You should inherit it and override some methods to define custom requests in your project.\n\nThe main idea is use the Command Pattern. The benefits are:\n\n * Your code is decoupled to detail network request framework, it's easy to replace it. Actually, YTKNetwork is originally based on ASIHttpRequest, we just spent two days to switch to AFNetworking.\n * Handle common logic in base class.\n * Easier Persistence\n\nBut YTKNetwork is not suitable if your project is very simple. You can use AFNetworking directly in controller.\n\n## Installation\n\nTo use YTKNetwork add the following to your Podfile\n\n    pod 'YTKNetwork'\n\nOr add this in your Cartfile:\n\n    github \"yuantiku/YTKNetwork\" ~> 3.0\n\n## Requirements\n\n| YTKNetwork Version | AFNetworking Version |  Minimum iOS Target | Note |\n|:------------------:|:--------------------:|:-------------------:|:-----|\n| 3.x | 4.x | iOS 9 | Xcode 11+ is required. |\n| 2.x | 3.x | iOS 7 | Xcode 7+ is required. |\n| 1.x | 2.x | iOS 6 | n/a |\n\nYTKNetwork is based on AFNetworking. You can find more detail about version compatibility at [AFNetworking README](https://github.com/AFNetworking/AFNetworking).\n\n## Guide & Demo\n\n * [Basic Usage Guide](Docs/BasicGuide_en.md)\n * [YTKNetwork 2.0 Migration Guide(Simplified Chinese)](Docs/2.0_MigrationGuide_cn.md)\n\n## Contributors\n\n * [lancy][lancyGithub]\n * [maojj][maojjGithub]\n * [veecci][veecciGithub]\n * [tangqiaoboy][tangqiaoboyGithub]\n * [skyline75489][skyline75489Github]\n * [joeshang][joeshangGithub]\n\n## Acknowledgements\n\n * [AFNetworking]\n * [AFDownloadRequestOperation]\n\nThanks for their great work.\n\n## License\n\nYTKNetwork is available under the MIT license. See the LICENSE file for more info.\n\n<!-- external links -->\n\n[AFNetworking]:https://github.com/AFNetworking/AFNetworking\n[AFDownloadRequestOperation]:https://github.com/steipete/AFDownloadRequestOperation\n\n[YuanTiKu]:http://www.yuantiku.com\n[YuanSoTi]:http://www.yuansouti.com/\n[YuanFuDao]:http://www.yuanfudao.com\n[FenBiZhiBoKe]:http://ke.fenbi.com/\n[tangqiaoboyGithub]:https://github.com/tangqiaoboy\n[lancyGithub]:https://github.com/lancy\n[maojjGithub]:https://github.com/maojj\n[veecciGithub]:https://github.com/veecci\n[skyline75489Github]:https://github.com/skyline75489\n[joeshangGithub]:https://github.com/joeshang\n"
  },
  {
    "path": "YTKNetwork/YTKBaseRequest.h",
    "content": "//\n//  YTKBaseRequest.h\n//\n//  Copyright (c) 2012-2016 YTKNetwork https://github.com/yuantiku\n//\n//  Permission is hereby granted, free of charge, to any person obtaining a copy\n//  of this software and associated documentation files (the \"Software\"), to deal\n//  in the Software without restriction, including without limitation the rights\n//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n//  copies of the Software, and to permit persons to whom the Software is\n//  furnished to do so, subject to the following conditions:\n//\n//  The above copyright notice and this permission notice shall be included in\n//  all copies or substantial portions of the Software.\n//\n//  THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n//  THE SOFTWARE.\n\n#import <Foundation/Foundation.h>\n\nNS_ASSUME_NONNULL_BEGIN\n\nFOUNDATION_EXPORT NSString *const YTKRequestValidationErrorDomain;\n\nNS_ENUM(NSInteger) {\n    YTKRequestValidationErrorInvalidStatusCode = -8,\n    YTKRequestValidationErrorInvalidJSONFormat = -9,\n};\n\n///  HTTP Request method.\ntypedef NS_ENUM(NSInteger, YTKRequestMethod) {\n    YTKRequestMethodGET = 0,\n    YTKRequestMethodPOST,\n    YTKRequestMethodHEAD,\n    YTKRequestMethodPUT,\n    YTKRequestMethodDELETE,\n    YTKRequestMethodPATCH,\n};\n\n///  Request serializer type.\ntypedef NS_ENUM(NSInteger, YTKRequestSerializerType) {\n    YTKRequestSerializerTypeHTTP = 0,\n    YTKRequestSerializerTypeJSON,\n};\n\n///  Response serializer type, which determines response serialization process and\n///  the type of `responseObject`.\ntypedef NS_ENUM(NSInteger, YTKResponseSerializerType) {\n    /// NSData type\n    YTKResponseSerializerTypeHTTP,\n    /// JSON object type\n    YTKResponseSerializerTypeJSON,\n    /// NSXMLParser type\n    YTKResponseSerializerTypeXMLParser,\n};\n\n///  Request priority\ntypedef NS_ENUM(NSInteger, YTKRequestPriority) {\n    YTKRequestPriorityLow = -4L,\n    YTKRequestPriorityDefault = 0,\n    YTKRequestPriorityHigh = 4,\n};\n\n@protocol AFMultipartFormData;\n\ntypedef void (^AFConstructingBlock)(id<AFMultipartFormData> formData);\ntypedef void (^AFURLSessionTaskProgressBlock)(NSProgress *);\n\n@class YTKBaseRequest;\n\ntypedef void(^YTKRequestCompletionBlock)(__kindof YTKBaseRequest *request);\n\n///  The YTKRequestDelegate protocol defines several optional methods you can use\n///  to receive network-related messages. All the delegate methods will be called\n///  on the main queue.\n@protocol YTKRequestDelegate <NSObject>\n\n@optional\n///  Tell the delegate that the request has finished successfully.\n///\n///  @param request The corresponding request.\n- (void)requestFinished:(__kindof YTKBaseRequest *)request;\n\n///  Tell the delegate that the request has failed.\n///\n///  @param request The corresponding request.\n- (void)requestFailed:(__kindof YTKBaseRequest *)request;\n\n@end\n\n///  The YTKRequestAccessory protocol defines several optional methods that can be\n///  used to track the status of a request. Objects that conforms this protocol\n///  (\"accessories\") can perform additional configurations accordingly. All the\n///  accessory methods will be called on the main queue.\n@protocol YTKRequestAccessory <NSObject>\n\n@optional\n\n///  Inform the accessory that the request is about to start.\n///\n///  @param request The corresponding request.\n- (void)requestWillStart:(id)request;\n\n///  Inform the accessory that the request is about to stop. This method is called\n///  before executing `requestFinished` and `successCompletionBlock`.\n///\n///  @param request The corresponding request.\n- (void)requestWillStop:(id)request;\n\n///  Inform the accessory that the request has already stoped. This method is called\n///  after executing `requestFinished` and `successCompletionBlock`.\n///\n///  @param request The corresponding request.\n- (void)requestDidStop:(id)request;\n\n@end\n\n///  YTKBaseRequest is the abstract class of network request. It provides many options\n///  for constructing request. It's the base class of `YTKRequest`.\n@interface YTKBaseRequest : NSObject\n\n#pragma mark - Request and Response Information\n///=============================================================================\n/// @name Request and Response Information\n///=============================================================================\n\n///  The underlying NSURLSessionTask.\n///\n///  @warning This value is actually nil and should not be accessed before the request starts.\n@property (nonatomic, strong, readonly) NSURLSessionTask *requestTask;\n\n///  Shortcut for `requestTask.currentRequest`.\n@property (nonatomic, strong, readonly) NSURLRequest *currentRequest;\n\n///  Shortcut for `requestTask.originalRequest`.\n@property (nonatomic, strong, readonly) NSURLRequest *originalRequest;\n\n///  Shortcut for `requestTask.response`.\n@property (nonatomic, strong, readonly) NSHTTPURLResponse *response;\n\n///  The response status code.\n@property (nonatomic, readonly) NSInteger responseStatusCode;\n\n///  The response header fields.\n@property (nonatomic, strong, readonly, nullable) NSDictionary *responseHeaders;\n\n///  The raw data representation of response. Note this value can be nil if request failed.\n@property (nonatomic, strong, readonly, nullable) NSData *responseData;\n\n///  The string representation of response. Note this value can be nil if request failed.\n@property (nonatomic, strong, readonly, nullable) NSString *responseString;\n\n///  This serialized response object. The actual type of this object is determined by\n///  `YTKResponseSerializerType`. Note this value can be nil if request failed.\n///\n///  @discussion If `resumableDownloadPath` and DownloadTask is using, this value will\n///              be the path to which file is successfully saved (NSURL), or nil if request failed.\n@property (nonatomic, strong, readonly, nullable) id responseObject;\n\n///  If you use `YTKResponseSerializerTypeJSON`, this is a convenience (and sematic) getter\n///  for the response object. Otherwise this value is nil.\n@property (nonatomic, strong, readonly, nullable) id responseJSONObject;\n\n///  This error can be either serialization error or network error. If nothing wrong happens\n///  this value will be nil.\n@property (nonatomic, strong, readonly, nullable) NSError *error;\n\n///  Return cancelled state of request task.\n@property (nonatomic, readonly, getter=isCancelled) BOOL cancelled;\n\n///  Executing state of request task.\n@property (nonatomic, readonly, getter=isExecuting) BOOL executing;\n\n\n#pragma mark - Request Configuration\n///=============================================================================\n/// @name Request Configuration\n///=============================================================================\n\n///  Tag can be used to identify request. Default value is 0.\n@property (nonatomic) NSInteger tag;\n\n///  The userInfo can be used to store additional info about the request. Default is nil.\n@property (nonatomic, strong, nullable) NSDictionary *userInfo;\n\n///  The delegate object of the request. If you choose block style callback you can ignore this.\n///  Default is nil.\n@property (nonatomic, weak, nullable) id<YTKRequestDelegate> delegate;\n\n///  The success callback. Note if this value is not nil and `requestFinished` delegate method is\n///  also implemented, both will be executed but delegate method is first called. This block\n///  will be called on the main queue.\n@property (nonatomic, copy, nullable) YTKRequestCompletionBlock successCompletionBlock;\n\n///  The failure callback. Note if this value is not nil and `requestFailed` delegate method is\n///  also implemented, both will be executed but delegate method is first called. This block\n///  will be called on the main queue.\n@property (nonatomic, copy, nullable) YTKRequestCompletionBlock failureCompletionBlock;\n\n///  This can be used to add several accessories object. Note if you use `addAccessory` to add accessory\n///  this array will be automatically created. Default is nil.\n@property (nonatomic, strong, nullable) NSMutableArray<id<YTKRequestAccessory>> *requestAccessories;\n\n///  This can be use to construct HTTP body when needed in POST request. Default is nil.\n@property (nonatomic, copy, nullable) AFConstructingBlock constructingBodyBlock;\n\n///  This value is used to perform resumable download request. Default is nil.\n///\n///  @discussion NSURLSessionDownloadTask is used when this value is not nil.\n///              The exist file at the path will be removed before the request starts. If request succeed, file will\n///              be saved to this path automatically, otherwise the response will be saved to `responseData`\n///              and `responseString`. For this to work, server must support `Range` and response with\n///              proper `Last-Modified` and/or `Etag`. See `NSURLSessionDownloadTask` for more detail.\n@property (nonatomic, strong, nullable) NSString *resumableDownloadPath;\n\n///  You can use this block to track the download progress. See also `resumableDownloadPath`.\n@property (nonatomic, copy, nullable) AFURLSessionTaskProgressBlock resumableDownloadProgressBlock;\n\n///  You can use this block to track the upload progress.\n@property (nonatomic, copy, nullable) AFURLSessionTaskProgressBlock uploadProgressBlock;\n\n///  The priority of the request. Default is `YTKRequestPriorityDefault`.\n@property (nonatomic) YTKRequestPriority requestPriority;\n\n///  Set completion callbacks\n- (void)setCompletionBlockWithSuccess:(nullable YTKRequestCompletionBlock)success\n                              failure:(nullable YTKRequestCompletionBlock)failure;\n\n///  Nil out both success and failure callback blocks.\n- (void)clearCompletionBlock;\n\n///  Convenience method to add request accessory. See also `requestAccessories`.\n- (void)addAccessory:(id<YTKRequestAccessory>)accessory;\n\n\n#pragma mark - Request Action\n///=============================================================================\n/// @name Request Action\n///=============================================================================\n\n///  Append self to request queue and start the request.\n- (void)start;\n\n///  Remove self from request queue and cancel the request.\n- (void)stop;\n\n///  Convenience method to start the request with block callbacks.\n- (void)startWithCompletionBlockWithSuccess:(nullable YTKRequestCompletionBlock)success\n                                    failure:(nullable YTKRequestCompletionBlock)failure;\n\n\n#pragma mark - Subclass Override\n///=============================================================================\n/// @name Subclass Override\n///=============================================================================\n\n///  Called on background thread after request succeeded but before switching to main thread. Note if\n///  cache is loaded, this method WILL be called on the main thread, just like `requestCompleteFilter`.\n- (void)requestCompletePreprocessor;\n\n///  Called on the main thread after request succeeded.\n- (void)requestCompleteFilter;\n\n///  Called on background thread after request failed but before switching to main thread. See also\n///  `requestCompletePreprocessor`.\n- (void)requestFailedPreprocessor;\n\n///  Called on the main thread when request failed.\n- (void)requestFailedFilter;\n\n///  The baseURL of request. This should only contain the host part of URL, e.g., http://www.example.com.\n///  See also `requestUrl`\n- (NSString *)baseUrl;\n\n///  The URL path of request. This should only contain the path part of URL, e.g., /v1/user. See alse `baseUrl`.\n///\n///  @discussion This will be concated with `baseUrl` using [NSURL URLWithString:relativeToURL].\n///              Because of this, it is recommended that the usage should stick to rules stated above.\n///              Otherwise the result URL may not be correctly formed. See also `URLString:relativeToURL`\n///              for more information.\n///\n///              Additionally, if `requestUrl` itself is a valid URL, it will be used as the result URL and\n///              `baseUrl` will be ignored.\n- (NSString *)requestUrl;\n\n///  Optional CDN URL for request.\n- (NSString *)cdnUrl;\n\n///  Request timeout interval. Default is 60s.\n///\n///  @discussion When using `resumableDownloadPath`(NSURLSessionDownloadTask), the session seems to completely ignore\n///              `timeoutInterval` property of `NSURLRequest`. One effective way to set timeout would be using\n///              `timeoutIntervalForResource` of `NSURLSessionConfiguration`.\n- (NSTimeInterval)requestTimeoutInterval;\n\n///  Additional request argument.\n- (nullable id)requestArgument;\n\n///  Override this method to filter requests with certain arguments when caching.\n- (id)cacheFileNameFilterForRequestArgument:(id)argument;\n\n///  HTTP request method.\n- (YTKRequestMethod)requestMethod;\n\n///  Request serializer type.\n- (YTKRequestSerializerType)requestSerializerType;\n\n///  Response serializer type. See also `responseObject`.\n- (YTKResponseSerializerType)responseSerializerType;\n\n///  Username and password used for HTTP authorization. Should be formed as @[@\"Username\", @\"Password\"].\n- (nullable NSArray<NSString *> *)requestAuthorizationHeaderFieldArray;\n\n///  Additional HTTP request header field.\n- (nullable NSDictionary<NSString *, NSString *> *)requestHeaderFieldValueDictionary;\n\n///  Use this to build custom request. If this method return non-nil value, `requestUrl`, `requestTimeoutInterval`,\n///  `requestArgument`, `allowsCellularAccess`, `requestMethod` and `requestSerializerType` will all be ignored.\n- (nullable NSURLRequest *)buildCustomUrlRequest;\n\n///  Should use CDN when sending request.\n- (BOOL)useCDN;\n\n///  Whether the request is allowed to use the cellular radio (if present). Default is YES.\n- (BOOL)allowsCellularAccess;\n\n///  The validator will be used to test if `responseJSONObject` is correctly formed.\n- (nullable id)jsonValidator;\n\n///  This validator will be used to test if `responseStatusCode` is valid.\n- (BOOL)statusCodeValidator;\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "YTKNetwork/YTKBaseRequest.m",
    "content": "//\n//  YTKBaseRequest.m\n//\n//  Copyright (c) 2012-2016 YTKNetwork https://github.com/yuantiku\n//\n//  Permission is hereby granted, free of charge, to any person obtaining a copy\n//  of this software and associated documentation files (the \"Software\"), to deal\n//  in the Software without restriction, including without limitation the rights\n//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n//  copies of the Software, and to permit persons to whom the Software is\n//  furnished to do so, subject to the following conditions:\n//\n//  The above copyright notice and this permission notice shall be included in\n//  all copies or substantial portions of the Software.\n//\n//  THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n//  THE SOFTWARE.\n\n#import \"YTKBaseRequest.h\"\n#import \"YTKNetworkAgent.h\"\n#import \"YTKNetworkPrivate.h\"\n\nNSString *const YTKRequestValidationErrorDomain = @\"com.yuantiku.request.validation\";\n\n@interface YTKBaseRequest ()\n\n@property (nonatomic, strong, readwrite) NSURLSessionTask *requestTask;\n@property (nonatomic, strong, readwrite) NSData *responseData;\n@property (nonatomic, strong, readwrite) id responseJSONObject;\n@property (nonatomic, strong, readwrite) id responseObject;\n@property (nonatomic, strong, readwrite) NSString *responseString;\n@property (nonatomic, strong, readwrite) NSError *error;\n\n@end\n\n@implementation YTKBaseRequest\n\n#pragma mark - Request and Response Information\n\n- (NSHTTPURLResponse *)response {\n    return (NSHTTPURLResponse *)self.requestTask.response;\n}\n\n- (NSInteger)responseStatusCode {\n    return self.response.statusCode;\n}\n\n- (NSDictionary *)responseHeaders {\n    return self.response.allHeaderFields;\n}\n\n- (NSURLRequest *)currentRequest {\n    return self.requestTask.currentRequest;\n}\n\n- (NSURLRequest *)originalRequest {\n    return self.requestTask.originalRequest;\n}\n\n- (BOOL)isCancelled {\n    if (!self.requestTask) {\n        return NO;\n    }\n    return self.requestTask.state == NSURLSessionTaskStateCanceling;\n}\n\n- (BOOL)isExecuting {\n    if (!self.requestTask) {\n        return NO;\n    }\n    return self.requestTask.state == NSURLSessionTaskStateRunning;\n}\n\n#pragma mark - Request Configuration\n\n- (void)setCompletionBlockWithSuccess:(YTKRequestCompletionBlock)success\n                              failure:(YTKRequestCompletionBlock)failure {\n    self.successCompletionBlock = success;\n    self.failureCompletionBlock = failure;\n}\n\n- (void)clearCompletionBlock {\n    // nil out to break the retain cycle.\n    self.successCompletionBlock = nil;\n    self.failureCompletionBlock = nil;\n    self.uploadProgressBlock = nil;\n}\n\n- (void)addAccessory:(id<YTKRequestAccessory>)accessory {\n    if (!self.requestAccessories) {\n        self.requestAccessories = [NSMutableArray array];\n    }\n    [self.requestAccessories addObject:accessory];\n}\n\n#pragma mark - Request Action\n\n- (void)start {\n    [self toggleAccessoriesWillStartCallBack];\n    [[YTKNetworkAgent sharedAgent] addRequest:self];\n}\n\n- (void)stop {\n    [self toggleAccessoriesWillStopCallBack];\n    self.delegate = nil;\n    [[YTKNetworkAgent sharedAgent] cancelRequest:self];\n    [self toggleAccessoriesDidStopCallBack];\n}\n\n- (void)startWithCompletionBlockWithSuccess:(YTKRequestCompletionBlock)success\n                                    failure:(YTKRequestCompletionBlock)failure {\n    [self setCompletionBlockWithSuccess:success failure:failure];\n    [self start];\n}\n\n#pragma mark - Subclass Override\n\n- (void)requestCompletePreprocessor {\n}\n\n- (void)requestCompleteFilter {\n}\n\n- (void)requestFailedPreprocessor {\n}\n\n- (void)requestFailedFilter {\n}\n\n- (NSString *)requestUrl {\n    return @\"\";\n}\n\n- (NSString *)cdnUrl {\n    return @\"\";\n}\n\n- (NSString *)baseUrl {\n    return @\"\";\n}\n\n- (NSTimeInterval)requestTimeoutInterval {\n    return 60;\n}\n\n- (id)requestArgument {\n    return nil;\n}\n\n- (id)cacheFileNameFilterForRequestArgument:(id)argument {\n    return argument;\n}\n\n- (YTKRequestMethod)requestMethod {\n    return YTKRequestMethodGET;\n}\n\n- (YTKRequestSerializerType)requestSerializerType {\n    return YTKRequestSerializerTypeHTTP;\n}\n\n- (YTKResponseSerializerType)responseSerializerType {\n    return YTKResponseSerializerTypeJSON;\n}\n\n- (NSArray *)requestAuthorizationHeaderFieldArray {\n    return nil;\n}\n\n- (NSDictionary *)requestHeaderFieldValueDictionary {\n    return nil;\n}\n\n- (NSURLRequest *)buildCustomUrlRequest {\n    return nil;\n}\n\n- (BOOL)useCDN {\n    return NO;\n}\n\n- (BOOL)allowsCellularAccess {\n    return YES;\n}\n\n- (id)jsonValidator {\n    return nil;\n}\n\n- (BOOL)statusCodeValidator {\n    NSInteger statusCode = [self responseStatusCode];\n    return (statusCode >= 200 && statusCode <= 299);\n}\n\n#pragma mark - NSObject\n\n- (NSString *)description {\n    return [NSString stringWithFormat:@\"<%@: %p>{ URL: %@ } { method: %@ } { arguments: %@ }\", NSStringFromClass([self class]), self, self.currentRequest.URL, self.currentRequest.HTTPMethod, self.requestArgument];\n}\n\n@end\n"
  },
  {
    "path": "YTKNetwork/YTKBatchRequest.h",
    "content": "//\n//  YTKBatchRequest.h\n//\n//  Copyright (c) 2012-2016 YTKNetwork https://github.com/yuantiku\n//\n//  Permission is hereby granted, free of charge, to any person obtaining a copy\n//  of this software and associated documentation files (the \"Software\"), to deal\n//  in the Software without restriction, including without limitation the rights\n//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n//  copies of the Software, and to permit persons to whom the Software is\n//  furnished to do so, subject to the following conditions:\n//\n//  The above copyright notice and this permission notice shall be included in\n//  all copies or substantial portions of the Software.\n//\n//  THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n//  THE SOFTWARE.\n\n#import <Foundation/Foundation.h>\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class YTKRequest;\n@class YTKBatchRequest;\n@protocol YTKRequestAccessory;\n\n///  The YTKBatchRequestDelegate protocol defines several optional methods you can use\n///  to receive network-related messages. All the delegate methods will be called\n///  on the main queue. Note the delegate methods will be called when all the requests\n///  of batch request finishes.\n@protocol YTKBatchRequestDelegate <NSObject>\n\n@optional\n///  Tell the delegate that the batch request has finished successfully/\n///\n///  @param batchRequest The corresponding batch request.\n- (void)batchRequestFinished:(YTKBatchRequest *)batchRequest;\n\n///  Tell the delegate that the batch request has failed.\n///\n///  @param batchRequest The corresponding batch request.\n- (void)batchRequestFailed:(YTKBatchRequest *)batchRequest;\n\n@end\n\n///  YTKBatchRequest can be used to batch several YTKRequest. Note that when used inside YTKBatchRequest, a single\n///  YTKRequest will have its own callback and delegate cleared, in favor of the batch request callback.\n@interface YTKBatchRequest : NSObject\n\n///  All the requests are stored in this array.\n@property (nonatomic, strong, readonly) NSArray<YTKRequest *> *requestArray;\n\n///  The delegate object of the batch request. Default is nil.\n@property (nonatomic, weak, nullable) id<YTKBatchRequestDelegate> delegate;\n\n///  The success callback. Note this will be called only if all the requests are finished.\n///  This block will be called on the main queue.\n@property (nonatomic, copy, nullable) void (^successCompletionBlock)(YTKBatchRequest *);\n\n///  The failure callback. Note this will be called if one of the requests fails.\n///  This block will be called on the main queue.\n@property (nonatomic, copy, nullable) void (^failureCompletionBlock)(YTKBatchRequest *);\n\n///  Tag can be used to identify batch request. Default value is 0.\n@property (nonatomic) NSInteger tag;\n\n///  This can be used to add several accessories object. Note if you use `addAccessory` to add acceesory\n///  this array will be automatically created. Default is nil.\n@property (nonatomic, strong, nullable) NSMutableArray<id<YTKRequestAccessory>> *requestAccessories;\n\n///  The first request that failed (and causing the batch request to fail).\n@property (nonatomic, strong, readonly, nullable) YTKRequest *failedRequest;\n\n///  Creates a `YTKBatchRequest` with a bunch of requests.\n///\n///  @param requestArray requests useds to create batch request.\n///\n- (instancetype)initWithRequestArray:(NSArray<YTKRequest *> *)requestArray;\n\n///  Set completion callbacks\n- (void)setCompletionBlockWithSuccess:(nullable void (^)(YTKBatchRequest *batchRequest))success\n                              failure:(nullable void (^)(YTKBatchRequest *batchRequest))failure;\n\n///  Nil out both success and failure callback blocks.\n- (void)clearCompletionBlock;\n\n///  Convenience method to add request accessory. See also `requestAccessories`.\n- (void)addAccessory:(id<YTKRequestAccessory>)accessory;\n\n///  Append all the requests to queue.\n- (void)start;\n\n///  Stop all the requests of the batch request.\n- (void)stop;\n\n///  Convenience method to start the batch request with block callbacks.\n- (void)startWithCompletionBlockWithSuccess:(nullable void (^)(YTKBatchRequest *batchRequest))success\n                                    failure:(nullable void (^)(YTKBatchRequest *batchRequest))failure;\n\n///  Whether all response data is from local cache.\n- (BOOL)isDataFromCache;\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "YTKNetwork/YTKBatchRequest.m",
    "content": "//\n//  YTKBatchRequest.m\n//\n//  Copyright (c) 2012-2016 YTKNetwork https://github.com/yuantiku\n//\n//  Permission is hereby granted, free of charge, to any person obtaining a copy\n//  of this software and associated documentation files (the \"Software\"), to deal\n//  in the Software without restriction, including without limitation the rights\n//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n//  copies of the Software, and to permit persons to whom the Software is\n//  furnished to do so, subject to the following conditions:\n//\n//  The above copyright notice and this permission notice shall be included in\n//  all copies or substantial portions of the Software.\n//\n//  THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n//  THE SOFTWARE.\n\n#import \"YTKBatchRequest.h\"\n#import \"YTKNetworkPrivate.h\"\n#import \"YTKBatchRequestAgent.h\"\n#import \"YTKRequest.h\"\n\n@interface YTKBatchRequest() <YTKRequestDelegate>\n\n@property (nonatomic) NSInteger finishedCount;\n\n@end\n\n@implementation YTKBatchRequest\n\n- (instancetype)initWithRequestArray:(NSArray<YTKRequest *> *)requestArray {\n    self = [super init];\n    if (self) {\n        _requestArray = [requestArray copy];\n        _finishedCount = 0;\n        for (YTKRequest * req in _requestArray) {\n            if (![req isKindOfClass:[YTKRequest class]]) {\n                YTKLog(@\"Error, request item must be YTKRequest instance.\");\n                return nil;\n            }\n        }\n    }\n    return self;\n}\n\n- (void)start {\n    if (_finishedCount > 0) {\n        YTKLog(@\"Error! Batch request has already started.\");\n        return;\n    }\n    _failedRequest = nil;\n    [[YTKBatchRequestAgent sharedAgent] addBatchRequest:self];\n    [self toggleAccessoriesWillStartCallBack];\n    for (YTKRequest * req in _requestArray) {\n        req.delegate = self;\n        [req clearCompletionBlock];\n        [req start];\n    }\n}\n\n- (void)stop {\n    [self toggleAccessoriesWillStopCallBack];\n    _delegate = nil;\n    [self clearRequest];\n    [self toggleAccessoriesDidStopCallBack];\n    [[YTKBatchRequestAgent sharedAgent] removeBatchRequest:self];\n}\n\n- (void)startWithCompletionBlockWithSuccess:(void (^)(YTKBatchRequest *batchRequest))success\n                                    failure:(void (^)(YTKBatchRequest *batchRequest))failure {\n    [self setCompletionBlockWithSuccess:success failure:failure];\n    [self start];\n}\n\n- (void)setCompletionBlockWithSuccess:(void (^)(YTKBatchRequest *batchRequest))success\n                              failure:(void (^)(YTKBatchRequest *batchRequest))failure {\n    self.successCompletionBlock = success;\n    self.failureCompletionBlock = failure;\n}\n\n- (void)clearCompletionBlock {\n    // nil out to break the retain cycle.\n    self.successCompletionBlock = nil;\n    self.failureCompletionBlock = nil;\n}\n\n- (BOOL)isDataFromCache {\n    BOOL result = YES;\n    for (YTKRequest *request in _requestArray) {\n        if (!request.isDataFromCache) {\n            result = NO;\n        }\n    }\n    return result;\n}\n\n\n- (void)dealloc {\n    [self clearRequest];\n}\n\n#pragma mark - Network Request Delegate\n\n- (void)requestFinished:(YTKRequest *)request {\n    _finishedCount++;\n    if (_finishedCount == _requestArray.count) {\n        [self toggleAccessoriesWillStopCallBack];\n        if ([_delegate respondsToSelector:@selector(batchRequestFinished:)]) {\n            [_delegate batchRequestFinished:self];\n        }\n        if (_successCompletionBlock) {\n            _successCompletionBlock(self);\n        }\n        [self clearCompletionBlock];\n        [self toggleAccessoriesDidStopCallBack];\n        [[YTKBatchRequestAgent sharedAgent] removeBatchRequest:self];\n    }\n}\n\n- (void)requestFailed:(YTKRequest *)request {\n    _failedRequest = request;\n    [self toggleAccessoriesWillStopCallBack];\n    // Stop\n    for (YTKRequest *req in _requestArray) {\n        [req stop];\n    }\n    // Callback\n    if ([_delegate respondsToSelector:@selector(batchRequestFailed:)]) {\n        [_delegate batchRequestFailed:self];\n    }\n    if (_failureCompletionBlock) {\n        _failureCompletionBlock(self);\n    }\n    // Clear\n    [self clearCompletionBlock];\n\n    [self toggleAccessoriesDidStopCallBack];\n    [[YTKBatchRequestAgent sharedAgent] removeBatchRequest:self];\n}\n\n- (void)clearRequest {\n    for (YTKRequest * req in _requestArray) {\n        [req stop];\n    }\n    [self clearCompletionBlock];\n}\n\n#pragma mark - Request Accessoies\n\n- (void)addAccessory:(id<YTKRequestAccessory>)accessory {\n    if (!self.requestAccessories) {\n        self.requestAccessories = [NSMutableArray array];\n    }\n    [self.requestAccessories addObject:accessory];\n}\n\n@end\n"
  },
  {
    "path": "YTKNetwork/YTKBatchRequestAgent.h",
    "content": "//\n//  YTKBatchRequestAgent.h\n//\n//  Copyright (c) 2012-2016 YTKNetwork https://github.com/yuantiku\n//\n//  Permission is hereby granted, free of charge, to any person obtaining a copy\n//  of this software and associated documentation files (the \"Software\"), to deal\n//  in the Software without restriction, including without limitation the rights\n//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n//  copies of the Software, and to permit persons to whom the Software is\n//  furnished to do so, subject to the following conditions:\n//\n//  The above copyright notice and this permission notice shall be included in\n//  all copies or substantial portions of the Software.\n//\n//  THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n//  THE SOFTWARE.\n\n#import <Foundation/Foundation.h>\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class YTKBatchRequest;\n\n///  YTKBatchRequestAgent handles batch request management. It keeps track of all\n///  the batch requests.\n@interface YTKBatchRequestAgent : NSObject\n\n- (instancetype)init NS_UNAVAILABLE;\n+ (instancetype)new NS_UNAVAILABLE;\n\n///  Get the shared batch request agent.\n+ (YTKBatchRequestAgent *)sharedAgent;\n\n///  Add a batch request.\n- (void)addBatchRequest:(YTKBatchRequest *)request;\n\n///  Remove a previously added batch request.\n- (void)removeBatchRequest:(YTKBatchRequest *)request;\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "YTKNetwork/YTKBatchRequestAgent.m",
    "content": "//\n//  YTKBatchRequestAgent.m\n//\n//  Copyright (c) 2012-2016 YTKNetwork https://github.com/yuantiku\n//\n//  Permission is hereby granted, free of charge, to any person obtaining a copy\n//  of this software and associated documentation files (the \"Software\"), to deal\n//  in the Software without restriction, including without limitation the rights\n//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n//  copies of the Software, and to permit persons to whom the Software is\n//  furnished to do so, subject to the following conditions:\n//\n//  The above copyright notice and this permission notice shall be included in\n//  all copies or substantial portions of the Software.\n//\n//  THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n//  THE SOFTWARE.\n\n#import \"YTKBatchRequestAgent.h\"\n#import \"YTKBatchRequest.h\"\n\n@interface YTKBatchRequestAgent()\n\n@property (strong, nonatomic) NSMutableArray<YTKBatchRequest *> *requestArray;\n\n@end\n\n@implementation YTKBatchRequestAgent\n\n+ (YTKBatchRequestAgent *)sharedAgent {\n    static id sharedInstance = nil;\n    static dispatch_once_t onceToken;\n    dispatch_once(&onceToken, ^{\n        sharedInstance = [[self alloc] init];\n    });\n    return sharedInstance;\n}\n\n- (instancetype)init {\n    self = [super init];\n    if (self) {\n        _requestArray = [NSMutableArray array];\n    }\n    return self;\n}\n\n- (void)addBatchRequest:(YTKBatchRequest *)request {\n    @synchronized(self) {\n        [_requestArray addObject:request];\n    }\n}\n\n- (void)removeBatchRequest:(YTKBatchRequest *)request {\n    @synchronized(self) {\n        [_requestArray removeObject:request];\n    }\n}\n\n@end\n"
  },
  {
    "path": "YTKNetwork/YTKChainRequest.h",
    "content": "//\n//  YTKChainRequest.h\n//\n//  Copyright (c) 2012-2016 YTKNetwork https://github.com/yuantiku\n//\n//  Permission is hereby granted, free of charge, to any person obtaining a copy\n//  of this software and associated documentation files (the \"Software\"), to deal\n//  in the Software without restriction, including without limitation the rights\n//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n//  copies of the Software, and to permit persons to whom the Software is\n//  furnished to do so, subject to the following conditions:\n//\n//  The above copyright notice and this permission notice shall be included in\n//  all copies or substantial portions of the Software.\n//\n//  THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n//  THE SOFTWARE.\n\n#import <Foundation/Foundation.h>\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class YTKChainRequest;\n@class YTKBaseRequest;\n@protocol YTKRequestAccessory;\n\n///  The YTKChainRequestDelegate protocol defines several optional methods you can use\n///  to receive network-related messages. All the delegate methods will be called\n///  on the main queue. Note the delegate methods will be called when all the requests\n///  of chain request finishes.\n@protocol YTKChainRequestDelegate <NSObject>\n\n@optional\n///  Tell the delegate that the chain request has finished successfully.\n///\n///  @param chainRequest The corresponding chain request.\n- (void)chainRequestFinished:(YTKChainRequest *)chainRequest;\n\n///  Tell the delegate that the chain request has failed.\n///\n///  @param chainRequest The corresponding chain request.\n///  @param request      First failed request that causes the whole request to fail.\n- (void)chainRequestFailed:(YTKChainRequest *)chainRequest failedBaseRequest:(YTKBaseRequest*)request;\n\n@end\n\ntypedef void (^YTKChainCallback)(YTKChainRequest *chainRequest, YTKBaseRequest *baseRequest);\n\n///  YTKBatchRequest can be used to chain several YTKRequest so that one will only starts after another finishes.\n///  Note that when used inside YTKChainRequest, a single YTKRequest will have its own callback and delegate\n///  cleared, in favor of the batch request callback.\n@interface YTKChainRequest : NSObject\n\n///  All the requests are stored in this array.\n- (NSArray<YTKBaseRequest *> *)requestArray;\n\n///  The delegate object of the chain request. Default is nil.\n@property (nonatomic, weak, nullable) id<YTKChainRequestDelegate> delegate;\n\n///  This can be used to add several accessories object. Note if you use `addAccessory` to add acceesory\n///  this array will be automatically created. Default is nil.\n@property (nonatomic, strong, nullable) NSMutableArray<id<YTKRequestAccessory>> *requestAccessories;\n\n///  Convenience method to add request accessory. See also `requestAccessories`.\n- (void)addAccessory:(id<YTKRequestAccessory>)accessory;\n\n///  Start the chain request, adding first request in the chain to request queue.\n- (void)start;\n\n///  Stop the chain request. Remaining request in chain will be cancelled.\n- (void)stop;\n\n///  Add request to request chain.\n///\n///  @param request  The request to be chained.\n///  @param callback The finish callback\n- (void)addRequest:(YTKBaseRequest *)request callback:(nullable YTKChainCallback)callback;\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "YTKNetwork/YTKChainRequest.m",
    "content": "//\n//  YTKChainRequest.m\n//\n//  Copyright (c) 2012-2016 YTKNetwork https://github.com/yuantiku\n//\n//  Permission is hereby granted, free of charge, to any person obtaining a copy\n//  of this software and associated documentation files (the \"Software\"), to deal\n//  in the Software without restriction, including without limitation the rights\n//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n//  copies of the Software, and to permit persons to whom the Software is\n//  furnished to do so, subject to the following conditions:\n//\n//  The above copyright notice and this permission notice shall be included in\n//  all copies or substantial portions of the Software.\n//\n//  THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n//  THE SOFTWARE.\n\n#import \"YTKChainRequest.h\"\n#import \"YTKChainRequestAgent.h\"\n#import \"YTKNetworkPrivate.h\"\n#import \"YTKBaseRequest.h\"\n\n@interface YTKChainRequest()<YTKRequestDelegate>\n\n@property (strong, nonatomic) NSMutableArray<YTKBaseRequest *> *requestArray;\n@property (strong, nonatomic) NSMutableArray<YTKChainCallback> *requestCallbackArray;\n@property (assign, nonatomic) NSUInteger nextRequestIndex;\n@property (strong, nonatomic) YTKChainCallback emptyCallback;\n\n@end\n\n@implementation YTKChainRequest\n\n- (instancetype)init {\n    self = [super init];\n    if (self) {\n        _nextRequestIndex = 0;\n        _requestArray = [NSMutableArray array];\n        _requestCallbackArray = [NSMutableArray array];\n        _emptyCallback = ^(YTKChainRequest *chainRequest, YTKBaseRequest *baseRequest) {\n            // do nothing\n        };\n    }\n    return self;\n}\n\n- (void)start {\n    if (_nextRequestIndex > 0) {\n        YTKLog(@\"Error! Chain request has already started.\");\n        return;\n    }\n\n    if ([_requestArray count] > 0) {\n        [self toggleAccessoriesWillStartCallBack];\n        [self startNextRequest];\n        [[YTKChainRequestAgent sharedAgent] addChainRequest:self];\n    } else {\n        YTKLog(@\"Error! Chain request array is empty.\");\n    }\n}\n\n- (void)stop {\n    [self toggleAccessoriesWillStopCallBack];\n    [self clearRequest];\n    [[YTKChainRequestAgent sharedAgent] removeChainRequest:self];\n    [self toggleAccessoriesDidStopCallBack];\n}\n\n- (void)addRequest:(YTKBaseRequest *)request callback:(YTKChainCallback)callback {\n    [_requestArray addObject:request];\n    if (callback != nil) {\n        [_requestCallbackArray addObject:callback];\n    } else {\n        [_requestCallbackArray addObject:_emptyCallback];\n    }\n}\n\n- (NSArray<YTKBaseRequest *> *)requestArray {\n    return _requestArray;\n}\n\n- (BOOL)startNextRequest {\n    if (_nextRequestIndex < [_requestArray count]) {\n        YTKBaseRequest *request = _requestArray[_nextRequestIndex];\n        _nextRequestIndex++;\n        request.delegate = self;\n        [request clearCompletionBlock];\n        [request start];\n        return YES;\n    } else {\n        return NO;\n    }\n}\n\n#pragma mark - Network Request Delegate\n\n- (void)requestFinished:(YTKBaseRequest *)request {\n    NSUInteger currentRequestIndex = _nextRequestIndex - 1;\n    YTKChainCallback callback = _requestCallbackArray[currentRequestIndex];\n    callback(self, request);\n    if (![self startNextRequest]) {\n        [self toggleAccessoriesWillStopCallBack];\n        if ([_delegate respondsToSelector:@selector(chainRequestFinished:)]) {\n            [_delegate chainRequestFinished:self];\n            [[YTKChainRequestAgent sharedAgent] removeChainRequest:self];\n        }\n        [self toggleAccessoriesDidStopCallBack];\n    }\n}\n\n- (void)requestFailed:(YTKBaseRequest *)request {\n    [self toggleAccessoriesWillStopCallBack];\n    if ([_delegate respondsToSelector:@selector(chainRequestFailed:failedBaseRequest:)]) {\n        [_delegate chainRequestFailed:self failedBaseRequest:request];\n        [[YTKChainRequestAgent sharedAgent] removeChainRequest:self];\n    }\n    [self toggleAccessoriesDidStopCallBack];\n}\n\n- (void)clearRequest {\n    NSUInteger currentRequestIndex = _nextRequestIndex - 1;\n    if (currentRequestIndex < [_requestArray count]) {\n        YTKBaseRequest *request = _requestArray[currentRequestIndex];\n        [request stop];\n    }\n    [_requestArray removeAllObjects];\n    [_requestCallbackArray removeAllObjects];\n}\n\n#pragma mark - Request Accessoies\n\n- (void)addAccessory:(id<YTKRequestAccessory>)accessory {\n    if (!self.requestAccessories) {\n        self.requestAccessories = [NSMutableArray array];\n    }\n    [self.requestAccessories addObject:accessory];\n}\n\n@end\n"
  },
  {
    "path": "YTKNetwork/YTKChainRequestAgent.h",
    "content": "//\n//  YTKChainRequestAgent.h\n//\n//  Copyright (c) 2012-2016 YTKNetwork https://github.com/yuantiku\n//\n//  Permission is hereby granted, free of charge, to any person obtaining a copy\n//  of this software and associated documentation files (the \"Software\"), to deal\n//  in the Software without restriction, including without limitation the rights\n//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n//  copies of the Software, and to permit persons to whom the Software is\n//  furnished to do so, subject to the following conditions:\n//\n//  The above copyright notice and this permission notice shall be included in\n//  all copies or substantial portions of the Software.\n//\n//  THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n//  THE SOFTWARE.\n\n#import <Foundation/Foundation.h>\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class YTKChainRequest;\n\n///  YTKChainRequestAgent handles chain request management. It keeps track of all\n///  the chain requests.\n@interface YTKChainRequestAgent : NSObject\n\n- (instancetype)init NS_UNAVAILABLE;\n+ (instancetype)new NS_UNAVAILABLE;\n\n///  Get the shared chain request agent.\n+ (YTKChainRequestAgent *)sharedAgent;\n\n///  Add a chain request.\n- (void)addChainRequest:(YTKChainRequest *)request;\n\n///  Remove a previously added chain request.\n- (void)removeChainRequest:(YTKChainRequest *)request;\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "YTKNetwork/YTKChainRequestAgent.m",
    "content": "//\n//  YTKChainRequestAgent.m\n//\n//  Copyright (c) 2012-2016 YTKNetwork https://github.com/yuantiku\n//\n//  Permission is hereby granted, free of charge, to any person obtaining a copy\n//  of this software and associated documentation files (the \"Software\"), to deal\n//  in the Software without restriction, including without limitation the rights\n//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n//  copies of the Software, and to permit persons to whom the Software is\n//  furnished to do so, subject to the following conditions:\n//\n//  The above copyright notice and this permission notice shall be included in\n//  all copies or substantial portions of the Software.\n//\n//  THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n//  THE SOFTWARE.\n\n#import \"YTKChainRequestAgent.h\"\n#import \"YTKChainRequest.h\"\n\n@interface YTKChainRequestAgent()\n\n@property (strong, nonatomic) NSMutableArray<YTKChainRequest *> *requestArray;\n\n@end\n\n@implementation YTKChainRequestAgent\n\n+ (YTKChainRequestAgent *)sharedAgent {\n    static id sharedInstance = nil;\n    static dispatch_once_t onceToken;\n    dispatch_once(&onceToken, ^{\n        sharedInstance = [[self alloc] init];\n    });\n    return sharedInstance;\n}\n\n- (instancetype)init {\n    self = [super init];\n    if (self) {\n        _requestArray = [NSMutableArray array];\n    }\n    return self;\n}\n\n- (void)addChainRequest:(YTKChainRequest *)request {\n    @synchronized(self) {\n        [_requestArray addObject:request];\n    }\n}\n\n- (void)removeChainRequest:(YTKChainRequest *)request {\n    @synchronized(self) {\n        [_requestArray removeObject:request];\n    }\n}\n\n@end\n"
  },
  {
    "path": "YTKNetwork/YTKNetwork.h",
    "content": "//\n//  YTKNetwork.h\n//\n//  Copyright (c) 2012-2016 YTKNetwork https://github.com/yuantiku\n//\n//  Permission is hereby granted, free of charge, to any person obtaining a copy\n//  of this software and associated documentation files (the \"Software\"), to deal\n//  in the Software without restriction, including without limitation the rights\n//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n//  copies of the Software, and to permit persons to whom the Software is\n//  furnished to do so, subject to the following conditions:\n//\n//  The above copyright notice and this permission notice shall be included in\n//  all copies or substantial portions of the Software.\n//\n//  THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n//  THE SOFTWARE.\n\n#import <Foundation/Foundation.h>\n\n#ifndef _YTKNETWORK_\n    #define _YTKNETWORK_\n\n#if __has_include(<YTKNetwork/YTKNetwork.h>)\n\n    FOUNDATION_EXPORT double YTKNetworkVersionNumber;\n    FOUNDATION_EXPORT const unsigned char YTKNetworkVersionString[];\n\n    #import <YTKNetwork/YTKRequest.h>\n    #import <YTKNetwork/YTKBaseRequest.h>\n    #import <YTKNetwork/YTKNetworkAgent.h>\n    #import <YTKNetwork/YTKBatchRequest.h>\n    #import <YTKNetwork/YTKBatchRequestAgent.h>\n    #import <YTKNetwork/YTKChainRequest.h>\n    #import <YTKNetwork/YTKChainRequestAgent.h>\n    #import <YTKNetwork/YTKNetworkConfig.h>\n    #import <YTKNetwork/YTKRequestEventAccessory.h>\n\n#else\n\n    #import \"YTKRequest.h\"\n    #import \"YTKBaseRequest.h\"\n    #import \"YTKNetworkAgent.h\"\n    #import \"YTKBatchRequest.h\"\n    #import \"YTKBatchRequestAgent.h\"\n    #import \"YTKChainRequest.h\"\n    #import \"YTKChainRequestAgent.h\"\n    #import \"YTKNetworkConfig.h\"\n    #import \"YTKRequestEventAccessory.h\"\n\n#endif /* __has_include */\n\n#endif /* _YTKNETWORK_ */\n"
  },
  {
    "path": "YTKNetwork/YTKNetworkAgent.h",
    "content": "//\n//  YTKNetworkAgent.h\n//\n//  Copyright (c) 2012-2016 YTKNetwork https://github.com/yuantiku\n//\n//  Permission is hereby granted, free of charge, to any person obtaining a copy\n//  of this software and associated documentation files (the \"Software\"), to deal\n//  in the Software without restriction, including without limitation the rights\n//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n//  copies of the Software, and to permit persons to whom the Software is\n//  furnished to do so, subject to the following conditions:\n//\n//  The above copyright notice and this permission notice shall be included in\n//  all copies or substantial portions of the Software.\n//\n//  THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n//  THE SOFTWARE.\n\n#import <Foundation/Foundation.h>\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class YTKBaseRequest;\n\n///  YTKNetworkAgent is the underlying class that handles actual request generation,\n///  serialization and response handling.\n@interface YTKNetworkAgent : NSObject\n\n- (instancetype)init NS_UNAVAILABLE;\n+ (instancetype)new NS_UNAVAILABLE;\n\n///  Get the shared agent.\n+ (YTKNetworkAgent *)sharedAgent;\n\n///  Add request to session and start it.\n- (void)addRequest:(YTKBaseRequest *)request;\n\n///  Cancel a request that was previously added.\n- (void)cancelRequest:(YTKBaseRequest *)request;\n\n///  Cancel all requests that were previously added.\n- (void)cancelAllRequests;\n\n///  Return the constructed URL of request.\n///\n///  @param request The request to parse. Should not be nil.\n///\n///  @return The result URL.\n- (NSString *)buildRequestUrl:(YTKBaseRequest *)request;\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "YTKNetwork/YTKNetworkAgent.m",
    "content": "//\n//  YTKNetworkAgent.m\n//\n//  Copyright (c) 2012-2016 YTKNetwork https://github.com/yuantiku\n//\n//  Permission is hereby granted, free of charge, to any person obtaining a copy\n//  of this software and associated documentation files (the \"Software\"), to deal\n//  in the Software without restriction, including without limitation the rights\n//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n//  copies of the Software, and to permit persons to whom the Software is\n//  furnished to do so, subject to the following conditions:\n//\n//  The above copyright notice and this permission notice shall be included in\n//  all copies or substantial portions of the Software.\n//\n//  THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n//  THE SOFTWARE.\n\n#import \"YTKNetworkAgent.h\"\n#import \"YTKNetworkConfig.h\"\n#import \"YTKNetworkPrivate.h\"\n#import <pthread/pthread.h>\n\n#if __has_include(<AFNetworking/AFHTTPSessionManager.h>)\n#import <AFNetworking/AFHTTPSessionManager.h>\n#else\n#import <AFNetworking/AFHTTPSessionManager.h>\n#endif\n\n#define Lock() pthread_mutex_lock(&_lock)\n#define Unlock() pthread_mutex_unlock(&_lock)\n\n#define kYTKNetworkIncompleteDownloadFolderName @\"Incomplete\"\n\n@implementation YTKNetworkAgent {\n    AFHTTPSessionManager *_manager;\n    YTKNetworkConfig *_config;\n    AFJSONResponseSerializer *_jsonResponseSerializer;\n    AFXMLParserResponseSerializer *_xmlParserResponseSerialzier;\n    NSMutableDictionary<NSNumber *, YTKBaseRequest *> *_requestsRecord;\n\n    dispatch_queue_t _processingQueue;\n    pthread_mutex_t _lock;\n    NSIndexSet *_allStatusCodes;\n}\n\n+ (YTKNetworkAgent *)sharedAgent {\n    static id sharedInstance = nil;\n    static dispatch_once_t onceToken;\n    dispatch_once(&onceToken, ^{\n        sharedInstance = [[self alloc] init];\n    });\n    return sharedInstance;\n}\n\n- (instancetype)init {\n    self = [super init];\n    if (self) {\n        _config = [YTKNetworkConfig sharedConfig];\n        _manager = [[AFHTTPSessionManager alloc] initWithSessionConfiguration:_config.sessionConfiguration];\n        _requestsRecord = [NSMutableDictionary dictionary];\n        _processingQueue = dispatch_queue_create(\"com.yuantiku.networkagent.processing\", DISPATCH_QUEUE_CONCURRENT);\n        _allStatusCodes = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(100, 500)];\n        pthread_mutex_init(&_lock, NULL);\n\n        _manager.securityPolicy = _config.securityPolicy;\n        _manager.responseSerializer = [AFHTTPResponseSerializer serializer];\n        // Take over the status code validation\n        _manager.responseSerializer.acceptableStatusCodes = _allStatusCodes;\n        _manager.completionQueue = _processingQueue;\n        [_manager setTaskDidFinishCollectingMetricsBlock:_config.collectingMetricsBlock];\n    }\n    return self;\n}\n\n- (AFJSONResponseSerializer *)jsonResponseSerializer {\n    static dispatch_once_t onceToken;\n    dispatch_once(&onceToken, ^{\n        _jsonResponseSerializer = [AFJSONResponseSerializer serializer];\n        _jsonResponseSerializer.acceptableStatusCodes = _allStatusCodes;\n    });\n    return _jsonResponseSerializer;\n}\n\n- (AFXMLParserResponseSerializer *)xmlParserResponseSerialzier {\n    static dispatch_once_t onceToken;\n    dispatch_once(&onceToken, ^{\n        _xmlParserResponseSerialzier = [AFXMLParserResponseSerializer serializer];\n        _xmlParserResponseSerialzier.acceptableStatusCodes = _allStatusCodes;\n    });\n    return _xmlParserResponseSerialzier;\n}\n\n#pragma mark -\n\n- (NSString *)buildRequestUrl:(YTKBaseRequest *)request {\n    NSParameterAssert(request != nil);\n\n    NSString *detailUrl = [request requestUrl];\n    NSURL *temp = [NSURL URLWithString:detailUrl];\n    // If detailUrl is valid URL\n    if (temp && temp.host && temp.scheme) {\n        return detailUrl;\n    }\n    // Filter URL if needed\n    NSArray *filters = [_config urlFilters];\n    for (id<YTKUrlFilterProtocol> f in filters) {\n        detailUrl = [f filterUrl:detailUrl withRequest:request];\n    }\n\n    NSString *baseUrl;\n    if ([request useCDN]) {\n        if ([request cdnUrl].length > 0) {\n            baseUrl = [request cdnUrl];\n        } else {\n            baseUrl = [_config cdnUrl];\n        }\n    } else {\n        if ([request baseUrl].length > 0) {\n            baseUrl = [request baseUrl];\n        } else {\n            baseUrl = [_config baseUrl];\n        }\n    }\n    // URL slash compatibility\n    NSURL *url = [NSURL URLWithString:baseUrl];\n\n    if (baseUrl.length > 0 && ![baseUrl hasSuffix:@\"/\"]) {\n        url = [url URLByAppendingPathComponent:@\"\"];\n    }\n\n    return [NSURL URLWithString:detailUrl relativeToURL:url].absoluteString;\n}\n\n- (AFHTTPRequestSerializer *)requestSerializerForRequest:(YTKBaseRequest *)request {\n    AFHTTPRequestSerializer *requestSerializer = nil;\n    if (request.requestSerializerType == YTKRequestSerializerTypeHTTP) {\n        requestSerializer = [AFHTTPRequestSerializer serializer];\n    } else if (request.requestSerializerType == YTKRequestSerializerTypeJSON) {\n        requestSerializer = [AFJSONRequestSerializer serializer];\n    }\n\n    requestSerializer.timeoutInterval = [request requestTimeoutInterval];\n    requestSerializer.allowsCellularAccess = [request allowsCellularAccess];\n\n    // If api needs server username and password\n    NSArray<NSString *> *authorizationHeaderFieldArray = [request requestAuthorizationHeaderFieldArray];\n    if (authorizationHeaderFieldArray != nil) {\n        [requestSerializer setAuthorizationHeaderFieldWithUsername:authorizationHeaderFieldArray.firstObject\n                                                          password:authorizationHeaderFieldArray.lastObject];\n    }\n\n    // If api needs to add custom value to HTTPHeaderField\n    NSDictionary<NSString *, NSString *> *headerFieldValueDictionary = [request requestHeaderFieldValueDictionary];\n    if (headerFieldValueDictionary != nil) {\n        for (NSString *httpHeaderField in headerFieldValueDictionary.allKeys) {\n            NSString *value = headerFieldValueDictionary[httpHeaderField];\n            [requestSerializer setValue:value forHTTPHeaderField:httpHeaderField];\n        }\n    }\n    return requestSerializer;\n}\n\n- (NSURLSessionTask *)sessionTaskForRequest:(YTKBaseRequest *)request error:(NSError * _Nullable __autoreleasing *)error {\n    YTKRequestMethod method = [request requestMethod];\n    NSString *url = [self buildRequestUrl:request];\n    id param = request.requestArgument;\n    AFConstructingBlock constructingBlock = [request constructingBodyBlock];\n    AFURLSessionTaskProgressBlock uploadProgressBlock = [request uploadProgressBlock];\n    AFHTTPRequestSerializer *requestSerializer = [self requestSerializerForRequest:request];\n\n    switch (method) {\n        case YTKRequestMethodGET:\n            if (request.resumableDownloadPath) {\n                return [self downloadTaskWithDownloadPath:request.resumableDownloadPath\n                                        requestSerializer:requestSerializer\n                                                URLString:url\n                                               parameters:param\n                                                 progress:request.resumableDownloadProgressBlock\n                                                    error:error];\n            } else {\n                return [self dataTaskWithHTTPMethod:@\"GET\"\n                                  requestSerializer:requestSerializer\n                                          URLString:url\n                                         parameters:param\n                                              error:error];\n            }\n        case YTKRequestMethodPOST:\n            return [self dataTaskWithHTTPMethod:@\"POST\"\n                              requestSerializer:requestSerializer\n                                      URLString:url\n                                     parameters:param\n                                 uploadProgress:uploadProgressBlock\n                      constructingBodyWithBlock:constructingBlock\n                                          error:error];\n        case YTKRequestMethodHEAD:\n            return [self dataTaskWithHTTPMethod:@\"HEAD\"\n                              requestSerializer:requestSerializer\n                                      URLString:url\n                                     parameters:param\n                                          error:error];\n        case YTKRequestMethodPUT:\n            return [self dataTaskWithHTTPMethod:@\"PUT\"\n                              requestSerializer:requestSerializer\n                                      URLString:url\n                                     parameters:param\n                                 uploadProgress:uploadProgressBlock\n                      constructingBodyWithBlock:constructingBlock\n                                          error:error];\n        case YTKRequestMethodDELETE:\n            return [self dataTaskWithHTTPMethod:@\"DELETE\"\n                              requestSerializer:requestSerializer\n                                      URLString:url\n                                     parameters:param\n                                          error:error];\n        case YTKRequestMethodPATCH:\n            return [self dataTaskWithHTTPMethod:@\"PATCH\"\n                              requestSerializer:requestSerializer\n                                      URLString:url\n                                     parameters:param\n                                          error:error];\n    }\n}\n\n- (void)addRequest:(YTKBaseRequest *)request {\n    NSParameterAssert(request != nil);\n\n    NSError * __autoreleasing requestSerializationError = nil;\n\n    NSURLRequest *customUrlRequest= [request buildCustomUrlRequest];\n    if (customUrlRequest) {\n        __block NSURLSessionDataTask *dataTask = nil;\n        dataTask = [_manager dataTaskWithRequest:customUrlRequest\n                                  uploadProgress:nil\n                                downloadProgress:nil\n                               completionHandler:^(NSURLResponse * _Nonnull response, id  _Nullable responseObject, NSError * _Nullable error) {\n            [self handleRequestResult:dataTask responseObject:responseObject error:error];\n        }];\n        request.requestTask = dataTask;\n    } else {\n        request.requestTask = [self sessionTaskForRequest:request error:&requestSerializationError];\n    }\n\n    if (requestSerializationError) {\n        [self requestDidFailWithRequest:request error:requestSerializationError];\n        return;\n    }\n\n    NSAssert(request.requestTask != nil, @\"requestTask should not be nil\");\n\n    // Set request task priority\n    if ([request.requestTask respondsToSelector:@selector(priority)]) {\n        switch (request.requestPriority) {\n            case YTKRequestPriorityHigh:\n                request.requestTask.priority = NSURLSessionTaskPriorityHigh;\n                break;\n            case YTKRequestPriorityLow:\n                request.requestTask.priority = NSURLSessionTaskPriorityLow;\n                break;\n            case YTKRequestPriorityDefault:\n                /*!!fall through*/\n            default:\n                request.requestTask.priority = NSURLSessionTaskPriorityDefault;\n                break;\n        }\n    }\n\n    // Retain request\n    YTKLog(@\"Add request: %@\", NSStringFromClass([request class]));\n    [self addRequestToRecord:request];\n    [request.requestTask resume];\n}\n\n- (void)cancelRequest:(YTKBaseRequest *)request {\n    NSParameterAssert(request != nil);\n\n    if (request.resumableDownloadPath && [self incompleteDownloadTempPathForDownloadPath:request.resumableDownloadPath] != nil) {\n        NSURLSessionDownloadTask *requestTask = (NSURLSessionDownloadTask *)request.requestTask;\n        [requestTask cancelByProducingResumeData:^(NSData *resumeData) {\n            NSURL *localUrl = [self incompleteDownloadTempPathForDownloadPath:request.resumableDownloadPath];\n            [resumeData writeToURL:localUrl atomically:YES];\n        }];\n    } else {\n        [request.requestTask cancel];\n    }\n\n    [self removeRequestFromRecord:request];\n    [request clearCompletionBlock];\n}\n\n- (void)cancelAllRequests {\n    Lock();\n    NSArray *allKeys = [_requestsRecord allKeys];\n    Unlock();\n    if (allKeys && allKeys.count > 0) {\n        NSArray *copiedKeys = [allKeys copy];\n        for (NSNumber *key in copiedKeys) {\n            Lock();\n            YTKBaseRequest *request = _requestsRecord[key];\n            Unlock();\n            // We are using non-recursive lock.\n            // Do not lock `stop`, otherwise deadlock may occur.\n            [request stop];\n        }\n    }\n}\n\n- (BOOL)validateResult:(YTKBaseRequest *)request error:(NSError * _Nullable __autoreleasing *)error {\n    BOOL result = [request statusCodeValidator];\n    if (!result) {\n        if (error) {\n            NSString *desc = [NSString stringWithFormat:@\"Invalid status code (%ld)\", (long)[request responseStatusCode]];\n            *error = [NSError errorWithDomain:YTKRequestValidationErrorDomain code:YTKRequestValidationErrorInvalidStatusCode userInfo:@{NSLocalizedDescriptionKey:desc}];\n        }\n        return result;\n    }\n    id json = [request responseJSONObject];\n    id validator = [request jsonValidator];\n    if (json && validator) {\n        result = [YTKNetworkUtils validateJSON:json withValidator:validator];\n        if (!result) {\n            if (error) {\n                *error = [NSError errorWithDomain:YTKRequestValidationErrorDomain code:YTKRequestValidationErrorInvalidJSONFormat userInfo:@{NSLocalizedDescriptionKey:@\"Invalid JSON format\"}];\n            }\n            return result;\n        }\n    }\n    return YES;\n}\n\n- (void)handleRequestResult:(NSURLSessionTask *)task responseObject:(id)responseObject error:(NSError *)error {\n    Lock();\n    YTKBaseRequest *request = _requestsRecord[@(task.taskIdentifier)];\n    Unlock();\n\n    // When the request is cancelled and removed from records, the underlying\n    // AFNetworking failure callback will still kicks in, resulting in a nil `request`.\n    //\n    // Here we choose to completely ignore cancelled tasks. Neither success or failure\n    // callback will be called.\n    if (!request) {\n        return;\n    }\n\n    YTKLog(@\"Finished Request: %@\", NSStringFromClass([request class]));\n\n    NSError * __autoreleasing serializationError = nil;\n    NSError * __autoreleasing validationError = nil;\n\n    NSError *requestError = nil;\n    BOOL succeed = NO;\n\n    request.responseObject = responseObject;\n    if ([request.responseObject isKindOfClass:[NSData class]]) {\n        request.responseData = responseObject;\n        request.responseString = [[NSString alloc] initWithData:responseObject encoding:[YTKNetworkUtils stringEncodingWithRequest:request]];\n\n        switch (request.responseSerializerType) {\n            case YTKResponseSerializerTypeHTTP:\n                // Default serializer. Do nothing.\n                break;\n            case YTKResponseSerializerTypeJSON:\n                request.responseObject = [self.jsonResponseSerializer responseObjectForResponse:task.response data:request.responseData error:&serializationError];\n                request.responseJSONObject = request.responseObject;\n                break;\n            case YTKResponseSerializerTypeXMLParser:\n                request.responseObject = [self.xmlParserResponseSerialzier responseObjectForResponse:task.response data:request.responseData error:&serializationError];\n                break;\n        }\n    }\n    if (error) {\n        succeed = NO;\n        requestError = error;\n    } else if (serializationError) {\n        succeed = NO;\n        requestError = serializationError;\n    } else {\n        succeed = [self validateResult:request error:&validationError];\n        requestError = validationError;\n    }\n\n    if (succeed) {\n        [self requestDidSucceedWithRequest:request];\n    } else {\n        [self requestDidFailWithRequest:request error:requestError];\n    }\n\n    dispatch_async(dispatch_get_main_queue(), ^{\n        [self removeRequestFromRecord:request];\n        [request clearCompletionBlock];\n    });\n}\n\n- (void)requestDidSucceedWithRequest:(YTKBaseRequest *)request {\n    @autoreleasepool {\n        [request requestCompletePreprocessor];\n    }\n    dispatch_async(dispatch_get_main_queue(), ^{\n        [request toggleAccessoriesWillStopCallBack];\n        [request requestCompleteFilter];\n\n        if (request.delegate != nil) {\n            [request.delegate requestFinished:request];\n        }\n        if (request.successCompletionBlock) {\n            request.successCompletionBlock(request);\n        }\n        [request toggleAccessoriesDidStopCallBack];\n    });\n}\n\n- (void)requestDidFailWithRequest:(YTKBaseRequest *)request error:(NSError *)error {\n    request.error = error;\n    YTKLog(@\"Request %@ failed, status code = %ld, error = %@\",\n           NSStringFromClass([request class]), (long)request.responseStatusCode, error.localizedDescription);\n\n    // Save incomplete download data.\n    NSData *incompleteDownloadData = error.userInfo[NSURLSessionDownloadTaskResumeData];\n    NSURL *localUrl = nil;\n    if (request.resumableDownloadPath) {\n        localUrl = [self incompleteDownloadTempPathForDownloadPath:request.resumableDownloadPath];\n    }\n    if (incompleteDownloadData && localUrl != nil) {\n        [incompleteDownloadData writeToURL:localUrl atomically:YES];\n    }\n\n    // Load response from file and clean up if download task failed.\n    if ([request.responseObject isKindOfClass:[NSURL class]]) {\n        NSURL *url = request.responseObject;\n        if (url.isFileURL && [[NSFileManager defaultManager] fileExistsAtPath:url.path]) {\n            request.responseData = [NSData dataWithContentsOfURL:url];\n            request.responseString = [[NSString alloc] initWithData:request.responseData encoding:[YTKNetworkUtils stringEncodingWithRequest:request]];\n\n            [[NSFileManager defaultManager] removeItemAtURL:url error:nil];\n        }\n        request.responseObject = nil;\n    }\n\n    @autoreleasepool {\n        [request requestFailedPreprocessor];\n    }\n    dispatch_async(dispatch_get_main_queue(), ^{\n        [request toggleAccessoriesWillStopCallBack];\n        [request requestFailedFilter];\n\n        if (request.delegate != nil) {\n            [request.delegate requestFailed:request];\n        }\n        if (request.failureCompletionBlock) {\n            request.failureCompletionBlock(request);\n        }\n        [request toggleAccessoriesDidStopCallBack];\n    });\n}\n\n- (void)addRequestToRecord:(YTKBaseRequest *)request {\n    Lock();\n    _requestsRecord[@(request.requestTask.taskIdentifier)] = request;\n    Unlock();\n}\n\n- (void)removeRequestFromRecord:(YTKBaseRequest *)request {\n    Lock();\n    [_requestsRecord removeObjectForKey:@(request.requestTask.taskIdentifier)];\n    YTKLog(@\"Request queue size = %zd\", [_requestsRecord count]);\n    Unlock();\n}\n\n#pragma mark -\n\n- (NSURLSessionDataTask *)dataTaskWithHTTPMethod:(NSString *)method\n                               requestSerializer:(AFHTTPRequestSerializer *)requestSerializer\n                                       URLString:(NSString *)URLString\n                                      parameters:(id)parameters\n                                           error:(NSError * _Nullable __autoreleasing *)error {\n    return [self dataTaskWithHTTPMethod:method\n                      requestSerializer:requestSerializer\n                              URLString:URLString\n                             parameters:parameters\n                         uploadProgress:nil\n              constructingBodyWithBlock:nil\n                                  error:error];\n}\n\n- (NSURLSessionDataTask *)dataTaskWithHTTPMethod:(NSString *)method\n                               requestSerializer:(AFHTTPRequestSerializer *)requestSerializer\n                                       URLString:(NSString *)URLString\n                                      parameters:(id)parameters\n                                  uploadProgress:(AFURLSessionTaskProgressBlock)uploadProgress\n                       constructingBodyWithBlock:(nullable void (^)(id <AFMultipartFormData> formData))block\n                                           error:(NSError * _Nullable __autoreleasing *)error {\n    NSMutableURLRequest *request = nil;\n\n    if (block) {\n        request = [requestSerializer multipartFormRequestWithMethod:method URLString:URLString parameters:parameters constructingBodyWithBlock:block error:error];\n    } else {\n        request = [requestSerializer requestWithMethod:method URLString:URLString parameters:parameters error:error];\n    }\n\n    __block NSURLSessionDataTask *dataTask = nil;\n    dataTask = [_manager dataTaskWithRequest:request\n                              uploadProgress:uploadProgress\n                            downloadProgress:nil\n                           completionHandler:^(NSURLResponse * __unused response, id responseObject, NSError *_error) {\n                               [self handleRequestResult:dataTask responseObject:responseObject error:_error];\n                           }];\n\n    return dataTask;\n}\n\n- (NSURLSessionDownloadTask *)downloadTaskWithDownloadPath:(NSString *)downloadPath\n                                         requestSerializer:(AFHTTPRequestSerializer *)requestSerializer\n                                                 URLString:(NSString *)URLString\n                                                parameters:(id)parameters\n                                                  progress:(nullable void (^)(NSProgress *downloadProgress))downloadProgressBlock\n                                                     error:(NSError * _Nullable __autoreleasing *)error {\n    // add parameters to URL;\n    NSMutableURLRequest *urlRequest = [requestSerializer requestWithMethod:@\"GET\" URLString:URLString parameters:parameters error:error];\n\n    NSString *downloadTargetPath;\n    BOOL isDirectory;\n    if (![[NSFileManager defaultManager] fileExistsAtPath:downloadPath isDirectory:&isDirectory]) {\n        isDirectory = NO;\n    }\n    // If targetPath is a directory, use the file name we got from the urlRequest.\n    // Make sure downloadTargetPath is always a file, not directory.\n    if (isDirectory) {\n        NSString *fileName = [urlRequest.URL lastPathComponent];\n        downloadTargetPath = [NSString pathWithComponents:@[downloadPath, fileName]];\n    } else {\n        downloadTargetPath = downloadPath;\n    }\n\n    // AFN use `moveItemAtURL` to move downloaded file to target path,\n    // this method aborts the move attempt if a file already exist at the path.\n    // So we remove the exist file before we start the download task.\n    // https://github.com/AFNetworking/AFNetworking/issues/3775\n    if ([[NSFileManager defaultManager] fileExistsAtPath:downloadTargetPath]) {\n        [[NSFileManager defaultManager] removeItemAtPath:downloadTargetPath error:nil];\n    }\n\n    BOOL resumeSucceeded = NO;\n    __block NSURLSessionDownloadTask *downloadTask = nil;\n    NSURL *localUrl = [self incompleteDownloadTempPathForDownloadPath:downloadPath];\n    if (localUrl != nil) {\n        BOOL resumeDataFileExists = [[NSFileManager defaultManager] fileExistsAtPath:localUrl.path];\n        NSData *data = [NSData dataWithContentsOfURL:localUrl];\n        BOOL resumeDataIsValid = [YTKNetworkUtils validateResumeData:data];\n\n        BOOL canBeResumed = resumeDataFileExists && resumeDataIsValid;\n        // Try to resume with resumeData.\n        // Even though we try to validate the resumeData, this may still fail and raise excecption.\n        if (canBeResumed) {\n            @try {\n                downloadTask = [_manager downloadTaskWithResumeData:data progress:downloadProgressBlock destination:^NSURL * _Nonnull(NSURL * _Nonnull targetPath, NSURLResponse * _Nonnull response) {\n                    return [NSURL fileURLWithPath:downloadTargetPath isDirectory:NO];\n                } completionHandler:\n                                ^(NSURLResponse * _Nonnull response, NSURL * _Nullable filePath, NSError * _Nullable error) {\n                                    [self handleRequestResult:downloadTask responseObject:filePath error:error];\n                                }];\n                resumeSucceeded = YES;\n            } @catch (NSException *exception) {\n                YTKLog(@\"Resume download failed, reason = %@\", exception.reason);\n                resumeSucceeded = NO;\n            }\n        }\n    }\n    if (!resumeSucceeded) {\n        downloadTask = [_manager downloadTaskWithRequest:urlRequest progress:downloadProgressBlock destination:^NSURL * _Nonnull(NSURL * _Nonnull targetPath, NSURLResponse * _Nonnull response) {\n            return [NSURL fileURLWithPath:downloadTargetPath isDirectory:NO];\n        } completionHandler:\n                        ^(NSURLResponse * _Nonnull response, NSURL * _Nullable filePath, NSError * _Nullable error) {\n                            [self handleRequestResult:downloadTask responseObject:filePath error:error];\n                        }];\n    }\n    return downloadTask;\n}\n\n#pragma mark - Resumable Download\n\n- (NSString *)incompleteDownloadTempCacheFolder {\n    NSFileManager *fileManager = [NSFileManager new];\n    NSString *cacheFolder = [NSTemporaryDirectory() stringByAppendingPathComponent:kYTKNetworkIncompleteDownloadFolderName];\n\n    BOOL isDirectory = NO;\n    if ([fileManager fileExistsAtPath:cacheFolder isDirectory:&isDirectory] && isDirectory) {\n        return cacheFolder;\n    }\n    NSError *error = nil;\n    if ([fileManager createDirectoryAtPath:cacheFolder withIntermediateDirectories:YES attributes:nil error:&error] && error == nil) {\n        return cacheFolder;\n    }\n    YTKLog(@\"Failed to create cache directory at %@ with error: %@\", cacheFolder, error != nil ? error.localizedDescription : @\"unkown\");\n    return nil;\n}\n\n- (NSURL *)incompleteDownloadTempPathForDownloadPath:(NSString *)downloadPath {\n    if (downloadPath == nil || downloadPath.length == 0) {\n        return nil;\n    }\n    NSString *tempPath = nil;\n    NSString *md5URLString = [YTKNetworkUtils md5StringFromString:downloadPath];\n    tempPath = [[self incompleteDownloadTempCacheFolder] stringByAppendingPathComponent:md5URLString];\n    return tempPath == nil ? nil : [NSURL fileURLWithPath:tempPath];\n}\n\n#pragma mark - Testing\n\n- (AFHTTPSessionManager *)manager {\n    return _manager;\n}\n\n- (void)resetURLSessionManager {\n    _manager = [AFHTTPSessionManager manager];\n}\n\n- (void)resetURLSessionManagerWithConfiguration:(NSURLSessionConfiguration *)configuration {\n    _manager = [[AFHTTPSessionManager alloc] initWithSessionConfiguration:configuration];\n}\n\n@end\n"
  },
  {
    "path": "YTKNetwork/YTKNetworkConfig.h",
    "content": "//\n//  YTKNetworkConfig.h\n//\n//  Copyright (c) 2012-2016 YTKNetwork https://github.com/yuantiku\n//\n//  Permission is hereby granted, free of charge, to any person obtaining a copy\n//  of this software and associated documentation files (the \"Software\"), to deal\n//  in the Software without restriction, including without limitation the rights\n//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n//  copies of the Software, and to permit persons to whom the Software is\n//  furnished to do so, subject to the following conditions:\n//\n//  The above copyright notice and this permission notice shall be included in\n//  all copies or substantial portions of the Software.\n//\n//  THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n//  THE SOFTWARE.\n\n#import <Foundation/Foundation.h>\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class YTKBaseRequest;\n@class AFSecurityPolicy;\n\ntypedef void (^AFURLSessionTaskDidFinishCollectingMetricsBlock)(NSURLSession *session, NSURLSessionTask *task, NSURLSessionTaskMetrics * metrics) API_AVAILABLE(ios(10), macosx(10.12), watchos(3), tvos(10));\n\n///  YTKUrlFilterProtocol can be used to append common parameters to requests before sending them.\n@protocol YTKUrlFilterProtocol <NSObject>\n///  Preprocess request URL before actually sending them.\n///\n///  @param originUrl request's origin URL, which is returned by `requestUrl`\n///  @param request   request itself\n///\n///  @return A new url which will be used as a new `requestUrl`\n- (NSString *)filterUrl:(NSString *)originUrl withRequest:(YTKBaseRequest *)request;\n@end\n\n///  YTKCacheDirPathFilterProtocol can be used to append common path components when caching response results\n@protocol YTKCacheDirPathFilterProtocol <NSObject>\n///  Preprocess cache path before actually saving them.\n///\n///  @param originPath original base cache path, which is generated in `YTKRequest` class.\n///  @param request    request itself\n///\n///  @return A new path which will be used as base path when caching.\n- (NSString *)filterCacheDirPath:(NSString *)originPath withRequest:(YTKBaseRequest *)request;\n@end\n\n///  YTKNetworkConfig stored global network-related configurations, which will be used in `YTKNetworkAgent`\n///  to form and filter requests, as well as caching response.\n@interface YTKNetworkConfig : NSObject\n\n- (instancetype)init NS_UNAVAILABLE;\n+ (instancetype)new NS_UNAVAILABLE;\n\n///  Return a shared config object.\n+ (YTKNetworkConfig *)sharedConfig;\n\n///  Request base URL, such as \"http://www.yuantiku.com\". Default is empty string.\n@property (nonatomic, strong) NSString *baseUrl;\n///  Request CDN URL. Default is empty string.\n@property (nonatomic, strong) NSString *cdnUrl;\n///  URL filters. See also `YTKUrlFilterProtocol`.\n@property (nonatomic, strong, readonly) NSArray<id<YTKUrlFilterProtocol>> *urlFilters;\n///  Cache path filters. See also `YTKCacheDirPathFilterProtocol`.\n@property (nonatomic, strong, readonly) NSArray<id<YTKCacheDirPathFilterProtocol>> *cacheDirPathFilters;\n///  Security policy will be used by AFNetworking. See also `AFSecurityPolicy`.\n@property (nonatomic, strong) AFSecurityPolicy *securityPolicy;\n///  Whether to log debug info. Default is NO;\n@property (nonatomic) BOOL debugLogEnabled;\n///  SessionConfiguration will be used to initialize AFHTTPSessionManager. Default is nil.\n@property (nonatomic, strong, nullable) NSURLSessionConfiguration* sessionConfiguration;\n///  NSURLSessionTaskMetrics\n@property (nonatomic, strong) AFURLSessionTaskDidFinishCollectingMetricsBlock collectingMetricsBlock API_AVAILABLE(ios(10), macosx(10.12), watchos(3), tvos(10));\n\n///  Add a new URL filter.\n- (void)addUrlFilter:(id<YTKUrlFilterProtocol>)filter;\n///  Remove all URL filters.\n- (void)clearUrlFilter;\n///  Add a new cache path filter\n- (void)addCacheDirPathFilter:(id<YTKCacheDirPathFilterProtocol>)filter;\n///  Clear all cache path filters.\n- (void)clearCacheDirPathFilter;\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "YTKNetwork/YTKNetworkConfig.m",
    "content": "//\n//  YTKNetworkConfig.m\n//\n//  Copyright (c) 2012-2016 YTKNetwork https://github.com/yuantiku\n//\n//  Permission is hereby granted, free of charge, to any person obtaining a copy\n//  of this software and associated documentation files (the \"Software\"), to deal\n//  in the Software without restriction, including without limitation the rights\n//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n//  copies of the Software, and to permit persons to whom the Software is\n//  furnished to do so, subject to the following conditions:\n//\n//  The above copyright notice and this permission notice shall be included in\n//  all copies or substantial portions of the Software.\n//\n//  THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n//  THE SOFTWARE.\n\n#import \"YTKNetworkConfig.h\"\n#import \"YTKBaseRequest.h\"\n\n#if __has_include(<AFNetworking/AFSecurityPolicy.h>)\n#import <AFNetworking/AFSecurityPolicy.h>\n#else\n#import <AFNetworking/AFSecurityPolicy.h>\n#endif\n\n@implementation YTKNetworkConfig {\n    NSMutableArray<id<YTKUrlFilterProtocol>> *_urlFilters;\n    NSMutableArray<id<YTKCacheDirPathFilterProtocol>> *_cacheDirPathFilters;\n}\n\n+ (YTKNetworkConfig *)sharedConfig {\n    static id sharedInstance = nil;\n    static dispatch_once_t onceToken;\n    dispatch_once(&onceToken, ^{\n        sharedInstance = [[self alloc] init];\n    });\n    return sharedInstance;\n}\n\n- (instancetype)init {\n    self = [super init];\n    if (self) {\n        _baseUrl = @\"\";\n        _cdnUrl = @\"\";\n        _urlFilters = [NSMutableArray array];\n        _cacheDirPathFilters = [NSMutableArray array];\n        _securityPolicy = [AFSecurityPolicy defaultPolicy];\n        _debugLogEnabled = NO;\n    }\n    return self;\n}\n\n- (void)addUrlFilter:(id<YTKUrlFilterProtocol>)filter {\n    [_urlFilters addObject:filter];\n}\n\n- (void)clearUrlFilter {\n    [_urlFilters removeAllObjects];\n}\n\n- (void)addCacheDirPathFilter:(id<YTKCacheDirPathFilterProtocol>)filter {\n    [_cacheDirPathFilters addObject:filter];\n}\n\n- (void)clearCacheDirPathFilter {\n    [_cacheDirPathFilters removeAllObjects];\n}\n\n- (NSArray<id<YTKUrlFilterProtocol>> *)urlFilters {\n    return [_urlFilters copy];\n}\n\n- (NSArray<id<YTKCacheDirPathFilterProtocol>> *)cacheDirPathFilters {\n    return [_cacheDirPathFilters copy];\n}\n\n#pragma mark - NSObject\n\n- (NSString *)description {\n    return [NSString stringWithFormat:@\"<%@: %p>{ baseURL: %@ } { cdnURL: %@ }\", NSStringFromClass([self class]), self, self.baseUrl, self.cdnUrl];\n}\n\n@end\n"
  },
  {
    "path": "YTKNetwork/YTKNetworkPrivate.h",
    "content": "//\n//  YTKNetworkPrivate.h\n//\n//  Copyright (c) 2012-2016 YTKNetwork https://github.com/yuantiku\n//\n//  Permission is hereby granted, free of charge, to any person obtaining a copy\n//  of this software and associated documentation files (the \"Software\"), to deal\n//  in the Software without restriction, including without limitation the rights\n//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n//  copies of the Software, and to permit persons to whom the Software is\n//  furnished to do so, subject to the following conditions:\n//\n//  The above copyright notice and this permission notice shall be included in\n//  all copies or substantial portions of the Software.\n//\n//  THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n//  THE SOFTWARE.\n\n#import <Foundation/Foundation.h>\n#import \"YTKRequest.h\"\n#import \"YTKBaseRequest.h\"\n#import \"YTKBatchRequest.h\"\n#import \"YTKChainRequest.h\"\n#import \"YTKNetworkAgent.h\"\n#import \"YTKNetworkConfig.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\nFOUNDATION_EXPORT void YTKLog(NSString *format, ...) NS_FORMAT_FUNCTION(1,2);\n\n@class AFHTTPSessionManager;\n\n@interface YTKNetworkUtils : NSObject\n\n+ (BOOL)validateJSON:(id)json withValidator:(id)jsonValidator;\n\n+ (void)addDoNotBackupAttribute:(NSString *)path;\n\n+ (NSString *)md5StringFromString:(NSString *)string;\n\n+ (NSString *)appVersionString;\n\n+ (NSStringEncoding)stringEncodingWithRequest:(YTKBaseRequest *)request;\n\n+ (BOOL)validateResumeData:(NSData *)data;\n\n@end\n\n@interface YTKRequest (Getter)\n\n- (NSString *)cacheBasePath;\n\n@end\n\n@interface YTKBaseRequest (Setter)\n\n@property (nonatomic, strong, readwrite) NSURLSessionTask *requestTask;\n@property (nonatomic, strong, readwrite, nullable) NSData *responseData;\n@property (nonatomic, strong, readwrite, nullable) id responseJSONObject;\n@property (nonatomic, strong, readwrite, nullable) id responseObject;\n@property (nonatomic, strong, readwrite, nullable) NSString *responseString;\n@property (nonatomic, strong, readwrite, nullable) NSError *error;\n\n@end\n\n@interface YTKBaseRequest (RequestAccessory)\n\n- (void)toggleAccessoriesWillStartCallBack;\n- (void)toggleAccessoriesWillStopCallBack;\n- (void)toggleAccessoriesDidStopCallBack;\n\n@end\n\n@interface YTKBatchRequest (RequestAccessory)\n\n- (void)toggleAccessoriesWillStartCallBack;\n- (void)toggleAccessoriesWillStopCallBack;\n- (void)toggleAccessoriesDidStopCallBack;\n\n@end\n\n@interface YTKChainRequest (RequestAccessory)\n\n- (void)toggleAccessoriesWillStartCallBack;\n- (void)toggleAccessoriesWillStopCallBack;\n- (void)toggleAccessoriesDidStopCallBack;\n\n@end\n\n@interface YTKNetworkAgent (Private)\n\n- (AFHTTPSessionManager *)manager;\n- (void)resetURLSessionManager;\n- (void)resetURLSessionManagerWithConfiguration:(NSURLSessionConfiguration *)configuration;\n\n- (NSString *)incompleteDownloadTempCacheFolder;\n\n@end\n\nNS_ASSUME_NONNULL_END\n\n"
  },
  {
    "path": "YTKNetwork/YTKNetworkPrivate.m",
    "content": "//\n//  YTKNetworkPrivate.m\n//\n//  Copyright (c) 2012-2016 YTKNetwork https://github.com/yuantiku\n//\n//  Permission is hereby granted, free of charge, to any person obtaining a copy\n//  of this software and associated documentation files (the \"Software\"), to deal\n//  in the Software without restriction, including without limitation the rights\n//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n//  copies of the Software, and to permit persons to whom the Software is\n//  furnished to do so, subject to the following conditions:\n//\n//  The above copyright notice and this permission notice shall be included in\n//  all copies or substantial portions of the Software.\n//\n//  THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n//  THE SOFTWARE.\n\n#import <CommonCrypto/CommonDigest.h>\n#import \"YTKNetworkPrivate.h\"\n\n#if __has_include(<AFNetworking/AFURLRequestSerialization.h>)\n#import <AFNetworking/AFURLRequestSerialization.h>\n#else\n#import <AFNetworking/AFURLRequestSerialization.h>\n#endif\n\nvoid YTKLog(NSString *format, ...) {\n#ifdef DEBUG\n    if (![YTKNetworkConfig sharedConfig].debugLogEnabled) {\n        return;\n    }\n    va_list argptr;\n    va_start(argptr, format);\n    NSLogv(format, argptr);\n    va_end(argptr);\n#endif\n}\n\n@implementation YTKNetworkUtils\n\n+ (BOOL)validateJSON:(id)json withValidator:(id)jsonValidator {\n    if ([json isKindOfClass:[NSDictionary class]] &&\n        [jsonValidator isKindOfClass:[NSDictionary class]]) {\n        NSDictionary * dict = json;\n        NSDictionary * validator = jsonValidator;\n        BOOL result = YES;\n        NSEnumerator * enumerator = [validator keyEnumerator];\n        NSString * key;\n        while ((key = [enumerator nextObject]) != nil) {\n            id value = dict[key];\n            id format = validator[key];\n            if ([value isKindOfClass:[NSDictionary class]]\n                || [value isKindOfClass:[NSArray class]]) {\n                result = [self validateJSON:value withValidator:format];\n                if (!result) {\n                    break;\n                }\n            } else {\n                if ([value isKindOfClass:format] == NO &&\n                    [value isKindOfClass:[NSNull class]] == NO) {\n                    result = NO;\n                    break;\n                }\n            }\n        }\n        return result;\n    } else if ([json isKindOfClass:[NSArray class]] &&\n               [jsonValidator isKindOfClass:[NSArray class]]) {\n        NSArray * validatorArray = (NSArray *)jsonValidator;\n        if (validatorArray.count > 0) {\n            NSArray * array = json;\n            NSDictionary * validator = jsonValidator[0];\n            for (id item in array) {\n                BOOL result = [self validateJSON:item withValidator:validator];\n                if (!result) {\n                    return NO;\n                }\n            }\n        }\n        return YES;\n    } else if ([json isKindOfClass:jsonValidator]) {\n        return YES;\n    } else {\n        return NO;\n    }\n}\n\n+ (void)addDoNotBackupAttribute:(NSString *)path {\n    NSURL *url = [NSURL fileURLWithPath:path];\n    NSError *error = nil;\n    [url setResourceValue:[NSNumber numberWithBool:YES] forKey:NSURLIsExcludedFromBackupKey error:&error];\n    if (error) {\n        YTKLog(@\"error to set do not backup attribute, error = %@\", error);\n    }\n}\n\n+ (NSString *)md5StringFromString:(NSString *)string {\n    NSParameterAssert(string != nil && [string length] > 0);\n\n    const char *value = [string UTF8String];\n\n    unsigned char outputBuffer[CC_MD5_DIGEST_LENGTH];\n    CC_MD5(value, (CC_LONG)strlen(value), outputBuffer);\n\n    NSMutableString *outputString = [[NSMutableString alloc] initWithCapacity:CC_MD5_DIGEST_LENGTH * 2];\n    for(NSInteger count = 0; count < CC_MD5_DIGEST_LENGTH; count++){\n        [outputString appendFormat:@\"%02x\", outputBuffer[count]];\n    }\n\n    return outputString;\n}\n\n+ (NSString *)appVersionString {\n    return [[[NSBundle mainBundle] infoDictionary] objectForKey:@\"CFBundleShortVersionString\"];\n}\n\n+ (NSStringEncoding)stringEncodingWithRequest:(YTKBaseRequest *)request {\n    // From AFNetworking 2.6.3\n    NSStringEncoding stringEncoding = NSUTF8StringEncoding;\n    NSString *encodingName = [request.response.textEncodingName copy];\n    if (encodingName) {\n        CFStringEncoding encoding = CFStringConvertIANACharSetNameToEncoding((CFStringRef)encodingName);\n        if (encoding != kCFStringEncodingInvalidId) {\n            stringEncoding = CFStringConvertEncodingToNSStringEncoding(encoding);\n        }\n    }\n    return stringEncoding;\n}\n\n+ (BOOL)validateResumeData:(NSData *)data {\n    // From http://stackoverflow.com/a/22137510/3562486\n    if (!data || [data length] < 1) return NO;\n\n    NSError *error;\n    NSDictionary *resumeDictionary = [NSPropertyListSerialization propertyListWithData:data options:NSPropertyListImmutable format:NULL error:&error];\n    if (!resumeDictionary || error) return NO;\n\n    // Before iOS 9 & Mac OS X 10.11\n#if (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED < 90000)\\\n|| (defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && __MAC_OS_X_VERSION_MAX_ALLOWED < 101100)\n    NSString *localFilePath = [resumeDictionary objectForKey:@\"NSURLSessionResumeInfoLocalPath\"];\n    if ([localFilePath length] < 1) return NO;\n    return [[NSFileManager defaultManager] fileExistsAtPath:localFilePath];\n#endif\n    // After iOS 9 we can not actually detects if the cache file exists. This plist file has a somehow\n    // complicated structure. Besides, the plist structure is different between iOS 9 and iOS 10.\n    // We can only assume that the plist being successfully parsed means the resume data is valid.\n    return YES;\n}\n\n@end\n\n@implementation YTKBaseRequest (RequestAccessory)\n\n- (void)toggleAccessoriesWillStartCallBack {\n    for (id<YTKRequestAccessory> accessory in self.requestAccessories) {\n        if ([accessory respondsToSelector:@selector(requestWillStart:)]) {\n            [accessory requestWillStart:self];\n        }\n    }\n}\n\n- (void)toggleAccessoriesWillStopCallBack {\n    for (id<YTKRequestAccessory> accessory in self.requestAccessories) {\n        if ([accessory respondsToSelector:@selector(requestWillStop:)]) {\n            [accessory requestWillStop:self];\n        }\n    }\n}\n\n- (void)toggleAccessoriesDidStopCallBack {\n    for (id<YTKRequestAccessory> accessory in self.requestAccessories) {\n        if ([accessory respondsToSelector:@selector(requestDidStop:)]) {\n            [accessory requestDidStop:self];\n        }\n    }\n}\n\n@end\n\n@implementation YTKBatchRequest (RequestAccessory)\n\n- (void)toggleAccessoriesWillStartCallBack {\n    for (id<YTKRequestAccessory> accessory in self.requestAccessories) {\n        if ([accessory respondsToSelector:@selector(requestWillStart:)]) {\n            [accessory requestWillStart:self];\n        }\n    }\n}\n\n- (void)toggleAccessoriesWillStopCallBack {\n    for (id<YTKRequestAccessory> accessory in self.requestAccessories) {\n        if ([accessory respondsToSelector:@selector(requestWillStop:)]) {\n            [accessory requestWillStop:self];\n        }\n    }\n}\n\n- (void)toggleAccessoriesDidStopCallBack {\n    for (id<YTKRequestAccessory> accessory in self.requestAccessories) {\n        if ([accessory respondsToSelector:@selector(requestDidStop:)]) {\n            [accessory requestDidStop:self];\n        }\n    }\n}\n\n@end\n\n@implementation YTKChainRequest (RequestAccessory)\n\n- (void)toggleAccessoriesWillStartCallBack {\n    for (id<YTKRequestAccessory> accessory in self.requestAccessories) {\n        if ([accessory respondsToSelector:@selector(requestWillStart:)]) {\n            [accessory requestWillStart:self];\n        }\n    }\n}\n\n- (void)toggleAccessoriesWillStopCallBack {\n    for (id<YTKRequestAccessory> accessory in self.requestAccessories) {\n        if ([accessory respondsToSelector:@selector(requestWillStop:)]) {\n            [accessory requestWillStop:self];\n        }\n    }\n}\n\n- (void)toggleAccessoriesDidStopCallBack {\n    for (id<YTKRequestAccessory> accessory in self.requestAccessories) {\n        if ([accessory respondsToSelector:@selector(requestDidStop:)]) {\n            [accessory requestDidStop:self];\n        }\n    }\n}\n\n@end\n"
  },
  {
    "path": "YTKNetwork/YTKRequest.h",
    "content": "//\n//  YTKRequest.h\n//\n//  Copyright (c) 2012-2016 YTKNetwork https://github.com/yuantiku\n//\n//  Permission is hereby granted, free of charge, to any person obtaining a copy\n//  of this software and associated documentation files (the \"Software\"), to deal\n//  in the Software without restriction, including without limitation the rights\n//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n//  copies of the Software, and to permit persons to whom the Software is\n//  furnished to do so, subject to the following conditions:\n//\n//  The above copyright notice and this permission notice shall be included in\n//  all copies or substantial portions of the Software.\n//\n//  THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n//  THE SOFTWARE.\n\n#import \"YTKBaseRequest.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\nFOUNDATION_EXPORT NSString *const YTKRequestCacheErrorDomain;\n\nNS_ENUM(NSInteger) {\n    YTKRequestCacheErrorExpired = -1,\n    YTKRequestCacheErrorVersionMismatch = -2,\n    YTKRequestCacheErrorSensitiveDataMismatch = -3,\n    YTKRequestCacheErrorAppVersionMismatch = -4,\n    YTKRequestCacheErrorInvalidCacheTime = -5,\n    YTKRequestCacheErrorInvalidMetadata = -6,\n    YTKRequestCacheErrorInvalidCacheData = -7,\n};\n\n///  YTKRequest is the base class you should inherit to create your own request class.\n///  Based on YTKBaseRequest, YTKRequest adds local caching feature. Note download\n///  request will not be cached whatsoever, because download request may involve complicated\n///  cache control policy controlled by `Cache-Control`, `Last-Modified`, etc.\n@interface YTKRequest : YTKBaseRequest\n\n///  Whether to use cache as response or not.\n///  Default is NO, which means caching will take effect with specific arguments.\n///  Note that `cacheTimeInSeconds` default is -1. As a result cache data is not actually\n///  used as response unless you return a positive value in `cacheTimeInSeconds`.\n///\n///  Also note that this option does not affect storing the response, which means response will always be saved\n///  even `ignoreCache` is YES.\n@property (nonatomic) BOOL ignoreCache;\n\n///  Whether data is from local cache.\n- (BOOL)isDataFromCache;\n\n///  Manually load cache from storage.\n///\n///  @param error If an error occurred causing cache loading failed, an error object will be passed, otherwise NULL.\n///\n///  @return Whether cache is successfully loaded.\n- (BOOL)loadCacheWithError:(NSError * __autoreleasing *)error;\n\n///  Start request without reading local cache even if it exists. Use this to update local cache.\n- (void)startWithoutCache;\n\n///  Save response data (probably from another request) to this request's cache location\n- (void)saveResponseDataToCacheFile:(NSData *)data;\n\n#pragma mark - Subclass Override\n\n///  The max time duration that cache can stay in disk until it's considered expired.\n///  Default is -1, which means response is not actually saved as cache.\n- (NSInteger)cacheTimeInSeconds;\n\n///  Version can be used to identify and invalidate local cache. Default is 0.\n- (long long)cacheVersion;\n\n///  This can be used as additional identifier that tells the cache needs updating.\n///\n///  @discussion The `description` string of this object will be used as an identifier to verify whether cache\n///              is invalid. Using `NSArray` or `NSDictionary` as return value type is recommended. However,\n///              If you intend to use your custom class type, make sure that `description` is correctly implemented.\n- (nullable id)cacheSensitiveData;\n\n///  Whether cache is asynchronously written to storage. Default is YES.\n- (BOOL)writeCacheAsynchronously;\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "YTKNetwork/YTKRequest.m",
    "content": "//\n//  YTKRequest.m\n//\n//  Copyright (c) 2012-2016 YTKNetwork https://github.com/yuantiku\n//\n//  Permission is hereby granted, free of charge, to any person obtaining a copy\n//  of this software and associated documentation files (the \"Software\"), to deal\n//  in the Software without restriction, including without limitation the rights\n//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n//  copies of the Software, and to permit persons to whom the Software is\n//  furnished to do so, subject to the following conditions:\n//\n//  The above copyright notice and this permission notice shall be included in\n//  all copies or substantial portions of the Software.\n//\n//  THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n//  THE SOFTWARE.\n\n#import \"YTKNetworkConfig.h\"\n#import \"YTKRequest.h\"\n#import \"YTKNetworkPrivate.h\"\n\n#ifndef NSFoundationVersionNumber_iOS_8_0\n#define NSFoundationVersionNumber_With_QoS_Available 1140.11\n#else\n#define NSFoundationVersionNumber_With_QoS_Available NSFoundationVersionNumber_iOS_8_0\n#endif\n\nNSString *const YTKRequestCacheErrorDomain = @\"com.yuantiku.request.caching\";\n\nstatic dispatch_queue_t ytkrequest_cache_writing_queue() {\n    static dispatch_queue_t queue;\n    static dispatch_once_t onceToken;\n    dispatch_once(&onceToken, ^{\n        dispatch_queue_attr_t attr = DISPATCH_QUEUE_SERIAL;\n        if (NSFoundationVersionNumber >= NSFoundationVersionNumber_With_QoS_Available) {\n            attr = dispatch_queue_attr_make_with_qos_class(attr, QOS_CLASS_BACKGROUND, 0);\n        }\n        queue = dispatch_queue_create(\"com.yuantiku.ytkrequest.caching\", attr);\n    });\n\n    return queue;\n}\n\n@interface YTKCacheMetadata : NSObject<NSSecureCoding>\n\n@property (nonatomic, assign) long long version;\n@property (nonatomic, strong) NSString *sensitiveDataString;\n@property (nonatomic, assign) NSStringEncoding stringEncoding;\n@property (nonatomic, strong) NSDate *creationDate;\n@property (nonatomic, strong) NSString *appVersionString;\n\n@end\n\n@implementation YTKCacheMetadata\n\n+ (BOOL)supportsSecureCoding {\n    return YES;\n}\n\n- (void)encodeWithCoder:(NSCoder *)aCoder {\n    [aCoder encodeObject:@(self.version) forKey:NSStringFromSelector(@selector(version))];\n    [aCoder encodeObject:self.sensitiveDataString forKey:NSStringFromSelector(@selector(sensitiveDataString))];\n    [aCoder encodeObject:@(self.stringEncoding) forKey:NSStringFromSelector(@selector(stringEncoding))];\n    [aCoder encodeObject:self.creationDate forKey:NSStringFromSelector(@selector(creationDate))];\n    [aCoder encodeObject:self.appVersionString forKey:NSStringFromSelector(@selector(appVersionString))];\n}\n\n- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder {\n    self = [self init];\n    if (!self) {\n        return nil;\n    }\n\n    self.version = [[aDecoder decodeObjectOfClass:[NSNumber class] forKey:NSStringFromSelector(@selector(version))] integerValue];\n    self.sensitiveDataString = [aDecoder decodeObjectOfClass:[NSString class] forKey:NSStringFromSelector(@selector(sensitiveDataString))];\n    self.stringEncoding = [[aDecoder decodeObjectOfClass:[NSNumber class] forKey:NSStringFromSelector(@selector(stringEncoding))] integerValue];\n    self.creationDate = [aDecoder decodeObjectOfClass:[NSDate class] forKey:NSStringFromSelector(@selector(creationDate))];\n    self.appVersionString = [aDecoder decodeObjectOfClass:[NSString class] forKey:NSStringFromSelector(@selector(appVersionString))];\n\n    return self;\n}\n\n@end\n\n@interface YTKRequest()\n\n@property (nonatomic, strong) NSData *cacheData;\n@property (nonatomic, strong) NSString *cacheString;\n@property (nonatomic, strong) id cacheJSON;\n@property (nonatomic, strong) NSXMLParser *cacheXML;\n\n@property (nonatomic, strong) YTKCacheMetadata *cacheMetadata;\n@property (nonatomic, assign) BOOL dataFromCache;\n\n@end\n\n@implementation YTKRequest\n\n- (void)start {\n    if (self.ignoreCache) {\n        [self startWithoutCache];\n        return;\n    }\n\n    // Do not cache download request.\n    if (self.resumableDownloadPath) {\n        [self startWithoutCache];\n        return;\n    }\n\n    if (![self loadCacheWithError:nil]) {\n        [self startWithoutCache];\n        return;\n    }\n\n    _dataFromCache = YES;\n\n    dispatch_async(dispatch_get_main_queue(), ^{\n        [self requestCompletePreprocessor];\n        [self requestCompleteFilter];\n        YTKRequest *strongSelf = self;\n        [strongSelf.delegate requestFinished:strongSelf];\n        if (strongSelf.successCompletionBlock) {\n            strongSelf.successCompletionBlock(strongSelf);\n        }\n        [strongSelf clearCompletionBlock];\n    });\n}\n\n- (void)startWithoutCache {\n    [self clearCacheVariables];\n    [super start];\n}\n\n#pragma mark - Network Request Delegate\n\n- (void)requestCompletePreprocessor {\n    [super requestCompletePreprocessor];\n\n    if (self.writeCacheAsynchronously) {\n        dispatch_async(ytkrequest_cache_writing_queue(), ^{\n            [self saveResponseDataToCacheFile:[super responseData]];\n        });\n    } else {\n        [self saveResponseDataToCacheFile:[super responseData]];\n    }\n}\n\n#pragma mark - Subclass Override\n\n- (NSInteger)cacheTimeInSeconds {\n    return -1;\n}\n\n- (long long)cacheVersion {\n    return 0;\n}\n\n- (id)cacheSensitiveData {\n    return nil;\n}\n\n- (BOOL)writeCacheAsynchronously {\n    return YES;\n}\n\n#pragma mark -\n\n- (BOOL)isDataFromCache {\n    return _dataFromCache;\n}\n\n- (NSData *)responseData {\n    if (_cacheData) {\n        return _cacheData;\n    }\n    return [super responseData];\n}\n\n- (NSString *)responseString {\n    if (_cacheString) {\n        return _cacheString;\n    }\n    return [super responseString];\n}\n\n- (id)responseJSONObject {\n    if (_cacheJSON) {\n        return _cacheJSON;\n    }\n    return [super responseJSONObject];\n}\n\n- (id)responseObject {\n    if (_cacheJSON) {\n        return _cacheJSON;\n    }\n    if (_cacheXML) {\n        return _cacheXML;\n    }\n    if (_cacheData) {\n        return _cacheData;\n    }\n    return [super responseObject];\n}\n\n#pragma mark -\n\n- (BOOL)loadCacheWithError:(NSError * _Nullable __autoreleasing *)error {\n    // Make sure cache time in valid.\n    if ([self cacheTimeInSeconds] < 0) {\n        if (error) {\n            *error = [NSError errorWithDomain:YTKRequestCacheErrorDomain code:YTKRequestCacheErrorInvalidCacheTime userInfo:@{ NSLocalizedDescriptionKey:@\"Invalid cache time\"}];\n        }\n        return NO;\n    }\n\n    // Try load metadata.\n    if (![self loadCacheMetadata]) {\n        if (error) {\n            *error = [NSError errorWithDomain:YTKRequestCacheErrorDomain code:YTKRequestCacheErrorInvalidMetadata userInfo:@{ NSLocalizedDescriptionKey:@\"Invalid metadata. Cache may not exist\"}];\n        }\n        return NO;\n    }\n\n    // Check if cache is still valid.\n    if (![self validateCacheWithError:error]) {\n        return NO;\n    }\n\n    // Try load cache.\n    if (![self loadCacheData]) {\n        if (error) {\n            *error = [NSError errorWithDomain:YTKRequestCacheErrorDomain code:YTKRequestCacheErrorInvalidCacheData userInfo:@{ NSLocalizedDescriptionKey:@\"Invalid cache data\"}];\n        }\n        return NO;\n    }\n\n    return YES;\n}\n\n- (BOOL)validateCacheWithError:(NSError * _Nullable __autoreleasing *)error {\n    // Date\n    NSDate *creationDate = self.cacheMetadata.creationDate;\n    NSTimeInterval duration = -[creationDate timeIntervalSinceNow];\n    if (duration < 0 || duration > [self cacheTimeInSeconds]) {\n        if (error) {\n            *error = [NSError errorWithDomain:YTKRequestCacheErrorDomain code:YTKRequestCacheErrorExpired userInfo:@{ NSLocalizedDescriptionKey:@\"Cache expired\"}];\n        }\n        return NO;\n    }\n    // Version\n    long long cacheVersionFileContent = self.cacheMetadata.version;\n    if (cacheVersionFileContent != [self cacheVersion]) {\n        if (error) {\n            *error = [NSError errorWithDomain:YTKRequestCacheErrorDomain code:YTKRequestCacheErrorVersionMismatch userInfo:@{ NSLocalizedDescriptionKey:@\"Cache version mismatch\"}];\n        }\n        return NO;\n    }\n    // Sensitive data\n    NSString *sensitiveDataString = self.cacheMetadata.sensitiveDataString;\n    NSString *currentSensitiveDataString = ((NSObject *)[self cacheSensitiveData]).description;\n    if (sensitiveDataString || currentSensitiveDataString) {\n        // If one of the strings is nil, short-circuit evaluation will trigger\n        if (sensitiveDataString.length != currentSensitiveDataString.length || ![sensitiveDataString isEqualToString:currentSensitiveDataString]) {\n            if (error) {\n                *error = [NSError errorWithDomain:YTKRequestCacheErrorDomain code:YTKRequestCacheErrorSensitiveDataMismatch userInfo:@{ NSLocalizedDescriptionKey:@\"Cache sensitive data mismatch\"}];\n            }\n            return NO;\n        }\n    }\n    // App version\n    NSString *appVersionString = self.cacheMetadata.appVersionString;\n    NSString *currentAppVersionString = [YTKNetworkUtils appVersionString];\n    if (appVersionString || currentAppVersionString) {\n        if (appVersionString.length != currentAppVersionString.length || ![appVersionString isEqualToString:currentAppVersionString]) {\n            if (error) {\n                *error = [NSError errorWithDomain:YTKRequestCacheErrorDomain code:YTKRequestCacheErrorAppVersionMismatch userInfo:@{ NSLocalizedDescriptionKey:@\"App version mismatch\"}];\n            }\n            return NO;\n        }\n    }\n    return YES;\n}\n\n- (BOOL)loadCacheMetadata {\n    NSString *path = [self cacheMetadataFilePath];\n    NSFileManager * fileManager = [NSFileManager defaultManager];\n    if ([fileManager fileExistsAtPath:path isDirectory:nil]) {\n        @try {\n            _cacheMetadata = [NSKeyedUnarchiver unarchiveObjectWithFile:path];\n            return YES;\n        } @catch (NSException *exception) {\n            YTKLog(@\"Load cache metadata failed, reason = %@\", exception.reason);\n            return NO;\n        }\n    }\n    return NO;\n}\n\n- (BOOL)loadCacheData {\n    NSString *path = [self cacheFilePath];\n    NSFileManager *fileManager = [NSFileManager defaultManager];\n    NSError *error = nil;\n\n    if ([fileManager fileExistsAtPath:path isDirectory:nil]) {\n        NSData *data = [NSData dataWithContentsOfFile:path];\n        _cacheData = data;\n        _cacheString = [[NSString alloc] initWithData:_cacheData encoding:self.cacheMetadata.stringEncoding];\n        switch (self.responseSerializerType) {\n            case YTKResponseSerializerTypeHTTP:\n                // Do nothing.\n                return YES;\n            case YTKResponseSerializerTypeJSON:\n                _cacheJSON = [NSJSONSerialization JSONObjectWithData:_cacheData options:(NSJSONReadingOptions)0 error:&error];\n                return error == nil;\n            case YTKResponseSerializerTypeXMLParser:\n                _cacheXML = [[NSXMLParser alloc] initWithData:_cacheData];\n                return YES;\n        }\n    }\n    return NO;\n}\n\n- (void)saveResponseDataToCacheFile:(NSData *)data {\n    if ([self cacheTimeInSeconds] > 0 && ![self isDataFromCache]) {\n        if (data != nil) {\n            @try {\n                // New data will always overwrite old data.\n                [data writeToFile:[self cacheFilePath] atomically:YES];\n\n                YTKCacheMetadata *metadata = [[YTKCacheMetadata alloc] init];\n                metadata.version = [self cacheVersion];\n                metadata.sensitiveDataString = ((NSObject *)[self cacheSensitiveData]).description;\n                metadata.stringEncoding = [YTKNetworkUtils stringEncodingWithRequest:self];\n                metadata.creationDate = [NSDate date];\n                metadata.appVersionString = [YTKNetworkUtils appVersionString];\n                [NSKeyedArchiver archiveRootObject:metadata toFile:[self cacheMetadataFilePath]];\n            } @catch (NSException *exception) {\n                YTKLog(@\"Save cache failed, reason = %@\", exception.reason);\n            }\n        }\n    }\n}\n\n- (void)clearCacheVariables {\n    _cacheData = nil;\n    _cacheXML = nil;\n    _cacheJSON = nil;\n    _cacheString = nil;\n    _cacheMetadata = nil;\n    _dataFromCache = NO;\n}\n\n#pragma mark -\n\n- (void)createDirectoryIfNeeded:(NSString *)path {\n    NSFileManager *fileManager = [NSFileManager defaultManager];\n    BOOL isDir;\n    if (![fileManager fileExistsAtPath:path isDirectory:&isDir]) {\n        [self createBaseDirectoryAtPath:path];\n    } else {\n        if (!isDir) {\n            NSError *error = nil;\n            [fileManager removeItemAtPath:path error:&error];\n            [self createBaseDirectoryAtPath:path];\n        }\n    }\n}\n\n- (void)createBaseDirectoryAtPath:(NSString *)path {\n    NSError *error = nil;\n    [[NSFileManager defaultManager] createDirectoryAtPath:path withIntermediateDirectories:YES\n                                               attributes:nil error:&error];\n    if (error) {\n        YTKLog(@\"create cache directory failed, error = %@\", error);\n    } else {\n        [YTKNetworkUtils addDoNotBackupAttribute:path];\n    }\n}\n\n- (NSString *)cacheBasePath {\n    NSString *pathOfLibrary = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) objectAtIndex:0];\n    NSString *path = [pathOfLibrary stringByAppendingPathComponent:@\"LazyRequestCache\"];\n\n    // Filter cache base path\n    NSArray<id<YTKCacheDirPathFilterProtocol>> *filters = [[YTKNetworkConfig sharedConfig] cacheDirPathFilters];\n    if (filters.count > 0) {\n        for (id<YTKCacheDirPathFilterProtocol> f in filters) {\n            path = [f filterCacheDirPath:path withRequest:self];\n        }\n    }\n\n    [self createDirectoryIfNeeded:path];\n    return path;\n}\n\n- (NSString *)cacheFileName {\n    NSString *requestUrl = [self requestUrl];\n    NSString *baseUrl = [YTKNetworkConfig sharedConfig].baseUrl;\n    id argument = [self cacheFileNameFilterForRequestArgument:[self requestArgument]];\n    NSString *requestInfo = [NSString stringWithFormat:@\"Method:%ld Host:%@ Url:%@ Argument:%@\",\n                             (long)[self requestMethod], baseUrl, requestUrl, argument];\n    NSString *cacheFileName = [YTKNetworkUtils md5StringFromString:requestInfo];\n    return cacheFileName;\n}\n\n- (NSString *)cacheFilePath {\n    NSString *cacheFileName = [self cacheFileName];\n    NSString *path = [self cacheBasePath];\n    path = [path stringByAppendingPathComponent:cacheFileName];\n    return path;\n}\n\n- (NSString *)cacheMetadataFilePath {\n    NSString *cacheMetadataFileName = [NSString stringWithFormat:@\"%@.metadata\", [self cacheFileName]];\n    NSString *path = [self cacheBasePath];\n    path = [path stringByAppendingPathComponent:cacheMetadataFileName];\n    return path;\n}\n\n@end\n"
  },
  {
    "path": "YTKNetwork/YTKRequestEventAccessory.h",
    "content": "//\n//  YTKRequestEventAccessory.h\n//  YTKNetwork\n//\n//  Created by Chuanren Shang on 2020/8/17.\n//\n\n#import \"YTKBaseRequest.h\"\n#import \"YTKBatchRequest.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface YTKRequestEventAccessory : NSObject <YTKRequestAccessory>\n\n@property (nonatomic, copy, nullable) void (^willStartBlock)(id);\n@property (nonatomic, copy, nullable) void (^willStopBlock)(id);\n@property (nonatomic, copy, nullable) void (^didStopBlock)(id);\n\n@end\n\n@interface YTKBaseRequest (YTKRequestEventAccessory)\n\n- (void)startWithWillStart:(nullable YTKRequestCompletionBlock)willStart\n                  willStop:(nullable YTKRequestCompletionBlock)willStop\n                   success:(nullable YTKRequestCompletionBlock)success\n                   failure:(nullable YTKRequestCompletionBlock)failure\n                   didStop:(nullable YTKRequestCompletionBlock)didStop;\n\n@end\n\n@interface YTKBatchRequest (YTKRequestEventAccessory)\n\n- (void)startWithWillStart:(nullable void (^)(YTKBatchRequest *batchRequest))willStart\n                  willStop:(nullable void (^)(YTKBatchRequest *batchRequest))willStop\n                   success:(nullable void (^)(YTKBatchRequest *batchRequest))success\n                   failure:(nullable void (^)(YTKBatchRequest *batchRequest))failure\n                   didStop:(nullable void (^)(YTKBatchRequest *batchRequest))didStop;\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "YTKNetwork/YTKRequestEventAccessory.m",
    "content": "//\n//  YTKRequestEventAccessory.m\n//  YTKNetwork\n//\n//  Created by Chuanren Shang on 2020/8/17.\n//\n\n#import \"YTKRequestEventAccessory.h\"\n\n@implementation YTKRequestEventAccessory\n\n- (void)requestWillStart:(id)request {\n    if (self.willStartBlock != nil) {\n        self.willStartBlock(request);\n        self.willStartBlock = nil;\n    }\n}\n\n- (void)requestWillStop:(id)request {\n    if (self.willStopBlock != nil) {\n        self.willStopBlock(request);\n        self.willStopBlock = nil;\n    }\n}\n\n- (void)requestDidStop:(id)request {\n    if (self.didStopBlock != nil) {\n        self.didStopBlock(request);\n        self.didStopBlock = nil;\n    }\n}\n\n@end\n\n@implementation YTKBaseRequest (YTKRequestEventAccessory)\n\n- (void)startWithWillStart:(nullable YTKRequestCompletionBlock)willStart\n                  willStop:(nullable YTKRequestCompletionBlock)willStop\n                   success:(nullable YTKRequestCompletionBlock)success\n                   failure:(nullable YTKRequestCompletionBlock)failure\n                   didStop:(nullable YTKRequestCompletionBlock)didStop {\n    YTKRequestEventAccessory *accessory = [YTKRequestEventAccessory new];\n    accessory.willStartBlock = willStart;\n    accessory.willStopBlock = willStop;\n    accessory.didStopBlock = didStop;\n    [self addAccessory:accessory];\n    [self startWithCompletionBlockWithSuccess:success\n                                      failure:failure];\n}\n\n@end\n\n@implementation YTKBatchRequest (YTKRequestEventAccessory)\n\n- (void)startWithWillStart:(nullable void (^)(YTKBatchRequest *batchRequest))willStart\n                  willStop:(nullable void (^)(YTKBatchRequest *batchRequest))willStop\n                   success:(nullable void (^)(YTKBatchRequest *batchRequest))success\n                   failure:(nullable void (^)(YTKBatchRequest *batchRequest))failure\n                   didStop:(nullable void (^)(YTKBatchRequest *batchRequest))didStop {\n    YTKRequestEventAccessory *accessory = [YTKRequestEventAccessory new];\n    accessory.willStartBlock = willStart;\n    accessory.willStopBlock = willStop;\n    accessory.didStopBlock = didStop;\n    [self addAccessory:accessory];\n    [self startWithCompletionBlockWithSuccess:success\n                                      failure:failure];\n}\n\n@end\n"
  },
  {
    "path": "YTKNetwork.podspec",
    "content": "Pod::Spec.new do |s|\n\n  s.name         = \"YTKNetwork\"\n  s.version      = \"3.0.6\"\n  s.summary      = \"YTKNetwork is a high level request util based on AFNetworking.\"\n  s.homepage     = \"https://github.com/yuantiku/YTKNetwork\"\n  s.license      = \"MIT\"\n  s.author       = {\n                    \"tangqiao\" => \"tangqiao@fenbi.com\",\n                    \"lancy\" => \"lancy@fenbi.com\",\n                    \"maojj\" => \"maojj@fenbi.com\",\n                    \"liujl\" => \"liujl@fenbi.com\",\n                    \"shangcr\" => \"shangcr@fenbi.com\"\n }\n  s.source        = { :git => \"https://github.com/yuantiku/YTKNetwork.git\", :tag => s.version.to_s }\n  s.source_files  = \"YTKNetwork/*.{h,m}\"\n  s.requires_arc  = true\n\n  s.private_header_files = \"YTKNetwork/YTKNetworkPrivate.h\"\n\n  s.ios.deployment_target = \"9.0\"\n  s.osx.deployment_target = \"10.10\"\n  s.watchos.deployment_target = \"2.0\"\n  s.tvos.deployment_target = \"9.0\"\n  s.framework = \"CFNetwork\"\n\n  s.dependency \"AFNetworking/NSURLSession\", \"~> 4.0\"\nend\n"
  },
  {
    "path": "YTKNetwork.xcodeproj/project.pbxproj",
    "content": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 46;\n\tobjects = {\n\n/* Begin PBXBuildFile section */\n\t\t2D244E0D1D4ED6470031202D /* YTKNetwork.h in Headers */ = {isa = PBXBuildFile; fileRef = 2D244E0C1D4ED6470031202D /* YTKNetwork.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t2D244E141D4ED6470031202D /* YTKNetwork.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2D244E091D4ED6470031202D /* YTKNetwork.framework */; };\n\t\t2D244E361D4ED7910031202D /* YTKBaseRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = 2D244E241D4ED7910031202D /* YTKBaseRequest.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t2D244E371D4ED7910031202D /* YTKBaseRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 2D244E251D4ED7910031202D /* YTKBaseRequest.m */; };\n\t\t2D244E381D4ED7910031202D /* YTKBatchRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = 2D244E261D4ED7910031202D /* YTKBatchRequest.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t2D244E391D4ED7910031202D /* YTKBatchRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 2D244E271D4ED7910031202D /* YTKBatchRequest.m */; };\n\t\t2D244E3A1D4ED7910031202D /* YTKBatchRequestAgent.h in Headers */ = {isa = PBXBuildFile; fileRef = 2D244E281D4ED7910031202D /* YTKBatchRequestAgent.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t2D244E3B1D4ED7910031202D /* YTKBatchRequestAgent.m in Sources */ = {isa = PBXBuildFile; fileRef = 2D244E291D4ED7910031202D /* YTKBatchRequestAgent.m */; };\n\t\t2D244E3C1D4ED7910031202D /* YTKChainRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = 2D244E2A1D4ED7910031202D /* YTKChainRequest.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t2D244E3D1D4ED7910031202D /* YTKChainRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 2D244E2B1D4ED7910031202D /* YTKChainRequest.m */; };\n\t\t2D244E3E1D4ED7910031202D /* YTKChainRequestAgent.h in Headers */ = {isa = PBXBuildFile; fileRef = 2D244E2C1D4ED7910031202D /* YTKChainRequestAgent.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t2D244E3F1D4ED7910031202D /* YTKChainRequestAgent.m in Sources */ = {isa = PBXBuildFile; fileRef = 2D244E2D1D4ED7910031202D /* YTKChainRequestAgent.m */; };\n\t\t2D244E401D4ED7910031202D /* YTKNetworkAgent.h in Headers */ = {isa = PBXBuildFile; fileRef = 2D244E2E1D4ED7910031202D /* YTKNetworkAgent.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t2D244E411D4ED7910031202D /* YTKNetworkAgent.m in Sources */ = {isa = PBXBuildFile; fileRef = 2D244E2F1D4ED7910031202D /* YTKNetworkAgent.m */; };\n\t\t2D244E421D4ED7910031202D /* YTKNetworkConfig.h in Headers */ = {isa = PBXBuildFile; fileRef = 2D244E301D4ED7910031202D /* YTKNetworkConfig.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t2D244E431D4ED7910031202D /* YTKNetworkConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = 2D244E311D4ED7910031202D /* YTKNetworkConfig.m */; };\n\t\t2D244E441D4ED7910031202D /* YTKNetworkPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 2D244E321D4ED7910031202D /* YTKNetworkPrivate.h */; settings = {ATTRIBUTES = (Private, ); }; };\n\t\t2D244E451D4ED7910031202D /* YTKNetworkPrivate.m in Sources */ = {isa = PBXBuildFile; fileRef = 2D244E331D4ED7910031202D /* YTKNetworkPrivate.m */; };\n\t\t2D244E461D4ED7910031202D /* YTKRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = 2D244E341D4ED7910031202D /* YTKRequest.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t2D244E471D4ED7920031202D /* YTKRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 2D244E351D4ED7910031202D /* YTKRequest.m */; };\n\t\t2D244E631D4EDC7E0031202D /* AFNetworking.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2D244E621D4EDC7E0031202D /* AFNetworking.framework */; };\n\t\t2D244E641D4EDCCA0031202D /* AFNetworking.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2D244E621D4EDC7E0031202D /* AFNetworking.framework */; };\n\t\t2D58ADB71D59910500FA6347 /* YTKBaseRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 2D244E251D4ED7910031202D /* YTKBaseRequest.m */; };\n\t\t2D58ADB81D59910500FA6347 /* YTKBatchRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 2D244E271D4ED7910031202D /* YTKBatchRequest.m */; };\n\t\t2D58ADB91D59910500FA6347 /* YTKBatchRequestAgent.m in Sources */ = {isa = PBXBuildFile; fileRef = 2D244E291D4ED7910031202D /* YTKBatchRequestAgent.m */; };\n\t\t2D58ADBA1D59910500FA6347 /* YTKChainRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 2D244E2B1D4ED7910031202D /* YTKChainRequest.m */; };\n\t\t2D58ADBB1D59910500FA6347 /* YTKChainRequestAgent.m in Sources */ = {isa = PBXBuildFile; fileRef = 2D244E2D1D4ED7910031202D /* YTKChainRequestAgent.m */; };\n\t\t2D58ADBC1D59910500FA6347 /* YTKNetworkAgent.m in Sources */ = {isa = PBXBuildFile; fileRef = 2D244E2F1D4ED7910031202D /* YTKNetworkAgent.m */; };\n\t\t2D58ADBD1D59910500FA6347 /* YTKNetworkConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = 2D244E311D4ED7910031202D /* YTKNetworkConfig.m */; };\n\t\t2D58ADBE1D59910500FA6347 /* YTKNetworkPrivate.m in Sources */ = {isa = PBXBuildFile; fileRef = 2D244E331D4ED7910031202D /* YTKNetworkPrivate.m */; };\n\t\t2D58ADBF1D59910500FA6347 /* YTKRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 2D244E351D4ED7910031202D /* YTKRequest.m */; };\n\t\t2D58ADC01D59912700FA6347 /* YTKBaseRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = 2D244E241D4ED7910031202D /* YTKBaseRequest.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t2D58ADC11D59912700FA6347 /* YTKBatchRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = 2D244E261D4ED7910031202D /* YTKBatchRequest.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t2D58ADC21D59912700FA6347 /* YTKBatchRequestAgent.h in Headers */ = {isa = PBXBuildFile; fileRef = 2D244E281D4ED7910031202D /* YTKBatchRequestAgent.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t2D58ADC31D59912700FA6347 /* YTKChainRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = 2D244E2A1D4ED7910031202D /* YTKChainRequest.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t2D58ADC41D59912700FA6347 /* YTKChainRequestAgent.h in Headers */ = {isa = PBXBuildFile; fileRef = 2D244E2C1D4ED7910031202D /* YTKChainRequestAgent.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t2D58ADC51D59912700FA6347 /* YTKNetworkAgent.h in Headers */ = {isa = PBXBuildFile; fileRef = 2D244E2E1D4ED7910031202D /* YTKNetworkAgent.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t2D58ADC61D59912700FA6347 /* YTKNetworkConfig.h in Headers */ = {isa = PBXBuildFile; fileRef = 2D244E301D4ED7910031202D /* YTKNetworkConfig.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t2D58ADC71D59912700FA6347 /* YTKNetworkPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 2D244E321D4ED7910031202D /* YTKNetworkPrivate.h */; settings = {ATTRIBUTES = (Private, ); }; };\n\t\t2D58ADC81D59912700FA6347 /* YTKRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = 2D244E341D4ED7910031202D /* YTKRequest.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t2D58ADC91D59912700FA6347 /* YTKNetwork.h in Headers */ = {isa = PBXBuildFile; fileRef = 2D244E0C1D4ED6470031202D /* YTKNetwork.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t2D58ADCC1D59967D00FA6347 /* AFNetworking.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2D58ADCA1D5993FB00FA6347 /* AFNetworking.framework */; };\n\t\t2D58ADDC1D59973D00FA6347 /* YTKNetwork.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2D58ADD21D59973D00FA6347 /* YTKNetwork.framework */; };\n\t\t2D58ADE91D5997D300FA6347 /* YTKBaseRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 2D244E251D4ED7910031202D /* YTKBaseRequest.m */; };\n\t\t2D58ADEA1D5997D300FA6347 /* YTKBatchRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 2D244E271D4ED7910031202D /* YTKBatchRequest.m */; };\n\t\t2D58ADEB1D5997D300FA6347 /* YTKBatchRequestAgent.m in Sources */ = {isa = PBXBuildFile; fileRef = 2D244E291D4ED7910031202D /* YTKBatchRequestAgent.m */; };\n\t\t2D58ADEC1D5997D300FA6347 /* YTKChainRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 2D244E2B1D4ED7910031202D /* YTKChainRequest.m */; };\n\t\t2D58ADED1D5997D300FA6347 /* YTKChainRequestAgent.m in Sources */ = {isa = PBXBuildFile; fileRef = 2D244E2D1D4ED7910031202D /* YTKChainRequestAgent.m */; };\n\t\t2D58ADEE1D5997D300FA6347 /* YTKNetworkAgent.m in Sources */ = {isa = PBXBuildFile; fileRef = 2D244E2F1D4ED7910031202D /* YTKNetworkAgent.m */; };\n\t\t2D58ADEF1D5997D300FA6347 /* YTKNetworkConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = 2D244E311D4ED7910031202D /* YTKNetworkConfig.m */; };\n\t\t2D58ADF01D5997D300FA6347 /* YTKNetworkPrivate.m in Sources */ = {isa = PBXBuildFile; fileRef = 2D244E331D4ED7910031202D /* YTKNetworkPrivate.m */; };\n\t\t2D58ADF11D5997D300FA6347 /* YTKRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 2D244E351D4ED7910031202D /* YTKRequest.m */; };\n\t\t2D58ADF41D59980C00FA6347 /* AFNetworking.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2D58ADF21D5997F600FA6347 /* AFNetworking.framework */; };\n\t\t2D58ADF51D59986500FA6347 /* YTKBaseRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = 2D244E241D4ED7910031202D /* YTKBaseRequest.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t2D58ADF61D59986500FA6347 /* YTKBatchRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = 2D244E261D4ED7910031202D /* YTKBatchRequest.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t2D58ADF71D59986500FA6347 /* YTKChainRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = 2D244E2A1D4ED7910031202D /* YTKChainRequest.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t2D58ADF81D59986500FA6347 /* YTKNetworkConfig.h in Headers */ = {isa = PBXBuildFile; fileRef = 2D244E301D4ED7910031202D /* YTKNetworkConfig.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t2D58ADF91D59986500FA6347 /* YTKRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = 2D244E341D4ED7910031202D /* YTKRequest.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t2D58ADFA1D59986500FA6347 /* YTKNetwork.h in Headers */ = {isa = PBXBuildFile; fileRef = 2D244E0C1D4ED6470031202D /* YTKNetwork.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t2D58ADFB1D59987400FA6347 /* YTKBatchRequestAgent.h in Headers */ = {isa = PBXBuildFile; fileRef = 2D244E281D4ED7910031202D /* YTKBatchRequestAgent.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t2D58ADFC1D59987400FA6347 /* YTKChainRequestAgent.h in Headers */ = {isa = PBXBuildFile; fileRef = 2D244E2C1D4ED7910031202D /* YTKChainRequestAgent.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t2D58ADFD1D59987400FA6347 /* YTKNetworkAgent.h in Headers */ = {isa = PBXBuildFile; fileRef = 2D244E2E1D4ED7910031202D /* YTKNetworkAgent.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t2D58ADFE1D59987400FA6347 /* YTKNetworkPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 2D244E321D4ED7910031202D /* YTKNetworkPrivate.h */; settings = {ATTRIBUTES = (Private, ); }; };\n\t\t2D58AE0D1D5999CE00FA6347 /* AFNetworking.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2D58ADF21D5997F600FA6347 /* AFNetworking.framework */; };\n\t\t2D58AE0F1D5999F700FA6347 /* AFNetworking.framework in Copy Framework */ = {isa = PBXBuildFile; fileRef = 2D58ADF21D5997F600FA6347 /* AFNetworking.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };\n\t\t2D6B77451D599C6F000C3BF2 /* AFNetworking.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2DC79A851D599B9600197527 /* AFNetworking.framework */; };\n\t\t2D6B77471D599C83000C3BF2 /* AFNetworking.framework in Copy Framework */ = {isa = PBXBuildFile; fileRef = 2DC79A851D599B9600197527 /* AFNetworking.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };\n\t\t2DC79A6E1D599B0F00197527 /* YTKNetwork.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2DC79A651D599B0F00197527 /* YTKNetwork.framework */; };\n\t\t2DC79A7C1D599B6B00197527 /* YTKBaseRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 2D244E251D4ED7910031202D /* YTKBaseRequest.m */; };\n\t\t2DC79A7D1D599B6B00197527 /* YTKBatchRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 2D244E271D4ED7910031202D /* YTKBatchRequest.m */; };\n\t\t2DC79A7E1D599B6B00197527 /* YTKBatchRequestAgent.m in Sources */ = {isa = PBXBuildFile; fileRef = 2D244E291D4ED7910031202D /* YTKBatchRequestAgent.m */; };\n\t\t2DC79A7F1D599B6B00197527 /* YTKChainRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 2D244E2B1D4ED7910031202D /* YTKChainRequest.m */; };\n\t\t2DC79A801D599B6B00197527 /* YTKChainRequestAgent.m in Sources */ = {isa = PBXBuildFile; fileRef = 2D244E2D1D4ED7910031202D /* YTKChainRequestAgent.m */; };\n\t\t2DC79A811D599B6B00197527 /* YTKNetworkAgent.m in Sources */ = {isa = PBXBuildFile; fileRef = 2D244E2F1D4ED7910031202D /* YTKNetworkAgent.m */; };\n\t\t2DC79A821D599B6B00197527 /* YTKNetworkConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = 2D244E311D4ED7910031202D /* YTKNetworkConfig.m */; };\n\t\t2DC79A831D599B6B00197527 /* YTKNetworkPrivate.m in Sources */ = {isa = PBXBuildFile; fileRef = 2D244E331D4ED7910031202D /* YTKNetworkPrivate.m */; };\n\t\t2DC79A841D599B6B00197527 /* YTKRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 2D244E351D4ED7910031202D /* YTKRequest.m */; };\n\t\t2DC79A871D599BAB00197527 /* AFNetworking.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2DC79A851D599B9600197527 /* AFNetworking.framework */; };\n\t\t2DC79A881D599C1C00197527 /* YTKBaseRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = 2D244E241D4ED7910031202D /* YTKBaseRequest.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t2DC79A891D599C1C00197527 /* YTKBatchRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = 2D244E261D4ED7910031202D /* YTKBatchRequest.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t2DC79A8A1D599C1C00197527 /* YTKBatchRequestAgent.h in Headers */ = {isa = PBXBuildFile; fileRef = 2D244E281D4ED7910031202D /* YTKBatchRequestAgent.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t2DC79A8B1D599C1C00197527 /* YTKChainRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = 2D244E2A1D4ED7910031202D /* YTKChainRequest.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t2DC79A8C1D599C1C00197527 /* YTKChainRequestAgent.h in Headers */ = {isa = PBXBuildFile; fileRef = 2D244E2C1D4ED7910031202D /* YTKChainRequestAgent.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t2DC79A8D1D599C1C00197527 /* YTKNetworkAgent.h in Headers */ = {isa = PBXBuildFile; fileRef = 2D244E2E1D4ED7910031202D /* YTKNetworkAgent.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t2DC79A8E1D599C1C00197527 /* YTKNetworkConfig.h in Headers */ = {isa = PBXBuildFile; fileRef = 2D244E301D4ED7910031202D /* YTKNetworkConfig.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t2DC79A8F1D599C1C00197527 /* YTKNetworkPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 2D244E321D4ED7910031202D /* YTKNetworkPrivate.h */; settings = {ATTRIBUTES = (Private, ); }; };\n\t\t2DC79A901D599C1C00197527 /* YTKRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = 2D244E341D4ED7910031202D /* YTKRequest.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t2DC79A911D599C1C00197527 /* YTKNetwork.h in Headers */ = {isa = PBXBuildFile; fileRef = 2D244E0C1D4ED6470031202D /* YTKNetwork.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t2DCFCBF71D4EE10D002CAC24 /* AFNetworking.framework in Copy Framework */ = {isa = PBXBuildFile; fileRef = 2D244E621D4EDC7E0031202D /* AFNetworking.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };\n\t\t2DDCF9C41DA7B71600F5793B /* YTKCacheTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 2DDCF9BA1DA7B71600F5793B /* YTKCacheTests.m */; };\n\t\t2DDCF9C51DA7B71600F5793B /* YTKCacheTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 2DDCF9BA1DA7B71600F5793B /* YTKCacheTests.m */; };\n\t\t2DDCF9C61DA7B71600F5793B /* YTKCacheTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 2DDCF9BA1DA7B71600F5793B /* YTKCacheTests.m */; };\n\t\t2DDCF9C71DA7B71600F5793B /* YTKConcurrencyTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 2DDCF9BB1DA7B71600F5793B /* YTKConcurrencyTests.m */; };\n\t\t2DDCF9C81DA7B71600F5793B /* YTKConcurrencyTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 2DDCF9BB1DA7B71600F5793B /* YTKConcurrencyTests.m */; };\n\t\t2DDCF9C91DA7B71600F5793B /* YTKConcurrencyTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 2DDCF9BB1DA7B71600F5793B /* YTKConcurrencyTests.m */; };\n\t\t2DDCF9CA1DA7B71600F5793B /* YTKJSONValidatorTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 2DDCF9BC1DA7B71600F5793B /* YTKJSONValidatorTests.m */; };\n\t\t2DDCF9CB1DA7B71600F5793B /* YTKJSONValidatorTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 2DDCF9BC1DA7B71600F5793B /* YTKJSONValidatorTests.m */; };\n\t\t2DDCF9CC1DA7B71600F5793B /* YTKJSONValidatorTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 2DDCF9BC1DA7B71600F5793B /* YTKJSONValidatorTests.m */; };\n\t\t2DDCF9D01DA7B71600F5793B /* YTKNetworkRequestTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 2DDCF9BE1DA7B71600F5793B /* YTKNetworkRequestTests.m */; };\n\t\t2DDCF9D11DA7B71600F5793B /* YTKNetworkRequestTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 2DDCF9BE1DA7B71600F5793B /* YTKNetworkRequestTests.m */; };\n\t\t2DDCF9D21DA7B71600F5793B /* YTKNetworkRequestTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 2DDCF9BE1DA7B71600F5793B /* YTKNetworkRequestTests.m */; };\n\t\t2DDCF9D31DA7B71600F5793B /* YTKPerformanceTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 2DDCF9BF1DA7B71600F5793B /* YTKPerformanceTests.m */; };\n\t\t2DDCF9D41DA7B71600F5793B /* YTKPerformanceTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 2DDCF9BF1DA7B71600F5793B /* YTKPerformanceTests.m */; };\n\t\t2DDCF9D51DA7B71600F5793B /* YTKPerformanceTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 2DDCF9BF1DA7B71600F5793B /* YTKPerformanceTests.m */; };\n\t\t2DDCF9D61DA7B71600F5793B /* YTKRequestFilterTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 2DDCF9C01DA7B71600F5793B /* YTKRequestFilterTests.m */; };\n\t\t2DDCF9D71DA7B71600F5793B /* YTKRequestFilterTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 2DDCF9C01DA7B71600F5793B /* YTKRequestFilterTests.m */; };\n\t\t2DDCF9D81DA7B71600F5793B /* YTKRequestFilterTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 2DDCF9C01DA7B71600F5793B /* YTKRequestFilterTests.m */; };\n\t\t2DDCF9D91DA7B71600F5793B /* YTKResumableDownloadTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 2DDCF9C11DA7B71600F5793B /* YTKResumableDownloadTests.m */; };\n\t\t2DDCF9DA1DA7B71600F5793B /* YTKResumableDownloadTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 2DDCF9C11DA7B71600F5793B /* YTKResumableDownloadTests.m */; };\n\t\t2DDCF9DB1DA7B71600F5793B /* YTKResumableDownloadTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 2DDCF9C11DA7B71600F5793B /* YTKResumableDownloadTests.m */; };\n\t\t2DDCF9DC1DA7B71600F5793B /* YTKTestCase.m in Sources */ = {isa = PBXBuildFile; fileRef = 2DDCF9C31DA7B71600F5793B /* YTKTestCase.m */; };\n\t\t2DDCF9DD1DA7B71600F5793B /* YTKTestCase.m in Sources */ = {isa = PBXBuildFile; fileRef = 2DDCF9C31DA7B71600F5793B /* YTKTestCase.m */; };\n\t\t2DDCF9DE1DA7B71600F5793B /* YTKTestCase.m in Sources */ = {isa = PBXBuildFile; fileRef = 2DDCF9C31DA7B71600F5793B /* YTKTestCase.m */; };\n\t\t2DDCF9E31DA7B72B00F5793B /* YTKBasicCacheDirFilter.m in Sources */ = {isa = PBXBuildFile; fileRef = 2DDCF9E01DA7B72B00F5793B /* YTKBasicCacheDirFilter.m */; };\n\t\t2DDCF9E41DA7B72B00F5793B /* YTKBasicCacheDirFilter.m in Sources */ = {isa = PBXBuildFile; fileRef = 2DDCF9E01DA7B72B00F5793B /* YTKBasicCacheDirFilter.m */; };\n\t\t2DDCF9E51DA7B72B00F5793B /* YTKBasicCacheDirFilter.m in Sources */ = {isa = PBXBuildFile; fileRef = 2DDCF9E01DA7B72B00F5793B /* YTKBasicCacheDirFilter.m */; };\n\t\t2DDCF9E61DA7B72B00F5793B /* YTKBasicUrlFilter.m in Sources */ = {isa = PBXBuildFile; fileRef = 2DDCF9E21DA7B72B00F5793B /* YTKBasicUrlFilter.m */; };\n\t\t2DDCF9E71DA7B72B00F5793B /* YTKBasicUrlFilter.m in Sources */ = {isa = PBXBuildFile; fileRef = 2DDCF9E21DA7B72B00F5793B /* YTKBasicUrlFilter.m */; };\n\t\t2DDCF9E81DA7B72B00F5793B /* YTKBasicUrlFilter.m in Sources */ = {isa = PBXBuildFile; fileRef = 2DDCF9E21DA7B72B00F5793B /* YTKBasicUrlFilter.m */; };\n\t\t2DDCF9FB1DA7B73B00F5793B /* YTKBasicAuthRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 2DDCF9EA1DA7B73B00F5793B /* YTKBasicAuthRequest.m */; };\n\t\t2DDCF9FC1DA7B73B00F5793B /* YTKBasicAuthRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 2DDCF9EA1DA7B73B00F5793B /* YTKBasicAuthRequest.m */; };\n\t\t2DDCF9FD1DA7B73B00F5793B /* YTKBasicAuthRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 2DDCF9EA1DA7B73B00F5793B /* YTKBasicAuthRequest.m */; };\n\t\t2DDCF9FE1DA7B73B00F5793B /* YTKBasicHTTPRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 2DDCF9EC1DA7B73B00F5793B /* YTKBasicHTTPRequest.m */; };\n\t\t2DDCF9FF1DA7B73B00F5793B /* YTKBasicHTTPRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 2DDCF9EC1DA7B73B00F5793B /* YTKBasicHTTPRequest.m */; };\n\t\t2DDCFA001DA7B73B00F5793B /* YTKBasicHTTPRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 2DDCF9EC1DA7B73B00F5793B /* YTKBasicHTTPRequest.m */; };\n\t\t2DDCFA011DA7B73B00F5793B /* YTKCustomCacheRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 2DDCF9EE1DA7B73B00F5793B /* YTKCustomCacheRequest.m */; };\n\t\t2DDCFA021DA7B73B00F5793B /* YTKCustomCacheRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 2DDCF9EE1DA7B73B00F5793B /* YTKCustomCacheRequest.m */; };\n\t\t2DDCFA031DA7B73B00F5793B /* YTKCustomCacheRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 2DDCF9EE1DA7B73B00F5793B /* YTKCustomCacheRequest.m */; };\n\t\t2DDCFA041DA7B73B00F5793B /* YTKCustomHeaderFieldRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 2DDCF9F01DA7B73B00F5793B /* YTKCustomHeaderFieldRequest.m */; };\n\t\t2DDCFA051DA7B73B00F5793B /* YTKCustomHeaderFieldRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 2DDCF9F01DA7B73B00F5793B /* YTKCustomHeaderFieldRequest.m */; };\n\t\t2DDCFA061DA7B73B00F5793B /* YTKCustomHeaderFieldRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 2DDCF9F01DA7B73B00F5793B /* YTKCustomHeaderFieldRequest.m */; };\n\t\t2DDCFA071DA7B73B00F5793B /* YTKDownloadRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 2DDCF9F21DA7B73B00F5793B /* YTKDownloadRequest.m */; };\n\t\t2DDCFA081DA7B73B00F5793B /* YTKDownloadRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 2DDCF9F21DA7B73B00F5793B /* YTKDownloadRequest.m */; };\n\t\t2DDCFA091DA7B73B00F5793B /* YTKDownloadRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 2DDCF9F21DA7B73B00F5793B /* YTKDownloadRequest.m */; };\n\t\t2DDCFA0A1DA7B73B00F5793B /* YTKJSONValidatorRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 2DDCF9F41DA7B73B00F5793B /* YTKJSONValidatorRequest.m */; };\n\t\t2DDCFA0B1DA7B73B00F5793B /* YTKJSONValidatorRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 2DDCF9F41DA7B73B00F5793B /* YTKJSONValidatorRequest.m */; };\n\t\t2DDCFA0C1DA7B73B00F5793B /* YTKJSONValidatorRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 2DDCF9F41DA7B73B00F5793B /* YTKJSONValidatorRequest.m */; };\n\t\t2DDCFA0D1DA7B73B00F5793B /* YTKStatusCodeValidatorRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 2DDCF9F61DA7B73B00F5793B /* YTKStatusCodeValidatorRequest.m */; };\n\t\t2DDCFA0E1DA7B73B00F5793B /* YTKStatusCodeValidatorRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 2DDCF9F61DA7B73B00F5793B /* YTKStatusCodeValidatorRequest.m */; };\n\t\t2DDCFA0F1DA7B73B00F5793B /* YTKStatusCodeValidatorRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 2DDCF9F61DA7B73B00F5793B /* YTKStatusCodeValidatorRequest.m */; };\n\t\t2DDCFA101DA7B73B00F5793B /* YTKTimeoutRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 2DDCF9F81DA7B73B00F5793B /* YTKTimeoutRequest.m */; };\n\t\t2DDCFA111DA7B73B00F5793B /* YTKTimeoutRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 2DDCF9F81DA7B73B00F5793B /* YTKTimeoutRequest.m */; };\n\t\t2DDCFA121DA7B73B00F5793B /* YTKTimeoutRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 2DDCF9F81DA7B73B00F5793B /* YTKTimeoutRequest.m */; };\n\t\t2DDCFA131DA7B73B00F5793B /* YTKXMLRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 2DDCF9FA1DA7B73B00F5793B /* YTKXMLRequest.m */; };\n\t\t2DDCFA141DA7B73B00F5793B /* YTKXMLRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 2DDCF9FA1DA7B73B00F5793B /* YTKXMLRequest.m */; };\n\t\t2DDCFA151DA7B73B00F5793B /* YTKXMLRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 2DDCF9FA1DA7B73B00F5793B /* YTKXMLRequest.m */; };\n\t\t2DF836161DA7CA190076B1EB /* NSString+YTKUrlUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 2DF836131DA7C7FB0076B1EB /* NSString+YTKUrlUtils.m */; };\n\t\t2DF836171DA7CA1B0076B1EB /* NSString+YTKUrlUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 2DF836131DA7C7FB0076B1EB /* NSString+YTKUrlUtils.m */; };\n\t\t2DF836181DA7CA1B0076B1EB /* NSString+YTKUrlUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 2DF836131DA7C7FB0076B1EB /* NSString+YTKUrlUtils.m */; };\n/* End PBXBuildFile section */\n\n/* Begin PBXContainerItemProxy section */\n\t\t2D244E151D4ED6470031202D /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = 2D244E001D4ED6460031202D /* Project object */;\n\t\t\tproxyType = 1;\n\t\t\tremoteGlobalIDString = 2D244E081D4ED6470031202D;\n\t\t\tremoteInfo = YTKNetwork;\n\t\t};\n\t\t2D58ADDD1D59973D00FA6347 /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = 2D244E001D4ED6460031202D /* Project object */;\n\t\t\tproxyType = 1;\n\t\t\tremoteGlobalIDString = 2D58ADD11D59973D00FA6347;\n\t\t\tremoteInfo = \"YTKNetwork tvOS\";\n\t\t};\n\t\t2DC79A6F1D599B0F00197527 /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = 2D244E001D4ED6460031202D /* Project object */;\n\t\t\tproxyType = 1;\n\t\t\tremoteGlobalIDString = 2DC79A641D599B0F00197527;\n\t\t\tremoteInfo = \"YTKNetwork macOS\";\n\t\t};\n/* End PBXContainerItemProxy section */\n\n/* Begin PBXCopyFilesBuildPhase section */\n\t\t2D58AE0E1D5999E700FA6347 /* Copy Framework */ = {\n\t\t\tisa = PBXCopyFilesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tdstPath = \"\";\n\t\t\tdstSubfolderSpec = 10;\n\t\t\tfiles = (\n\t\t\t\t2D58AE0F1D5999F700FA6347 /* AFNetworking.framework in Copy Framework */,\n\t\t\t);\n\t\t\tname = \"Copy Framework\";\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t2D6B77461D599C74000C3BF2 /* Copy Framework */ = {\n\t\t\tisa = PBXCopyFilesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tdstPath = \"\";\n\t\t\tdstSubfolderSpec = 10;\n\t\t\tfiles = (\n\t\t\t\t2D6B77471D599C83000C3BF2 /* AFNetworking.framework in Copy Framework */,\n\t\t\t);\n\t\t\tname = \"Copy Framework\";\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t2DCFCBF61D4EE101002CAC24 /* Copy Framework */ = {\n\t\t\tisa = PBXCopyFilesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tdstPath = \"\";\n\t\t\tdstSubfolderSpec = 10;\n\t\t\tfiles = (\n\t\t\t\t2DCFCBF71D4EE10D002CAC24 /* AFNetworking.framework in Copy Framework */,\n\t\t\t);\n\t\t\tname = \"Copy Framework\";\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXCopyFilesBuildPhase section */\n\n/* Begin PBXFileReference section */\n\t\t2D244E091D4ED6470031202D /* YTKNetwork.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = YTKNetwork.framework; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t2D244E0C1D4ED6470031202D /* YTKNetwork.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = YTKNetwork.h; sourceTree = \"<group>\"; };\n\t\t2D244E0E1D4ED6470031202D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = ../Framework/Info.plist; sourceTree = \"<group>\"; };\n\t\t2D244E131D4ED6470031202D /* YTKNetwork iOSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = \"YTKNetwork iOSTests.xctest\"; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t2D244E1A1D4ED6470031202D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = \"<group>\"; };\n\t\t2D244E241D4ED7910031202D /* YTKBaseRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = YTKBaseRequest.h; path = YTKNetwork/YTKBaseRequest.h; sourceTree = \"<group>\"; };\n\t\t2D244E251D4ED7910031202D /* YTKBaseRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = YTKBaseRequest.m; path = YTKNetwork/YTKBaseRequest.m; sourceTree = \"<group>\"; };\n\t\t2D244E261D4ED7910031202D /* YTKBatchRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = YTKBatchRequest.h; path = YTKNetwork/YTKBatchRequest.h; sourceTree = \"<group>\"; };\n\t\t2D244E271D4ED7910031202D /* YTKBatchRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = YTKBatchRequest.m; path = YTKNetwork/YTKBatchRequest.m; sourceTree = \"<group>\"; };\n\t\t2D244E281D4ED7910031202D /* YTKBatchRequestAgent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = YTKBatchRequestAgent.h; path = YTKNetwork/YTKBatchRequestAgent.h; sourceTree = \"<group>\"; };\n\t\t2D244E291D4ED7910031202D /* YTKBatchRequestAgent.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = YTKBatchRequestAgent.m; path = YTKNetwork/YTKBatchRequestAgent.m; sourceTree = \"<group>\"; };\n\t\t2D244E2A1D4ED7910031202D /* YTKChainRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = YTKChainRequest.h; path = YTKNetwork/YTKChainRequest.h; sourceTree = \"<group>\"; };\n\t\t2D244E2B1D4ED7910031202D /* YTKChainRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = YTKChainRequest.m; path = YTKNetwork/YTKChainRequest.m; sourceTree = \"<group>\"; };\n\t\t2D244E2C1D4ED7910031202D /* YTKChainRequestAgent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = YTKChainRequestAgent.h; path = YTKNetwork/YTKChainRequestAgent.h; sourceTree = \"<group>\"; };\n\t\t2D244E2D1D4ED7910031202D /* YTKChainRequestAgent.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = YTKChainRequestAgent.m; path = YTKNetwork/YTKChainRequestAgent.m; sourceTree = \"<group>\"; };\n\t\t2D244E2E1D4ED7910031202D /* YTKNetworkAgent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = YTKNetworkAgent.h; path = YTKNetwork/YTKNetworkAgent.h; sourceTree = \"<group>\"; };\n\t\t2D244E2F1D4ED7910031202D /* YTKNetworkAgent.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = YTKNetworkAgent.m; path = YTKNetwork/YTKNetworkAgent.m; sourceTree = \"<group>\"; };\n\t\t2D244E301D4ED7910031202D /* YTKNetworkConfig.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = YTKNetworkConfig.h; path = YTKNetwork/YTKNetworkConfig.h; sourceTree = \"<group>\"; };\n\t\t2D244E311D4ED7910031202D /* YTKNetworkConfig.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = YTKNetworkConfig.m; path = YTKNetwork/YTKNetworkConfig.m; sourceTree = \"<group>\"; };\n\t\t2D244E321D4ED7910031202D /* YTKNetworkPrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = YTKNetworkPrivate.h; path = YTKNetwork/YTKNetworkPrivate.h; sourceTree = \"<group>\"; };\n\t\t2D244E331D4ED7910031202D /* YTKNetworkPrivate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = YTKNetworkPrivate.m; path = YTKNetwork/YTKNetworkPrivate.m; sourceTree = \"<group>\"; };\n\t\t2D244E341D4ED7910031202D /* YTKRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = YTKRequest.h; path = YTKNetwork/YTKRequest.h; sourceTree = \"<group>\"; };\n\t\t2D244E351D4ED7910031202D /* YTKRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = YTKRequest.m; path = YTKNetwork/YTKRequest.m; sourceTree = \"<group>\"; };\n\t\t2D244E621D4EDC7E0031202D /* AFNetworking.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AFNetworking.framework; path = Carthage/Build/iOS/AFNetworking.framework; sourceTree = \"<group>\"; };\n\t\t2D58ADAF1D598FE700FA6347 /* YTKNetwork.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = YTKNetwork.framework; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t2D58ADCA1D5993FB00FA6347 /* AFNetworking.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AFNetworking.framework; path = Carthage/Build/watchOS/AFNetworking.framework; sourceTree = \"<group>\"; };\n\t\t2D58ADD21D59973D00FA6347 /* YTKNetwork.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = YTKNetwork.framework; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t2D58ADDB1D59973D00FA6347 /* YTKNetwork tvOSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = \"YTKNetwork tvOSTests.xctest\"; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t2D58ADF21D5997F600FA6347 /* AFNetworking.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AFNetworking.framework; path = Carthage/Build/tvOS/AFNetworking.framework; sourceTree = \"<group>\"; };\n\t\t2DC79A651D599B0F00197527 /* YTKNetwork.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = YTKNetwork.framework; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t2DC79A6D1D599B0F00197527 /* YTKNetwork macOSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = \"YTKNetwork macOSTests.xctest\"; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t2DC79A851D599B9600197527 /* AFNetworking.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AFNetworking.framework; path = Carthage/Build/Mac/AFNetworking.framework; sourceTree = \"<group>\"; };\n\t\t2DDCF9BA1DA7B71600F5793B /* YTKCacheTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = YTKCacheTests.m; path = \"Test Cases/YTKCacheTests.m\"; sourceTree = \"<group>\"; };\n\t\t2DDCF9BB1DA7B71600F5793B /* YTKConcurrencyTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = YTKConcurrencyTests.m; path = \"Test Cases/YTKConcurrencyTests.m\"; sourceTree = \"<group>\"; };\n\t\t2DDCF9BC1DA7B71600F5793B /* YTKJSONValidatorTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = YTKJSONValidatorTests.m; path = \"Test Cases/YTKJSONValidatorTests.m\"; sourceTree = \"<group>\"; };\n\t\t2DDCF9BE1DA7B71600F5793B /* YTKNetworkRequestTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = YTKNetworkRequestTests.m; path = \"Test Cases/YTKNetworkRequestTests.m\"; sourceTree = \"<group>\"; };\n\t\t2DDCF9BF1DA7B71600F5793B /* YTKPerformanceTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = YTKPerformanceTests.m; path = \"Test Cases/YTKPerformanceTests.m\"; sourceTree = \"<group>\"; };\n\t\t2DDCF9C01DA7B71600F5793B /* YTKRequestFilterTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = YTKRequestFilterTests.m; path = \"Test Cases/YTKRequestFilterTests.m\"; sourceTree = \"<group>\"; };\n\t\t2DDCF9C11DA7B71600F5793B /* YTKResumableDownloadTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = YTKResumableDownloadTests.m; path = \"Test Cases/YTKResumableDownloadTests.m\"; sourceTree = \"<group>\"; };\n\t\t2DDCF9C21DA7B71600F5793B /* YTKTestCase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = YTKTestCase.h; path = \"Test Cases/YTKTestCase.h\"; sourceTree = \"<group>\"; };\n\t\t2DDCF9C31DA7B71600F5793B /* YTKTestCase.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = YTKTestCase.m; path = \"Test Cases/YTKTestCase.m\"; sourceTree = \"<group>\"; };\n\t\t2DDCF9DF1DA7B72B00F5793B /* YTKBasicCacheDirFilter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = YTKBasicCacheDirFilter.h; path = Utils/YTKBasicCacheDirFilter.h; sourceTree = \"<group>\"; };\n\t\t2DDCF9E01DA7B72B00F5793B /* YTKBasicCacheDirFilter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = YTKBasicCacheDirFilter.m; path = Utils/YTKBasicCacheDirFilter.m; sourceTree = \"<group>\"; };\n\t\t2DDCF9E11DA7B72B00F5793B /* YTKBasicUrlFilter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = YTKBasicUrlFilter.h; path = Utils/YTKBasicUrlFilter.h; sourceTree = \"<group>\"; };\n\t\t2DDCF9E21DA7B72B00F5793B /* YTKBasicUrlFilter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = YTKBasicUrlFilter.m; path = Utils/YTKBasicUrlFilter.m; sourceTree = \"<group>\"; };\n\t\t2DDCF9E91DA7B73B00F5793B /* YTKBasicAuthRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = YTKBasicAuthRequest.h; path = Requests/YTKBasicAuthRequest.h; sourceTree = \"<group>\"; };\n\t\t2DDCF9EA1DA7B73B00F5793B /* YTKBasicAuthRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = YTKBasicAuthRequest.m; path = Requests/YTKBasicAuthRequest.m; sourceTree = \"<group>\"; };\n\t\t2DDCF9EB1DA7B73B00F5793B /* YTKBasicHTTPRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = YTKBasicHTTPRequest.h; path = Requests/YTKBasicHTTPRequest.h; sourceTree = \"<group>\"; };\n\t\t2DDCF9EC1DA7B73B00F5793B /* YTKBasicHTTPRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = YTKBasicHTTPRequest.m; path = Requests/YTKBasicHTTPRequest.m; sourceTree = \"<group>\"; };\n\t\t2DDCF9ED1DA7B73B00F5793B /* YTKCustomCacheRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = YTKCustomCacheRequest.h; path = Requests/YTKCustomCacheRequest.h; sourceTree = \"<group>\"; };\n\t\t2DDCF9EE1DA7B73B00F5793B /* YTKCustomCacheRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = YTKCustomCacheRequest.m; path = Requests/YTKCustomCacheRequest.m; sourceTree = \"<group>\"; };\n\t\t2DDCF9EF1DA7B73B00F5793B /* YTKCustomHeaderFieldRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = YTKCustomHeaderFieldRequest.h; path = Requests/YTKCustomHeaderFieldRequest.h; sourceTree = \"<group>\"; };\n\t\t2DDCF9F01DA7B73B00F5793B /* YTKCustomHeaderFieldRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = YTKCustomHeaderFieldRequest.m; path = Requests/YTKCustomHeaderFieldRequest.m; sourceTree = \"<group>\"; };\n\t\t2DDCF9F11DA7B73B00F5793B /* YTKDownloadRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = YTKDownloadRequest.h; path = Requests/YTKDownloadRequest.h; sourceTree = \"<group>\"; };\n\t\t2DDCF9F21DA7B73B00F5793B /* YTKDownloadRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = YTKDownloadRequest.m; path = Requests/YTKDownloadRequest.m; sourceTree = \"<group>\"; };\n\t\t2DDCF9F31DA7B73B00F5793B /* YTKJSONValidatorRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = YTKJSONValidatorRequest.h; path = Requests/YTKJSONValidatorRequest.h; sourceTree = \"<group>\"; };\n\t\t2DDCF9F41DA7B73B00F5793B /* YTKJSONValidatorRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = YTKJSONValidatorRequest.m; path = Requests/YTKJSONValidatorRequest.m; sourceTree = \"<group>\"; };\n\t\t2DDCF9F51DA7B73B00F5793B /* YTKStatusCodeValidatorRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = YTKStatusCodeValidatorRequest.h; path = Requests/YTKStatusCodeValidatorRequest.h; sourceTree = \"<group>\"; };\n\t\t2DDCF9F61DA7B73B00F5793B /* YTKStatusCodeValidatorRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = YTKStatusCodeValidatorRequest.m; path = Requests/YTKStatusCodeValidatorRequest.m; sourceTree = \"<group>\"; };\n\t\t2DDCF9F71DA7B73B00F5793B /* YTKTimeoutRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = YTKTimeoutRequest.h; path = Requests/YTKTimeoutRequest.h; sourceTree = \"<group>\"; };\n\t\t2DDCF9F81DA7B73B00F5793B /* YTKTimeoutRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = YTKTimeoutRequest.m; path = Requests/YTKTimeoutRequest.m; sourceTree = \"<group>\"; };\n\t\t2DDCF9F91DA7B73B00F5793B /* YTKXMLRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = YTKXMLRequest.h; path = Requests/YTKXMLRequest.h; sourceTree = \"<group>\"; };\n\t\t2DDCF9FA1DA7B73B00F5793B /* YTKXMLRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = YTKXMLRequest.m; path = Requests/YTKXMLRequest.m; sourceTree = \"<group>\"; };\n\t\t2DF836121DA7C7FB0076B1EB /* NSString+YTKUrlUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = \"NSString+YTKUrlUtils.h\"; path = \"Utils/NSString+YTKUrlUtils.h\"; sourceTree = \"<group>\"; };\n\t\t2DF836131DA7C7FB0076B1EB /* NSString+YTKUrlUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = \"NSString+YTKUrlUtils.m\"; path = \"Utils/NSString+YTKUrlUtils.m\"; sourceTree = \"<group>\"; };\n/* End PBXFileReference section */\n\n/* Begin PBXFrameworksBuildPhase section */\n\t\t2D244E051D4ED6470031202D /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t2D244E641D4EDCCA0031202D /* AFNetworking.framework in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t2D244E101D4ED6470031202D /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t2D244E141D4ED6470031202D /* YTKNetwork.framework in Frameworks */,\n\t\t\t\t2D244E631D4EDC7E0031202D /* AFNetworking.framework in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t2D58ADAB1D598FE700FA6347 /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t2D58ADCC1D59967D00FA6347 /* AFNetworking.framework in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t2D58ADCE1D59973D00FA6347 /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t2D58ADF41D59980C00FA6347 /* AFNetworking.framework in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t2D58ADD81D59973D00FA6347 /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t2D58ADDC1D59973D00FA6347 /* YTKNetwork.framework in Frameworks */,\n\t\t\t\t2D58AE0D1D5999CE00FA6347 /* AFNetworking.framework in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t2DC79A611D599B0F00197527 /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t2DC79A871D599BAB00197527 /* AFNetworking.framework in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t2DC79A6A1D599B0F00197527 /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t2DC79A6E1D599B0F00197527 /* YTKNetwork.framework in Frameworks */,\n\t\t\t\t2D6B77451D599C6F000C3BF2 /* AFNetworking.framework in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXFrameworksBuildPhase section */\n\n/* Begin PBXGroup section */\n\t\t2D244DFF1D4ED6460031202D = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t2D244E231D4ED7830031202D /* YTKNetwork */,\n\t\t\t\t2D244E0B1D4ED6470031202D /* Supporting Files */,\n\t\t\t\t2D244E171D4ED6470031202D /* YTKNetworkTests */,\n\t\t\t\t2D244E0A1D4ED6470031202D /* Products */,\n\t\t\t\t2D244E611D4EDC590031202D /* Dependency */,\n\t\t\t);\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t2D244E0A1D4ED6470031202D /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t2D244E091D4ED6470031202D /* YTKNetwork.framework */,\n\t\t\t\t2D244E131D4ED6470031202D /* YTKNetwork iOSTests.xctest */,\n\t\t\t\t2D58ADAF1D598FE700FA6347 /* YTKNetwork.framework */,\n\t\t\t\t2D58ADD21D59973D00FA6347 /* YTKNetwork.framework */,\n\t\t\t\t2D58ADDB1D59973D00FA6347 /* YTKNetwork tvOSTests.xctest */,\n\t\t\t\t2DC79A651D599B0F00197527 /* YTKNetwork.framework */,\n\t\t\t\t2DC79A6D1D599B0F00197527 /* YTKNetwork macOSTests.xctest */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t2D244E0B1D4ED6470031202D /* Supporting Files */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t2D244E0C1D4ED6470031202D /* YTKNetwork.h */,\n\t\t\t\t2D244E0E1D4ED6470031202D /* Info.plist */,\n\t\t\t);\n\t\t\tname = \"Supporting Files\";\n\t\t\tpath = YTKNetwork;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t2D244E171D4ED6470031202D /* YTKNetworkTests */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t2D513AAD1D50811300E475EA /* Test Cases */,\n\t\t\t\t2D513AAC1D50810800E475EA /* Utils */,\n\t\t\t\t2DAB7EA81D50227D009F6257 /* Requests */,\n\t\t\t\t2D244E1A1D4ED6470031202D /* Info.plist */,\n\t\t\t);\n\t\t\tpath = YTKNetworkTests;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t2D244E231D4ED7830031202D /* YTKNetwork */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t2D244E241D4ED7910031202D /* YTKBaseRequest.h */,\n\t\t\t\t2D244E251D4ED7910031202D /* YTKBaseRequest.m */,\n\t\t\t\t2D244E261D4ED7910031202D /* YTKBatchRequest.h */,\n\t\t\t\t2D244E271D4ED7910031202D /* YTKBatchRequest.m */,\n\t\t\t\t2D244E281D4ED7910031202D /* YTKBatchRequestAgent.h */,\n\t\t\t\t2D244E291D4ED7910031202D /* YTKBatchRequestAgent.m */,\n\t\t\t\t2D244E2A1D4ED7910031202D /* YTKChainRequest.h */,\n\t\t\t\t2D244E2B1D4ED7910031202D /* YTKChainRequest.m */,\n\t\t\t\t2D244E2C1D4ED7910031202D /* YTKChainRequestAgent.h */,\n\t\t\t\t2D244E2D1D4ED7910031202D /* YTKChainRequestAgent.m */,\n\t\t\t\t2D244E2E1D4ED7910031202D /* YTKNetworkAgent.h */,\n\t\t\t\t2D244E2F1D4ED7910031202D /* YTKNetworkAgent.m */,\n\t\t\t\t2D244E301D4ED7910031202D /* YTKNetworkConfig.h */,\n\t\t\t\t2D244E311D4ED7910031202D /* YTKNetworkConfig.m */,\n\t\t\t\t2D244E321D4ED7910031202D /* YTKNetworkPrivate.h */,\n\t\t\t\t2D244E331D4ED7910031202D /* YTKNetworkPrivate.m */,\n\t\t\t\t2D244E341D4ED7910031202D /* YTKRequest.h */,\n\t\t\t\t2D244E351D4ED7910031202D /* YTKRequest.m */,\n\t\t\t);\n\t\t\tname = YTKNetwork;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t2D244E611D4EDC590031202D /* Dependency */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t2DC79A851D599B9600197527 /* AFNetworking.framework */,\n\t\t\t\t2D58ADF21D5997F600FA6347 /* AFNetworking.framework */,\n\t\t\t\t2D58ADCA1D5993FB00FA6347 /* AFNetworking.framework */,\n\t\t\t\t2D244E621D4EDC7E0031202D /* AFNetworking.framework */,\n\t\t\t);\n\t\t\tname = Dependency;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t2D513AAC1D50810800E475EA /* Utils */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t2DDCF9DF1DA7B72B00F5793B /* YTKBasicCacheDirFilter.h */,\n\t\t\t\t2DDCF9E01DA7B72B00F5793B /* YTKBasicCacheDirFilter.m */,\n\t\t\t\t2DDCF9E11DA7B72B00F5793B /* YTKBasicUrlFilter.h */,\n\t\t\t\t2DDCF9E21DA7B72B00F5793B /* YTKBasicUrlFilter.m */,\n\t\t\t\t2DF836121DA7C7FB0076B1EB /* NSString+YTKUrlUtils.h */,\n\t\t\t\t2DF836131DA7C7FB0076B1EB /* NSString+YTKUrlUtils.m */,\n\t\t\t);\n\t\t\tname = Utils;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t2D513AAD1D50811300E475EA /* Test Cases */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t2DDCF9BA1DA7B71600F5793B /* YTKCacheTests.m */,\n\t\t\t\t2DDCF9BB1DA7B71600F5793B /* YTKConcurrencyTests.m */,\n\t\t\t\t2DDCF9BC1DA7B71600F5793B /* YTKJSONValidatorTests.m */,\n\t\t\t\t2DDCF9BE1DA7B71600F5793B /* YTKNetworkRequestTests.m */,\n\t\t\t\t2DDCF9BF1DA7B71600F5793B /* YTKPerformanceTests.m */,\n\t\t\t\t2DDCF9C01DA7B71600F5793B /* YTKRequestFilterTests.m */,\n\t\t\t\t2DDCF9C11DA7B71600F5793B /* YTKResumableDownloadTests.m */,\n\t\t\t\t2DDCF9C21DA7B71600F5793B /* YTKTestCase.h */,\n\t\t\t\t2DDCF9C31DA7B71600F5793B /* YTKTestCase.m */,\n\t\t\t);\n\t\t\tname = \"Test Cases\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t2DAB7EA81D50227D009F6257 /* Requests */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t2DDCF9E91DA7B73B00F5793B /* YTKBasicAuthRequest.h */,\n\t\t\t\t2DDCF9EA1DA7B73B00F5793B /* YTKBasicAuthRequest.m */,\n\t\t\t\t2DDCF9EB1DA7B73B00F5793B /* YTKBasicHTTPRequest.h */,\n\t\t\t\t2DDCF9EC1DA7B73B00F5793B /* YTKBasicHTTPRequest.m */,\n\t\t\t\t2DDCF9ED1DA7B73B00F5793B /* YTKCustomCacheRequest.h */,\n\t\t\t\t2DDCF9EE1DA7B73B00F5793B /* YTKCustomCacheRequest.m */,\n\t\t\t\t2DDCF9EF1DA7B73B00F5793B /* YTKCustomHeaderFieldRequest.h */,\n\t\t\t\t2DDCF9F01DA7B73B00F5793B /* YTKCustomHeaderFieldRequest.m */,\n\t\t\t\t2DDCF9F11DA7B73B00F5793B /* YTKDownloadRequest.h */,\n\t\t\t\t2DDCF9F21DA7B73B00F5793B /* YTKDownloadRequest.m */,\n\t\t\t\t2DDCF9F31DA7B73B00F5793B /* YTKJSONValidatorRequest.h */,\n\t\t\t\t2DDCF9F41DA7B73B00F5793B /* YTKJSONValidatorRequest.m */,\n\t\t\t\t2DDCF9F51DA7B73B00F5793B /* YTKStatusCodeValidatorRequest.h */,\n\t\t\t\t2DDCF9F61DA7B73B00F5793B /* YTKStatusCodeValidatorRequest.m */,\n\t\t\t\t2DDCF9F71DA7B73B00F5793B /* YTKTimeoutRequest.h */,\n\t\t\t\t2DDCF9F81DA7B73B00F5793B /* YTKTimeoutRequest.m */,\n\t\t\t\t2DDCF9F91DA7B73B00F5793B /* YTKXMLRequest.h */,\n\t\t\t\t2DDCF9FA1DA7B73B00F5793B /* YTKXMLRequest.m */,\n\t\t\t);\n\t\t\tname = Requests;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXGroup section */\n\n/* Begin PBXHeadersBuildPhase section */\n\t\t2D244E061D4ED6470031202D /* Headers */ = {\n\t\t\tisa = PBXHeadersBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t2D244E421D4ED7910031202D /* YTKNetworkConfig.h in Headers */,\n\t\t\t\t2D244E361D4ED7910031202D /* YTKBaseRequest.h in Headers */,\n\t\t\t\t2D244E381D4ED7910031202D /* YTKBatchRequest.h in Headers */,\n\t\t\t\t2D244E3C1D4ED7910031202D /* YTKChainRequest.h in Headers */,\n\t\t\t\t2D244E461D4ED7910031202D /* YTKRequest.h in Headers */,\n\t\t\t\t2D244E3E1D4ED7910031202D /* YTKChainRequestAgent.h in Headers */,\n\t\t\t\t2D244E3A1D4ED7910031202D /* YTKBatchRequestAgent.h in Headers */,\n\t\t\t\t2D244E401D4ED7910031202D /* YTKNetworkAgent.h in Headers */,\n\t\t\t\t2D244E0D1D4ED6470031202D /* YTKNetwork.h in Headers */,\n\t\t\t\t2D244E441D4ED7910031202D /* YTKNetworkPrivate.h in Headers */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t2D58ADAC1D598FE700FA6347 /* Headers */ = {\n\t\t\tisa = PBXHeadersBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t2D58ADC01D59912700FA6347 /* YTKBaseRequest.h in Headers */,\n\t\t\t\t2D58ADC11D59912700FA6347 /* YTKBatchRequest.h in Headers */,\n\t\t\t\t2D58ADC31D59912700FA6347 /* YTKChainRequest.h in Headers */,\n\t\t\t\t2D58ADC61D59912700FA6347 /* YTKNetworkConfig.h in Headers */,\n\t\t\t\t2D58ADC81D59912700FA6347 /* YTKRequest.h in Headers */,\n\t\t\t\t2D58ADC21D59912700FA6347 /* YTKBatchRequestAgent.h in Headers */,\n\t\t\t\t2D58ADC41D59912700FA6347 /* YTKChainRequestAgent.h in Headers */,\n\t\t\t\t2D58ADC51D59912700FA6347 /* YTKNetworkAgent.h in Headers */,\n\t\t\t\t2D58ADC91D59912700FA6347 /* YTKNetwork.h in Headers */,\n\t\t\t\t2D58ADC71D59912700FA6347 /* YTKNetworkPrivate.h in Headers */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t2D58ADCF1D59973D00FA6347 /* Headers */ = {\n\t\t\tisa = PBXHeadersBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t2D58ADF51D59986500FA6347 /* YTKBaseRequest.h in Headers */,\n\t\t\t\t2D58ADF61D59986500FA6347 /* YTKBatchRequest.h in Headers */,\n\t\t\t\t2D58ADF71D59986500FA6347 /* YTKChainRequest.h in Headers */,\n\t\t\t\t2D58ADF81D59986500FA6347 /* YTKNetworkConfig.h in Headers */,\n\t\t\t\t2D58ADF91D59986500FA6347 /* YTKRequest.h in Headers */,\n\t\t\t\t2D58ADFB1D59987400FA6347 /* YTKBatchRequestAgent.h in Headers */,\n\t\t\t\t2D58ADFC1D59987400FA6347 /* YTKChainRequestAgent.h in Headers */,\n\t\t\t\t2D58ADFD1D59987400FA6347 /* YTKNetworkAgent.h in Headers */,\n\t\t\t\t2D58ADFA1D59986500FA6347 /* YTKNetwork.h in Headers */,\n\t\t\t\t2D58ADFE1D59987400FA6347 /* YTKNetworkPrivate.h in Headers */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t2DC79A621D599B0F00197527 /* Headers */ = {\n\t\t\tisa = PBXHeadersBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t2DC79A881D599C1C00197527 /* YTKBaseRequest.h in Headers */,\n\t\t\t\t2DC79A891D599C1C00197527 /* YTKBatchRequest.h in Headers */,\n\t\t\t\t2DC79A8B1D599C1C00197527 /* YTKChainRequest.h in Headers */,\n\t\t\t\t2DC79A8E1D599C1C00197527 /* YTKNetworkConfig.h in Headers */,\n\t\t\t\t2DC79A8A1D599C1C00197527 /* YTKBatchRequestAgent.h in Headers */,\n\t\t\t\t2DC79A8C1D599C1C00197527 /* YTKChainRequestAgent.h in Headers */,\n\t\t\t\t2DC79A8D1D599C1C00197527 /* YTKNetworkAgent.h in Headers */,\n\t\t\t\t2DC79A901D599C1C00197527 /* YTKRequest.h in Headers */,\n\t\t\t\t2DC79A911D599C1C00197527 /* YTKNetwork.h in Headers */,\n\t\t\t\t2DC79A8F1D599C1C00197527 /* YTKNetworkPrivate.h in Headers */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXHeadersBuildPhase section */\n\n/* Begin PBXNativeTarget section */\n\t\t2D244E081D4ED6470031202D /* YTKNetwork iOS */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 2D244E1D1D4ED6470031202D /* Build configuration list for PBXNativeTarget \"YTKNetwork iOS\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t2D244E041D4ED6470031202D /* Sources */,\n\t\t\t\t2D244E051D4ED6470031202D /* Frameworks */,\n\t\t\t\t2D244E061D4ED6470031202D /* Headers */,\n\t\t\t\t2D244E071D4ED6470031202D /* Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = \"YTKNetwork iOS\";\n\t\t\tproductName = YTKNetwork;\n\t\t\tproductReference = 2D244E091D4ED6470031202D /* YTKNetwork.framework */;\n\t\t\tproductType = \"com.apple.product-type.framework\";\n\t\t};\n\t\t2D244E121D4ED6470031202D /* YTKNetwork iOSTests */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 2D244E201D4ED6470031202D /* Build configuration list for PBXNativeTarget \"YTKNetwork iOSTests\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t2D244E0F1D4ED6470031202D /* Sources */,\n\t\t\t\t2D244E101D4ED6470031202D /* Frameworks */,\n\t\t\t\t2D244E111D4ED6470031202D /* Resources */,\n\t\t\t\t2DCFCBF61D4EE101002CAC24 /* Copy Framework */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t\t2D244E161D4ED6470031202D /* PBXTargetDependency */,\n\t\t\t);\n\t\t\tname = \"YTKNetwork iOSTests\";\n\t\t\tproductName = YTKNetworkTests;\n\t\t\tproductReference = 2D244E131D4ED6470031202D /* YTKNetwork iOSTests.xctest */;\n\t\t\tproductType = \"com.apple.product-type.bundle.unit-test\";\n\t\t};\n\t\t2D58ADAE1D598FE700FA6347 /* YTKNetwork watchOS */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 2D58ADB61D598FE700FA6347 /* Build configuration list for PBXNativeTarget \"YTKNetwork watchOS\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t2D58ADAA1D598FE700FA6347 /* Sources */,\n\t\t\t\t2D58ADAB1D598FE700FA6347 /* Frameworks */,\n\t\t\t\t2D58ADAC1D598FE700FA6347 /* Headers */,\n\t\t\t\t2D58ADAD1D598FE700FA6347 /* Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = \"YTKNetwork watchOS\";\n\t\t\tproductName = \"YTKNetwork watchOS\";\n\t\t\tproductReference = 2D58ADAF1D598FE700FA6347 /* YTKNetwork.framework */;\n\t\t\tproductType = \"com.apple.product-type.framework\";\n\t\t};\n\t\t2D58ADD11D59973D00FA6347 /* YTKNetwork tvOS */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 2D58ADE31D59973D00FA6347 /* Build configuration list for PBXNativeTarget \"YTKNetwork tvOS\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t2D58ADCD1D59973D00FA6347 /* Sources */,\n\t\t\t\t2D58ADCE1D59973D00FA6347 /* Frameworks */,\n\t\t\t\t2D58ADCF1D59973D00FA6347 /* Headers */,\n\t\t\t\t2D58ADD01D59973D00FA6347 /* Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = \"YTKNetwork tvOS\";\n\t\t\tproductName = \"YTKNetwork tvOS\";\n\t\t\tproductReference = 2D58ADD21D59973D00FA6347 /* YTKNetwork.framework */;\n\t\t\tproductType = \"com.apple.product-type.framework\";\n\t\t};\n\t\t2D58ADDA1D59973D00FA6347 /* YTKNetwork tvOSTests */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 2D58ADE61D59973D00FA6347 /* Build configuration list for PBXNativeTarget \"YTKNetwork tvOSTests\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t2D58ADD71D59973D00FA6347 /* Sources */,\n\t\t\t\t2D58ADD81D59973D00FA6347 /* Frameworks */,\n\t\t\t\t2D58ADD91D59973D00FA6347 /* Resources */,\n\t\t\t\t2D58AE0E1D5999E700FA6347 /* Copy Framework */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t\t2D58ADDE1D59973D00FA6347 /* PBXTargetDependency */,\n\t\t\t);\n\t\t\tname = \"YTKNetwork tvOSTests\";\n\t\t\tproductName = \"YTKNetwork tvOSTests\";\n\t\t\tproductReference = 2D58ADDB1D59973D00FA6347 /* YTKNetwork tvOSTests.xctest */;\n\t\t\tproductType = \"com.apple.product-type.bundle.unit-test\";\n\t\t};\n\t\t2DC79A641D599B0F00197527 /* YTKNetwork macOS */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 2DC79A7A1D599B0F00197527 /* Build configuration list for PBXNativeTarget \"YTKNetwork macOS\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t2DC79A601D599B0F00197527 /* Sources */,\n\t\t\t\t2DC79A611D599B0F00197527 /* Frameworks */,\n\t\t\t\t2DC79A621D599B0F00197527 /* Headers */,\n\t\t\t\t2DC79A631D599B0F00197527 /* Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = \"YTKNetwork macOS\";\n\t\t\tproductName = \"YTKNetwork macOS\";\n\t\t\tproductReference = 2DC79A651D599B0F00197527 /* YTKNetwork.framework */;\n\t\t\tproductType = \"com.apple.product-type.framework\";\n\t\t};\n\t\t2DC79A6C1D599B0F00197527 /* YTKNetwork macOSTests */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 2DC79A7B1D599B0F00197527 /* Build configuration list for PBXNativeTarget \"YTKNetwork macOSTests\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t2DC79A691D599B0F00197527 /* Sources */,\n\t\t\t\t2DC79A6A1D599B0F00197527 /* Frameworks */,\n\t\t\t\t2DC79A6B1D599B0F00197527 /* Resources */,\n\t\t\t\t2D6B77461D599C74000C3BF2 /* Copy Framework */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t\t2DC79A701D599B0F00197527 /* PBXTargetDependency */,\n\t\t\t);\n\t\t\tname = \"YTKNetwork macOSTests\";\n\t\t\tproductName = \"YTKNetwork macOSTests\";\n\t\t\tproductReference = 2DC79A6D1D599B0F00197527 /* YTKNetwork macOSTests.xctest */;\n\t\t\tproductType = \"com.apple.product-type.bundle.unit-test\";\n\t\t};\n/* End PBXNativeTarget section */\n\n/* Begin PBXProject section */\n\t\t2D244E001D4ED6460031202D /* Project object */ = {\n\t\t\tisa = PBXProject;\n\t\t\tattributes = {\n\t\t\t\tLastUpgradeCheck = 0800;\n\t\t\t\tORGANIZATIONNAME = skyline;\n\t\t\t\tTargetAttributes = {\n\t\t\t\t\t2D244E081D4ED6470031202D = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 7.3.1;\n\t\t\t\t\t};\n\t\t\t\t\t2D244E121D4ED6470031202D = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 7.3.1;\n\t\t\t\t\t};\n\t\t\t\t\t2D58ADAE1D598FE700FA6347 = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 7.3.1;\n\t\t\t\t\t};\n\t\t\t\t\t2D58ADD11D59973D00FA6347 = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 7.3.1;\n\t\t\t\t\t};\n\t\t\t\t\t2D58ADDA1D59973D00FA6347 = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 7.3.1;\n\t\t\t\t\t};\n\t\t\t\t\t2DC79A641D599B0F00197527 = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 8.0;\n\t\t\t\t\t\tDevelopmentTeam = W865B39M7D;\n\t\t\t\t\t\tDevelopmentTeamName = \"Chester Liu (Personal Team)\";\n\t\t\t\t\t\tProvisioningStyle = Automatic;\n\t\t\t\t\t};\n\t\t\t\t\t2DC79A6C1D599B0F00197527 = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 8.0;\n\t\t\t\t\t\tDevelopmentTeam = W865B39M7D;\n\t\t\t\t\t\tDevelopmentTeamName = \"Chester Liu (Personal Team)\";\n\t\t\t\t\t\tProvisioningStyle = Automatic;\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t\tbuildConfigurationList = 2D244E031D4ED6460031202D /* Build configuration list for PBXProject \"YTKNetwork\" */;\n\t\t\tcompatibilityVersion = \"Xcode 3.2\";\n\t\t\tdevelopmentRegion = English;\n\t\t\thasScannedForEncodings = 0;\n\t\t\tknownRegions = (\n\t\t\t\ten,\n\t\t\t);\n\t\t\tmainGroup = 2D244DFF1D4ED6460031202D;\n\t\t\tproductRefGroup = 2D244E0A1D4ED6470031202D /* Products */;\n\t\t\tprojectDirPath = \"\";\n\t\t\tprojectRoot = \"\";\n\t\t\ttargets = (\n\t\t\t\t2D244E081D4ED6470031202D /* YTKNetwork iOS */,\n\t\t\t\t2D58ADAE1D598FE700FA6347 /* YTKNetwork watchOS */,\n\t\t\t\t2DC79A641D599B0F00197527 /* YTKNetwork macOS */,\n\t\t\t\t2D58ADD11D59973D00FA6347 /* YTKNetwork tvOS */,\n\t\t\t\t2D244E121D4ED6470031202D /* YTKNetwork iOSTests */,\n\t\t\t\t2DC79A6C1D599B0F00197527 /* YTKNetwork macOSTests */,\n\t\t\t\t2D58ADDA1D59973D00FA6347 /* YTKNetwork tvOSTests */,\n\t\t\t);\n\t\t};\n/* End PBXProject section */\n\n/* Begin PBXResourcesBuildPhase section */\n\t\t2D244E071D4ED6470031202D /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t2D244E111D4ED6470031202D /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t2D58ADAD1D598FE700FA6347 /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t2D58ADD01D59973D00FA6347 /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t2D58ADD91D59973D00FA6347 /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t2DC79A631D599B0F00197527 /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t2DC79A6B1D599B0F00197527 /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXResourcesBuildPhase section */\n\n/* Begin PBXSourcesBuildPhase section */\n\t\t2D244E041D4ED6470031202D /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t2D244E3D1D4ED7910031202D /* YTKChainRequest.m in Sources */,\n\t\t\t\t2D244E471D4ED7920031202D /* YTKRequest.m in Sources */,\n\t\t\t\t2D244E431D4ED7910031202D /* YTKNetworkConfig.m in Sources */,\n\t\t\t\t2D244E411D4ED7910031202D /* YTKNetworkAgent.m in Sources */,\n\t\t\t\t2D244E451D4ED7910031202D /* YTKNetworkPrivate.m in Sources */,\n\t\t\t\t2D244E371D4ED7910031202D /* YTKBaseRequest.m in Sources */,\n\t\t\t\t2D244E391D4ED7910031202D /* YTKBatchRequest.m in Sources */,\n\t\t\t\t2D244E3B1D4ED7910031202D /* YTKBatchRequestAgent.m in Sources */,\n\t\t\t\t2D244E3F1D4ED7910031202D /* YTKChainRequestAgent.m in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t2D244E0F1D4ED6470031202D /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t2DDCFA101DA7B73B00F5793B /* YTKTimeoutRequest.m in Sources */,\n\t\t\t\t2DDCFA0A1DA7B73B00F5793B /* YTKJSONValidatorRequest.m in Sources */,\n\t\t\t\t2DDCF9C71DA7B71600F5793B /* YTKConcurrencyTests.m in Sources */,\n\t\t\t\t2DDCFA0D1DA7B73B00F5793B /* YTKStatusCodeValidatorRequest.m in Sources */,\n\t\t\t\t2DF836161DA7CA190076B1EB /* NSString+YTKUrlUtils.m in Sources */,\n\t\t\t\t2DDCF9D91DA7B71600F5793B /* YTKResumableDownloadTests.m in Sources */,\n\t\t\t\t2DDCFA041DA7B73B00F5793B /* YTKCustomHeaderFieldRequest.m in Sources */,\n\t\t\t\t2DDCF9D01DA7B71600F5793B /* YTKNetworkRequestTests.m in Sources */,\n\t\t\t\t2DDCF9CA1DA7B71600F5793B /* YTKJSONValidatorTests.m in Sources */,\n\t\t\t\t2DDCFA131DA7B73B00F5793B /* YTKXMLRequest.m in Sources */,\n\t\t\t\t2DDCF9E61DA7B72B00F5793B /* YTKBasicUrlFilter.m in Sources */,\n\t\t\t\t2DDCF9E31DA7B72B00F5793B /* YTKBasicCacheDirFilter.m in Sources */,\n\t\t\t\t2DDCF9C41DA7B71600F5793B /* YTKCacheTests.m in Sources */,\n\t\t\t\t2DDCFA071DA7B73B00F5793B /* YTKDownloadRequest.m in Sources */,\n\t\t\t\t2DDCF9D31DA7B71600F5793B /* YTKPerformanceTests.m in Sources */,\n\t\t\t\t2DDCF9FE1DA7B73B00F5793B /* YTKBasicHTTPRequest.m in Sources */,\n\t\t\t\t2DDCFA011DA7B73B00F5793B /* YTKCustomCacheRequest.m in Sources */,\n\t\t\t\t2DDCF9FB1DA7B73B00F5793B /* YTKBasicAuthRequest.m in Sources */,\n\t\t\t\t2DDCF9DC1DA7B71600F5793B /* YTKTestCase.m in Sources */,\n\t\t\t\t2DDCF9D61DA7B71600F5793B /* YTKRequestFilterTests.m in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t2D58ADAA1D598FE700FA6347 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t2D58ADB71D59910500FA6347 /* YTKBaseRequest.m in Sources */,\n\t\t\t\t2D58ADB81D59910500FA6347 /* YTKBatchRequest.m in Sources */,\n\t\t\t\t2D58ADB91D59910500FA6347 /* YTKBatchRequestAgent.m in Sources */,\n\t\t\t\t2D58ADBA1D59910500FA6347 /* YTKChainRequest.m in Sources */,\n\t\t\t\t2D58ADBB1D59910500FA6347 /* YTKChainRequestAgent.m in Sources */,\n\t\t\t\t2D58ADBC1D59910500FA6347 /* YTKNetworkAgent.m in Sources */,\n\t\t\t\t2D58ADBD1D59910500FA6347 /* YTKNetworkConfig.m in Sources */,\n\t\t\t\t2D58ADBE1D59910500FA6347 /* YTKNetworkPrivate.m in Sources */,\n\t\t\t\t2D58ADBF1D59910500FA6347 /* YTKRequest.m in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t2D58ADCD1D59973D00FA6347 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t2D58ADE91D5997D300FA6347 /* YTKBaseRequest.m in Sources */,\n\t\t\t\t2D58ADEA1D5997D300FA6347 /* YTKBatchRequest.m in Sources */,\n\t\t\t\t2D58ADEB1D5997D300FA6347 /* YTKBatchRequestAgent.m in Sources */,\n\t\t\t\t2D58ADEC1D5997D300FA6347 /* YTKChainRequest.m in Sources */,\n\t\t\t\t2D58ADED1D5997D300FA6347 /* YTKChainRequestAgent.m in Sources */,\n\t\t\t\t2D58ADEE1D5997D300FA6347 /* YTKNetworkAgent.m in Sources */,\n\t\t\t\t2D58ADEF1D5997D300FA6347 /* YTKNetworkConfig.m in Sources */,\n\t\t\t\t2D58ADF01D5997D300FA6347 /* YTKNetworkPrivate.m in Sources */,\n\t\t\t\t2D58ADF11D5997D300FA6347 /* YTKRequest.m in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t2D58ADD71D59973D00FA6347 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t2DDCFA121DA7B73B00F5793B /* YTKTimeoutRequest.m in Sources */,\n\t\t\t\t2DDCFA0C1DA7B73B00F5793B /* YTKJSONValidatorRequest.m in Sources */,\n\t\t\t\t2DDCF9C91DA7B71600F5793B /* YTKConcurrencyTests.m in Sources */,\n\t\t\t\t2DDCFA0F1DA7B73B00F5793B /* YTKStatusCodeValidatorRequest.m in Sources */,\n\t\t\t\t2DF836181DA7CA1B0076B1EB /* NSString+YTKUrlUtils.m in Sources */,\n\t\t\t\t2DDCF9DB1DA7B71600F5793B /* YTKResumableDownloadTests.m in Sources */,\n\t\t\t\t2DDCFA061DA7B73B00F5793B /* YTKCustomHeaderFieldRequest.m in Sources */,\n\t\t\t\t2DDCF9D21DA7B71600F5793B /* YTKNetworkRequestTests.m in Sources */,\n\t\t\t\t2DDCF9CC1DA7B71600F5793B /* YTKJSONValidatorTests.m in Sources */,\n\t\t\t\t2DDCFA151DA7B73B00F5793B /* YTKXMLRequest.m in Sources */,\n\t\t\t\t2DDCF9E81DA7B72B00F5793B /* YTKBasicUrlFilter.m in Sources */,\n\t\t\t\t2DDCF9E51DA7B72B00F5793B /* YTKBasicCacheDirFilter.m in Sources */,\n\t\t\t\t2DDCF9C61DA7B71600F5793B /* YTKCacheTests.m in Sources */,\n\t\t\t\t2DDCFA091DA7B73B00F5793B /* YTKDownloadRequest.m in Sources */,\n\t\t\t\t2DDCF9D51DA7B71600F5793B /* YTKPerformanceTests.m in Sources */,\n\t\t\t\t2DDCFA001DA7B73B00F5793B /* YTKBasicHTTPRequest.m in Sources */,\n\t\t\t\t2DDCFA031DA7B73B00F5793B /* YTKCustomCacheRequest.m in Sources */,\n\t\t\t\t2DDCF9FD1DA7B73B00F5793B /* YTKBasicAuthRequest.m in Sources */,\n\t\t\t\t2DDCF9DE1DA7B71600F5793B /* YTKTestCase.m in Sources */,\n\t\t\t\t2DDCF9D81DA7B71600F5793B /* YTKRequestFilterTests.m in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t2DC79A601D599B0F00197527 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t2DC79A7C1D599B6B00197527 /* YTKBaseRequest.m in Sources */,\n\t\t\t\t2DC79A7D1D599B6B00197527 /* YTKBatchRequest.m in Sources */,\n\t\t\t\t2DC79A7E1D599B6B00197527 /* YTKBatchRequestAgent.m in Sources */,\n\t\t\t\t2DC79A7F1D599B6B00197527 /* YTKChainRequest.m in Sources */,\n\t\t\t\t2DC79A801D599B6B00197527 /* YTKChainRequestAgent.m in Sources */,\n\t\t\t\t2DC79A811D599B6B00197527 /* YTKNetworkAgent.m in Sources */,\n\t\t\t\t2DC79A821D599B6B00197527 /* YTKNetworkConfig.m in Sources */,\n\t\t\t\t2DC79A831D599B6B00197527 /* YTKNetworkPrivate.m in Sources */,\n\t\t\t\t2DC79A841D599B6B00197527 /* YTKRequest.m in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t2DC79A691D599B0F00197527 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t2DDCFA111DA7B73B00F5793B /* YTKTimeoutRequest.m in Sources */,\n\t\t\t\t2DDCFA0B1DA7B73B00F5793B /* YTKJSONValidatorRequest.m in Sources */,\n\t\t\t\t2DDCF9C81DA7B71600F5793B /* YTKConcurrencyTests.m in Sources */,\n\t\t\t\t2DDCFA0E1DA7B73B00F5793B /* YTKStatusCodeValidatorRequest.m in Sources */,\n\t\t\t\t2DF836171DA7CA1B0076B1EB /* NSString+YTKUrlUtils.m in Sources */,\n\t\t\t\t2DDCF9DA1DA7B71600F5793B /* YTKResumableDownloadTests.m in Sources */,\n\t\t\t\t2DDCFA051DA7B73B00F5793B /* YTKCustomHeaderFieldRequest.m in Sources */,\n\t\t\t\t2DDCF9D11DA7B71600F5793B /* YTKNetworkRequestTests.m in Sources */,\n\t\t\t\t2DDCF9CB1DA7B71600F5793B /* YTKJSONValidatorTests.m in Sources */,\n\t\t\t\t2DDCFA141DA7B73B00F5793B /* YTKXMLRequest.m in Sources */,\n\t\t\t\t2DDCF9E71DA7B72B00F5793B /* YTKBasicUrlFilter.m in Sources */,\n\t\t\t\t2DDCF9E41DA7B72B00F5793B /* YTKBasicCacheDirFilter.m in Sources */,\n\t\t\t\t2DDCF9C51DA7B71600F5793B /* YTKCacheTests.m in Sources */,\n\t\t\t\t2DDCFA081DA7B73B00F5793B /* YTKDownloadRequest.m in Sources */,\n\t\t\t\t2DDCF9D41DA7B71600F5793B /* YTKPerformanceTests.m in Sources */,\n\t\t\t\t2DDCF9FF1DA7B73B00F5793B /* YTKBasicHTTPRequest.m in Sources */,\n\t\t\t\t2DDCFA021DA7B73B00F5793B /* YTKCustomCacheRequest.m in Sources */,\n\t\t\t\t2DDCF9FC1DA7B73B00F5793B /* YTKBasicAuthRequest.m in Sources */,\n\t\t\t\t2DDCF9DD1DA7B71600F5793B /* YTKTestCase.m in Sources */,\n\t\t\t\t2DDCF9D71DA7B71600F5793B /* YTKRequestFilterTests.m in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXSourcesBuildPhase section */\n\n/* Begin PBXTargetDependency section */\n\t\t2D244E161D4ED6470031202D /* PBXTargetDependency */ = {\n\t\t\tisa = PBXTargetDependency;\n\t\t\ttarget = 2D244E081D4ED6470031202D /* YTKNetwork iOS */;\n\t\t\ttargetProxy = 2D244E151D4ED6470031202D /* PBXContainerItemProxy */;\n\t\t};\n\t\t2D58ADDE1D59973D00FA6347 /* PBXTargetDependency */ = {\n\t\t\tisa = PBXTargetDependency;\n\t\t\ttarget = 2D58ADD11D59973D00FA6347 /* YTKNetwork tvOS */;\n\t\t\ttargetProxy = 2D58ADDD1D59973D00FA6347 /* PBXContainerItemProxy */;\n\t\t};\n\t\t2DC79A701D599B0F00197527 /* PBXTargetDependency */ = {\n\t\t\tisa = PBXTargetDependency;\n\t\t\ttarget = 2DC79A641D599B0F00197527 /* YTKNetwork macOS */;\n\t\t\ttargetProxy = 2DC79A6F1D599B0F00197527 /* PBXContainerItemProxy */;\n\t\t};\n/* End PBXTargetDependency section */\n\n/* Begin XCBuildConfiguration section */\n\t\t2D244E1B1D4ED6470031202D /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++0x\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\t\"CODE_SIGN_IDENTITY[sdk=iphoneos*]\" = \"iPhone Developer\";\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tCURRENT_PROJECT_VERSION = 1;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = dwarf;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_TESTABILITY = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_DYNAMIC_NO_PIC = NO;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 9.3;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = YES;\n\t\t\t\tONLY_ACTIVE_ARCH = YES;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t\tVERSIONING_SYSTEM = \"apple-generic\";\n\t\t\t\tVERSION_INFO_PREFIX = \"\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t2D244E1C1D4ED6470031202D /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++0x\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\t\"CODE_SIGN_IDENTITY[sdk=iphoneos*]\" = \"iPhone Developer\";\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tCURRENT_PROJECT_VERSION = 1;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = \"dwarf-with-dsym\";\n\t\t\t\tENABLE_NS_ASSERTIONS = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 9.3;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = NO;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t\tVALIDATE_PRODUCT = YES;\n\t\t\t\tVERSIONING_SYSTEM = \"apple-generic\";\n\t\t\t\tVERSION_INFO_PREFIX = \"\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t2D244E1E1D4ED6470031202D /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\t\"CODE_SIGN_IDENTITY[sdk=iphoneos*]\" = \"\";\n\t\t\t\tDEFINES_MODULE = YES;\n\t\t\t\tDYLIB_COMPATIBILITY_VERSION = 1;\n\t\t\t\tDYLIB_CURRENT_VERSION = 1;\n\t\t\t\tDYLIB_INSTALL_NAME_BASE = \"@rpath\";\n\t\t\t\tFRAMEWORK_SEARCH_PATHS = \"$(PROJECT_DIR)/Carthage/Build/iOS\";\n\t\t\t\tHEADER_SEARCH_PATHS = \"\";\n\t\t\t\tINFOPLIST_FILE = \"$(SRCROOT)/Framework/Info.plist\";\n\t\t\t\tINSTALL_PATH = \"$(LOCAL_LIBRARY_DIR)/Frameworks\";\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 8.0;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks @loader_path/Frameworks\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"com.fenbi.YTKNetwork-iOS\";\n\t\t\t\tPRODUCT_NAME = YTKNetwork;\n\t\t\t\tSKIP_INSTALL = YES;\n\t\t\t\tTVOS_DEPLOYMENT_TARGET = 9.0;\n\t\t\t\tWATCHOS_DEPLOYMENT_TARGET = 2.0;\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t2D244E1F1D4ED6470031202D /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\t\"CODE_SIGN_IDENTITY[sdk=iphoneos*]\" = \"\";\n\t\t\t\tDEFINES_MODULE = YES;\n\t\t\t\tDYLIB_COMPATIBILITY_VERSION = 1;\n\t\t\t\tDYLIB_CURRENT_VERSION = 1;\n\t\t\t\tDYLIB_INSTALL_NAME_BASE = \"@rpath\";\n\t\t\t\tFRAMEWORK_SEARCH_PATHS = \"$(PROJECT_DIR)/Carthage/Build/iOS\";\n\t\t\t\tHEADER_SEARCH_PATHS = \"\";\n\t\t\t\tINFOPLIST_FILE = \"$(SRCROOT)/Framework/Info.plist\";\n\t\t\t\tINSTALL_PATH = \"$(LOCAL_LIBRARY_DIR)/Frameworks\";\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 8.0;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks @loader_path/Frameworks\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"com.fenbi.YTKNetwork-iOS\";\n\t\t\t\tPRODUCT_NAME = YTKNetwork;\n\t\t\t\tSKIP_INSTALL = YES;\n\t\t\t\tTVOS_DEPLOYMENT_TARGET = 9.0;\n\t\t\t\tWATCHOS_DEPLOYMENT_TARGET = 2.0;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t2D244E211D4ED6470031202D /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\t\"CODE_SIGN_IDENTITY[sdk=iphoneos*]\" = \"\";\n\t\t\t\tFRAMEWORK_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"$(PROJECT_DIR)/Carthage/Build/iOS\",\n\t\t\t\t);\n\t\t\t\tHEADER_SEARCH_PATHS = \"$(PROJECT_DIR)/Carthage/Build/iOS/AFNetworking.framework/Headers\";\n\t\t\t\tINFOPLIST_FILE = YTKNetworkTests/Info.plist;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks @loader_path/Frameworks\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.fenbi.YTKNetworkTests;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t2D244E221D4ED6470031202D /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\t\"CODE_SIGN_IDENTITY[sdk=iphoneos*]\" = \"\";\n\t\t\t\tFRAMEWORK_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"$(PROJECT_DIR)/Carthage/Build/iOS\",\n\t\t\t\t);\n\t\t\t\tHEADER_SEARCH_PATHS = \"$(PROJECT_DIR)/Carthage/Build/iOS/AFNetworking.framework/Headers\";\n\t\t\t\tINFOPLIST_FILE = YTKNetworkTests/Info.plist;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks @loader_path/Frameworks\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.fenbi.YTKNetworkTests;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t2D58ADB41D598FE700FA6347 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tAPPLICATION_EXTENSION_API_ONLY = NO;\n\t\t\t\t\"CODE_SIGN_IDENTITY[sdk=watchos*]\" = \"\";\n\t\t\t\tDEFINES_MODULE = YES;\n\t\t\t\tDYLIB_COMPATIBILITY_VERSION = 1;\n\t\t\t\tDYLIB_CURRENT_VERSION = 1;\n\t\t\t\tDYLIB_INSTALL_NAME_BASE = \"@rpath\";\n\t\t\t\tFRAMEWORK_SEARCH_PATHS = \"$(PROJECT_DIR)/Carthage/Build/watchOS\";\n\t\t\t\tINFOPLIST_FILE = ./Framework/Info.plist;\n\t\t\t\tINSTALL_PATH = \"$(LOCAL_LIBRARY_DIR)/Frameworks\";\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks @loader_path/Frameworks\";\n\t\t\t\tMACOSX_DEPLOYMENT_TARGET = 10.9;\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"com.fenbi.YTKNetwork-watchOS\";\n\t\t\t\tPRODUCT_NAME = YTKNetwork;\n\t\t\t\tSDKROOT = watchos;\n\t\t\t\tSKIP_INSTALL = YES;\n\t\t\t\tTARGETED_DEVICE_FAMILY = 4;\n\t\t\t\tTVOS_DEPLOYMENT_TARGET = 9.0;\n\t\t\t\tWATCHOS_DEPLOYMENT_TARGET = 2.0;\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t2D58ADB51D598FE700FA6347 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tAPPLICATION_EXTENSION_API_ONLY = NO;\n\t\t\t\t\"CODE_SIGN_IDENTITY[sdk=watchos*]\" = \"\";\n\t\t\t\tDEFINES_MODULE = YES;\n\t\t\t\tDYLIB_COMPATIBILITY_VERSION = 1;\n\t\t\t\tDYLIB_CURRENT_VERSION = 1;\n\t\t\t\tDYLIB_INSTALL_NAME_BASE = \"@rpath\";\n\t\t\t\tFRAMEWORK_SEARCH_PATHS = \"$(PROJECT_DIR)/Carthage/Build/watchOS\";\n\t\t\t\tINFOPLIST_FILE = ./Framework/Info.plist;\n\t\t\t\tINSTALL_PATH = \"$(LOCAL_LIBRARY_DIR)/Frameworks\";\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks @loader_path/Frameworks\";\n\t\t\t\tMACOSX_DEPLOYMENT_TARGET = 10.9;\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"com.fenbi.YTKNetwork-watchOS\";\n\t\t\t\tPRODUCT_NAME = YTKNetwork;\n\t\t\t\tSDKROOT = watchos;\n\t\t\t\tSKIP_INSTALL = YES;\n\t\t\t\tTARGETED_DEVICE_FAMILY = 4;\n\t\t\t\tTVOS_DEPLOYMENT_TARGET = 9.0;\n\t\t\t\tWATCHOS_DEPLOYMENT_TARGET = 2.0;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t2D58ADE41D59973D00FA6347 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\t\"CODE_SIGN_IDENTITY[sdk=appletvos*]\" = \"\";\n\t\t\t\tDEFINES_MODULE = YES;\n\t\t\t\tDYLIB_COMPATIBILITY_VERSION = 1;\n\t\t\t\tDYLIB_CURRENT_VERSION = 1;\n\t\t\t\tDYLIB_INSTALL_NAME_BASE = \"@rpath\";\n\t\t\t\tFRAMEWORK_SEARCH_PATHS = \"$(PROJECT_DIR)/Carthage/Build/tvOS\";\n\t\t\t\tINFOPLIST_FILE = ./Framework/Info.plist;\n\t\t\t\tINSTALL_PATH = \"$(LOCAL_LIBRARY_DIR)/Frameworks\";\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 8.0;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks @loader_path/Frameworks\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"com.fenbi.YTKNetwork-tvOS\";\n\t\t\t\tPRODUCT_NAME = YTKNetwork;\n\t\t\t\tSDKROOT = appletvos;\n\t\t\t\tSKIP_INSTALL = YES;\n\t\t\t\tTARGETED_DEVICE_FAMILY = 3;\n\t\t\t\tTVOS_DEPLOYMENT_TARGET = 9.0;\n\t\t\t\tWATCHOS_DEPLOYMENT_TARGET = 2.0;\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t2D58ADE51D59973D00FA6347 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\t\"CODE_SIGN_IDENTITY[sdk=appletvos*]\" = \"\";\n\t\t\t\tDEFINES_MODULE = YES;\n\t\t\t\tDYLIB_COMPATIBILITY_VERSION = 1;\n\t\t\t\tDYLIB_CURRENT_VERSION = 1;\n\t\t\t\tDYLIB_INSTALL_NAME_BASE = \"@rpath\";\n\t\t\t\tFRAMEWORK_SEARCH_PATHS = \"$(PROJECT_DIR)/Carthage/Build/tvOS\";\n\t\t\t\tINFOPLIST_FILE = ./Framework/Info.plist;\n\t\t\t\tINSTALL_PATH = \"$(LOCAL_LIBRARY_DIR)/Frameworks\";\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 8.0;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks @loader_path/Frameworks\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"com.fenbi.YTKNetwork-tvOS\";\n\t\t\t\tPRODUCT_NAME = YTKNetwork;\n\t\t\t\tSDKROOT = appletvos;\n\t\t\t\tSKIP_INSTALL = YES;\n\t\t\t\tTARGETED_DEVICE_FAMILY = 3;\n\t\t\t\tTVOS_DEPLOYMENT_TARGET = 9.0;\n\t\t\t\tWATCHOS_DEPLOYMENT_TARGET = 2.0;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t2D58ADE71D59973D00FA6347 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tCODE_SIGN_IDENTITY = \"\";\n\t\t\t\tFRAMEWORK_SEARCH_PATHS = \"$(PROJECT_DIR)/Carthage/Build/tvOS\";\n\t\t\t\tHEADER_SEARCH_PATHS = \"$(PROJECT_DIR)/Carthage/Build/tvOS/AFNetworking.framework/Headers\";\n\t\t\t\tINFOPLIST_FILE = ./YTKNetworkTests/Info.plist;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks @loader_path/Frameworks\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"com.fenbi.YTKNetwork-tvOSTests\";\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSDKROOT = appletvos;\n\t\t\t\tTVOS_DEPLOYMENT_TARGET = 9.2;\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t2D58ADE81D59973D00FA6347 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tCODE_SIGN_IDENTITY = \"\";\n\t\t\t\tFRAMEWORK_SEARCH_PATHS = \"$(PROJECT_DIR)/Carthage/Build/tvOS\";\n\t\t\t\tHEADER_SEARCH_PATHS = \"$(PROJECT_DIR)/Carthage/Build/tvOS/AFNetworking.framework/Headers\";\n\t\t\t\tINFOPLIST_FILE = ./YTKNetworkTests/Info.plist;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks @loader_path/Frameworks\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"com.fenbi.YTKNetwork-tvOSTests\";\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSDKROOT = appletvos;\n\t\t\t\tTVOS_DEPLOYMENT_TARGET = 9.2;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t2DC79A761D599B0F00197527 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCODE_SIGN_IDENTITY = \"\";\n\t\t\t\tCOMBINE_HIDPI_IMAGES = YES;\n\t\t\t\tDEFINES_MODULE = YES;\n\t\t\t\tDYLIB_COMPATIBILITY_VERSION = 1;\n\t\t\t\tDYLIB_CURRENT_VERSION = 1;\n\t\t\t\tDYLIB_INSTALL_NAME_BASE = \"@rpath\";\n\t\t\t\tFRAMEWORK_SEARCH_PATHS = \"$(PROJECT_DIR)/Carthage/Build/Mac\";\n\t\t\t\tFRAMEWORK_VERSION = A;\n\t\t\t\tINFOPLIST_FILE = ./Framework/Info.plist;\n\t\t\t\tINSTALL_PATH = \"$(LOCAL_LIBRARY_DIR)/Frameworks\";\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 8.0;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/../Frameworks @loader_path/Frameworks\";\n\t\t\t\tMACOSX_DEPLOYMENT_TARGET = 10.9;\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"com.fenbi.YTKNetwork-macOS\";\n\t\t\t\tPRODUCT_NAME = YTKNetwork;\n\t\t\t\tSDKROOT = macosx;\n\t\t\t\tSKIP_INSTALL = YES;\n\t\t\t\tTVOS_DEPLOYMENT_TARGET = 9.0;\n\t\t\t\tWATCHOS_DEPLOYMENT_TARGET = 2.0;\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t2DC79A771D599B0F00197527 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCODE_SIGN_IDENTITY = \"\";\n\t\t\t\tCOMBINE_HIDPI_IMAGES = YES;\n\t\t\t\tDEFINES_MODULE = YES;\n\t\t\t\tDYLIB_COMPATIBILITY_VERSION = 1;\n\t\t\t\tDYLIB_CURRENT_VERSION = 1;\n\t\t\t\tDYLIB_INSTALL_NAME_BASE = \"@rpath\";\n\t\t\t\tFRAMEWORK_SEARCH_PATHS = \"$(PROJECT_DIR)/Carthage/Build/Mac\";\n\t\t\t\tFRAMEWORK_VERSION = A;\n\t\t\t\tINFOPLIST_FILE = ./Framework/Info.plist;\n\t\t\t\tINSTALL_PATH = \"$(LOCAL_LIBRARY_DIR)/Frameworks\";\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 8.0;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/../Frameworks @loader_path/Frameworks\";\n\t\t\t\tMACOSX_DEPLOYMENT_TARGET = 10.9;\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"com.fenbi.YTKNetwork-macOS\";\n\t\t\t\tPRODUCT_NAME = YTKNetwork;\n\t\t\t\tSDKROOT = macosx;\n\t\t\t\tSKIP_INSTALL = YES;\n\t\t\t\tTVOS_DEPLOYMENT_TARGET = 9.0;\n\t\t\t\tWATCHOS_DEPLOYMENT_TARGET = 2.0;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t2DC79A781D599B0F00197527 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCODE_SIGN_IDENTITY = \"\";\n\t\t\t\tCOMBINE_HIDPI_IMAGES = YES;\n\t\t\t\tFRAMEWORK_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"$(PROJECT_DIR)/Carthage/Build/Mac\",\n\t\t\t\t);\n\t\t\t\tHEADER_SEARCH_PATHS = \"$(PROJECT_DIR)/Carthage/Build/Mac/AFNetworking.framework/Headers\";\n\t\t\t\tINFOPLIST_FILE = ./YTKNetworkTests/Info.plist;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks\";\n\t\t\t\tMACOSX_DEPLOYMENT_TARGET = 10.11;\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"com.fenbi.YTKNetwork-macOSTests\";\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSDKROOT = macosx;\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t2DC79A791D599B0F00197527 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCODE_SIGN_IDENTITY = \"\";\n\t\t\t\tCOMBINE_HIDPI_IMAGES = YES;\n\t\t\t\tFRAMEWORK_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"$(PROJECT_DIR)/Carthage/Build/Mac\",\n\t\t\t\t);\n\t\t\t\tHEADER_SEARCH_PATHS = \"$(PROJECT_DIR)/Carthage/Build/Mac/AFNetworking.framework/Headers\";\n\t\t\t\tINFOPLIST_FILE = ./YTKNetworkTests/Info.plist;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks\";\n\t\t\t\tMACOSX_DEPLOYMENT_TARGET = 10.11;\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"com.fenbi.YTKNetwork-macOSTests\";\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSDKROOT = macosx;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n/* End XCBuildConfiguration section */\n\n/* Begin XCConfigurationList section */\n\t\t2D244E031D4ED6460031202D /* Build configuration list for PBXProject \"YTKNetwork\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t2D244E1B1D4ED6470031202D /* Debug */,\n\t\t\t\t2D244E1C1D4ED6470031202D /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t2D244E1D1D4ED6470031202D /* Build configuration list for PBXNativeTarget \"YTKNetwork iOS\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t2D244E1E1D4ED6470031202D /* Debug */,\n\t\t\t\t2D244E1F1D4ED6470031202D /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t2D244E201D4ED6470031202D /* Build configuration list for PBXNativeTarget \"YTKNetwork iOSTests\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t2D244E211D4ED6470031202D /* Debug */,\n\t\t\t\t2D244E221D4ED6470031202D /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t2D58ADB61D598FE700FA6347 /* Build configuration list for PBXNativeTarget \"YTKNetwork watchOS\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t2D58ADB41D598FE700FA6347 /* Debug */,\n\t\t\t\t2D58ADB51D598FE700FA6347 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t2D58ADE31D59973D00FA6347 /* Build configuration list for PBXNativeTarget \"YTKNetwork tvOS\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t2D58ADE41D59973D00FA6347 /* Debug */,\n\t\t\t\t2D58ADE51D59973D00FA6347 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t2D58ADE61D59973D00FA6347 /* Build configuration list for PBXNativeTarget \"YTKNetwork tvOSTests\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t2D58ADE71D59973D00FA6347 /* Debug */,\n\t\t\t\t2D58ADE81D59973D00FA6347 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t2DC79A7A1D599B0F00197527 /* Build configuration list for PBXNativeTarget \"YTKNetwork macOS\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t2DC79A761D599B0F00197527 /* Debug */,\n\t\t\t\t2DC79A771D599B0F00197527 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t2DC79A7B1D599B0F00197527 /* Build configuration list for PBXNativeTarget \"YTKNetwork macOSTests\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t2DC79A781D599B0F00197527 /* Debug */,\n\t\t\t\t2DC79A791D599B0F00197527 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n/* End XCConfigurationList section */\n\t};\n\trootObject = 2D244E001D4ED6460031202D /* Project object */;\n}\n"
  },
  {
    "path": "YTKNetwork.xcodeproj/project.xcworkspace/contents.xcworkspacedata",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Workspace\n   version = \"1.0\">\n   <FileRef\n      location = \"self:YTKNetwork.xcodeproj\">\n   </FileRef>\n</Workspace>\n"
  },
  {
    "path": "YTKNetwork.xcodeproj/xcshareddata/xcschemes/YTKNetwork iOS.xcscheme",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"0800\"\n   version = \"1.3\">\n   <BuildAction\n      parallelizeBuildables = \"YES\"\n      buildImplicitDependencies = \"YES\">\n      <BuildActionEntries>\n         <BuildActionEntry\n            buildForTesting = \"YES\"\n            buildForRunning = \"YES\"\n            buildForProfiling = \"YES\"\n            buildForArchiving = \"YES\"\n            buildForAnalyzing = \"YES\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"2D244E081D4ED6470031202D\"\n               BuildableName = \"YTKNetwork.framework\"\n               BlueprintName = \"YTKNetwork iOS\"\n               ReferencedContainer = \"container:YTKNetwork.xcodeproj\">\n            </BuildableReference>\n         </BuildActionEntry>\n      </BuildActionEntries>\n   </BuildAction>\n   <TestAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\">\n      <Testables>\n         <TestableReference\n            skipped = \"NO\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"2D244E121D4ED6470031202D\"\n               BuildableName = \"YTKNetwork iOSTests.xctest\"\n               BlueprintName = \"YTKNetwork iOSTests\"\n               ReferencedContainer = \"container:YTKNetwork.xcodeproj\">\n            </BuildableReference>\n         </TestableReference>\n      </Testables>\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"2D244E081D4ED6470031202D\"\n            BuildableName = \"YTKNetwork.framework\"\n            BlueprintName = \"YTKNetwork iOS\"\n            ReferencedContainer = \"container:YTKNetwork.xcodeproj\">\n         </BuildableReference>\n      </MacroExpansion>\n      <AdditionalOptions>\n      </AdditionalOptions>\n   </TestAction>\n   <LaunchAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      launchStyle = \"0\"\n      useCustomWorkingDirectory = \"NO\"\n      ignoresPersistentStateOnLaunch = \"NO\"\n      debugDocumentVersioning = \"YES\"\n      debugServiceExtension = \"internal\"\n      allowLocationSimulation = \"YES\">\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"2D244E081D4ED6470031202D\"\n            BuildableName = \"YTKNetwork.framework\"\n            BlueprintName = \"YTKNetwork iOS\"\n            ReferencedContainer = \"container:YTKNetwork.xcodeproj\">\n         </BuildableReference>\n      </MacroExpansion>\n      <AdditionalOptions>\n      </AdditionalOptions>\n   </LaunchAction>\n   <ProfileAction\n      buildConfiguration = \"Release\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\"\n      savedToolIdentifier = \"\"\n      useCustomWorkingDirectory = \"NO\"\n      debugDocumentVersioning = \"YES\">\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"2D244E081D4ED6470031202D\"\n            BuildableName = \"YTKNetwork.framework\"\n            BlueprintName = \"YTKNetwork iOS\"\n            ReferencedContainer = \"container:YTKNetwork.xcodeproj\">\n         </BuildableReference>\n      </MacroExpansion>\n   </ProfileAction>\n   <AnalyzeAction\n      buildConfiguration = \"Debug\">\n   </AnalyzeAction>\n   <ArchiveAction\n      buildConfiguration = \"Release\"\n      revealArchiveInOrganizer = \"YES\">\n   </ArchiveAction>\n</Scheme>\n"
  },
  {
    "path": "YTKNetwork.xcodeproj/xcshareddata/xcschemes/YTKNetwork macOS.xcscheme",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"0800\"\n   version = \"1.3\">\n   <BuildAction\n      parallelizeBuildables = \"YES\"\n      buildImplicitDependencies = \"YES\">\n      <BuildActionEntries>\n         <BuildActionEntry\n            buildForTesting = \"YES\"\n            buildForRunning = \"YES\"\n            buildForProfiling = \"YES\"\n            buildForArchiving = \"YES\"\n            buildForAnalyzing = \"YES\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"2DC79A641D599B0F00197527\"\n               BuildableName = \"YTKNetwork.framework\"\n               BlueprintName = \"YTKNetwork macOS\"\n               ReferencedContainer = \"container:YTKNetwork.xcodeproj\">\n            </BuildableReference>\n         </BuildActionEntry>\n      </BuildActionEntries>\n   </BuildAction>\n   <TestAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\">\n      <Testables>\n         <TestableReference\n            skipped = \"NO\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"2DC79A6C1D599B0F00197527\"\n               BuildableName = \"YTKNetwork macOSTests.xctest\"\n               BlueprintName = \"YTKNetwork macOSTests\"\n               ReferencedContainer = \"container:YTKNetwork.xcodeproj\">\n            </BuildableReference>\n         </TestableReference>\n      </Testables>\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"2DC79A641D599B0F00197527\"\n            BuildableName = \"YTKNetwork.framework\"\n            BlueprintName = \"YTKNetwork macOS\"\n            ReferencedContainer = \"container:YTKNetwork.xcodeproj\">\n         </BuildableReference>\n      </MacroExpansion>\n      <AdditionalOptions>\n      </AdditionalOptions>\n   </TestAction>\n   <LaunchAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      launchStyle = \"0\"\n      useCustomWorkingDirectory = \"NO\"\n      ignoresPersistentStateOnLaunch = \"NO\"\n      debugDocumentVersioning = \"YES\"\n      debugServiceExtension = \"internal\"\n      allowLocationSimulation = \"YES\">\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"2DC79A641D599B0F00197527\"\n            BuildableName = \"YTKNetwork.framework\"\n            BlueprintName = \"YTKNetwork macOS\"\n            ReferencedContainer = \"container:YTKNetwork.xcodeproj\">\n         </BuildableReference>\n      </MacroExpansion>\n      <AdditionalOptions>\n      </AdditionalOptions>\n   </LaunchAction>\n   <ProfileAction\n      buildConfiguration = \"Release\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\"\n      savedToolIdentifier = \"\"\n      useCustomWorkingDirectory = \"NO\"\n      debugDocumentVersioning = \"YES\">\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"2DC79A641D599B0F00197527\"\n            BuildableName = \"YTKNetwork.framework\"\n            BlueprintName = \"YTKNetwork macOS\"\n            ReferencedContainer = \"container:YTKNetwork.xcodeproj\">\n         </BuildableReference>\n      </MacroExpansion>\n   </ProfileAction>\n   <AnalyzeAction\n      buildConfiguration = \"Debug\">\n   </AnalyzeAction>\n   <ArchiveAction\n      buildConfiguration = \"Release\"\n      revealArchiveInOrganizer = \"YES\">\n   </ArchiveAction>\n</Scheme>\n"
  },
  {
    "path": "YTKNetwork.xcodeproj/xcshareddata/xcschemes/YTKNetwork tvOS.xcscheme",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"0800\"\n   version = \"1.3\">\n   <BuildAction\n      parallelizeBuildables = \"YES\"\n      buildImplicitDependencies = \"YES\">\n      <BuildActionEntries>\n         <BuildActionEntry\n            buildForTesting = \"YES\"\n            buildForRunning = \"YES\"\n            buildForProfiling = \"YES\"\n            buildForArchiving = \"YES\"\n            buildForAnalyzing = \"YES\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"2D58ADD11D59973D00FA6347\"\n               BuildableName = \"YTKNetwork.framework\"\n               BlueprintName = \"YTKNetwork tvOS\"\n               ReferencedContainer = \"container:YTKNetwork.xcodeproj\">\n            </BuildableReference>\n         </BuildActionEntry>\n      </BuildActionEntries>\n   </BuildAction>\n   <TestAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\">\n      <Testables>\n         <TestableReference\n            skipped = \"NO\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"2D58ADDA1D59973D00FA6347\"\n               BuildableName = \"YTKNetwork tvOSTests.xctest\"\n               BlueprintName = \"YTKNetwork tvOSTests\"\n               ReferencedContainer = \"container:YTKNetwork.xcodeproj\">\n            </BuildableReference>\n         </TestableReference>\n      </Testables>\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"2D58ADD11D59973D00FA6347\"\n            BuildableName = \"YTKNetwork.framework\"\n            BlueprintName = \"YTKNetwork tvOS\"\n            ReferencedContainer = \"container:YTKNetwork.xcodeproj\">\n         </BuildableReference>\n      </MacroExpansion>\n      <AdditionalOptions>\n      </AdditionalOptions>\n   </TestAction>\n   <LaunchAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      launchStyle = \"0\"\n      useCustomWorkingDirectory = \"NO\"\n      ignoresPersistentStateOnLaunch = \"NO\"\n      debugDocumentVersioning = \"YES\"\n      debugServiceExtension = \"internal\"\n      allowLocationSimulation = \"YES\">\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"2D58ADD11D59973D00FA6347\"\n            BuildableName = \"YTKNetwork.framework\"\n            BlueprintName = \"YTKNetwork tvOS\"\n            ReferencedContainer = \"container:YTKNetwork.xcodeproj\">\n         </BuildableReference>\n      </MacroExpansion>\n      <AdditionalOptions>\n      </AdditionalOptions>\n   </LaunchAction>\n   <ProfileAction\n      buildConfiguration = \"Release\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\"\n      savedToolIdentifier = \"\"\n      useCustomWorkingDirectory = \"NO\"\n      debugDocumentVersioning = \"YES\">\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"2D58ADD11D59973D00FA6347\"\n            BuildableName = \"YTKNetwork.framework\"\n            BlueprintName = \"YTKNetwork tvOS\"\n            ReferencedContainer = \"container:YTKNetwork.xcodeproj\">\n         </BuildableReference>\n      </MacroExpansion>\n   </ProfileAction>\n   <AnalyzeAction\n      buildConfiguration = \"Debug\">\n   </AnalyzeAction>\n   <ArchiveAction\n      buildConfiguration = \"Release\"\n      revealArchiveInOrganizer = \"YES\">\n   </ArchiveAction>\n</Scheme>\n"
  },
  {
    "path": "YTKNetwork.xcodeproj/xcshareddata/xcschemes/YTKNetwork watchOS.xcscheme",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"0800\"\n   version = \"1.3\">\n   <BuildAction\n      parallelizeBuildables = \"YES\"\n      buildImplicitDependencies = \"YES\">\n      <BuildActionEntries>\n         <BuildActionEntry\n            buildForTesting = \"YES\"\n            buildForRunning = \"YES\"\n            buildForProfiling = \"YES\"\n            buildForArchiving = \"YES\"\n            buildForAnalyzing = \"YES\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"2D58ADAE1D598FE700FA6347\"\n               BuildableName = \"YTKNetwork.framework\"\n               BlueprintName = \"YTKNetwork watchOS\"\n               ReferencedContainer = \"container:YTKNetwork.xcodeproj\">\n            </BuildableReference>\n         </BuildActionEntry>\n      </BuildActionEntries>\n   </BuildAction>\n   <TestAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\">\n      <Testables>\n      </Testables>\n      <AdditionalOptions>\n      </AdditionalOptions>\n   </TestAction>\n   <LaunchAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      launchStyle = \"0\"\n      useCustomWorkingDirectory = \"NO\"\n      ignoresPersistentStateOnLaunch = \"NO\"\n      debugDocumentVersioning = \"YES\"\n      debugServiceExtension = \"internal\"\n      allowLocationSimulation = \"YES\">\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"2D58ADAE1D598FE700FA6347\"\n            BuildableName = \"YTKNetwork.framework\"\n            BlueprintName = \"YTKNetwork watchOS\"\n            ReferencedContainer = \"container:YTKNetwork.xcodeproj\">\n         </BuildableReference>\n      </MacroExpansion>\n      <AdditionalOptions>\n      </AdditionalOptions>\n   </LaunchAction>\n   <ProfileAction\n      buildConfiguration = \"Release\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\"\n      savedToolIdentifier = \"\"\n      useCustomWorkingDirectory = \"NO\"\n      debugDocumentVersioning = \"YES\">\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"2D58ADAE1D598FE700FA6347\"\n            BuildableName = \"YTKNetwork.framework\"\n            BlueprintName = \"YTKNetwork watchOS\"\n            ReferencedContainer = \"container:YTKNetwork.xcodeproj\">\n         </BuildableReference>\n      </MacroExpansion>\n   </ProfileAction>\n   <AnalyzeAction\n      buildConfiguration = \"Debug\">\n   </AnalyzeAction>\n   <ArchiveAction\n      buildConfiguration = \"Release\"\n      revealArchiveInOrganizer = \"YES\">\n   </ArchiveAction>\n</Scheme>\n"
  },
  {
    "path": "YTKNetworkDemo/Accessory/YTKAnimatingRequestAccessory.h",
    "content": "//\n//  YTKAnimatingRequestAccessory.h\n//  Ape_uni\n//\n//  Created by Chenyu Lan on 10/30/14.\n//  Copyright (c) 2014 Fenbi. All rights reserved.\n//\n\n#import <UIKit/UIKit.h>\n\n#import \"YTKBaseRequest.h\"\n\n@interface YTKAnimatingRequestAccessory : NSObject <YTKRequestAccessory>\n\n@property(nonatomic, weak) UIView *animatingView;\n\n@property(nonatomic, strong) NSString *animatingText;\n\n- (id)initWithAnimatingView:(UIView *)animatingView;\n\n- (id)initWithAnimatingView:(UIView *)animatingView animatingText:(NSString *)animatingText;\n\n+ (id)accessoryWithAnimatingView:(UIView *)animatingView;\n\n+ (id)accessoryWithAnimatingView:(UIView *)animatingView animatingText:(NSString *)animatingText;\n\n@end\n"
  },
  {
    "path": "YTKNetworkDemo/Accessory/YTKAnimatingRequestAccessory.m",
    "content": "//\n//  YTKAnimatingRequestAccessory.m\n//  Ape_uni\n//\n//  Created by Chenyu Lan on 10/30/14.\n//  Copyright (c) 2014 Fenbi. All rights reserved.\n//\n\n#import \"YTKAnimatingRequestAccessory.h\"\n//#import \"YTKAlertUtils.h\"\n\n\n@implementation YTKAnimatingRequestAccessory\n\n- (id)initWithAnimatingView:(UIView *)animatingView animatingText:(NSString *)animatingText {\n    self = [super init];\n    if (self) {\n        _animatingView = animatingView;\n        _animatingText = animatingText;\n    }\n    return self;\n}\n\n- (id)initWithAnimatingView:(UIView *)animatingView {\n    self = [super init];\n    if (self) {\n        _animatingView = animatingView;\n    }\n    return self;\n}\n\n+ (id)accessoryWithAnimatingView:(UIView *)animatingView {\n    return [[self alloc] initWithAnimatingView:animatingView];\n}\n\n+ (id)accessoryWithAnimatingView:(UIView *)animatingView animatingText:(NSString *)animatingText {\n    return [[self alloc] initWithAnimatingView:animatingView animatingText:animatingText];\n}\n\n- (void)requestWillStart:(id)request {\n    if (_animatingView) {\n        dispatch_async(dispatch_get_main_queue(), ^{\n            // TODO: show loading\n            // [YTKAlertUtils showLoadingAlertView:_animatingText inView:_animatingView];\n            NSLog(@\" loading start\");\n        });\n    }\n}\n\n- (void)requestWillStop:(id)request {\n    if (_animatingView) {\n        dispatch_async(dispatch_get_main_queue(), ^{\n            // TODO: hide loading\n            //[YTKAlertUtils hideLoadingAlertView:_animatingView];\n            NSLog(@\" loading finished\");\n        });\n    }\n}\n\n@end\n"
  },
  {
    "path": "YTKNetworkDemo/Accessory/YTKBaseRequest+AnimatingAccessory.h",
    "content": "//\n// Created by Chenyu Lan on 10/30/14.\n// Copyright (c) 2014 Fenbi. All rights reserved.\n//\n\n#import <Foundation/Foundation.h>\n#import <UIKit/UIKit.h>\n#import \"YTKBaseRequest.h\"\n\n@interface YTKBaseRequest (AnimatingAccessory)\n\n@property (weak, nonatomic) UIView *animatingView;\n\n@property (strong, nonatomic) NSString *animatingText;\n\n@end\n"
  },
  {
    "path": "YTKNetworkDemo/Accessory/YTKBaseRequest+AnimatingAccessory.m",
    "content": "//\n// Created by Chenyu Lan on 10/30/14.\n// Copyright (c) 2014 Fenbi. All rights reserved.\n//\n\n#import \"YTKBaseRequest+AnimatingAccessory.h\"\n#import \"YTKAnimatingRequestAccessory.h\"\n\n\n@implementation YTKBaseRequest (AnimatingAccessory)\n\n- (YTKAnimatingRequestAccessory *)animatingRequestAccessory {\n    for (id accessory in self.requestAccessories) {\n        if ([accessory isKindOfClass:[YTKAnimatingRequestAccessory class]]){\n            return accessory;\n        }\n    }\n    return nil;\n}\n\n- (UIView *)animatingView {\n    return self.animatingRequestAccessory.animatingView;\n}\n\n- (void)setAnimatingView:(UIView *)animatingView {\n    if (!self.animatingRequestAccessory) {\n        [self addAccessory:[YTKAnimatingRequestAccessory accessoryWithAnimatingView:animatingView animatingText:nil]];\n    } else {\n        self.animatingRequestAccessory.animatingView = animatingView;\n    }\n}\n\n- (NSString *)animatingText {\n    return self.animatingRequestAccessory.animatingText;\n}\n\n- (void)setAnimatingText:(NSString *)animatingText {\n    if (!self.animatingRequestAccessory) {\n        [self addAccessory:[YTKAnimatingRequestAccessory accessoryWithAnimatingView:nil animatingText:animatingText]];\n    } else {\n        self.animatingRequestAccessory.animatingText = animatingText;\n    }\n}\n\n@end\n"
  },
  {
    "path": "YTKNetworkDemo/Accessory/YTKBatchRequest+AnimatingAccessory.h",
    "content": "//\n// Created by Chenyu Lan on 10/30/14.\n// Copyright (c) 2014 Fenbi. All rights reserved.\n//\n\n#import <Foundation/Foundation.h>\n#import <UIKit/UIKit.h>\n#import \"YTKBatchRequest.h\"\n\n@interface YTKBatchRequest (AnimatingAccessory)\n\n@property (weak, nonatomic) UIView *animatingView;\n\n@property (strong, nonatomic) NSString *animatingText;\n\n@end\n"
  },
  {
    "path": "YTKNetworkDemo/Accessory/YTKBatchRequest+AnimatingAccessory.m",
    "content": "//\n// Created by Chenyu Lan on 10/30/14.\n// Copyright (c) 2014 Fenbi. All rights reserved.\n//\n\n#import \"YTKBatchRequest+AnimatingAccessory.h\"\n#import \"YTKAnimatingRequestAccessory.h\"\n\n\n@implementation YTKBatchRequest (AnimatingAccessory)\n\n- (YTKAnimatingRequestAccessory *)animatingRequestAccessory {\n    for (id accessory in self.requestAccessories) {\n        if ([accessory isKindOfClass:[YTKAnimatingRequestAccessory class]]){\n            return accessory;\n        }\n    }\n    return nil;\n}\n\n- (UIView *)animatingView {\n    return self.animatingRequestAccessory.animatingView;\n}\n\n- (void)setAnimatingView:(UIView *)animatingView {\n    if (!self.animatingRequestAccessory) {\n        [self addAccessory:[YTKAnimatingRequestAccessory accessoryWithAnimatingView:animatingView animatingText:nil]];\n    } else {\n        self.animatingRequestAccessory.animatingView = animatingView;\n    }\n}\n\n- (NSString *)animatingText {\n    return self.animatingRequestAccessory.animatingText;\n}\n\n- (void)setAnimatingText:(NSString *)animatingText {\n    if (!self.animatingRequestAccessory) {\n        [self addAccessory:[YTKAnimatingRequestAccessory accessoryWithAnimatingView:nil animatingText:animatingText]];\n    } else {\n        self.animatingRequestAccessory.animatingText = animatingText;\n    }\n}\n\n@end\n"
  },
  {
    "path": "YTKNetworkDemo/Accessory/YTKChainRequest+AnimatingAccessory.h",
    "content": "//\n// Created by Chenyu Lan on 10/30/14.\n// Copyright (c) 2014 Fenbi. All rights reserved.\n//\n\n#import <Foundation/Foundation.h>\n#import <UIKit/UIKit.h>\n#import \"YTKChainRequest.h\"\n\n@interface YTKChainRequest (AnimatingAccessory)\n\n@property (weak, nonatomic) UIView *animatingView;\n\n@property (strong, nonatomic) NSString *animatingText;\n\n@end\n"
  },
  {
    "path": "YTKNetworkDemo/Accessory/YTKChainRequest+AnimatingAccessory.m",
    "content": "//\n// Created by Chenyu Lan on 10/30/14.\n// Copyright (c) 2014 Fenbi. All rights reserved.\n//\n\n#import \"YTKChainRequest+AnimatingAccessory.h\"\n#import \"YTKAnimatingRequestAccessory.h\"\n\n\n@implementation YTKChainRequest (AnimatingAccessory)\n\n- (YTKAnimatingRequestAccessory *)animatingRequestAccessory {\n    for (id accessory in self.requestAccessories) {\n        if ([accessory isKindOfClass:[YTKAnimatingRequestAccessory class]]){\n            return accessory;\n        }\n    }\n    return nil;\n}\n\n- (UIView *)animatingView {\n    return self.animatingRequestAccessory.animatingView;\n}\n\n- (void)setAnimatingView:(UIView *)animatingView {\n    if (!self.animatingRequestAccessory) {\n        [self addAccessory:[YTKAnimatingRequestAccessory accessoryWithAnimatingView:animatingView animatingText:nil]];\n    } else {\n        self.animatingRequestAccessory.animatingView = animatingView;\n    }\n}\n\n- (NSString *)animatingText {\n    return self.animatingRequestAccessory.animatingText;\n}\n\n- (void)setAnimatingText:(NSString *)animatingText {\n    if (!self.animatingRequestAccessory) {\n        [self addAccessory:[YTKAnimatingRequestAccessory accessoryWithAnimatingView:nil animatingText:animatingText]];\n    } else {\n        self.animatingRequestAccessory.animatingText = animatingText;\n    }\n}\n\n@end\n"
  },
  {
    "path": "YTKNetworkDemo/Podfile",
    "content": "target 'YTKNetworkDemo' do\n    pod 'YTKNetwork', :path => '../'\n    pod 'AFNetworking', '~> 4.0'\nend\n\ntarget 'YTKNetworkDemoTests' do\n    pod 'YTKNetwork', :path => '../'\nend\n\n"
  },
  {
    "path": "YTKNetworkDemo/YTKNetworkDemo/AppDelegate.h",
    "content": "//\n//  AppDelegate.h\n//  YTKNetworkDemo\n//\n//  Created by Chenyu Lan on 10/28/14.\n//  Copyright (c) 2014 yuantiku.com. All rights reserved.\n//\n\n#import <UIKit/UIKit.h>\n\n@interface AppDelegate : UIResponder <UIApplicationDelegate>\n\n@property (strong, nonatomic) UIWindow *window;\n\n\n@end\n\n"
  },
  {
    "path": "YTKNetworkDemo/YTKNetworkDemo/AppDelegate.m",
    "content": "//\n//  AppDelegate.m\n//  YTKNetworkDemo\n//\n//  Created by Chenyu Lan on 10/28/14.\n//  Copyright (c) 2014 yuantiku.com. All rights reserved.\n//\n\n#import \"AppDelegate.h\"\n#import \"YTKNetworkConfig.h\"\n#import \"YTKUrlArgumentsFilter.h\"\n\n@interface AppDelegate ()\n\n@end\n\n@implementation AppDelegate\n\n- (void)setupRequestFilters {\n    NSString *appVersion = [[[NSBundle mainBundle] infoDictionary] objectForKey:@\"CFBundleShortVersionString\"];\n    YTKNetworkConfig *config = [YTKNetworkConfig sharedConfig];\n    YTKUrlArgumentsFilter *urlFilter = [YTKUrlArgumentsFilter filterWithArguments:@{@\"version\": appVersion}];\n    [config addUrlFilter:urlFilter];\n}\n\n- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {\n    [self setupRequestFilters];\n    return YES;\n}\n\n- (void)applicationWillResignActive:(UIApplication *)application {\n    // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.\n    // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.\n}\n\n- (void)applicationDidEnterBackground:(UIApplication *)application {\n    // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.\n    // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.\n}\n\n- (void)applicationWillEnterForeground:(UIApplication *)application {\n    // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.\n}\n\n- (void)applicationDidBecomeActive:(UIApplication *)application {\n    // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.\n}\n\n- (void)applicationWillTerminate:(UIApplication *)application {\n    // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.\n}\n\n@end\n"
  },
  {
    "path": "YTKNetworkDemo/YTKNetworkDemo/Base.lproj/LaunchScreen.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.XIB\" version=\"3.0\" toolsVersion=\"6214\" systemVersion=\"14A314h\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" launchScreen=\"YES\" useTraitCollections=\"YES\">\n    <dependencies>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"6207\"/>\n        <capability name=\"Constraints with non-1.0 multipliers\" minToolsVersion=\"5.1\"/>\n    </dependencies>\n    <objects>\n        <placeholder placeholderIdentifier=\"IBFilesOwner\" id=\"-1\" userLabel=\"File's Owner\"/>\n        <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"-2\" customClass=\"UIResponder\"/>\n        <view contentMode=\"scaleToFill\" id=\"iN0-l3-epB\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"480\" height=\"480\"/>\n            <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n            <subviews>\n                <label opaque=\"NO\" clipsSubviews=\"YES\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"  Copyright (c) 2014 yuantiku.com. All rights reserved.\" textAlignment=\"center\" lineBreakMode=\"tailTruncation\" baselineAdjustment=\"alignBaselines\" minimumFontSize=\"9\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"8ie-xW-0ye\">\n                    <rect key=\"frame\" x=\"20\" y=\"439\" width=\"441\" height=\"21\"/>\n                    <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"17\"/>\n                    <color key=\"textColor\" cocoaTouchSystemColor=\"darkTextColor\"/>\n                    <nil key=\"highlightedColor\"/>\n                </label>\n                <label opaque=\"NO\" clipsSubviews=\"YES\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"YTKNetworkDemo\" textAlignment=\"center\" lineBreakMode=\"middleTruncation\" baselineAdjustment=\"alignBaselines\" minimumFontSize=\"18\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"kId-c2-rCX\">\n                    <rect key=\"frame\" x=\"20\" y=\"140\" width=\"441\" height=\"43\"/>\n                    <fontDescription key=\"fontDescription\" type=\"boldSystem\" pointSize=\"36\"/>\n                    <color key=\"textColor\" cocoaTouchSystemColor=\"darkTextColor\"/>\n                    <nil key=\"highlightedColor\"/>\n                </label>\n            </subviews>\n            <color key=\"backgroundColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"calibratedWhite\"/>\n            <constraints>\n                <constraint firstItem=\"kId-c2-rCX\" firstAttribute=\"centerY\" secondItem=\"iN0-l3-epB\" secondAttribute=\"bottom\" multiplier=\"1/3\" constant=\"1\" id=\"5cJ-9S-tgC\"/>\n                <constraint firstAttribute=\"centerX\" secondItem=\"kId-c2-rCX\" secondAttribute=\"centerX\" id=\"Koa-jz-hwk\"/>\n                <constraint firstAttribute=\"bottom\" secondItem=\"8ie-xW-0ye\" secondAttribute=\"bottom\" constant=\"20\" id=\"Kzo-t9-V3l\"/>\n                <constraint firstItem=\"8ie-xW-0ye\" firstAttribute=\"leading\" secondItem=\"iN0-l3-epB\" secondAttribute=\"leading\" constant=\"20\" symbolic=\"YES\" id=\"MfP-vx-nX0\"/>\n                <constraint firstAttribute=\"centerX\" secondItem=\"8ie-xW-0ye\" secondAttribute=\"centerX\" id=\"ZEH-qu-HZ9\"/>\n                <constraint firstItem=\"kId-c2-rCX\" firstAttribute=\"leading\" secondItem=\"iN0-l3-epB\" secondAttribute=\"leading\" constant=\"20\" symbolic=\"YES\" id=\"fvb-Df-36g\"/>\n            </constraints>\n            <nil key=\"simulatedStatusBarMetrics\"/>\n            <freeformSimulatedSizeMetrics key=\"simulatedDestinationMetrics\"/>\n            <point key=\"canvasLocation\" x=\"548\" y=\"455\"/>\n        </view>\n    </objects>\n</document>\n"
  },
  {
    "path": "YTKNetworkDemo/YTKNetworkDemo/Base.lproj/Main.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"6250\" systemVersion=\"14A389\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" initialViewController=\"BYZ-38-t0r\">\n    <dependencies>\n        <deployment identifier=\"iOS\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"6244\"/>\n    </dependencies>\n    <scenes>\n        <!--View Controller-->\n        <scene sceneID=\"tne-QT-ifu\">\n            <objects>\n                <viewController id=\"BYZ-38-t0r\" customClass=\"ViewController\" sceneMemberID=\"viewController\">\n                    <layoutGuides>\n                        <viewControllerLayoutGuide type=\"top\" id=\"y3c-jy-aDJ\"/>\n                        <viewControllerLayoutGuide type=\"bottom\" id=\"wfy-db-euE\"/>\n                    </layoutGuides>\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"8bC-Xf-vdC\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"320\" height=\"568\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <color key=\"backgroundColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"calibratedWhite\"/>\n                    </view>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"dkx-z0-nzr\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"132.80000000000001\" y=\"406.12\"/>\n        </scene>\n    </scenes>\n    <simulatedMetricsContainer key=\"defaultSimulatedMetrics\">\n        <simulatedStatusBarMetrics key=\"statusBar\"/>\n        <simulatedOrientationMetrics key=\"orientation\"/>\n        <simulatedScreenMetrics key=\"destination\" type=\"retina4\"/>\n    </simulatedMetricsContainer>\n</document>\n"
  },
  {
    "path": "YTKNetworkDemo/YTKNetworkDemo/GetImageApi.h",
    "content": "//\n//  GetImageApi.h\n//  YTKNetworkDemo\n//\n//  Created by TangQiao on 11/8/14.\n//  Copyright (c) 2014 yuantiku.com. All rights reserved.\n//\n\n#import \"YTKRequest.h\"\n\n@interface GetImageApi : YTKRequest\n\n- (id)initWithImageId:(NSString *)imageId;\n\n@end\n"
  },
  {
    "path": "YTKNetworkDemo/YTKNetworkDemo/GetImageApi.m",
    "content": "//\n//  GetImageApi.m\n//  YTKNetworkDemo\n//\n//  Created by TangQiao on 11/8/14.\n//  Copyright (c) 2014 yuantiku.com. All rights reserved.\n//\n\n#import \"GetImageApi.h\"\n\n@implementation GetImageApi {\n    NSString *_imageId;\n}\n\n- (id)initWithImageId:(NSString *)imageId {\n    self = [super init];\n    if (self) {\n        _imageId = imageId;\n    }\n    return self;\n}\n\n- (NSString *)requestUrl {\n    return [NSString stringWithFormat:@\"/iphone/images/%@\", _imageId];\n}\n\n- (BOOL)useCDN {\n    return YES;\n}\n\n- (NSString *)resumableDownloadPath {\n    NSString *libPath = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) objectAtIndex:0];\n    NSString *cachePath = [libPath stringByAppendingPathComponent:@\"Caches\"];\n    NSString *filePath = [cachePath stringByAppendingPathComponent:_imageId];\n    return filePath;\n}\n\n@end\n"
  },
  {
    "path": "YTKNetworkDemo/YTKNetworkDemo/GetUserInfoApi.h",
    "content": "//\n//  GetUserInfoApi.h\n//  YTKNetworkDemo\n//\n//  Created by TangQiao on 11/8/14.\n//  Copyright (c) 2014 yuantiku.com. All rights reserved.\n//\n\n#import \"YTKRequest.h\"\n\n@interface GetUserInfoApi : YTKRequest\n\n- (id)initWithUserId:(NSString *)userId;\n\n@end\n"
  },
  {
    "path": "YTKNetworkDemo/YTKNetworkDemo/GetUserInfoApi.m",
    "content": "//\n//  GetUserInfoApi.m\n//  YTKNetworkDemo\n//\n//  Created by TangQiao on 11/8/14.\n//  Copyright (c) 2014 yuantiku.com. All rights reserved.\n//\n\n#import \"GetUserInfoApi.h\"\n\n@implementation GetUserInfoApi {\n    NSString *_userId;\n}\n\n- (id)initWithUserId:(NSString *)userId {\n    self = [super init];\n    if (self) {\n        _userId = userId;\n    }\n    return self;\n}\n\n- (NSString *)requestUrl {\n    return @\"/iphone/users\";\n}\n\n- (id)requestArgument {\n    return @{ @\"id\": _userId };\n}\n\n- (id)jsonValidator {\n    return @{\n        @\"nick\": [NSString class],\n        @\"level\": [NSNumber class]\n    };\n}\n\n- (NSInteger)cacheTimeInSeconds {\n    return 60 * 3;\n}\n\n@end\n"
  },
  {
    "path": "YTKNetworkDemo/YTKNetworkDemo/Images.xcassets/AppIcon.appiconset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"60x60\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"60x60\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"76x76\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"76x76\",\n      \"scale\" : \"2x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "YTKNetworkDemo/YTKNetworkDemo/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>en</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>APPL</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>1.0</string>\n\t<key>CFBundleSignature</key>\n\t<string>????</string>\n\t<key>CFBundleVersion</key>\n\t<string>1</string>\n\t<key>LSRequiresIPhoneOS</key>\n\t<true/>\n\t<key>UILaunchStoryboardName</key>\n\t<string>LaunchScreen</string>\n\t<key>UIMainStoryboardFile</key>\n\t<string>Main</string>\n\t<key>UIRequiredDeviceCapabilities</key>\n\t<array>\n\t\t<string>armv7</string>\n\t</array>\n\t<key>UISupportedInterfaceOrientations</key>\n\t<array>\n\t\t<string>UIInterfaceOrientationPortrait</string>\n\t\t<string>UIInterfaceOrientationLandscapeLeft</string>\n\t\t<string>UIInterfaceOrientationLandscapeRight</string>\n\t</array>\n\t<key>UISupportedInterfaceOrientations~ipad</key>\n\t<array>\n\t\t<string>UIInterfaceOrientationPortrait</string>\n\t\t<string>UIInterfaceOrientationPortraitUpsideDown</string>\n\t\t<string>UIInterfaceOrientationLandscapeLeft</string>\n\t\t<string>UIInterfaceOrientationLandscapeRight</string>\n\t</array>\n</dict>\n</plist>\n"
  },
  {
    "path": "YTKNetworkDemo/YTKNetworkDemo/RegisterApi.h",
    "content": "//\n//  RegisterApi.h\n//  Solar\n//\n//  Created by TangQiao on 11/8/14.\n//  Copyright (c) 2014 fenbi. All rights reserved.\n//\n\n#import \"YTKRequest.h\"\n\n@interface RegisterApi : YTKRequest\n\n- (id)initWithUsername:(NSString *)username password:(NSString *)password;\n\n- (NSString *)userId;\n\n@end\n"
  },
  {
    "path": "YTKNetworkDemo/YTKNetworkDemo/RegisterApi.m",
    "content": "//\n//  RegisterApi.m\n//  Solar\n//\n//  Created by TangQiao on 11/8/14.\n//  Copyright (c) 2014 fenbi. All rights reserved.\n//\n\n#import \"RegisterApi.h\"\n\n@implementation RegisterApi {\n    NSString *_username;\n    NSString *_password;\n}\n\n- (id)initWithUsername:(NSString *)username password:(NSString *)password {\n    self = [super init];\n    if (self) {\n        _username = username;\n        _password = password;\n    }\n    return self;\n}\n\n- (NSString *)requestUrl {\n    return @\"/iphone/register\";\n}\n\n- (YTKRequestMethod)requestMethod {\n    return YTKRequestMethodPOST;\n}\n\n- (id)requestArgument {\n    return @{\n        @\"username\": _username,\n        @\"password\": _password\n    };\n}\n\n- (id)jsonValidator {\n    return @{\n        @\"userId\": [NSNumber class],\n        @\"nick\": [NSString class],\n        @\"level\": [NSNumber class]\n    };\n}\n\n- (NSString *)userId {\n    return [[[self responseJSONObject] objectForKey:@\"userId\"] stringValue];\n}\n\n@end\n"
  },
  {
    "path": "YTKNetworkDemo/YTKNetworkDemo/UploadImageApi.h",
    "content": "//\n//  UploadImageApi.h\n//  Solar\n//\n//  Created by tangqiao on 8/7/14.\n//  Copyright (c) 2014 fenbi. All rights reserved.\n//\n\n#import \"YTKRequest.h\"\n#import <UIKit/UIKit.h>\n\n@interface UploadImageApi : YTKRequest\n\n- (id)initWithImage:(UIImage *)image;\n\n- (NSString *)responseImageId;\n\n@end\n"
  },
  {
    "path": "YTKNetworkDemo/YTKNetworkDemo/UploadImageApi.m",
    "content": "//\n//  UploadImageApi.m\n//  Solar\n//\n//  Created by tangqiao on 8/7/14.\n//  Copyright (c) 2014 fenbi. All rights reserved.\n//\n\n#import \"UploadImageApi.h\"\n#import <AFNetworking/AFURLRequestSerialization.h>\n\n@implementation UploadImageApi {\n    UIImage *_image;\n}\n\n- (id)initWithImage:(UIImage *)image {\n    self = [super init];\n    if (self) {\n        _image = image;\n    }\n    return self;\n}\n\n- (YTKRequestMethod)requestMethod {\n    return YTKRequestMethodPOST;\n}\n\n- (NSString *)requestUrl {\n    return @\"/iphone/image/upload\";\n}\n\n- (AFConstructingBlock)constructingBodyBlock {\n    return ^(id<AFMultipartFormData> formData) {\n        NSData *data = UIImageJPEGRepresentation(_image, 0.9);\n        NSString *name = @\"image\";\n        NSString *formKey = @\"image\";\n        NSString *type = @\"image/jpeg\";\n        [formData appendPartWithFileData:data name:formKey fileName:name mimeType:type];\n    };\n}\n\n- (id)jsonValidator {\n    return @{ @\"imageId\": [NSString class] };\n}\n\n- (NSString *)responseImageId {\n    NSDictionary *dict = self.responseJSONObject;\n    return dict[@\"imageId\"];\n}\n\n@end\n"
  },
  {
    "path": "YTKNetworkDemo/YTKNetworkDemo/ViewController.h",
    "content": "//\n//  ViewController.h\n//  YTKNetworkDemo\n//\n//  Created by Chenyu Lan on 10/28/14.\n//  Copyright (c) 2014 yuantiku.com. All rights reserved.\n//\n\n#import <UIKit/UIKit.h>\n\n@interface ViewController : UIViewController\n\n\n@end\n\n"
  },
  {
    "path": "YTKNetworkDemo/YTKNetworkDemo/ViewController.m",
    "content": "//\n//  ViewController.m\n//  YTKNetworkDemo\n//\n//  Created by Chenyu Lan on 10/28/14.\n//  Copyright (c) 2014 yuantiku.com. All rights reserved.\n//\n\n#import \"ViewController.h\"\n#import \"YTKBatchRequest.h\"\n#import \"YTKChainRequest.h\"\n#import \"GetImageApi.h\"\n#import \"GetUserInfoApi.h\"\n#import \"RegisterApi.h\"\n#import \"YTKBaseRequest+AnimatingAccessory.h\"\n\n@interface ViewController ()<YTKChainRequestDelegate>\n\n@end\n\n@implementation ViewController\n\n/// Send batch request\n- (void)sendBatchRequest {\n    GetImageApi *a = [[GetImageApi alloc] initWithImageId:@\"1.jpg\"];\n    GetImageApi *b = [[GetImageApi alloc] initWithImageId:@\"2.jpg\"];\n    GetImageApi *c = [[GetImageApi alloc] initWithImageId:@\"3.jpg\"];\n    GetUserInfoApi *d = [[GetUserInfoApi alloc] initWithUserId:@\"123\"];\n    YTKBatchRequest *batchRequest = [[YTKBatchRequest alloc] initWithRequestArray:@[a, b, c, d]];\n    [batchRequest startWithCompletionBlockWithSuccess:^(YTKBatchRequest *batchRequest) {\n        NSLog(@\"succeed\");\n        NSArray *requests = batchRequest.requestArray;\n        GetImageApi *a = (GetImageApi *)requests[0];\n        GetImageApi *b = (GetImageApi *)requests[1];\n        GetImageApi *c = (GetImageApi *)requests[2];\n        GetUserInfoApi *user = (GetUserInfoApi *)requests[3];\n        // deal with requests result ...\n        NSLog(@\"%@, %@, %@, %@\", a, b, c, user);\n    } failure:^(YTKBatchRequest *batchRequest) {\n        NSLog(@\"failed\");\n    }];\n}\n\n- (void)sendChainRequest {\n    RegisterApi *reg = [[RegisterApi alloc] initWithUsername:@\"username\" password:@\"password\"];\n    YTKChainRequest *chainReq = [[YTKChainRequest alloc] init];\n    [chainReq addRequest:reg callback:^(YTKChainRequest *chainRequest, YTKBaseRequest *baseRequest) {\n        RegisterApi *result = (RegisterApi *)baseRequest;\n        NSString *userId = [result userId];\n        GetUserInfoApi *api = [[GetUserInfoApi alloc] initWithUserId:userId];\n        [chainRequest addRequest:api callback:nil];\n        \n    }];\n    chainReq.delegate = self;\n    // start to send request\n    [chainReq start];\n}\n\n- (void)chainRequestFinished:(YTKChainRequest *)chainRequest {\n    // all requests are done\n    \n}\n\n- (void)chainRequestFailed:(YTKChainRequest *)chainRequest failedBaseRequest:(YTKBaseRequest*)request {\n    // some one of request is failed\n}\n\n- (void)loadCacheData {\n    NSString *userId = @\"1\";\n    GetUserInfoApi *api = [[GetUserInfoApi alloc] initWithUserId:userId];\n    if ([api loadCacheWithError:nil]) {\n        NSDictionary *json = [api responseJSONObject];\n        NSLog(@\"json = %@\", json);\n        // show cached data\n    }\n\n    api.animatingText = @\"正在加载\";\n    api.animatingView = self.view;\n\n    [api startWithCompletionBlockWithSuccess:^(YTKBaseRequest *request) {\n        NSLog(@\"update ui\");\n    } failure:^(YTKBaseRequest *request) {\n        NSLog(@\"failed\");\n    }];\n}\n\n- (void)viewDidLoad {\n    [super viewDidLoad];\n}\n\n- (void)didReceiveMemoryWarning {\n    [super didReceiveMemoryWarning];\n    // Dispose of any resources that can be recreated.\n}\n\n@end\n"
  },
  {
    "path": "YTKNetworkDemo/YTKNetworkDemo/YTKUrlArgumentsFilter.h",
    "content": "//\n// Created by Chenyu Lan on 8/27/14.\n// Copyright (c) 2014 Fenbi. All rights reserved.\n//\n\n#import <Foundation/Foundation.h>\n#import \"YTKNetworkConfig.h\"\n#import \"YTKBaseRequest.h\"\n\n/// 给url追加arguments，用于全局参数，比如AppVersion, ApiVersion等\n@interface YTKUrlArgumentsFilter : NSObject <YTKUrlFilterProtocol>\n\n+ (YTKUrlArgumentsFilter *)filterWithArguments:(NSDictionary *)arguments;\n\n- (NSString *)filterUrl:(NSString *)originUrl withRequest:(YTKBaseRequest *)request;\n\n@end\n"
  },
  {
    "path": "YTKNetworkDemo/YTKNetworkDemo/YTKUrlArgumentsFilter.m",
    "content": "//\n// Created by Chenyu Lan on 8/27/14.\n// Copyright (c) 2014 Fenbi. All rights reserved.\n//\n\n#import \"YTKUrlArgumentsFilter.h\"\n#import \"AFURLRequestSerialization.h\"\n\n@implementation YTKUrlArgumentsFilter {\n    NSDictionary *_arguments;\n}\n\n+ (YTKUrlArgumentsFilter *)filterWithArguments:(NSDictionary *)arguments {\n    return [[self alloc] initWithArguments:arguments];\n}\n\n- (id)initWithArguments:(NSDictionary *)arguments {\n    self = [super init];\n    if (self) {\n        _arguments = arguments;\n    }\n    return self;\n}\n\n- (NSString *)filterUrl:(NSString *)originUrl withRequest:(YTKBaseRequest *)request {\n    return [self urlStringWithOriginUrlString:originUrl appendParameters:_arguments];\n}\n\n- (NSString *)urlStringWithOriginUrlString:(NSString *)originUrlString appendParameters:(NSDictionary *)parameters {\n    NSString *paraUrlString = AFQueryStringFromParameters(parameters);\n\n    if (!(paraUrlString.length > 0)) {\n        return originUrlString;\n    }\n\n    BOOL useDummyUrl = NO;\n    static NSString *dummyUrl = nil;\n    NSURLComponents *components = [NSURLComponents componentsWithString:originUrlString];\n    if (!components) {\n        useDummyUrl = YES;\n        if (!dummyUrl) {\n            dummyUrl = @\"http://www.dummy.com\";\n        }\n        components = [NSURLComponents componentsWithString:dummyUrl];\n    }\n\n    NSString *queryString = components.query ?: @\"\";\n    NSString *newQueryString = [queryString stringByAppendingFormat:queryString.length > 0 ? @\"&%@\" : @\"%@\", paraUrlString];\n\n    components.query = newQueryString;\n\n    if (useDummyUrl) {\n        return [components.URL.absoluteString substringFromIndex:dummyUrl.length - 1];\n    } else {\n        return components.URL.absoluteString;\n    }\n}\n\n@end\n"
  },
  {
    "path": "YTKNetworkDemo/YTKNetworkDemo/main.m",
    "content": "//\n//  main.m\n//  YTKNetworkDemo\n//\n//  Created by Chenyu Lan on 10/28/14.\n//  Copyright (c) 2014 yuantiku.com. All rights reserved.\n//\n\n#import <UIKit/UIKit.h>\n#import \"AppDelegate.h\"\n\nint main(int argc, char * argv[]) {\n    @autoreleasepool {\n        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));\n    }\n}\n"
  },
  {
    "path": "YTKNetworkDemo/YTKNetworkDemo.xcodeproj/project.pbxproj",
    "content": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 46;\n\tobjects = {\n\n/* Begin PBXBuildFile section */\n\t\t20D2D9721D268808009E13A2 /* YTKAnimatingRequestAccessory.m in Sources */ = {isa = PBXBuildFile; fileRef = 20D2D96B1D268808009E13A2 /* YTKAnimatingRequestAccessory.m */; };\n\t\t20D2D9731D268808009E13A2 /* YTKBaseRequest+AnimatingAccessory.m in Sources */ = {isa = PBXBuildFile; fileRef = 20D2D96D1D268808009E13A2 /* YTKBaseRequest+AnimatingAccessory.m */; };\n\t\t20D2D9741D268808009E13A2 /* YTKBatchRequest+AnimatingAccessory.m in Sources */ = {isa = PBXBuildFile; fileRef = 20D2D96F1D268808009E13A2 /* YTKBatchRequest+AnimatingAccessory.m */; };\n\t\t20D2D9751D268808009E13A2 /* YTKChainRequest+AnimatingAccessory.m in Sources */ = {isa = PBXBuildFile; fileRef = 20D2D9711D268808009E13A2 /* YTKChainRequest+AnimatingAccessory.m */; };\n\t\t25F1A00B1066754A19C74116 /* libPods-YTKNetworkDemo.a in Frameworks */ = {isa = PBXBuildFile; fileRef = F8B54B27A99DEF03E2DBB02C /* libPods-YTKNetworkDemo.a */; };\n\t\t45AB19C11A4656A600680858 /* YTKUrlArgumentsFilter.m in Sources */ = {isa = PBXBuildFile; fileRef = 45AB19C01A4656A600680858 /* YTKUrlArgumentsFilter.m */; };\n\t\t45BF1D401A0DC0A100DDB7E0 /* RegisterApi.m in Sources */ = {isa = PBXBuildFile; fileRef = 45BF1D3F1A0DC0A100DDB7E0 /* RegisterApi.m */; };\n\t\t45BF1D431A0DC40F00DDB7E0 /* GetUserInfoApi.m in Sources */ = {isa = PBXBuildFile; fileRef = 45BF1D421A0DC40F00DDB7E0 /* GetUserInfoApi.m */; };\n\t\t45BF1D461A0DC66E00DDB7E0 /* GetImageApi.m in Sources */ = {isa = PBXBuildFile; fileRef = 45BF1D451A0DC66E00DDB7E0 /* GetImageApi.m */; };\n\t\t45F710841A466D01001957BA /* UploadImageApi.m in Sources */ = {isa = PBXBuildFile; fileRef = 45F710831A466D01001957BA /* UploadImageApi.m */; };\n\t\tBF007FD919FF972C00816462 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = BF007FD819FF972C00816462 /* main.m */; };\n\t\tBF007FDC19FF972C00816462 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = BF007FDB19FF972C00816462 /* AppDelegate.m */; };\n\t\tBF007FDF19FF972C00816462 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = BF007FDE19FF972C00816462 /* ViewController.m */; };\n\t\tBF007FE219FF972C00816462 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = BF007FE019FF972C00816462 /* Main.storyboard */; };\n\t\tBF007FE419FF972C00816462 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = BF007FE319FF972C00816462 /* Images.xcassets */; };\n\t\tBF007FE719FF972C00816462 /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = BF007FE519FF972C00816462 /* LaunchScreen.xib */; };\n\t\tBF007FF319FF972C00816462 /* YTKNetworkDemoTests.m in Sources */ = {isa = PBXBuildFile; fileRef = BF007FF219FF972C00816462 /* YTKNetworkDemoTests.m */; };\n\t\tEDD64A8FB57EEC11DE6CEB4E /* libPods-YTKNetworkDemoTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 573535265CF5ECF05E1BBD90 /* libPods-YTKNetworkDemoTests.a */; };\n/* End PBXBuildFile section */\n\n/* Begin PBXContainerItemProxy section */\n\t\tBF007FED19FF972C00816462 /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = BF007FCB19FF972C00816462 /* Project object */;\n\t\t\tproxyType = 1;\n\t\t\tremoteGlobalIDString = BF007FD219FF972C00816462;\n\t\t\tremoteInfo = YTKNetworkDemo;\n\t\t};\n/* End PBXContainerItemProxy section */\n\n/* Begin PBXFileReference section */\n\t\t20D2D96A1D268808009E13A2 /* YTKAnimatingRequestAccessory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YTKAnimatingRequestAccessory.h; sourceTree = \"<group>\"; };\n\t\t20D2D96B1D268808009E13A2 /* YTKAnimatingRequestAccessory.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = YTKAnimatingRequestAccessory.m; sourceTree = \"<group>\"; };\n\t\t20D2D96C1D268808009E13A2 /* YTKBaseRequest+AnimatingAccessory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = \"YTKBaseRequest+AnimatingAccessory.h\"; sourceTree = \"<group>\"; };\n\t\t20D2D96D1D268808009E13A2 /* YTKBaseRequest+AnimatingAccessory.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = \"YTKBaseRequest+AnimatingAccessory.m\"; sourceTree = \"<group>\"; };\n\t\t20D2D96E1D268808009E13A2 /* YTKBatchRequest+AnimatingAccessory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = \"YTKBatchRequest+AnimatingAccessory.h\"; sourceTree = \"<group>\"; };\n\t\t20D2D96F1D268808009E13A2 /* YTKBatchRequest+AnimatingAccessory.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = \"YTKBatchRequest+AnimatingAccessory.m\"; sourceTree = \"<group>\"; };\n\t\t20D2D9701D268808009E13A2 /* YTKChainRequest+AnimatingAccessory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = \"YTKChainRequest+AnimatingAccessory.h\"; sourceTree = \"<group>\"; };\n\t\t20D2D9711D268808009E13A2 /* YTKChainRequest+AnimatingAccessory.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = \"YTKChainRequest+AnimatingAccessory.m\"; sourceTree = \"<group>\"; };\n\t\t45AB19BF1A4656A600680858 /* YTKUrlArgumentsFilter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YTKUrlArgumentsFilter.h; sourceTree = \"<group>\"; };\n\t\t45AB19C01A4656A600680858 /* YTKUrlArgumentsFilter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = YTKUrlArgumentsFilter.m; sourceTree = \"<group>\"; };\n\t\t45BF1D3E1A0DC0A100DDB7E0 /* RegisterApi.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RegisterApi.h; sourceTree = \"<group>\"; };\n\t\t45BF1D3F1A0DC0A100DDB7E0 /* RegisterApi.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RegisterApi.m; sourceTree = \"<group>\"; };\n\t\t45BF1D411A0DC40F00DDB7E0 /* GetUserInfoApi.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GetUserInfoApi.h; sourceTree = \"<group>\"; };\n\t\t45BF1D421A0DC40F00DDB7E0 /* GetUserInfoApi.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GetUserInfoApi.m; sourceTree = \"<group>\"; };\n\t\t45BF1D441A0DC66E00DDB7E0 /* GetImageApi.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GetImageApi.h; sourceTree = \"<group>\"; };\n\t\t45BF1D451A0DC66E00DDB7E0 /* GetImageApi.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GetImageApi.m; sourceTree = \"<group>\"; };\n\t\t45F710821A466D01001957BA /* UploadImageApi.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UploadImageApi.h; sourceTree = \"<group>\"; };\n\t\t45F710831A466D01001957BA /* UploadImageApi.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UploadImageApi.m; sourceTree = \"<group>\"; };\n\t\t573535265CF5ECF05E1BBD90 /* libPods-YTKNetworkDemoTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = \"libPods-YTKNetworkDemoTests.a\"; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t65526970D9E7FB74931FF110 /* Pods-YTKNetworkDemoTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = \"Pods-YTKNetworkDemoTests.release.xcconfig\"; path = \"Pods/Target Support Files/Pods-YTKNetworkDemoTests/Pods-YTKNetworkDemoTests.release.xcconfig\"; sourceTree = \"<group>\"; };\n\t\tBF007FD319FF972C00816462 /* YTKNetworkDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = YTKNetworkDemo.app; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\tBF007FD719FF972C00816462 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = \"<group>\"; };\n\t\tBF007FD819FF972C00816462 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = \"<group>\"; };\n\t\tBF007FDA19FF972C00816462 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = \"<group>\"; };\n\t\tBF007FDB19FF972C00816462 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = \"<group>\"; };\n\t\tBF007FDD19FF972C00816462 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = \"<group>\"; };\n\t\tBF007FDE19FF972C00816462 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = \"<group>\"; };\n\t\tBF007FE119FF972C00816462 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = \"<group>\"; };\n\t\tBF007FE319FF972C00816462 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = \"<group>\"; };\n\t\tBF007FE619FF972C00816462 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = \"<group>\"; };\n\t\tBF007FEC19FF972C00816462 /* YTKNetworkDemoTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = YTKNetworkDemoTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\tBF007FF119FF972C00816462 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = \"<group>\"; };\n\t\tBF007FF219FF972C00816462 /* YTKNetworkDemoTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = YTKNetworkDemoTests.m; sourceTree = \"<group>\"; };\n\t\tD30149728A908A3BBCCE924A /* Pods-YTKNetworkDemo.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = \"Pods-YTKNetworkDemo.release.xcconfig\"; path = \"Pods/Target Support Files/Pods-YTKNetworkDemo/Pods-YTKNetworkDemo.release.xcconfig\"; sourceTree = \"<group>\"; };\n\t\tF3A8BAC1ADCD712EF8786C33 /* Pods-YTKNetworkDemoTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = \"Pods-YTKNetworkDemoTests.debug.xcconfig\"; path = \"Pods/Target Support Files/Pods-YTKNetworkDemoTests/Pods-YTKNetworkDemoTests.debug.xcconfig\"; sourceTree = \"<group>\"; };\n\t\tF8B54B27A99DEF03E2DBB02C /* libPods-YTKNetworkDemo.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = \"libPods-YTKNetworkDemo.a\"; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\tFEEC7AA40163426AAD453013 /* Pods-YTKNetworkDemo.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = \"Pods-YTKNetworkDemo.debug.xcconfig\"; path = \"Pods/Target Support Files/Pods-YTKNetworkDemo/Pods-YTKNetworkDemo.debug.xcconfig\"; sourceTree = \"<group>\"; };\n/* End PBXFileReference section */\n\n/* Begin PBXFrameworksBuildPhase section */\n\t\tBF007FD019FF972C00816462 /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t25F1A00B1066754A19C74116 /* libPods-YTKNetworkDemo.a in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\tBF007FE919FF972C00816462 /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\tEDD64A8FB57EEC11DE6CEB4E /* libPods-YTKNetworkDemoTests.a in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXFrameworksBuildPhase section */\n\n/* Begin PBXGroup section */\n\t\t20D2D9691D2687FA009E13A2 /* Accessory */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t20D2D96A1D268808009E13A2 /* YTKAnimatingRequestAccessory.h */,\n\t\t\t\t20D2D96B1D268808009E13A2 /* YTKAnimatingRequestAccessory.m */,\n\t\t\t\t20D2D96C1D268808009E13A2 /* YTKBaseRequest+AnimatingAccessory.h */,\n\t\t\t\t20D2D96D1D268808009E13A2 /* YTKBaseRequest+AnimatingAccessory.m */,\n\t\t\t\t20D2D96E1D268808009E13A2 /* YTKBatchRequest+AnimatingAccessory.h */,\n\t\t\t\t20D2D96F1D268808009E13A2 /* YTKBatchRequest+AnimatingAccessory.m */,\n\t\t\t\t20D2D9701D268808009E13A2 /* YTKChainRequest+AnimatingAccessory.h */,\n\t\t\t\t20D2D9711D268808009E13A2 /* YTKChainRequest+AnimatingAccessory.m */,\n\t\t\t);\n\t\t\tpath = Accessory;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t22ACBE3609D2A3A9B22717B4 /* Pods */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tFEEC7AA40163426AAD453013 /* Pods-YTKNetworkDemo.debug.xcconfig */,\n\t\t\t\tD30149728A908A3BBCCE924A /* Pods-YTKNetworkDemo.release.xcconfig */,\n\t\t\t\tF3A8BAC1ADCD712EF8786C33 /* Pods-YTKNetworkDemoTests.debug.xcconfig */,\n\t\t\t\t65526970D9E7FB74931FF110 /* Pods-YTKNetworkDemoTests.release.xcconfig */,\n\t\t\t);\n\t\t\tname = Pods;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tBF007FCA19FF972C00816462 = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t20D2D9691D2687FA009E13A2 /* Accessory */,\n\t\t\t\tBF007FD519FF972C00816462 /* YTKNetworkDemo */,\n\t\t\t\tBF007FEF19FF972C00816462 /* YTKNetworkDemoTests */,\n\t\t\t\tBF007FD419FF972C00816462 /* Products */,\n\t\t\t\t22ACBE3609D2A3A9B22717B4 /* Pods */,\n\t\t\t\tF3D5E2006147748FD73B4DAE /* Frameworks */,\n\t\t\t);\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tBF007FD419FF972C00816462 /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tBF007FD319FF972C00816462 /* YTKNetworkDemo.app */,\n\t\t\t\tBF007FEC19FF972C00816462 /* YTKNetworkDemoTests.xctest */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tBF007FD519FF972C00816462 /* YTKNetworkDemo */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t45F710821A466D01001957BA /* UploadImageApi.h */,\n\t\t\t\t45F710831A466D01001957BA /* UploadImageApi.m */,\n\t\t\t\t45AB19BF1A4656A600680858 /* YTKUrlArgumentsFilter.h */,\n\t\t\t\t45AB19C01A4656A600680858 /* YTKUrlArgumentsFilter.m */,\n\t\t\t\t45BF1D3E1A0DC0A100DDB7E0 /* RegisterApi.h */,\n\t\t\t\t45BF1D3F1A0DC0A100DDB7E0 /* RegisterApi.m */,\n\t\t\t\t45BF1D411A0DC40F00DDB7E0 /* GetUserInfoApi.h */,\n\t\t\t\t45BF1D421A0DC40F00DDB7E0 /* GetUserInfoApi.m */,\n\t\t\t\t45BF1D441A0DC66E00DDB7E0 /* GetImageApi.h */,\n\t\t\t\t45BF1D451A0DC66E00DDB7E0 /* GetImageApi.m */,\n\t\t\t\tBF007FDA19FF972C00816462 /* AppDelegate.h */,\n\t\t\t\tBF007FDB19FF972C00816462 /* AppDelegate.m */,\n\t\t\t\tBF007FDD19FF972C00816462 /* ViewController.h */,\n\t\t\t\tBF007FDE19FF972C00816462 /* ViewController.m */,\n\t\t\t\tBF007FE019FF972C00816462 /* Main.storyboard */,\n\t\t\t\tBF007FE319FF972C00816462 /* Images.xcassets */,\n\t\t\t\tBF007FE519FF972C00816462 /* LaunchScreen.xib */,\n\t\t\t\tBF007FD619FF972C00816462 /* Supporting Files */,\n\t\t\t);\n\t\t\tpath = YTKNetworkDemo;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tBF007FD619FF972C00816462 /* Supporting Files */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tBF007FD719FF972C00816462 /* Info.plist */,\n\t\t\t\tBF007FD819FF972C00816462 /* main.m */,\n\t\t\t);\n\t\t\tname = \"Supporting Files\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tBF007FEF19FF972C00816462 /* YTKNetworkDemoTests */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tBF007FF219FF972C00816462 /* YTKNetworkDemoTests.m */,\n\t\t\t\tBF007FF019FF972C00816462 /* Supporting Files */,\n\t\t\t);\n\t\t\tpath = YTKNetworkDemoTests;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tBF007FF019FF972C00816462 /* Supporting Files */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tBF007FF119FF972C00816462 /* Info.plist */,\n\t\t\t);\n\t\t\tname = \"Supporting Files\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tF3D5E2006147748FD73B4DAE /* Frameworks */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tF8B54B27A99DEF03E2DBB02C /* libPods-YTKNetworkDemo.a */,\n\t\t\t\t573535265CF5ECF05E1BBD90 /* libPods-YTKNetworkDemoTests.a */,\n\t\t\t);\n\t\t\tname = Frameworks;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXGroup section */\n\n/* Begin PBXNativeTarget section */\n\t\tBF007FD219FF972C00816462 /* YTKNetworkDemo */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = BF007FF619FF972C00816462 /* Build configuration list for PBXNativeTarget \"YTKNetworkDemo\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t609DD632ED1E07363BD48FB2 /* [CP] Check Pods Manifest.lock */,\n\t\t\t\tBF007FCF19FF972C00816462 /* Sources */,\n\t\t\t\tBF007FD019FF972C00816462 /* Frameworks */,\n\t\t\t\tBF007FD119FF972C00816462 /* Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = YTKNetworkDemo;\n\t\t\tproductName = YTKNetworkDemo;\n\t\t\tproductReference = BF007FD319FF972C00816462 /* YTKNetworkDemo.app */;\n\t\t\tproductType = \"com.apple.product-type.application\";\n\t\t};\n\t\tBF007FEB19FF972C00816462 /* YTKNetworkDemoTests */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = BF007FF919FF972C00816462 /* Build configuration list for PBXNativeTarget \"YTKNetworkDemoTests\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t530C2FC27E9D057DF8080989 /* [CP] Check Pods Manifest.lock */,\n\t\t\t\tBF007FE819FF972C00816462 /* Sources */,\n\t\t\t\tBF007FE919FF972C00816462 /* Frameworks */,\n\t\t\t\tBF007FEA19FF972C00816462 /* Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t\tBF007FEE19FF972C00816462 /* PBXTargetDependency */,\n\t\t\t);\n\t\t\tname = YTKNetworkDemoTests;\n\t\t\tproductName = YTKNetworkDemoTests;\n\t\t\tproductReference = BF007FEC19FF972C00816462 /* YTKNetworkDemoTests.xctest */;\n\t\t\tproductType = \"com.apple.product-type.bundle.unit-test\";\n\t\t};\n/* End PBXNativeTarget section */\n\n/* Begin PBXProject section */\n\t\tBF007FCB19FF972C00816462 /* Project object */ = {\n\t\t\tisa = PBXProject;\n\t\t\tattributes = {\n\t\t\t\tLastUpgradeCheck = 0800;\n\t\t\t\tORGANIZATIONNAME = yuantiku.com;\n\t\t\t\tTargetAttributes = {\n\t\t\t\t\tBF007FD219FF972C00816462 = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 6.1;\n\t\t\t\t\t};\n\t\t\t\t\tBF007FEB19FF972C00816462 = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 6.1;\n\t\t\t\t\t\tTestTargetID = BF007FD219FF972C00816462;\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t\tbuildConfigurationList = BF007FCE19FF972C00816462 /* Build configuration list for PBXProject \"YTKNetworkDemo\" */;\n\t\t\tcompatibilityVersion = \"Xcode 3.2\";\n\t\t\tdevelopmentRegion = English;\n\t\t\thasScannedForEncodings = 0;\n\t\t\tknownRegions = (\n\t\t\t\tEnglish,\n\t\t\t\ten,\n\t\t\t\tBase,\n\t\t\t);\n\t\t\tmainGroup = BF007FCA19FF972C00816462;\n\t\t\tproductRefGroup = BF007FD419FF972C00816462 /* Products */;\n\t\t\tprojectDirPath = \"\";\n\t\t\tprojectRoot = \"\";\n\t\t\ttargets = (\n\t\t\t\tBF007FD219FF972C00816462 /* YTKNetworkDemo */,\n\t\t\t\tBF007FEB19FF972C00816462 /* YTKNetworkDemoTests */,\n\t\t\t);\n\t\t};\n/* End PBXProject section */\n\n/* Begin PBXResourcesBuildPhase section */\n\t\tBF007FD119FF972C00816462 /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\tBF007FE219FF972C00816462 /* Main.storyboard in Resources */,\n\t\t\t\tBF007FE719FF972C00816462 /* LaunchScreen.xib in Resources */,\n\t\t\t\tBF007FE419FF972C00816462 /* Images.xcassets in Resources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\tBF007FEA19FF972C00816462 /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXResourcesBuildPhase section */\n\n/* Begin PBXShellScriptBuildPhase section */\n\t\t530C2FC27E9D057DF8080989 /* [CP] Check Pods Manifest.lock */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputPaths = (\n\t\t\t\t\"${PODS_PODFILE_DIR_PATH}/Podfile.lock\",\n\t\t\t\t\"${PODS_ROOT}/Manifest.lock\",\n\t\t\t);\n\t\t\tname = \"[CP] Check Pods Manifest.lock\";\n\t\t\toutputPaths = (\n\t\t\t\t\"$(DERIVED_FILE_DIR)/Pods-YTKNetworkDemoTests-checkManifestLockResult.txt\",\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"diff \\\"${PODS_PODFILE_DIR_PATH}/Podfile.lock\\\" \\\"${PODS_ROOT}/Manifest.lock\\\" > /dev/null\\nif [ $? != 0 ] ; then\\n    # print error to STDERR\\n    echo \\\"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\\\" >&2\\n    exit 1\\nfi\\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\\necho \\\"SUCCESS\\\" > \\\"${SCRIPT_OUTPUT_FILE_0}\\\"\\n\";\n\t\t\tshowEnvVarsInLog = 0;\n\t\t};\n\t\t609DD632ED1E07363BD48FB2 /* [CP] Check Pods Manifest.lock */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputPaths = (\n\t\t\t\t\"${PODS_PODFILE_DIR_PATH}/Podfile.lock\",\n\t\t\t\t\"${PODS_ROOT}/Manifest.lock\",\n\t\t\t);\n\t\t\tname = \"[CP] Check Pods Manifest.lock\";\n\t\t\toutputPaths = (\n\t\t\t\t\"$(DERIVED_FILE_DIR)/Pods-YTKNetworkDemo-checkManifestLockResult.txt\",\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"diff \\\"${PODS_PODFILE_DIR_PATH}/Podfile.lock\\\" \\\"${PODS_ROOT}/Manifest.lock\\\" > /dev/null\\nif [ $? != 0 ] ; then\\n    # print error to STDERR\\n    echo \\\"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\\\" >&2\\n    exit 1\\nfi\\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\\necho \\\"SUCCESS\\\" > \\\"${SCRIPT_OUTPUT_FILE_0}\\\"\\n\";\n\t\t\tshowEnvVarsInLog = 0;\n\t\t};\n/* End PBXShellScriptBuildPhase section */\n\n/* Begin PBXSourcesBuildPhase section */\n\t\tBF007FCF19FF972C00816462 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t45BF1D461A0DC66E00DDB7E0 /* GetImageApi.m in Sources */,\n\t\t\t\tBF007FDF19FF972C00816462 /* ViewController.m in Sources */,\n\t\t\t\t20D2D9721D268808009E13A2 /* YTKAnimatingRequestAccessory.m in Sources */,\n\t\t\t\t45AB19C11A4656A600680858 /* YTKUrlArgumentsFilter.m in Sources */,\n\t\t\t\t45BF1D431A0DC40F00DDB7E0 /* GetUserInfoApi.m in Sources */,\n\t\t\t\tBF007FDC19FF972C00816462 /* AppDelegate.m in Sources */,\n\t\t\t\t45F710841A466D01001957BA /* UploadImageApi.m in Sources */,\n\t\t\t\tBF007FD919FF972C00816462 /* main.m in Sources */,\n\t\t\t\t20D2D9751D268808009E13A2 /* YTKChainRequest+AnimatingAccessory.m in Sources */,\n\t\t\t\t20D2D9731D268808009E13A2 /* YTKBaseRequest+AnimatingAccessory.m in Sources */,\n\t\t\t\t45BF1D401A0DC0A100DDB7E0 /* RegisterApi.m in Sources */,\n\t\t\t\t20D2D9741D268808009E13A2 /* YTKBatchRequest+AnimatingAccessory.m in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\tBF007FE819FF972C00816462 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\tBF007FF319FF972C00816462 /* YTKNetworkDemoTests.m in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXSourcesBuildPhase section */\n\n/* Begin PBXTargetDependency section */\n\t\tBF007FEE19FF972C00816462 /* PBXTargetDependency */ = {\n\t\t\tisa = PBXTargetDependency;\n\t\t\ttarget = BF007FD219FF972C00816462 /* YTKNetworkDemo */;\n\t\t\ttargetProxy = BF007FED19FF972C00816462 /* PBXContainerItemProxy */;\n\t\t};\n/* End PBXTargetDependency section */\n\n/* Begin PBXVariantGroup section */\n\t\tBF007FE019FF972C00816462 /* Main.storyboard */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\tBF007FE119FF972C00816462 /* Base */,\n\t\t\t);\n\t\t\tname = Main.storyboard;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tBF007FE519FF972C00816462 /* LaunchScreen.xib */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\tBF007FE619FF972C00816462 /* Base */,\n\t\t\t);\n\t\t\tname = LaunchScreen.xib;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXVariantGroup section */\n\n/* Begin XCBuildConfiguration section */\n\t\tBF007FF419FF972C00816462 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++0x\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\t\"CODE_SIGN_IDENTITY[sdk=iphoneos*]\" = \"iPhone Developer\";\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_TESTABILITY = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_DYNAMIC_NO_PIC = NO;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_SYMBOLS_PRIVATE_EXTERN = NO;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 9.0;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = YES;\n\t\t\t\tONLY_ACTIVE_ARCH = YES;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\tBF007FF519FF972C00816462 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++0x\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\t\"CODE_SIGN_IDENTITY[sdk=iphoneos*]\" = \"iPhone Developer\";\n\t\t\t\tCOPY_PHASE_STRIP = YES;\n\t\t\t\tENABLE_NS_ASSERTIONS = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 9.0;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = NO;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t\tVALIDATE_PRODUCT = YES;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\tBF007FF719FF972C00816462 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = FEEC7AA40163426AAD453013 /* Pods-YTKNetworkDemo.debug.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tHEADER_SEARCH_PATHS = \"$(inherited)\";\n\t\t\t\tINFOPLIST_FILE = YTKNetworkDemo/Info.plist;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 9.0;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"com.yuantiku.$(PRODUCT_NAME:rfc1034identifier)\";\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\tBF007FF819FF972C00816462 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = D30149728A908A3BBCCE924A /* Pods-YTKNetworkDemo.release.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tHEADER_SEARCH_PATHS = \"$(inherited)\";\n\t\t\t\tINFOPLIST_FILE = YTKNetworkDemo/Info.plist;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 9.0;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"com.yuantiku.$(PRODUCT_NAME:rfc1034identifier)\";\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\tBF007FFA19FF972C00816462 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = F3A8BAC1ADCD712EF8786C33 /* Pods-YTKNetworkDemoTests.debug.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tBUNDLE_LOADER = \"$(TEST_HOST)\";\n\t\t\t\tFRAMEWORK_SEARCH_PATHS = \"\";\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tHEADER_SEARCH_PATHS = \"$(inherited)\";\n\t\t\t\tINFOPLIST_FILE = YTKNetworkDemoTests/Info.plist;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks @loader_path/Frameworks\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"com.yuantiku.$(PRODUCT_NAME:rfc1034identifier)\";\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tTEST_HOST = \"$(BUILT_PRODUCTS_DIR)/YTKNetworkDemo.app/YTKNetworkDemo\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\tBF007FFB19FF972C00816462 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 65526970D9E7FB74931FF110 /* Pods-YTKNetworkDemoTests.release.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tBUNDLE_LOADER = \"$(TEST_HOST)\";\n\t\t\t\tFRAMEWORK_SEARCH_PATHS = \"\";\n\t\t\t\tHEADER_SEARCH_PATHS = \"$(inherited)\";\n\t\t\t\tINFOPLIST_FILE = YTKNetworkDemoTests/Info.plist;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks @loader_path/Frameworks\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"com.yuantiku.$(PRODUCT_NAME:rfc1034identifier)\";\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tTEST_HOST = \"$(BUILT_PRODUCTS_DIR)/YTKNetworkDemo.app/YTKNetworkDemo\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n/* End XCBuildConfiguration section */\n\n/* Begin XCConfigurationList section */\n\t\tBF007FCE19FF972C00816462 /* Build configuration list for PBXProject \"YTKNetworkDemo\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\tBF007FF419FF972C00816462 /* Debug */,\n\t\t\t\tBF007FF519FF972C00816462 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\tBF007FF619FF972C00816462 /* Build configuration list for PBXNativeTarget \"YTKNetworkDemo\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\tBF007FF719FF972C00816462 /* Debug */,\n\t\t\t\tBF007FF819FF972C00816462 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\tBF007FF919FF972C00816462 /* Build configuration list for PBXNativeTarget \"YTKNetworkDemoTests\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\tBF007FFA19FF972C00816462 /* Debug */,\n\t\t\t\tBF007FFB19FF972C00816462 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n/* End XCConfigurationList section */\n\t};\n\trootObject = BF007FCB19FF972C00816462 /* Project object */;\n}\n"
  },
  {
    "path": "YTKNetworkDemo/YTKNetworkDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Workspace\n   version = \"1.0\">\n   <FileRef\n      location = \"self:YTKNetworkDemo.xcodeproj\">\n   </FileRef>\n</Workspace>\n"
  },
  {
    "path": "YTKNetworkDemo/YTKNetworkDemo.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>IDEDidComputeMac32BitWarning</key>\n\t<true/>\n</dict>\n</plist>\n"
  },
  {
    "path": "YTKNetworkDemo/YTKNetworkDemo.xcodeproj/xcshareddata/xcschemes/YTKNetworkDemo.xcscheme",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"0800\"\n   version = \"1.3\">\n   <BuildAction\n      parallelizeBuildables = \"YES\"\n      buildImplicitDependencies = \"YES\">\n      <BuildActionEntries>\n         <BuildActionEntry\n            buildForTesting = \"YES\"\n            buildForRunning = \"YES\"\n            buildForProfiling = \"YES\"\n            buildForArchiving = \"YES\"\n            buildForAnalyzing = \"YES\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"BF007FD219FF972C00816462\"\n               BuildableName = \"YTKNetworkDemo.app\"\n               BlueprintName = \"YTKNetworkDemo\"\n               ReferencedContainer = \"container:YTKNetworkDemo.xcodeproj\">\n            </BuildableReference>\n         </BuildActionEntry>\n         <BuildActionEntry\n            buildForTesting = \"YES\"\n            buildForRunning = \"YES\"\n            buildForProfiling = \"NO\"\n            buildForArchiving = \"NO\"\n            buildForAnalyzing = \"YES\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"BF007FEB19FF972C00816462\"\n               BuildableName = \"YTKNetworkDemoTests.xctest\"\n               BlueprintName = \"YTKNetworkDemoTests\"\n               ReferencedContainer = \"container:YTKNetworkDemo.xcodeproj\">\n            </BuildableReference>\n         </BuildActionEntry>\n      </BuildActionEntries>\n   </BuildAction>\n   <TestAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\">\n      <Testables>\n         <TestableReference\n            skipped = \"NO\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"BF007FEB19FF972C00816462\"\n               BuildableName = \"YTKNetworkDemoTests.xctest\"\n               BlueprintName = \"YTKNetworkDemoTests\"\n               ReferencedContainer = \"container:YTKNetworkDemo.xcodeproj\">\n            </BuildableReference>\n         </TestableReference>\n      </Testables>\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"BF007FD219FF972C00816462\"\n            BuildableName = \"YTKNetworkDemo.app\"\n            BlueprintName = \"YTKNetworkDemo\"\n            ReferencedContainer = \"container:YTKNetworkDemo.xcodeproj\">\n         </BuildableReference>\n      </MacroExpansion>\n      <AdditionalOptions>\n      </AdditionalOptions>\n   </TestAction>\n   <LaunchAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      launchStyle = \"0\"\n      useCustomWorkingDirectory = \"NO\"\n      ignoresPersistentStateOnLaunch = \"NO\"\n      debugDocumentVersioning = \"YES\"\n      debugServiceExtension = \"internal\"\n      allowLocationSimulation = \"YES\">\n      <BuildableProductRunnable\n         runnableDebuggingMode = \"0\">\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"BF007FD219FF972C00816462\"\n            BuildableName = \"YTKNetworkDemo.app\"\n            BlueprintName = \"YTKNetworkDemo\"\n            ReferencedContainer = \"container:YTKNetworkDemo.xcodeproj\">\n         </BuildableReference>\n      </BuildableProductRunnable>\n      <AdditionalOptions>\n      </AdditionalOptions>\n   </LaunchAction>\n   <ProfileAction\n      buildConfiguration = \"Release\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\"\n      savedToolIdentifier = \"\"\n      useCustomWorkingDirectory = \"NO\"\n      debugDocumentVersioning = \"YES\">\n      <BuildableProductRunnable\n         runnableDebuggingMode = \"0\">\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"BF007FD219FF972C00816462\"\n            BuildableName = \"YTKNetworkDemo.app\"\n            BlueprintName = \"YTKNetworkDemo\"\n            ReferencedContainer = \"container:YTKNetworkDemo.xcodeproj\">\n         </BuildableReference>\n      </BuildableProductRunnable>\n   </ProfileAction>\n   <AnalyzeAction\n      buildConfiguration = \"Debug\">\n   </AnalyzeAction>\n   <ArchiveAction\n      buildConfiguration = \"Release\"\n      revealArchiveInOrganizer = \"YES\">\n   </ArchiveAction>\n</Scheme>\n"
  },
  {
    "path": "YTKNetworkDemo/YTKNetworkDemo.xcworkspace/contents.xcworkspacedata",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Workspace\n   version = \"1.0\">\n   <FileRef\n      location = \"group:YTKNetworkDemo.xcodeproj\">\n   </FileRef>\n   <FileRef\n      location = \"group:Pods/Pods.xcodeproj\">\n   </FileRef>\n</Workspace>\n"
  },
  {
    "path": "YTKNetworkDemo/YTKNetworkDemo.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>IDEDidComputeMac32BitWarning</key>\n\t<true/>\n</dict>\n</plist>\n"
  },
  {
    "path": "YTKNetworkDemo/YTKNetworkDemoTests/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>en</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>BNDL</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>1.0</string>\n\t<key>CFBundleSignature</key>\n\t<string>????</string>\n\t<key>CFBundleVersion</key>\n\t<string>1</string>\n</dict>\n</plist>\n"
  },
  {
    "path": "YTKNetworkDemo/YTKNetworkDemoTests/YTKNetworkDemoTests.m",
    "content": "//\n//  YTKNetworkDemoTests.m\n//  YTKNetworkDemoTests\n//\n//  Created by Chenyu Lan on 10/28/14.\n//  Copyright (c) 2014 yuantiku.com. All rights reserved.\n//\n\n#import <UIKit/UIKit.h>\n#import <XCTest/XCTest.h>\n\n@interface YTKNetworkDemoTests : XCTestCase\n\n@end\n\n@implementation YTKNetworkDemoTests\n\n- (void)setUp {\n    [super setUp];\n    // Put setup code here. This method is called before the invocation of each test method in the class.\n}\n\n- (void)tearDown {\n    // Put teardown code here. This method is called after the invocation of each test method in the class.\n    [super tearDown];\n}\n\n- (void)testExample {\n    // This is an example of a functional test case.\n    XCTAssert(YES, @\"Pass\");\n}\n\n- (void)testPerformanceExample {\n    // This is an example of a performance test case.\n    [self measureBlock:^{\n        // Put the code you want to measure the time of here.\n    }];\n}\n\n@end\n"
  },
  {
    "path": "YTKNetworkTests/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>en</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>BNDL</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>2.0</string>\n\t<key>CFBundleSignature</key>\n\t<string>????</string>\n\t<key>CFBundleVersion</key>\n\t<string>1</string>\n</dict>\n</plist>\n"
  },
  {
    "path": "YTKNetworkTests/Requests/YTKBasicAuthRequest.h",
    "content": "//\n//  YTKBasicAuthRequest.h\n//  YTKNetworkDemo\n//\n//  Created by skyline on 16/7/30.\n//  Copyright © 2016年 yuantiku.com. All rights reserved.\n//\n\n#import <Foundation/Foundation.h>\n#import \"YTKNetwork.h\"\n\n@interface YTKBasicAuthRequest : YTKRequest\n\n- (instancetype)initWithUsername:(NSString *)username password:(NSString *)password requestUrl:(NSString *)requestUrl;\n\n@end\n"
  },
  {
    "path": "YTKNetworkTests/Requests/YTKBasicAuthRequest.m",
    "content": "//\n//  YTKBasicAuthRequest.m\n//  YTKNetworkDemo\n//\n//  Created by skyline on 16/7/30.\n//  Copyright © 2016年 yuantiku.com. All rights reserved.\n//\n\n#import \"YTKBasicAuthRequest.h\"\n\n@interface YTKBasicAuthRequest ()\n\n@property (nonatomic, strong) NSString *username;\n@property (nonatomic, strong) NSString *password;\n@property (nonatomic, strong) NSString *url;\n\n@end\n\n@implementation YTKBasicAuthRequest\n\n- (instancetype)initWithUsername:(NSString *)username password:(NSString *)password requestUrl:(NSString *)requestUrl {\n    self = [super init];\n    if (self) {\n        _username = username;\n        _password = password;\n        _url = requestUrl;\n    }\n    return self;\n}\n\n- (NSString *)requestUrl {\n    return _url;\n}\n\n- (NSArray *)requestAuthorizationHeaderFieldArray {\n    return @[_username, _password];\n}\n\n@end\n"
  },
  {
    "path": "YTKNetworkTests/Requests/YTKBasicHTTPRequest.h",
    "content": "//\n//  YTKBasicHTTPGetRequest.h\n//  YTKNetworkDemo\n//\n//  Created by skyline on 16/7/29.\n//  Copyright © 2016年 yuantiku.com. All rights reserved.\n//\n\n#import <Foundation/Foundation.h>\n#import \"YTKNetwork.h\"\n\n@interface YTKBasicHTTPRequest : YTKRequest\n\n- (instancetype)initWithRequestUrl:(NSString *)url;\n- (instancetype)initWithRequestUrl:(NSString *)url method:(YTKRequestMethod)method;\n\n@end\n"
  },
  {
    "path": "YTKNetworkTests/Requests/YTKBasicHTTPRequest.m",
    "content": "//\n//  YTKBasicHTTPGetRequest.m\n//  YTKNetworkDemo\n//\n//  Created by skyline on 16/7/29.\n//  Copyright © 2016年 yuantiku.com. All rights reserved.\n//\n\n#import \"YTKBasicHTTPRequest.h\"\n\n@interface YTKBasicHTTPRequest ()\n\n@property (nonatomic, strong) NSString *url;\n@property (nonatomic, assign) YTKRequestMethod method;\n\n@end\n\n@implementation YTKBasicHTTPRequest\n\n- (instancetype)initWithRequestUrl:(NSString *)url {\n    return [self initWithRequestUrl:url method:YTKRequestMethodGET];\n}\n\n- (instancetype)initWithRequestUrl:(NSString *)url method:(YTKRequestMethod)method {\n    self = [super init];\n    if (self) {\n        _url = url;\n        _method = method;\n    }\n    return self;\n}\n- (NSString *)requestUrl {\n    return _url;\n}\n\n- (YTKRequestMethod)requestMethod {\n    return _method;\n}\n\n@end\n"
  },
  {
    "path": "YTKNetworkTests/Requests/YTKCustomCacheRequest.h",
    "content": "//\n//  YTKCustomCacheRequest.h\n//  YTKNetworkDemo\n//\n//  Created by skyline on 16/8/12.\n//  Copyright © 2016年 yuantiku.com. All rights reserved.\n//\n\n#import \"YTKBasicHTTPRequest.h\"\n\n@interface YTKCustomCacheRequest : YTKBasicHTTPRequest\n\n- (instancetype)initWithRequestUrl:(NSString *)url cacheTimeInSeconds:(NSInteger)time;\n\n- (instancetype)initWithRequestUrl:(NSString *)url cacheTimeInSeconds:(NSInteger)time cacheVersion:(long long)version cacheSensitiveData:(id)sensitiveData;\n\n@end\n"
  },
  {
    "path": "YTKNetworkTests/Requests/YTKCustomCacheRequest.m",
    "content": "//\n//  YTKCustomCacheRequest.m\n//  YTKNetworkDemo\n//\n//  Created by skyline on 16/8/12.\n//  Copyright © 2016年 yuantiku.com. All rights reserved.\n//\n\n#import \"YTKCustomCacheRequest.h\"\n\n@interface YTKCustomCacheRequest ()\n\n@property (nonatomic, assign) NSInteger cacheTimeInSeconds;\n@property (nonatomic, assign) long long cacheVersion;\n@property (nonatomic, strong) id cacheSensitiveData;\n@end\n\n@implementation YTKCustomCacheRequest\n\n- (instancetype)initWithRequestUrl:(NSString *)url cacheTimeInSeconds:(NSInteger)time {\n    self = [super initWithRequestUrl:url];\n    if (self) {\n        _cacheTimeInSeconds = time;\n        _cacheVersion = 0;\n        _cacheSensitiveData = nil;\n    }\n    return self;\n}\n\n- (instancetype)initWithRequestUrl:(NSString *)url cacheTimeInSeconds:(NSInteger)time cacheVersion:(long long)version cacheSensitiveData:(id)sensitiveData {\n    self = [super initWithRequestUrl:url];\n    if (self) {\n        _cacheTimeInSeconds = time;\n        _cacheVersion = version;\n        _cacheSensitiveData = sensitiveData;\n    }\n    return self;\n}\n\n- (NSInteger)cacheTimeInSeconds {\n    return _cacheTimeInSeconds;\n}\n\n- (long long)cacheVersion {\n    return _cacheVersion;\n}\n\n- (id)cacheSensitiveData {\n    return _cacheSensitiveData;\n}\n\n- (BOOL)writeCacheAsynchronously {\n    return NO; // For testing.\n}\n\n@end\n"
  },
  {
    "path": "YTKNetworkTests/Requests/YTKCustomHeaderFieldRequest.h",
    "content": "//\n//  YTKCustomHeaderFieldRequest.h\n//  YTKNetworkDemo\n//\n//  Created by skyline on 16/7/30.\n//  Copyright © 2016年 yuantiku.com. All rights reserved.\n//\n\n#import <Foundation/Foundation.h>\n#import \"YTKNetwork.h\"\n\n@interface YTKCustomHeaderFieldRequest : YTKRequest\n\n- (instancetype)initWithCustomHeaderField:(NSDictionary<NSString *, NSString *> *)headers requestUrl:(NSString *)requestUrl;\n\n@end\n"
  },
  {
    "path": "YTKNetworkTests/Requests/YTKCustomHeaderFieldRequest.m",
    "content": "//\n//  YTKCustomHeaderFieldRequest.m\n//  YTKNetworkDemo\n//\n//  Created by skyline on 16/7/30.\n//  Copyright © 2016年 yuantiku.com. All rights reserved.\n//\n\n#import \"YTKCustomHeaderFieldRequest.h\"\n\n@interface YTKCustomHeaderFieldRequest ()\n\n@property (nonatomic, strong) NSDictionary<NSString *, NSString *> *headers;\n@property (nonatomic, strong) NSString *url;\n\n@end\n\n@implementation YTKCustomHeaderFieldRequest\n\n- (instancetype)initWithCustomHeaderField:(NSDictionary<NSString *, NSString *> *)headers requestUrl:(NSString *)requestUrl {\n    self = [super init];\n    if (self) {\n        _headers = headers;\n        _url = requestUrl;\n    }\n    return self;\n}\n\n- (NSString *)requestUrl {\n    return _url;\n}\n\n- (NSDictionary<NSString *, NSString *> *)requestHeaderFieldValueDictionary {\n    return _headers;\n}\n@end\n"
  },
  {
    "path": "YTKNetworkTests/Requests/YTKDownloadRequest.h",
    "content": "//\n//  YTKDownloadRequest.h\n//  YTKNetwork\n//\n//  Created by skyline on 16/8/12.\n//  Copyright © 2016年 skyline. All rights reserved.\n//\n\n#import \"YTKTimeoutRequest.h\"\n\n@interface YTKDownloadRequest : YTKTimeoutRequest\n\n@end\n"
  },
  {
    "path": "YTKNetworkTests/Requests/YTKDownloadRequest.m",
    "content": "//\n//  YTKDownloadRequest.m\n//  YTKNetwork\n//\n//  Created by skyline on 16/8/12.\n//  Copyright © 2016年 skyline. All rights reserved.\n//\n\n#import \"YTKDownloadRequest.h\"\n\n@implementation YTKDownloadRequest\n\n- (YTKResponseSerializerType)responseSerializerType {\n    return YTKResponseSerializerTypeHTTP;\n}\n\n@end\n"
  },
  {
    "path": "YTKNetworkTests/Requests/YTKJSONValidatorRequest.h",
    "content": "//\n//  YTKJSONValidatorRequest.h\n//  YTKNetworkDemo\n//\n//  Created by skyline on 16/7/30.\n//  Copyright © 2016年 yuantiku.com. All rights reserved.\n//\n\n#import <Foundation/Foundation.h>\n#import \"YTKNetwork.h\"\n\n@interface YTKJSONValidatorRequest : YTKRequest\n\n- (instancetype)initWithJSONValidator:(id)validator requestUrl:(NSString *)requestUrl;\n\n@end\n"
  },
  {
    "path": "YTKNetworkTests/Requests/YTKJSONValidatorRequest.m",
    "content": "//\n//  YTKJSONValidatorRequest.m\n//  YTKNetworkDemo\n//\n//  Created by skyline on 16/7/30.\n//  Copyright © 2016年 yuantiku.com. All rights reserved.\n//\n\n#import \"YTKJSONValidatorRequest.h\"\n\n@interface YTKJSONValidatorRequest ()\n\n@property (nonatomic, strong) id validator;\n@property (nonatomic, strong) NSString *url;\n\n@end\n\n@implementation YTKJSONValidatorRequest\n\n- (instancetype)initWithJSONValidator:(id)validator requestUrl:(NSString *)requestUrl {\n    self = [super init];\n    if (self) {\n        _validator = validator;\n        _url = requestUrl;\n    }\n    return self;\n}\n\n- (id)jsonValidator {\n    return _validator;\n}\n\n- (NSString *)requestUrl {\n    return _url;\n}\n@end\n"
  },
  {
    "path": "YTKNetworkTests/Requests/YTKStatusCodeValidatorRequest.h",
    "content": "//\n//  YTKStatusCodeValidatorRequest.h\n//  YTKNetworkDemo\n//\n//  Created by skyline on 16/7/30.\n//  Copyright © 2016年 yuantiku.com. All rights reserved.\n//\n\n#import <Foundation/Foundation.h>\n#import \"YTKNetwork.h\"\n\n@interface YTKStatusCodeValidatorRequest : YTKRequest\n\n- (instancetype)initWithRequestUrl:(NSString *)requestUrl;\n\n@end\n"
  },
  {
    "path": "YTKNetworkTests/Requests/YTKStatusCodeValidatorRequest.m",
    "content": "//\n//  YTKStatusCodeValidatorRequest.m\n//  YTKNetworkDemo\n//\n//  Created by skyline on 16/7/30.\n//  Copyright © 2016年 yuantiku.com. All rights reserved.\n//\n\n#import \"YTKStatusCodeValidatorRequest.h\"\n\n@interface YTKStatusCodeValidatorRequest ()\n\n@property (nonatomic, strong) NSString *url;\n\n@end\n\n@implementation YTKStatusCodeValidatorRequest\n\n- (instancetype)initWithRequestUrl:(NSString *)requestUrl {\n    self = [super init];\n    if (self) {\n        _url = requestUrl;\n    }\n    return self;\n}\n\n- (NSString *)requestUrl {\n    return _url;\n}\n\n- (BOOL)statusCodeValidator {\n    return [self responseStatusCode] == 418;// 418 I'm a teapot\n}\n\n- (YTKResponseSerializerType)responseSerializerType {\n    return YTKResponseSerializerTypeHTTP;\n}\n\n@end\n"
  },
  {
    "path": "YTKNetworkTests/Requests/YTKTimeoutRequest.h",
    "content": "//\n//  YTKTImeoutRequest.h\n//  YTKNetworkDemo\n//\n//  Created by skyline on 16/7/30.\n//  Copyright © 2016年 yuantiku.com. All rights reserved.\n//\n\n#import <Foundation/Foundation.h>\n#import \"YTKNetwork.h\"\n\n@interface YTKTimeoutRequest : YTKRequest\n\n- (instancetype)initWithTimeout:(NSTimeInterval)timeout requestUrl:(NSString *)requestUrl;\n\n@end\n"
  },
  {
    "path": "YTKNetworkTests/Requests/YTKTimeoutRequest.m",
    "content": "//\n//  YTKTImeoutRequest.m\n//  YTKNetworkDemo\n//\n//  Created by skyline on 16/7/30.\n//  Copyright © 2016年 yuantiku.com. All rights reserved.\n//\n\n#import \"YTKTimeoutRequest.h\"\n\n@interface YTKTimeoutRequest ()\n\n@property (nonatomic, assign) NSTimeInterval timeout;\n@property (nonatomic, strong) NSString *url;\n\n@end\n\n@implementation YTKTimeoutRequest\n\n- (instancetype)initWithTimeout:(NSTimeInterval)timeout requestUrl:(NSString *)requestUrl {\n    self = [super init];\n    if (self) {\n        _timeout = timeout;\n        _url = requestUrl;\n    }\n    return self;\n}\n\n- (NSTimeInterval)requestTimeoutInterval {\n    return _timeout;\n}\n\n- (NSString *)requestUrl {\n    return _url;\n}\n\n@end\n"
  },
  {
    "path": "YTKNetworkTests/Requests/YTKXMLRequest.h",
    "content": "//\n//  YTKXMLRequest.h\n//  YTKNetwork\n//\n//  Created by skyline on 16/8/10.\n//  Copyright © 2016年 skyline. All rights reserved.\n//\n\n#import \"YTKBasicHTTPRequest.h\"\n\n@interface YTKXMLRequest : YTKBasicHTTPRequest\n\n@end\n"
  },
  {
    "path": "YTKNetworkTests/Requests/YTKXMLRequest.m",
    "content": "//\n//  YTKXMLRequest.m\n//  YTKNetwork\n//\n//  Created by skyline on 16/8/10.\n//  Copyright © 2016年 skyline. All rights reserved.\n//\n\n#import \"YTKXMLRequest.h\"\n\n@implementation YTKXMLRequest\n\n- (YTKResponseSerializerType)responseSerializerType {\n    return YTKResponseSerializerTypeXMLParser;\n}\n\n@end\n"
  },
  {
    "path": "YTKNetworkTests/Test Cases/YTKCacheTests.m",
    "content": "//\n//  YTKCacheTests.m\n//  YTKNetworkDemo\n//\n//  Created by skyline on 16/8/12.\n//  Copyright © 2016年 yuantiku.com. All rights reserved.\n//\n\n#import \"YTKTestCase.h\"\n#import \"YTKCustomCacheRequest.h\"\n#import \"YTKNetworkPrivate.h\"\n#import \"YTKBasicCacheDirFilter.h\"\n\n@interface YTKCacheTests : YTKTestCase\n\n@end\n\n@implementation YTKCacheTests\n\n- (void)setUp {\n    [super setUp];\n    [self clearCache];\n}\n\n- (void)tearDown {\n    [super tearDown];\n    [self clearCache];\n}\n\n- (void)clearCache {\n    YTKRequest *dummpRequest = [[YTKRequest alloc] init];\n    NSString *cacheBasePath = [dummpRequest cacheBasePath];\n    [self clearDirectory:cacheBasePath];\n}\n\n- (void)testBasicCache {\n    YTKCustomCacheRequest *req = [[YTKCustomCacheRequest alloc] initWithRequestUrl:@\"get\" cacheTimeInSeconds:5 cacheVersion:0 cacheSensitiveData:nil];\n    [self expectSuccess:req withAssertion:^(YTKBaseRequest *request) {\n        YTKRequest *_req = (YTKRequest *)request;\n        // First time. Data should not be from cache.\n        XCTAssertFalse(_req.isDataFromCache);\n    }];\n\n    // Request again.\n    // !! Do not put breakpoint here. Otherwise the \"now\" time will be invalid because debugger pause the program and the tests would fail.\n    // Same for tests below.\n    [self expectSuccess:req withAssertion:^(YTKBaseRequest *request) {\n        YTKRequest *_req = (YTKRequest *)request;\n        // This time data should be from cache.\n        XCTAssertTrue(_req.isDataFromCache);\n    }];\n\n    sleep(5);\n\n    [self expectSuccess:req withAssertion:^(YTKBaseRequest *request) {\n        // Cache should be expired.\n        YTKRequest *_req = (YTKRequest *)request;\n        XCTAssertFalse(_req.isDataFromCache);\n    }];\n}\n\n- (void)testIgnoreCache {\n    YTKCustomCacheRequest *req = [[YTKCustomCacheRequest alloc] initWithRequestUrl:@\"get\" cacheTimeInSeconds:5 cacheVersion:0 cacheSensitiveData:nil];\n\n    [self expectSuccess:req withAssertion:^(YTKBaseRequest *request) {\n        YTKRequest *_req = (YTKRequest *)request;\n        // First time. Data should not be from cache.\n        XCTAssertFalse(_req.isDataFromCache);\n    }];\n\n    YTKCustomCacheRequest *req2 = [[YTKCustomCacheRequest alloc] initWithRequestUrl:@\"get\" cacheTimeInSeconds:5 cacheVersion:0 cacheSensitiveData:nil];\n\n    req2.ignoreCache = YES;\n    [self expectSuccess:req2 withAssertion:^(YTKBaseRequest *request) {\n        YTKRequest *_req = (YTKRequest *)request;\n        // Cache should be ignored.\n        XCTAssertFalse(_req.isDataFromCache);\n    }];\n}\n\n- (void)testStartWithoutCache {\n    YTKCustomCacheRequest *req = [[YTKCustomCacheRequest alloc] initWithRequestUrl:@\"get\" cacheTimeInSeconds:5 cacheVersion:0 cacheSensitiveData:nil];\n\n    [self expectSuccess:req withAssertion:^(YTKBaseRequest *request) {\n        YTKRequest *_req = (YTKRequest *)request;\n        // First time. Data should not be from cache.\n        XCTAssertFalse(_req.isDataFromCache);\n    }];\n\n    XCTestExpectation *exp = [self expectationWithDescription:@\"Cache should be ignored\"];\n\n    YTKCustomCacheRequest *req2 = [[YTKCustomCacheRequest alloc] initWithRequestUrl:@\"get\" cacheTimeInSeconds:5 cacheVersion:0 cacheSensitiveData:nil];\n    req2.successCompletionBlock = ^(YTKBaseRequest *request) {\n        YTKRequest *_req = (YTKRequest *)request;\n        // Cache should be ignored.\n        XCTAssertFalse(_req.isDataFromCache);\n        [exp fulfill];\n    };\n    [req2 startWithoutCache];\n\n    [self waitForExpectationsWithCommonTimeout];\n\n    // Starting without cache does not affect the storage of cache data.\n    YTKCustomCacheRequest *req3 = [[YTKCustomCacheRequest alloc] initWithRequestUrl:@\"get\" cacheTimeInSeconds:5 cacheVersion:0 cacheSensitiveData:nil];\n    [self expectSuccess:req3 withAssertion:^(YTKBaseRequest *request) {\n        YTKRequest *_req = (YTKRequest *)request;\n        // This time data should be from cache.\n        XCTAssertTrue(_req.isDataFromCache);\n    }];\n}\n\n- (void)testCacheVersion {\n    YTKCustomCacheRequest *req = [[YTKCustomCacheRequest alloc] initWithRequestUrl:@\"get\" cacheTimeInSeconds:5 cacheVersion:0 cacheSensitiveData:nil];\n    [self expectSuccess:req withAssertion:^(YTKBaseRequest *request) {\n        YTKRequest *_req = (YTKRequest *)request;\n        // First time. Data should not be from cache.\n        XCTAssertFalse(_req.isDataFromCache);\n    }];\n\n    // Request again.\n    [self expectSuccess:req withAssertion:^(YTKBaseRequest *request) {\n        YTKRequest *_req = (YTKRequest *)request;\n        // This time data should be from cache.\n        XCTAssertTrue(_req.isDataFromCache);\n    }];\n\n    // Request with same URL but newer version.\n    YTKCustomCacheRequest *req2 = [[YTKCustomCacheRequest alloc] initWithRequestUrl:@\"get\" cacheTimeInSeconds:5 cacheVersion:1 cacheSensitiveData:nil];\n\n    [self expectSuccess:req2 withAssertion:^(YTKBaseRequest *request) {\n        YTKRequest *_req = (YTKRequest *)request;\n        // Data should not be from cache because version has changed.\n        XCTAssertFalse(_req.isDataFromCache);\n    }];\n\n    // Request again with newer version.\n    [self expectSuccess:req2 withAssertion:^(YTKBaseRequest *request) {\n        YTKRequest *_req = (YTKRequest *)request;\n        // This time data should be from cache.\n        XCTAssertTrue(_req.isDataFromCache);\n    }];\n}\n\n- (void)testCacheSensitiveData {\n    YTKCustomCacheRequest *req = [[YTKCustomCacheRequest alloc] initWithRequestUrl:@\"get\" cacheTimeInSeconds:5 cacheVersion:0 cacheSensitiveData:@{@\"userId\": @\"123456\"}];\n    [self expectSuccess:req withAssertion:^(YTKBaseRequest *request) {\n        YTKRequest *_req = (YTKRequest *)request;\n        // First time. Data should not be from cache.\n        XCTAssertFalse(_req.isDataFromCache);\n    }];\n\n    // Request again.\n    [self expectSuccess:req withAssertion:^(YTKBaseRequest *request) {\n        YTKRequest *_req = (YTKRequest *)request;\n        // This time data should be from cache.\n        XCTAssertTrue(_req.isDataFromCache);\n    }];\n\n    // Request with same URL but diffenert sensitive data.\n    YTKCustomCacheRequest *req2 = [[YTKCustomCacheRequest alloc] initWithRequestUrl:@\"get\" cacheTimeInSeconds:5 cacheVersion:0 cacheSensitiveData:@{@\"userId\": @\"456789\"}];\n\n    [self expectSuccess:req2 withAssertion:^(YTKBaseRequest *request) {\n        YTKRequest *_req = (YTKRequest *)request;\n        // Data should not be from cache because sensitive data has changed.\n        XCTAssertFalse(_req.isDataFromCache);\n    }];\n\n    // Request with same URL but no sensitive data.\n    YTKCustomCacheRequest *req3 = [[YTKCustomCacheRequest alloc] initWithRequestUrl:@\"get\" cacheTimeInSeconds:5 cacheVersion:0 cacheSensitiveData:nil];\n\n    [self expectSuccess:req3 withAssertion:^(YTKBaseRequest *request) {\n        YTKRequest *_req = (YTKRequest *)request;\n        // Data should not be from cache because sensitive data has changed.\n        XCTAssertFalse(_req.isDataFromCache);\n    }];\n\n    // Request again with newer sensitive data. This time previous cache is considered invalid.\n    YTKCustomCacheRequest *req4 = [[YTKCustomCacheRequest alloc] initWithRequestUrl:@\"get\" cacheTimeInSeconds:5 cacheVersion:0 cacheSensitiveData:@{@\"userId\": @\"456789\"}];\n\n    [self expectSuccess:req4 withAssertion:^(YTKBaseRequest *request) {\n        YTKRequest *_req = (YTKRequest *)request;\n        // This time data should not be from cache.\n        XCTAssertFalse(_req.isDataFromCache);\n    }];\n\n    // Request again with newer sensitive data. This time cache is valid again.\n    YTKCustomCacheRequest *req5 = [[YTKCustomCacheRequest alloc] initWithRequestUrl:@\"get\" cacheTimeInSeconds:5 cacheVersion:0 cacheSensitiveData:@{@\"userId\": @\"456789\"}];\n\n    [self expectSuccess:req5 withAssertion:^(YTKBaseRequest *request) {\n        YTKRequest *_req = (YTKRequest *)request;\n        // This time data should be from cache.\n        XCTAssertTrue(_req.isDataFromCache);\n    }];\n}\n\n- (void)testCacheIntegrityWithJSONResponse {\n    __block NSDictionary *originalJSONResponse;\n    __block NSString *originalStringResponse;\n    __block NSData *originalData;\n    YTKCustomCacheRequest *req = [[YTKCustomCacheRequest alloc] initWithRequestUrl:@\"get\" cacheTimeInSeconds:5 cacheVersion:0 cacheSensitiveData:nil];\n    [self expectSuccess:req withAssertion:^(YTKBaseRequest *request) {\n        YTKRequest *_req = (YTKRequest *)request;\n        // First time. Data should not be from cache.\n        originalJSONResponse = _req.responseJSONObject;\n        originalStringResponse = _req.responseString;\n        originalData = _req.responseData;\n        XCTAssertFalse(_req.isDataFromCache);\n    }];\n\n    // Request again.\n    YTKCustomCacheRequest *req2 = [[YTKCustomCacheRequest alloc] initWithRequestUrl:@\"get\" cacheTimeInSeconds:5 cacheVersion:0 cacheSensitiveData:nil];\n\n    [self expectSuccess:req2 withAssertion:^(YTKBaseRequest *request) {\n        YTKRequest *_req = (YTKRequest *)request;\n        // This time data should be from cache.\n        XCTAssertTrue(_req.isDataFromCache);\n        // Check if data is the same.\n        XCTAssertTrue([_req.responseJSONObject isEqualToDictionary:originalJSONResponse]);\n        XCTAssertTrue([_req.responseString isEqualToString:originalStringResponse]);\n        XCTAssertTrue([_req.responseData isEqualToData:originalData]);\n    }];\n}\n\n- (void)testShareCacheUsingSavedData {\n    YTKCustomCacheRequest *req1 = [[YTKCustomCacheRequest alloc] initWithRequestUrl:@\"get?key1=value1\" cacheTimeInSeconds:10];\n    YTKCustomCacheRequest *req2 = [[YTKCustomCacheRequest alloc] initWithRequestUrl:@\"get?key2=value2\" cacheTimeInSeconds:10];\n    YTKCustomCacheRequest *req3 = [[YTKCustomCacheRequest alloc] initWithRequestUrl:@\"get?key3=value3\" cacheTimeInSeconds:10];\n\n    [self expectSuccess:req1 withAssertion:^(YTKBaseRequest *request) {\n        [req2 saveResponseDataToCacheFile:request.responseData];\n        [req3 saveResponseDataToCacheFile:request.responseData];\n    }];\n\n    // Check if shared cache works\n    [self expectSuccess:req2 withAssertion:^(YTKBaseRequest *request) {\n        YTKRequest *_req = (YTKRequest *)request;\n        XCTAssertTrue(_req.isDataFromCache);\n\n        NSDictionary<NSString *, NSString *> *responseArgs = _req.responseJSONObject[@\"args\"];\n        XCTAssertTrue([responseArgs[@\"key1\"] isEqualToString:@\"value1\"]);\n    }];\n\n    [self expectSuccess:req3 withAssertion:^(YTKBaseRequest *request) {\n        YTKRequest *_req = (YTKRequest *)request;\n        XCTAssertTrue(_req.isDataFromCache);\n\n        NSDictionary<NSString *, NSString *> *responseArgs = _req.responseJSONObject[@\"args\"];\n        XCTAssertTrue([responseArgs[@\"key1\"] isEqualToString:@\"value1\"]);\n    }];\n}\n\n- (void)testCacheDirFilter {\n    NSString *const pathSuffix = @\"MyCachePath\";\n    // Add filter.\n    YTKBasicCacheDirFilter *filter = [YTKBasicCacheDirFilter filterWithPathComponent:pathSuffix];\n    [[YTKNetworkConfig sharedConfig] addCacheDirPathFilter:filter];\n\n    // Test caching logic.\n    YTKCustomCacheRequest *req = [[YTKCustomCacheRequest alloc] initWithRequestUrl:@\"get\" cacheTimeInSeconds:5 cacheVersion:0 cacheSensitiveData:nil];\n    [self expectSuccess:req withAssertion:^(YTKBaseRequest *request) {\n        YTKRequest *_req = (YTKRequest *)request;\n        // First time. Data should not be from cache.\n        XCTAssertFalse(_req.isDataFromCache);\n    }];\n\n    [self expectSuccess:req withAssertion:^(YTKBaseRequest *request) {\n        YTKRequest *_req = (YTKRequest *)request;\n        // This time data should be from cache.\n        XCTAssertTrue(_req.isDataFromCache);\n    }];\n\n    NSString *cachePath = [req cacheBasePath];\n    NSFileManager* fileManager = [[NSFileManager alloc] init];\n\n    // Test if new path is used.\n    BOOL isDir;\n    BOOL pathExists = [fileManager fileExistsAtPath:cachePath isDirectory:&isDir];\n    XCTAssertTrue(pathExists);\n    XCTAssertTrue(isDir);\n    XCTAssertTrue([cachePath hasSuffix:pathSuffix]);\n\n    // Clean up.\n    [self clearDirectory:cachePath];\n}\n\n@end\n"
  },
  {
    "path": "YTKNetworkTests/Test Cases/YTKConcurrencyTests.m",
    "content": "//\n//  YTKRequestConcurrency\u0010\u0010\u0010\u0010\u0010\u0010Test.m\n//  YTKNetwork\n//\n//  Created by skyline on 16/8/3.\n//  Copyright © 2016年 skyline. All rights reserved.\n//\n\n#import \"YTKTestCase.h\"\n#import \"YTKBasicHTTPRequest.h\"\n#import \"YTKNetworkPrivate.h\"\n\n@interface YTKConcurrencyTest : YTKTestCase\n\n@end\n\n@implementation YTKConcurrencyTest\n\n- (void)setUp {\n    [super setUp];\n}\n\n- (void)tearDown {\n    [super tearDown];\n}\n\n- (void)testBasicConcurrentRequestCreation {\n    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0ul);\n\n    NSInteger dispatchTarget = 1000;\n    __block NSInteger completionCount = 0;\n    __block NSInteger callbackCount = 0;\n    for (NSUInteger i = 0; i < dispatchTarget; i++) {\n        dispatch_async(queue, ^{\n            @autoreleasepool {\n                YTKBasicHTTPRequest *req = [[YTKBasicHTTPRequest alloc] init];\n                req.tag = i;\n\n                [req startWithCompletionBlockWithSuccess:nil failure:^(__kindof YTKBaseRequest * _Nonnull request) {\n                    // Left is from callback, right is captured by block.\n                    XCTAssertTrue(request.tag == i);\n                    callbackCount ++;\n                }];\n\n                // We just need to simulate concurrent request creation here.\n                [req.requestTask cancel];\n\n                NSLog(@\"Current req number: %zd\", i);\n                dispatch_sync(dispatch_get_main_queue(), ^{\n                    completionCount++;\n                });\n            }\n        });\n    }\n\n    while (callbackCount < dispatchTarget) {\n        [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];\n    }\n\n    XCTAssertTrue(completionCount == callbackCount);\n}\n\n@end\n"
  },
  {
    "path": "YTKNetworkTests/Test Cases/YTKJSONValidatorTests.m",
    "content": "//\n//  YTKJSONValidatorTests.m\n//  YTKNetworkDemo\n//\n//  Created by tangqiao on 6/10/15.\n//  Copyright (c) 2015 yuantiku.com. All rights reserved.\n//\n\n#import <XCTest/XCTest.h>\n#import \"YTKNetworkPrivate.h\"\n\n@interface YTKJSONValidatorTests : XCTestCase\n\n@end\n\n@implementation YTKJSONValidatorTests\n\n- (void)testCompoundDictionaryVailidateShouldSucceed {\n    NSDictionary *json = @{\n        @\"son\": @{\n            @\"age\": @14,\n        },\n        @\"name\": @\"family\"\n    };\n    NSDictionary *validator = @{\n        @\"son\": [NSDictionary class],\n        @\"name\": [NSString class]\n    };\n    BOOL result = [self validateJSON:json withValidator:validator];\n    XCTAssertTrue(result);\n}\n\n- (void)testCompoundDictionaryVailidateShouldFail {\n    NSDictionary *json = @{\n        @\"son\": @{\n            @\"age\": @14,\n        },\n        @\"name\": @\"family\"\n    };\n    NSDictionary *validator = @{\n        @\"son\": [NSDictionary class],\n        @\"name\": [NSNumber class]\n    };\n    BOOL result = [self validateJSON:json withValidator:validator];\n    XCTAssertFalse(result);\n}\n\n- (void)testSimpleArrayValidatorShouldSucceed {\n    NSArray *json = @[@1 , @2];\n    NSArray *validator = @[[NSNumber class]];\n    BOOL result = [self validateJSON:json withValidator:validator];\n    XCTAssertTrue(result);\n}\n\n- (void)testSimpleArrayValidatorShouldFail {\n    NSArray *json = @[@1 , @2];\n    NSArray *validator = @[[NSString class]];\n    BOOL result = [self validateJSON:json withValidator:validator];\n    XCTAssertFalse(result);\n}\n\n- (void)testEmptyArrayValidatorShouldSucceed {\n    NSArray *json = @[@{\n        @\"values\": @[]\n    }];\n    NSArray *validator = @[@{\n        @\"values\": @[]\n    }];\n    BOOL result = [self validateJSON:json withValidator:validator];\n    XCTAssertTrue(result);\n}\n\n- (BOOL)validateJSON:(id)json withValidator:(id)validator {\n    return [YTKNetworkUtils validateJSON:json withValidator:validator];\n}\n\n@end\n"
  },
  {
    "path": "YTKNetworkTests/Test Cases/YTKNetworkRequestTests.m",
    "content": "//\n//  YTKNetworkDemoTests.m\n//  YTKNetworkDemoTests\n//\n//  Created by Chenyu Lan on 10/28/14.\n//  Copyright (c) 2014 yuantiku.com. All rights reserved.\n//\n\n#import \"YTKTestCase.h\"\n#import \"YTKNetworkConfig.h\"\n#import \"YTKBasicHTTPRequest.h\"\n#import \"YTKXMLRequest.h\"\n#import \"YTKBasicAuthRequest.h\"\n#import \"YTKCustomHeaderFieldRequest.h\"\n#import \"YTKJSONValidatorRequest.h\"\n#import \"YTKStatusCodeValidatorRequest.h\"\n#import \"YTKTImeoutRequest.h\"\n\n@interface YTKNetworkRequestTests : YTKTestCase\n\n@end\n\n@implementation YTKNetworkRequestTests\n\n- (void)setUp {\n    [super setUp];\n}\n\n- (void)tearDown {\n    [super tearDown];\n}\n\n- (void)_testBuildRequestURLWithBaseURL:(NSString *)baseURL detailURL:(NSString *)detailURL resultURL:(NSString *)resultURL{\n    YTKNetworkConfig *config = [YTKNetworkConfig sharedConfig];\n    YTKNetworkAgent *agent = [YTKNetworkAgent sharedAgent];\n\n    config.baseUrl = baseURL;\n\n    YTKBasicHTTPRequest *request = [[YTKBasicHTTPRequest alloc] initWithRequestUrl:detailURL];\n    NSString *url = [agent buildRequestUrl:request];\n\n    XCTAssertTrue([url isEqualToString:resultURL]);\n}\n\n- (void)testBuildRequestURL {\n    [self _testBuildRequestURLWithBaseURL:@\"http://www.example.com\" detailURL:@\"get\" resultURL:@\"http://www.example.com/get\"];\n    [self _testBuildRequestURLWithBaseURL:@\"http://www.example.com/\" detailURL:@\"get\" resultURL:@\"http://www.example.com/get\"];\n    [self _testBuildRequestURLWithBaseURL:@\"https://www.example.com\" detailURL:@\"get\" resultURL:@\"https://www.example.com/get\"];\n    [self _testBuildRequestURLWithBaseURL:@\"http://www.example.com\" detailURL:@\"get/val\" resultURL:@\"http://www.example.com/get/val\"];\n    [self _testBuildRequestURLWithBaseURL:@\"http://www.example.com\" detailURL:@\"get/val/\" resultURL:@\"http://www.example.com/get/val/\"];\n    [self _testBuildRequestURLWithBaseURL:@\"https://www.example.com\" detailURL:@\"httpEndpoint\" resultURL:@\"https://www.example.com/httpEndpoint\"];\n\n    [self _testBuildRequestURLWithBaseURL:@\"\" detailURL:@\"http://www.example.com\" resultURL:@\"http://www.example.com\"];\n    [self _testBuildRequestURLWithBaseURL:@\"\" detailURL:@\"https://www.example.com\" resultURL:@\"https://www.example.com\"];\n    [self _testBuildRequestURLWithBaseURL:@\"http://www.something.com\" detailURL:@\"https://www.example.com\" resultURL:@\"https://www.example.com\"];\n}\n\n- (void)testBasicHTTPRequest {\n    YTKBasicHTTPRequest *get = [[YTKBasicHTTPRequest alloc] initWithRequestUrl:@\"get\" method:YTKRequestMethodGET];\n    [self expectSuccess:get];\n\n    YTKBasicHTTPRequest *post = [[YTKBasicHTTPRequest alloc] initWithRequestUrl:@\"post\" method:YTKRequestMethodPOST];\n    [self expectSuccess:post];\n\n    YTKBasicHTTPRequest *patch = [[YTKBasicHTTPRequest alloc] initWithRequestUrl:@\"patch\" method:YTKRequestMethodPATCH];\n    [self expectSuccess:patch];\n\n    YTKBasicHTTPRequest *put = [[YTKBasicHTTPRequest alloc] initWithRequestUrl:@\"put\" method:YTKRequestMethodPUT];\n    [self expectSuccess:put];\n\n    YTKBasicHTTPRequest *delete = [[YTKBasicHTTPRequest alloc] initWithRequestUrl:@\"delete\" method:YTKRequestMethodDELETE];\n    [self expectSuccess:delete];\n\n    YTKBasicHTTPRequest *fail404 = [[YTKBasicHTTPRequest alloc] initWithRequestUrl:@\"status/404\" method:YTKRequestMethodGET];\n    [self expectFailure:fail404];\n}\n\n- (void)testResponseHeaders {\n    YTKBasicHTTPRequest *req = [[YTKBasicHTTPRequest alloc] initWithRequestUrl:@\"response-headers?key=value\"];\n    [self expectSuccess:req withAssertion:^(YTKBaseRequest *request) {\n        NSDictionary<NSString *, NSString *> *responseHeaders = request.responseHeaders;\n        XCTAssertNotNil(responseHeaders);\n        XCTAssertTrue([responseHeaders[@\"key\"] isEqualToString:@\"value\"]);\n    }];\n}\n\n- (void)testCustomHeaderField {\n    YTKCustomHeaderFieldRequest *req = [[YTKCustomHeaderFieldRequest alloc] initWithCustomHeaderField:@{@\"Custom-Header-Field\": @\"CustomHeaderValue\"} requestUrl:@\"headers\"];\n    [self expectSuccess:req withAssertion:^(YTKBaseRequest *request) {\n        XCTAssertNotNil(request.responseJSONObject);\n        NSDictionary<NSString *, NSString *> *headers = request.responseJSONObject[@\"headers\"];\n        XCTAssertTrue([headers[@\"Custom-Header-Field\"] isEqualToString:@\"CustomHeaderValue\"]);\n    }];\n}\n\n- (void)testHTTPBasicAuthRequest {\n    YTKBasicAuthRequest *authSuccess = [[YTKBasicAuthRequest alloc] initWithUsername:@\"123\" password:@\"123\" requestUrl:@\"basic-auth/123/123\"];\n    [self expectSuccess:authSuccess];\n\n    YTKBasicAuthRequest *authFailure = [[YTKBasicAuthRequest alloc] initWithUsername:@\"123456\" password:@\"123\" requestUrl:@\"basic-auth/123/123\"];\n    [self expectFailure:authFailure];\n}\n\n- (void)testJSONValidator {\n    YTKJSONValidatorRequest *validateSuccess = [[YTKJSONValidatorRequest alloc] initWithJSONValidator:@{@\"headers\": [NSDictionary class], @\"args\": [NSDictionary class]} requestUrl:@\"get?key1=value&key2=123456\"];\n    [self expectSuccess:validateSuccess];\n\n    YTKJSONValidatorRequest *validateFailure = [[YTKJSONValidatorRequest alloc] initWithJSONValidator:@{@\"headers\": [NSDictionary class], @\"args\": [NSString class]} requestUrl:@\"get?key1=value&key2=123456\"];\n    [self expectFailure:validateFailure withAssertion:^(YTKBaseRequest *request) {\n        NSError *error = request.error;\n        XCTAssertTrue([error.domain isEqualToString:YTKRequestValidationErrorDomain]);\n        XCTAssertTrue(error.code == YTKRequestValidationErrorInvalidJSONFormat);\n    }];\n}\n\n- (void)testXMLRequest {\n    YTKXMLRequest *req = [[YTKXMLRequest alloc] initWithRequestUrl:@\"xml\"];\n    [self expectSuccess:req withAssertion:^(YTKBaseRequest *request) {\n        XCTAssertNotNil(request);\n        XCTAssertTrue([request.responseObject isMemberOfClass:[NSXMLParser class]]);\n    }];\n\n    YTKXMLRequest *req2 = [[YTKXMLRequest alloc] initWithRequestUrl:@\"get\"];\n    [self expectFailure:req2];\n}\n\n- (void)testStatusCodeValidator {\n    YTKStatusCodeValidatorRequest *validateSuccess = [[YTKStatusCodeValidatorRequest alloc] initWithRequestUrl:@\"status/418\"];\n    [self expectSuccess:validateSuccess];\n\n    YTKStatusCodeValidatorRequest *validateFailure = [[YTKStatusCodeValidatorRequest alloc] initWithRequestUrl:@\"status/200\"];\n    [self expectFailure:validateFailure withAssertion:^(YTKBaseRequest *request) {\n        NSError *error = request.error;\n        XCTAssertTrue([error.domain isEqualToString:YTKRequestValidationErrorDomain]);\n        XCTAssertTrue(error.code == YTKRequestValidationErrorInvalidStatusCode);\n    }];\n}\n\n- (void)testBatchRequest {\n    YTKBasicHTTPRequest *req1 = [[YTKBasicHTTPRequest alloc] initWithRequestUrl:@\"get?key1=value1\"];\n    YTKBasicHTTPRequest *req2 = [[YTKBasicHTTPRequest alloc] initWithRequestUrl:@\"get?key2=value2\"];\n    YTKBasicHTTPRequest *req3 = [[YTKBasicHTTPRequest alloc] initWithRequestUrl:@\"get?key3=value3\"];\n\n    XCTestExpectation *exp = [self expectationWithDescription:@\"Batch Request should succeed\"];\n\n    YTKBatchRequest *batch = [[YTKBatchRequest alloc] initWithRequestArray:@[req1, req2, req3]];\n    [batch startWithCompletionBlockWithSuccess:^(YTKBatchRequest * _Nonnull batchRequest) {\n        XCTAssertNotNil(batchRequest);\n        XCTAssertEqual(batchRequest.requestArray.count, 3);\n\n        YTKRequest *req1 = batchRequest.requestArray[0];\n        NSDictionary<NSString *, NSString *> *responseArgs1 = req1.responseJSONObject[@\"args\"];\n        XCTAssertTrue([responseArgs1[@\"key1\"] isEqualToString:@\"value1\"]);\n        XCTAssertNil(req1.successCompletionBlock);\n        XCTAssertNil(req1.failureCompletionBlock);\n\n        YTKRequest *req2 = batchRequest.requestArray[1];\n        NSDictionary<NSString *, NSString *> *responseArgs2 = req2.responseJSONObject[@\"args\"];\n        XCTAssertTrue([responseArgs2[@\"key2\"] isEqualToString:@\"value2\"]);\n        XCTAssertNil(req2.successCompletionBlock);\n        XCTAssertNil(req2.failureCompletionBlock);\n\n        YTKRequest *req3 = batchRequest.requestArray[2];\n        NSDictionary<NSString *, NSString *> *responseArgs3 = req3.responseJSONObject[@\"args\"];\n        XCTAssertTrue([responseArgs3[@\"key3\"] isEqualToString:@\"value3\"]);\n        XCTAssertNil(req3.successCompletionBlock);\n        XCTAssertNil(req3.failureCompletionBlock);\n\n        [exp fulfill];\n    } failure:^(YTKBatchRequest * _Nonnull batchRequest) {\n        XCTFail(@\"Batch Request should succeed, but failed\");\n    }];\n\n    [self waitForExpectationsWithCommonTimeout];\n}\n\n- (void)testChainRequest {\n    YTKBasicHTTPRequest *req1 = [[YTKBasicHTTPRequest alloc] initWithRequestUrl:@\"get?key1=value1\"];\n    YTKBasicHTTPRequest *req2 = [[YTKBasicHTTPRequest alloc] initWithRequestUrl:@\"get?key2=value2\"];\n    YTKBasicHTTPRequest *req3 = [[YTKBasicHTTPRequest alloc] initWithRequestUrl:@\"get?key3=value3\"];\n\n    XCTestExpectation *exp = [self expectationWithDescription:@\"Chain Request should succeed\"];\n\n    YTKChainRequest *chain = [[YTKChainRequest alloc] init];\n    [chain addRequest:req1 callback:^(YTKChainRequest * _Nonnull chainRequest, YTKBaseRequest * _Nonnull baseRequest) {\n        NSDictionary<NSString *, NSString *> *responseArgs1 = baseRequest.responseJSONObject[@\"args\"];\n        XCTAssertTrue([responseArgs1[@\"key1\"] isEqualToString:@\"value1\"]);\n        XCTAssertNil(baseRequest.successCompletionBlock);\n        XCTAssertNil(baseRequest.failureCompletionBlock);\n\n        [chainRequest addRequest:req2 callback:^(YTKChainRequest * _Nonnull chainRequest, YTKBaseRequest * _Nonnull baseRequest) {\n            NSDictionary<NSString *, NSString *> *responseArgs2 = baseRequest.responseJSONObject[@\"args\"];\n            XCTAssertTrue([responseArgs2[@\"key2\"] isEqualToString:@\"value2\"]);\n            XCTAssertNil(baseRequest.successCompletionBlock);\n            XCTAssertNil(baseRequest.failureCompletionBlock);\n\n            [chainRequest addRequest:req3 callback:^(YTKChainRequest * _Nonnull chainRequest, YTKBaseRequest * _Nonnull baseRequest) {\n                NSDictionary<NSString *, NSString *> *responseArgs3 = baseRequest.responseJSONObject[@\"args\"];\n                XCTAssertTrue([responseArgs3[@\"key3\"] isEqualToString:@\"value3\"]);\n                XCTAssertNil(baseRequest.successCompletionBlock);\n                XCTAssertNil(baseRequest.failureCompletionBlock);\n\n                [exp fulfill];\n            }];\n        }];\n    }];\n    [chain start];\n\n    [self waitForExpectationsWithCommonTimeout];\n}\n\n- (void)testTimeoutRequest {\n    YTKTimeoutRequest *timeoutSuccess = [[YTKTimeoutRequest alloc] initWithTimeout:5 requestUrl:@\"delay/3\"];\n    [self expectSuccess:timeoutSuccess];\n\n    YTKTimeoutRequest *timeoutFailure = [[YTKTimeoutRequest alloc] initWithTimeout:5 requestUrl:@\"delay/7\"];\n    [self expectFailure:timeoutFailure];\n}\n\n@end\n"
  },
  {
    "path": "YTKNetworkTests/Test Cases/YTKPerformanceTests.m",
    "content": "//\n//  YTKPerformanceTests.m\n//  YTKNetwork\n//\n//  Created by skyline on 16/8/3.\n//  Copyright © 2016年 skyline. All rights reserved.\n//\n\n#import \"YTKTestCase.h\"\n#import \"YTKBasicHTTPRequest.h\"\n\n@interface YTKPerformanceTests : YTKTestCase\n\n@end\n\n@implementation YTKPerformanceTests\n\n- (void)setUp {\n    [super setUp];\n}\n\n- (void)tearDown {\n    [super tearDown];\n}\n\n- (void)testBaseRequestCreationPerformance {\n    NSInteger targetCount = 1000;\n    // The measure block will be called several times.\n    [self measureBlock:^{\n        for (NSUInteger i = 0; i < targetCount; i++) {\n            @autoreleasepool {\n                YTKBasicHTTPRequest *req = [[YTKBasicHTTPRequest alloc] init];\n                [req startWithCompletionBlockWithSuccess:^(__kindof YTKBaseRequest * _Nonnull request) {\n                    NSNumber *result = request.responseObject;\n                    XCTAssertTrue([result isEqualToNumber:@(i)]);\n                } failure:nil];\n                [req.requestTask cancel];\n            }\n        }\n    }];\n}\n\n@end\n"
  },
  {
    "path": "YTKNetworkTests/Test Cases/YTKRequestFilterTests.m",
    "content": "//\n//  YTKRequestFilterTests.m\n//  YTKNetwork\n//\n//  Created by skyline on 16/8/2.\n//  Copyright © 2016年 skyline. All rights reserved.\n//\n\n#import \"YTKTestCase.h\"\n#import \"YTKNetwork.h\"\n#import \"YTKBasicUrlFilter.h\"\n#import \"YTKBasicHTTPRequest.h\"\n\n@interface YTKRequestFilterTests : YTKTestCase\n\n@end\n\n@implementation YTKRequestFilterTests\n\n- (void)setUp {\n    [super setUp];\n}\n\n- (void)tearDown {\n    [super tearDown];\n}\n\n- (void)testBasicFilter {\n    YTKBasicUrlFilter *filter = [YTKBasicUrlFilter filterWithArguments:@{@\"key\": @\"value\"}];\n    [[YTKNetworkConfig sharedConfig] addUrlFilter:filter];\n\n    YTKBasicHTTPRequest *req = [[YTKBasicHTTPRequest alloc] initWithRequestUrl:@\"get\"];\n    [self expectSuccess:req withAssertion:^(YTKBaseRequest *request) {\n        NSDictionary<NSString *, NSString *> *args = request.responseJSONObject[@\"args\"];\n        XCTAssertTrue([args[@\"key\"] isEqualToString:@\"value\"]);\n    }];\n}\n\n@end\n"
  },
  {
    "path": "YTKNetworkTests/Test Cases/YTKResumableDownloadTests.m",
    "content": "//\n//  YTKResumableDownloadTests.m\n//  YTKNetwork\n//\n//  Created by skyline on 16/8/12.\n//  Copyright © 2016年 skyline. All rights reserved.\n//\n\n#import \"YTKTestCase.h\"\n#import \"YTKDownloadRequest.h\"\n#import \"YTKNetworkPrivate.h\"\n#import \"AFNetworking.h\"\n\nNSString *const kTestDownloadURL = @\"https://qd.myapp.com/myapp/qqteam/AndroidQQ/mobileqq_android.apk\";\nNSString *const kTestFailDownloadURL = @\"https://qd.myapp.com/myapp/qqteam/AndroidQQ/mobileqq_android.apkfail\";\n\n@interface YTKResumableDownloadTests : YTKTestCase\n\n@end\n\n@implementation YTKResumableDownloadTests\n\n- (void)setUp {\n    [super setUp];\n    [self createDirectory:[self saveBasePath]];\n    [self clearDirectory:[[YTKNetworkAgent sharedAgent] incompleteDownloadTempCacheFolder]];\n\n    NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];\n    // Ignore cache\n    config.requestCachePolicy = NSURLRequestReloadIgnoringCacheData;\n    config.HTTPCookieAcceptPolicy = NSHTTPCookieAcceptPolicyNever;\n    // Force download failed because of timeout.\n    config.timeoutIntervalForResource = 1;\n    [[YTKNetworkAgent sharedAgent] resetURLSessionManagerWithConfiguration:config];\n    // Allow all content type\n    [[YTKNetworkAgent sharedAgent] manager].responseSerializer.acceptableContentTypes = nil;\n}\n\n- (void)tearDown {\n    [super tearDown];\n    [self clearDirectory:[self saveBasePath]];\n    [self clearDirectory:[[YTKNetworkAgent sharedAgent] incompleteDownloadTempCacheFolder]];\n}\n\n- (NSString *)saveBasePath {\n    NSString *pathOfLibrary = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) objectAtIndex:0];\n    NSString *path = [pathOfLibrary stringByAppendingPathComponent:@\"testResumableDownload\"];\n    return path;\n}\n\n- (void)testResumableDownloadWithFullPath {\n    // Timeout less than 1 second will be ignored.\n    // Here we assume that the file can not be fully downloaded in 1 second.\n    // !!If run this test for multiple times. Local cache or CDN cache may still kick in, causing very fast download\n    // speed and break this test.\n    YTKDownloadRequest *req = [[YTKDownloadRequest alloc] initWithTimeout:1 requestUrl:kTestDownloadURL];\n    req.resumableDownloadPath = [[self saveBasePath] stringByAppendingPathComponent:@\"downloaded.bin\"];\n    req.resumableDownloadProgressBlock = ^(NSProgress *progress) {\n        NSLog(@\"Downloading: %lld / %lld\", progress.completedUnitCount, progress.totalUnitCount);\n    };\n\n    [self expectFailure:req];\n\n    // Start the request again\n    [[YTKNetworkAgent sharedAgent] resetURLSessionManager];\n    // Allow all content type\n    [[YTKNetworkAgent sharedAgent] manager].responseSerializer.acceptableContentTypes = nil;\n\n    YTKDownloadRequest *req2 = [[YTKDownloadRequest alloc] initWithTimeout:self.networkTimeout requestUrl:kTestDownloadURL];\n    req2.resumableDownloadPath = [[self saveBasePath] stringByAppendingPathComponent:@\"downloaded.bin\"];\n    req2.resumableDownloadProgressBlock = ^(NSProgress *progress) {\n        XCTAssertTrue(progress.completedUnitCount > 0);\n        NSLog(@\"Downloading: %lld / %lld\", progress.completedUnitCount, progress.totalUnitCount);\n    };\n\n    [self expectSuccess:req2];\n}\n\n- (void)testResumableDownloadWithDirectoryPath {\n    YTKDownloadRequest *req = [[YTKDownloadRequest alloc] initWithTimeout:1 requestUrl:kTestDownloadURL];\n    req.resumableDownloadPath = [self saveBasePath];\n    req.resumableDownloadProgressBlock = ^(NSProgress *progress) {\n        NSLog(@\"Downloading: %lld / %lld\", progress.completedUnitCount, progress.totalUnitCount);\n    };\n\n    [self expectFailure:req];\n\n    [[YTKNetworkAgent sharedAgent] resetURLSessionManager];\n    [[YTKNetworkAgent sharedAgent] manager].responseSerializer.acceptableContentTypes = nil;\n\n    YTKDownloadRequest *req2 = [[YTKDownloadRequest alloc] initWithTimeout:self.networkTimeout requestUrl:kTestDownloadURL];\n    req2.resumableDownloadPath = [self saveBasePath];\n    req2.resumableDownloadProgressBlock = ^(NSProgress *progress) {\n        XCTAssertTrue(progress.completedUnitCount > 0);\n        NSLog(@\"Downloading: %lld / %lld\", progress.completedUnitCount, progress.totalUnitCount);\n    };\n\n    [self expectSuccess:req2];\n}\n\n- (void)testResumableDownloadOverwriteAndCleanup {\n    [[YTKNetworkAgent sharedAgent] resetURLSessionManager];\n    [[YTKNetworkAgent sharedAgent] manager].responseSerializer.acceptableContentTypes = nil;\n    NSString *path = [[self saveBasePath] stringByAppendingPathComponent:@\"downloaded.bin\"];\n\n    // Create a exist file\n    NSString *testString = @\"TEST\";\n    NSData *stringData = [testString dataUsingEncoding:NSUTF8StringEncoding];\n    [stringData writeToFile:path atomically:YES];\n\n    // Download req file\n    YTKDownloadRequest *req = [[YTKDownloadRequest alloc] initWithTimeout:self.networkTimeout requestUrl:kTestDownloadURL];\n    req.resumableDownloadPath = path;\n    req.resumableDownloadProgressBlock = ^(NSProgress *progress) {\n        XCTAssertTrue(progress.completedUnitCount > 0);\n        NSLog(@\"Downloading: %lld / %lld\", progress.completedUnitCount, progress.totalUnitCount);\n    };\n\n    [self expectSuccess:req];\n    XCTAssertTrue([[NSFileManager defaultManager] fileExistsAtPath:path]);\n    XCTAssertTrue(([[NSFileManager defaultManager] contentsAtPath:path].length > stringData.length));\n\n    YTKDownloadRequest *req2 = [[YTKDownloadRequest alloc] initWithTimeout:self.networkTimeout requestUrl:kTestFailDownloadURL];\n    req2.resumableDownloadPath = path;\n    req2.resumableDownloadProgressBlock = ^(NSProgress *progress) {\n        XCTAssertTrue(progress.completedUnitCount > 0);\n        NSLog(@\"Downloading: %lld / %lld\", progress.completedUnitCount, progress.totalUnitCount);\n    };\n\n    [self expectFailure:req2];\n    XCTAssertFalse([[NSFileManager defaultManager] fileExistsAtPath:path]);\n    XCTAssertTrue(req2.responseData.length > 0 && req2.responseString.length > 0);\n}\n\n@end\n"
  },
  {
    "path": "YTKNetworkTests/Test Cases/YTKTestCase.h",
    "content": "//\n//  YTKTestCase.h\n//  YTKNetwork\n//\n//  Created by skyline on 16/8/2.\n//  Copyright © 2016年 skyline. All rights reserved.\n//\n\n#import <XCTest/XCTest.h>\n\n@class YTKBaseRequest, YTKRequest;\n@interface YTKTestCase : XCTestCase\n\n@property (nonatomic, assign) NSTimeInterval networkTimeout;\n\n- (void)expectSuccess:(YTKRequest *)request;\n- (void)expectSuccess:(YTKRequest *)request withAssertion:(void(^)(YTKBaseRequest * request)) assertion;\n- (void)expectFailure:(YTKRequest *)request;\n- (void)expectFailure:(YTKRequest *)request withAssertion:(void(^)(YTKBaseRequest * request)) assertion;\n\n- (void)waitForExpectationsWithCommonTimeout;\n- (void)waitForExpectationsWithCommonTimeoutUsingHandler:(XCWaitCompletionHandler)handler;\n\n- (void)createDirectory:(NSString *)path;\n- (void)clearDirectory:(NSString *)path;\n\n@end\n"
  },
  {
    "path": "YTKNetworkTests/Test Cases/YTKTestCase.m",
    "content": "//\n//  YTKTestCase.m\n//  YTKNetwork\n//\n//  Created by skyline on 16/8/2.\n//  Copyright © 2016年 skyline. All rights reserved.\n//\n\n#import \"YTKTestCase.h\"\n#import \"YTKNetworkConfig.h\"\n#import \"YTKNetworkAgent.h\"\n#import \"YTKRequest.h\"\n\nNSString * const YTKNetworkingTestsBaseURLString = @\"https://httpbin.org/\";\n\n@implementation YTKTestCase\n\n- (void)setUp {\n    [super setUp];\n    self.networkTimeout = 20.0;\n    [YTKNetworkConfig sharedConfig].baseUrl = YTKNetworkingTestsBaseURLString;\n}\n\n- (void)tearDown {\n    [super tearDown];\n    [[YTKNetworkAgent sharedAgent] cancelAllRequests];\n    [YTKNetworkConfig sharedConfig].baseUrl = @\"\";\n    [YTKNetworkConfig sharedConfig].cdnUrl = @\"\";\n    [[YTKNetworkConfig sharedConfig] clearUrlFilter];\n    [[YTKNetworkConfig sharedConfig] clearCacheDirPathFilter];\n}\n\n- (void)expectSuccess:(YTKRequest *)request {\n    [self expectSuccess:request withAssertion:nil];\n}\n\n- (void)expectSuccess:(YTKRequest *)request withAssertion:(void(^)(YTKBaseRequest * request)) assertion {\n    XCTestExpectation *exp = [self expectationWithDescription:@\"Request should succeed\"];\n\n    [request startWithCompletionBlockWithSuccess:^(__kindof YTKBaseRequest * _Nonnull request) {\n        XCTAssertNotNil(request);\n        XCTAssertNil(request.error);\n        if (assertion) {\n            assertion(request);\n        }\n        [exp fulfill];\n    } failure:^(__kindof YTKBaseRequest * _Nonnull request) {\n        XCTFail(@\"Request should succeed, but failed\");\n        [exp fulfill];\n    }];\n\n    [self waitForExpectationsWithCommonTimeout];\n}\n\n- (void)expectFailure:(YTKRequest *)request {\n    [self expectFailure:request withAssertion:nil];\n}\n\n- (void)expectFailure:(YTKRequest *)request withAssertion:(void(^)(YTKBaseRequest * request)) assertion {\n    XCTestExpectation *exp = [self expectationWithDescription:@\"Request should fail\"];\n\n    [request startWithCompletionBlockWithSuccess:^(__kindof YTKBaseRequest * _Nonnull request) {\n        XCTFail(@\"Request should fail, but succeeded\");\n        [exp fulfill];\n    } failure:^(__kindof YTKBaseRequest * _Nonnull request) {\n        XCTAssertNotNil(request);\n        XCTAssertNotNil(request.error);\n        if (assertion) {\n            assertion(request);\n        }\n        [exp fulfill];\n    }];\n\n    [self waitForExpectationsWithCommonTimeout];\n}\n\n- (void)waitForExpectationsWithCommonTimeout {\n    [self waitForExpectationsWithCommonTimeoutUsingHandler:^(NSError * _Nullable error) {\n        if (error != nil) {\n            NSLog(@\"Error: %@\", error.localizedDescription);\n        }\n    }];\n}\n\n- (void)waitForExpectationsWithCommonTimeoutUsingHandler:(XCWaitCompletionHandler)handler {\n    [self waitForExpectationsWithTimeout:self.networkTimeout handler:handler];\n}\n\n#pragma mark -\n\n- (void)createDirectory:(NSString *)path {\n    NSError *error = nil;\n    [[NSFileManager defaultManager] createDirectoryAtPath:path withIntermediateDirectories:YES\n                                               attributes:nil error:&error];\n    if (error) {\n        NSLog(@\"Create directory error: %@\", error);\n    }\n}\n\n- (void)clearDirectory:(NSString *)path {\n    NSFileManager* fileManager = [[NSFileManager alloc] init];\n    if (![fileManager fileExistsAtPath:path isDirectory:nil]) {\n        return;\n    }\n    NSDirectoryEnumerator* enumerator = [fileManager enumeratorAtPath:path];\n    NSError *err = nil;\n    BOOL res;\n\n    NSString* file;\n    while (file = [enumerator nextObject]) {\n        res = [fileManager removeItemAtPath:[path stringByAppendingPathComponent:file] error:&err];\n        if (!res && err) {\n            NSLog(@\"Delete file error: %@\", err);\n        }\n    }\n}\n\n@end\n"
  },
  {
    "path": "YTKNetworkTests/Utils/NSString+YTKUrlUtils.h",
    "content": "//\n//  NSString+YTKUrlUtils.h\n//  YTKNetwork\n//\n//  Created by skyline on 16/10/7.\n//  Copyright © 2016年 skyline. All rights reserved.\n//\n\n#import <Foundation/Foundation.h>\n\n@interface NSString (YTKUrlUtils)\n\n- (NSString *)ytk_stringByAppendURLParameters:(NSDictionary *)parameters;\n\n@end\n"
  },
  {
    "path": "YTKNetworkTests/Utils/NSString+YTKUrlUtils.m",
    "content": "//\n//  NSString+YTKUrlUtils.m\n//  YTKNetwork\n//\n//  Created by skyline on 16/10/7.\n//  Copyright © 2016年 skyline. All rights reserved.\n//\n\n#import \"NSString+YTKUrlUtils.h\"\n#import <AFNetworking/AFNetworking.h>\n\n@implementation NSString (YTKUrlUtils)\n\n- (NSString *)ytk_stringByAppendURLParameters:(NSDictionary *)parameters {\n    NSString *paraUrlString = AFQueryStringFromParameters(parameters);\n\n    if (!(paraUrlString.length > 0)) {\n        return self;\n    }\n\n    BOOL useDummyUrl = NO;\n    static NSString *dummyUrl = nil;\n    NSURLComponents *components = [NSURLComponents componentsWithString:self];\n    if (!components) {\n        useDummyUrl = YES;\n        if (!dummyUrl) {\n            dummyUrl = @\"http://www.dummy.com\";\n        }\n        components = [NSURLComponents componentsWithString:dummyUrl];\n    }\n\n    NSString *queryString = components.query ?: @\"\";\n    NSString *newQueryString = [queryString stringByAppendingFormat:queryString.length > 0 ? @\"&%@\" : @\"%@\", paraUrlString];\n\n    components.query = newQueryString;\n\n    if (useDummyUrl) {\n        return [components.URL.absoluteString substringFromIndex:dummyUrl.length - 1];\n    } else {\n        return components.URL.absoluteString;\n    }\n}\n\n@end\n"
  },
  {
    "path": "YTKNetworkTests/Utils/YTKBasicCacheDirFilter.h",
    "content": "//\n//  YTKBasicCacheDirFilter.h\n//  YTKNetwork\n//\n//  Created by skyline on 16/8/14.\n//  Copyright © 2016年 skyline. All rights reserved.\n//\n\n#import <Foundation/Foundation.h>\n#import \"YTKNetworkConfig.h\"\n\n@interface YTKBasicCacheDirFilter : NSObject<YTKCacheDirPathFilterProtocol>\n\n+ (instancetype)filterWithPathComponent:(NSString *)component;\n\n@end\n"
  },
  {
    "path": "YTKNetworkTests/Utils/YTKBasicCacheDirFilter.m",
    "content": "//\n//  YTKBasicCacheDirFilter.m\n//  YTKNetwork\n//\n//  Created by skyline on 16/8/14.\n//  Copyright © 2016年 skyline. All rights reserved.\n//\n\n#import \"YTKBasicCacheDirFilter.h\"\n\n@interface YTKBasicCacheDirFilter ()\n\n@property (nonatomic, strong) NSString *pathComponent;\n\n@end\n\n@implementation YTKBasicCacheDirFilter\n\n+ (instancetype)filterWithPathComponent:(NSString *)component {\n    return [[self alloc] initWithComponent:component];\n}\n\n- (instancetype)initWithComponent:(NSString *)component {\n    self = [super init];\n    if (self) {\n        _pathComponent = component;\n    }\n    return self;\n}\n\n- (NSString *)filterCacheDirPath:(NSString *)originPath withRequest:(YTKBaseRequest *)request {\n    return  [originPath stringByAppendingPathComponent:_pathComponent];\n}\n\n@end\n"
  },
  {
    "path": "YTKNetworkTests/Utils/YTKBasicUrlFilter.h",
    "content": "//\n//  YTKBasicUrlFilter.h\n//  YTKNetworkDemo\n//\n//  Created by skyline on 16/7/30.\n//  Copyright © 2016年 yuantiku.com. All rights reserved.\n//\n\n#import <Foundation/Foundation.h>\n#import \"YTKNetworkConfig.h\"\n\n@protocol YTKUrlFilterProtocol;\n@interface YTKBasicUrlFilter : NSObject<YTKUrlFilterProtocol>\n\n+ (instancetype)filterWithArguments:(NSDictionary<NSString *, NSString *> *)arguments;\n\n@end\n"
  },
  {
    "path": "YTKNetworkTests/Utils/YTKBasicUrlFilter.m",
    "content": "//\n//  YTKBasicUrlFilter.m\n//  YTKNetworkDemo\n//\n//  Created by skyline on 16/7/30.\n//  Copyright © 2016年 yuantiku.com. All rights reserved.\n//\n\n#import \"YTKBasicUrlFilter.h\"\n#import \"YTKNetworkConfig.h\"\n#import \"NSString+YTKUrlUtils.h\"\n\n@interface YTKBasicUrlFilter ()\n\n@property NSDictionary *arguments;\n\n@end\n\n@implementation YTKBasicUrlFilter\n\n+ (instancetype)filterWithArguments:(NSDictionary *)arguments {\n    return [[self alloc] initWithArguments:arguments];\n}\n\n- (instancetype)initWithArguments:(NSDictionary *)arguments {\n    self = [super init];\n    if (self) {\n        _arguments = arguments;\n    }\n    return self;\n}\n\n- (NSString *)filterUrl:(NSString *)originUrl withRequest:(YTKBaseRequest *)request {\n    return [originUrl ytk_stringByAppendURLParameters:_arguments];\n}\n\n@end\n"
  }
]