From 3d70aea123b583c0cfcc9ba9f01d7e9c9876e4df Mon Sep 17 00:00:00 2001 From: hrbrmstr Date: Fri, 6 Sep 2019 07:35:10 -0400 Subject: [PATCH] removed soup --- Podfile | 8 +- Podfile.lock | 14 +- Pods/Just/LICENSE.md | 9 + Pods/Just/README.md | 156 ++ Pods/Just/Sources/Just/Just.swift | 1130 ++++++++++++++ Pods/Manifest.lock | 14 +- Pods/Pods.xcodeproj/project.pbxproj | 601 +++---- .../hrbrmstr.xcuserdatad/xcschemes/Just.xcscheme | 60 + .../xcschemes/SwiftSoup.xcscheme | 60 - .../xcschemes/xcschememanagement.plist | 4 +- Pods/SwiftSoup/LICENSE | 21 - Pods/SwiftSoup/README.md | 595 ------- Pods/SwiftSoup/Sources/ArrayExt.swift | 21 - Pods/SwiftSoup/Sources/Attribute.swift | 148 -- Pods/SwiftSoup/Sources/Attributes.swift | 264 ---- Pods/SwiftSoup/Sources/BooleanAttribute.swift | 26 - Pods/SwiftSoup/Sources/CharacterExt.swift | 81 - Pods/SwiftSoup/Sources/CharacterReader.swift | 463 ------ Pods/SwiftSoup/Sources/Cleaner.swift | 150 -- Pods/SwiftSoup/Sources/Collector.swift | 59 - Pods/SwiftSoup/Sources/CombiningEvaluator.swift | 127 -- Pods/SwiftSoup/Sources/Comment.swift | 66 - Pods/SwiftSoup/Sources/Connection.swift | 10 - Pods/SwiftSoup/Sources/DataNode.swift | 85 - Pods/SwiftSoup/Sources/DataUtil.swift | 24 - Pods/SwiftSoup/Sources/Document.swift | 562 ------- Pods/SwiftSoup/Sources/DocumentType.swift | 129 -- Pods/SwiftSoup/Sources/Element.swift | 1295 --------------- Pods/SwiftSoup/Sources/Elements.swift | 602 ------- Pods/SwiftSoup/Sources/Entities.swift | 382 ----- Pods/SwiftSoup/Sources/Evaluator.swift | 720 --------- Pods/SwiftSoup/Sources/Exception.swift | 22 - Pods/SwiftSoup/Sources/FormElement.swift | 125 -- Pods/SwiftSoup/Sources/HtmlTreeBuilder.swift | 771 --------- Pods/SwiftSoup/Sources/HtmlTreeBuilderState.swift | 1549 ------------------ Pods/SwiftSoup/Sources/HttpStatusException.swift | 10 - Pods/SwiftSoup/Sources/Node.swift | 808 ---------- Pods/SwiftSoup/Sources/NodeTraversor.swift | 50 - Pods/SwiftSoup/Sources/NodeVisitor.swift | 37 - Pods/SwiftSoup/Sources/OrderedDictionary.swift | 429 ----- Pods/SwiftSoup/Sources/OrderedSet.swift | 453 ------ Pods/SwiftSoup/Sources/ParseError.swift | 42 - Pods/SwiftSoup/Sources/ParseErrorList.swift | 52 - Pods/SwiftSoup/Sources/ParseSettings.swift | 59 - Pods/SwiftSoup/Sources/Parser.swift | 201 --- Pods/SwiftSoup/Sources/Pattern.swift | 84 - Pods/SwiftSoup/Sources/QueryParser.swift | 322 ---- Pods/SwiftSoup/Sources/Selector.swift | 163 -- .../SwiftSoup/Sources/SerializationException.swift | 10 - Pods/SwiftSoup/Sources/SimpleDictionary.swift | 39 - Pods/SwiftSoup/Sources/StreamReader.swift | 89 -- Pods/SwiftSoup/Sources/String.swift | 206 --- Pods/SwiftSoup/Sources/StringBuilder.swift | 165 -- Pods/SwiftSoup/Sources/StringUtil.swift | 262 ---- Pods/SwiftSoup/Sources/StructuralEvaluator.swift | 176 --- Pods/SwiftSoup/Sources/SwiftSoup.swift | 242 --- Pods/SwiftSoup/Sources/Tag.swift | 347 ----- Pods/SwiftSoup/Sources/TextNode.swift | 199 --- Pods/SwiftSoup/Sources/Token.swift | 396 ----- Pods/SwiftSoup/Sources/TokenQueue.swift | 428 ----- Pods/SwiftSoup/Sources/Tokeniser.swift | 311 ---- Pods/SwiftSoup/Sources/TokeniserState.swift | 1644 -------------------- Pods/SwiftSoup/Sources/TreeBuilder.swift | 98 -- Pods/SwiftSoup/Sources/UnicodeScalar.swift | 67 - Pods/SwiftSoup/Sources/Validate.swift | 133 -- Pods/SwiftSoup/Sources/Whitelist.swift | 650 -------- Pods/SwiftSoup/Sources/XmlDeclaration.swift | 77 - Pods/SwiftSoup/Sources/XmlTreeBuilder.swift | 146 -- Pods/Target Support Files/Just/Just-Info.plist | 26 + Pods/Target Support Files/Just/Just-dummy.m | 5 + Pods/Target Support Files/Just/Just-prefix.pch | 12 + Pods/Target Support Files/Just/Just-umbrella.h | 16 + Pods/Target Support Files/Just/Just.modulemap | 6 + Pods/Target Support Files/Just/Just.xcconfig | 11 + .../Pods-RSwitch-acknowledgements.markdown | 24 +- .../Pods-RSwitch-acknowledgements.plist | 24 +- ...RSwitch-frameworks-Debug-input-files.xcfilelist | 2 +- ...Switch-frameworks-Debug-output-files.xcfilelist | 2 +- ...witch-frameworks-Release-input-files.xcfilelist | 2 +- ...itch-frameworks-Release-output-files.xcfilelist | 2 +- .../Pods-RSwitch/Pods-RSwitch-frameworks.sh | 4 +- .../Pods-RSwitch/Pods-RSwitch.debug.xcconfig | 7 +- .../Pods-RSwitch/Pods-RSwitch.release.xcconfig | 7 +- .../SwiftSoup/SwiftSoup-Info.plist | 26 - .../SwiftSoup/SwiftSoup-dummy.m | 5 - .../SwiftSoup/SwiftSoup-prefix.pch | 12 - .../SwiftSoup/SwiftSoup-umbrella.h | 16 - .../SwiftSoup/SwiftSoup.modulemap | 6 - .../SwiftSoup/SwiftSoup.xcconfig | 10 - RSwitch.xcodeproj/project.pbxproj | 4 + RSwitch/Swift/AppDelegate.swift | 9 +- RSwitch/Swift/Downloaders/DownloadRStudio.swift | 95 +- RSwitch/Swift/Utils/Preferences.swift | 9 +- RSwitch/Swift/Utils/RStudioUtils.swift | 29 + 94 files changed, 1742 insertions(+), 17377 deletions(-) create mode 100644 Pods/Just/LICENSE.md create mode 100644 Pods/Just/README.md create mode 100644 Pods/Just/Sources/Just/Just.swift create mode 100644 Pods/Pods.xcodeproj/xcuserdata/hrbrmstr.xcuserdatad/xcschemes/Just.xcscheme delete mode 100644 Pods/Pods.xcodeproj/xcuserdata/hrbrmstr.xcuserdatad/xcschemes/SwiftSoup.xcscheme delete mode 100644 Pods/SwiftSoup/LICENSE delete mode 100644 Pods/SwiftSoup/README.md delete mode 100644 Pods/SwiftSoup/Sources/ArrayExt.swift delete mode 100644 Pods/SwiftSoup/Sources/Attribute.swift delete mode 100644 Pods/SwiftSoup/Sources/Attributes.swift delete mode 100644 Pods/SwiftSoup/Sources/BooleanAttribute.swift delete mode 100644 Pods/SwiftSoup/Sources/CharacterExt.swift delete mode 100644 Pods/SwiftSoup/Sources/CharacterReader.swift delete mode 100644 Pods/SwiftSoup/Sources/Cleaner.swift delete mode 100644 Pods/SwiftSoup/Sources/Collector.swift delete mode 100644 Pods/SwiftSoup/Sources/CombiningEvaluator.swift delete mode 100644 Pods/SwiftSoup/Sources/Comment.swift delete mode 100644 Pods/SwiftSoup/Sources/Connection.swift delete mode 100644 Pods/SwiftSoup/Sources/DataNode.swift delete mode 100644 Pods/SwiftSoup/Sources/DataUtil.swift delete mode 100644 Pods/SwiftSoup/Sources/Document.swift delete mode 100644 Pods/SwiftSoup/Sources/DocumentType.swift delete mode 100644 Pods/SwiftSoup/Sources/Element.swift delete mode 100644 Pods/SwiftSoup/Sources/Elements.swift delete mode 100644 Pods/SwiftSoup/Sources/Entities.swift delete mode 100644 Pods/SwiftSoup/Sources/Evaluator.swift delete mode 100644 Pods/SwiftSoup/Sources/Exception.swift delete mode 100644 Pods/SwiftSoup/Sources/FormElement.swift delete mode 100644 Pods/SwiftSoup/Sources/HtmlTreeBuilder.swift delete mode 100644 Pods/SwiftSoup/Sources/HtmlTreeBuilderState.swift delete mode 100644 Pods/SwiftSoup/Sources/HttpStatusException.swift delete mode 100644 Pods/SwiftSoup/Sources/Node.swift delete mode 100644 Pods/SwiftSoup/Sources/NodeTraversor.swift delete mode 100644 Pods/SwiftSoup/Sources/NodeVisitor.swift delete mode 100644 Pods/SwiftSoup/Sources/OrderedDictionary.swift delete mode 100644 Pods/SwiftSoup/Sources/OrderedSet.swift delete mode 100644 Pods/SwiftSoup/Sources/ParseError.swift delete mode 100644 Pods/SwiftSoup/Sources/ParseErrorList.swift delete mode 100644 Pods/SwiftSoup/Sources/ParseSettings.swift delete mode 100644 Pods/SwiftSoup/Sources/Parser.swift delete mode 100644 Pods/SwiftSoup/Sources/Pattern.swift delete mode 100644 Pods/SwiftSoup/Sources/QueryParser.swift delete mode 100644 Pods/SwiftSoup/Sources/Selector.swift delete mode 100644 Pods/SwiftSoup/Sources/SerializationException.swift delete mode 100644 Pods/SwiftSoup/Sources/SimpleDictionary.swift delete mode 100644 Pods/SwiftSoup/Sources/StreamReader.swift delete mode 100644 Pods/SwiftSoup/Sources/String.swift delete mode 100755 Pods/SwiftSoup/Sources/StringBuilder.swift delete mode 100644 Pods/SwiftSoup/Sources/StringUtil.swift delete mode 100644 Pods/SwiftSoup/Sources/StructuralEvaluator.swift delete mode 100644 Pods/SwiftSoup/Sources/SwiftSoup.swift delete mode 100644 Pods/SwiftSoup/Sources/Tag.swift delete mode 100644 Pods/SwiftSoup/Sources/TextNode.swift delete mode 100644 Pods/SwiftSoup/Sources/Token.swift delete mode 100644 Pods/SwiftSoup/Sources/TokenQueue.swift delete mode 100644 Pods/SwiftSoup/Sources/Tokeniser.swift delete mode 100644 Pods/SwiftSoup/Sources/TokeniserState.swift delete mode 100644 Pods/SwiftSoup/Sources/TreeBuilder.swift delete mode 100644 Pods/SwiftSoup/Sources/UnicodeScalar.swift delete mode 100644 Pods/SwiftSoup/Sources/Validate.swift delete mode 100644 Pods/SwiftSoup/Sources/Whitelist.swift delete mode 100644 Pods/SwiftSoup/Sources/XmlDeclaration.swift delete mode 100644 Pods/SwiftSoup/Sources/XmlTreeBuilder.swift create mode 100644 Pods/Target Support Files/Just/Just-Info.plist create mode 100644 Pods/Target Support Files/Just/Just-dummy.m create mode 100644 Pods/Target Support Files/Just/Just-prefix.pch create mode 100644 Pods/Target Support Files/Just/Just-umbrella.h create mode 100644 Pods/Target Support Files/Just/Just.modulemap create mode 100644 Pods/Target Support Files/Just/Just.xcconfig delete mode 100644 Pods/Target Support Files/SwiftSoup/SwiftSoup-Info.plist delete mode 100644 Pods/Target Support Files/SwiftSoup/SwiftSoup-dummy.m delete mode 100644 Pods/Target Support Files/SwiftSoup/SwiftSoup-prefix.pch delete mode 100644 Pods/Target Support Files/SwiftSoup/SwiftSoup-umbrella.h delete mode 100644 Pods/Target Support Files/SwiftSoup/SwiftSoup.modulemap delete mode 100644 Pods/Target Support Files/SwiftSoup/SwiftSoup.xcconfig create mode 100644 RSwitch/Swift/Utils/RStudioUtils.swift diff --git a/Podfile b/Podfile index f260a1c..85a0427 100644 --- a/Podfile +++ b/Podfile @@ -1,11 +1,11 @@ +source 'https://cdn.cocoapods.org/' + platform :osx, '10.14' -source 'https://cdn.cocoapods.org/' +use_frameworks! target 'RSwitch' do - use_frameworks! - - pod 'SwiftSoup' + pod 'Just' end diff --git a/Podfile.lock b/Podfile.lock index ad11e35..032d067 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -1,16 +1,16 @@ PODS: - - SwiftSoup (2.2.0) + - Just (0.8.0) DEPENDENCIES: - - SwiftSoup + - Just SPEC REPOS: - https://github.com/cocoapods/specs.git: - - SwiftSoup + trunk: + - Just SPEC CHECKSUMS: - SwiftSoup: 230991361c5ba249d140161860a3864a28b63860 + Just: aef5105fb2c7069b65aa6f21aec8f429057f9c19 -PODFILE CHECKSUM: d5db68a23a6fb36f3d94717563c9d5199d9f3bdf +PODFILE CHECKSUM: 0ed9277c30181dde6c0bb4a7b18f37dca46c8ec9 -COCOAPODS: 1.7.5 +COCOAPODS: 1.8.0.beta.2 diff --git a/Pods/Just/LICENSE.md b/Pods/Just/LICENSE.md new file mode 100644 index 0000000..5439ff0 --- /dev/null +++ b/Pods/Just/LICENSE.md @@ -0,0 +1,9 @@ +The MIT License (MIT) + +Copyright (c) 2015 Just contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/Pods/Just/README.md b/Pods/Just/README.md new file mode 100644 index 0000000..5790445 --- /dev/null +++ b/Pods/Just/README.md @@ -0,0 +1,156 @@ +[![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) +[![CocoaPods](https://img.shields.io/cocoapods/v/Just.svg)](https://cocoapods.org/pods/Just) +[![Build Status](https://travis-ci.org/JustHTTP/Just.svg?branch=master)](https://travis-ci.org/JustHTTP/Just) +![Supported Flatform](https://img.shields.io/cocoapods/p/Just.svg) + + + +Just is a client-side HTTP library inspired by [python-requests][] - HTTP for Humans. + +Just requires Swift 5. For Swift 4.2 support, use version [0.7.1][]. + +[0.7.1]: https://github.com/JustHTTP/Just/releases/tag/0.7.1 +[python-requests]: http://python-requests.org "python-requests" +[twitter]: https://twitter.com/JustHTTP + +# Features + +Just lets you to the following effortlessly: + +- URL queries +- custom headers +- form (`x-www-form-encoded`) / JSON HTTP body +- redirect control +- multipart file upload along with form values. +- basic/digest authentication +- cookies +- timeouts +- synchronous / asynchronous requests +- upload / download progress tracking for asynchronous requests +- link headers +- friendly accessible results + +# Use + +The simplest request with Just looks like this: + +```swift +// A simple get request +Just.get("http://httpbin.org/get") +``` + +The next example shows how to upload a file along with some data: + +```swift +// talk to registration end point +let r = Just.post( + "http://justiceleauge.org/member/register", + data: ["username": "barryallen", "password":"ReverseF1ashSucks"], + files: ["profile_photo": .url(fileURLWithPath:"flash.jpeg", nil)] +) + +if r.ok { /* success! */ } +``` + +Here's the same example done asynchronously: + +```swift +// talk to registration end point +Just.post( + "http://justiceleauge.org/member/register", + data: ["username": "barryallen", "password":"ReverseF1ashSucks"], + files: ["profile_photo": .url(fileURLWithPath:"flash.jpeg", nil)] +) { r in + if r.ok { /* success! */ } +} + +``` + +Read *Getting Started* [on the web][starting link] or +[in this playground][starting playground] to learn more! + +[starting playground]: https://github.com/JustHTTP/Just/blob/master/Docs/QuickStart.zip?raw=true +[starting link]: https://JustHTTP.github.io + +# Install + +Here are some ways to leverage Just. + +## Xcode + +Add `https://github.com/JustHTTP/Just.git` the usual way. + +## Swift Package Manager + +Add the following to your `dependencies`: + +```swift +.package(url: "https://github.com/JustHTTP/Just.git", from: "0.8.0") +``` + +… and `"Just"` to your target dependencies. + +## Carthage + +Include the following in your Cartfile: + + github "JustHTTP/Just" + +Just includes dynamic framework targets for both iOS and OS X. + +## CocoaPods + +The usual way: + + platform :ios, '8.0' + use_frameworks! + + target 'MyApp' do + pod 'Just' + end + +## Manual + +Drop `Just.xcodeproj` into your project navigator. Under the *General* tab of +your project settings, use the plus sign to add `Just.framework` to +*Linked Framework and Libraries*. Make sure to include the correct version +for your target's platform. + +It's also common to add Just as a git submodule to your projects repository: + + cd path/to/your/project + git submodule add https://github.org/JustHTTP/Just.git + + +## Source File + +Put `Just.swift` directly into your project. Alternately, put it in the +*Sources* folder of a playground. (The latter makes a fun way to explore the +web.) + + +[Carthage]: https://github.com/Carthage/Carthage "Carthage" + + +# Contribute + +Pull requests are welcome. Here are some tips for code contributors: + +Work in `Just.xcworkspace`. + +The tests for link headers relies on Github APIs, which has a low per-hour +limit. To overcome this, you can edit the Xcode build schemes and add +[environment variables][XcodeEnvVar] `GITHUB_TOKEN`. Learn more about +personal tokens [here][GithubToken]. + +For Xcode rebels, checkout `Makefile`. + +HTML documentation pages are generated by literate programmin tool [docco][] + +[docco]: http://jashkenas.github.io/docco/ "docco" +[GithubToken]: https://developer.github.com/v3/#increasing-the-unauthenticated-rate-limit-for-oauth-applications +[XcodeEnvVar]: http://nshipster.com/launch-arguments-and-environment-variables/ + +# License + +MIT, see [LICENSE.md](https://github.com/JustHTTP/Just/blob/master/LICENSE.md). diff --git a/Pods/Just/Sources/Just/Just.swift b/Pods/Just/Sources/Just/Just.swift new file mode 100644 index 0000000..487eb06 --- /dev/null +++ b/Pods/Just/Sources/Just/Just.swift @@ -0,0 +1,1130 @@ +import Foundation +#if canImport(FoundationNetworking) +import FoundationNetworking +#endif + +#if os(Linux) +import Dispatch +#endif + +// stolen from python-requests +let statusCodeDescriptions = [ + // Informational. + 100: "continue", + 101: "switching protocols", + 102: "processing", + 103: "checkpoint", + 122: "uri too long", + 200: "ok", + 201: "created", + 202: "accepted", + 203: "non authoritative info", + 204: "no content", + 205: "reset content", + 206: "partial content", + 207: "multi status", + 208: "already reported", + 226: "im used", + + // Redirection. + 300: "multiple choices", + 301: "moved permanently", + 302: "found", + 303: "see other", + 304: "not modified", + 305: "use proxy", + 306: "switch proxy", + 307: "temporary redirect", + 308: "permanent redirect", + + // Client Error. + 400: "bad request", + 401: "unauthorized", + 402: "payment required", + 403: "forbidden", + 404: "not found", + 405: "method not allowed", + 406: "not acceptable", + 407: "proxy authentication required", + 408: "request timeout", + 409: "conflict", + 410: "gone", + 411: "length required", + 412: "precondition failed", + 413: "request entity too large", + 414: "request uri too large", + 415: "unsupported media type", + 416: "requested range not satisfiable", + 417: "expectation failed", + 418: "im a teapot", + 422: "unprocessable entity", + 423: "locked", + 424: "failed dependency", + 425: "unordered collection", + 426: "upgrade required", + 428: "precondition required", + 429: "too many requests", + 431: "header fields too large", + 444: "no response", + 449: "retry with", + 450: "blocked by windows parental controls", + 451: "unavailable for legal reasons", + 499: "client closed request", + + // Server Error. + 500: "internal server error", + 501: "not implemented", + 502: "bad gateway", + 503: "service unavailable", + 504: "gateway timeout", + 505: "http version not supported", + 506: "variant also negotiates", + 507: "insufficient storage", + 509: "bandwidth limit exceeded", + 510: "not extended", +] + +public enum HTTPFile { + case url(URL, String?) // URL to a file, mimetype + case data(String, Foundation.Data, String?) // filename, data, mimetype + case text(String, String, String?) // filename, text, mimetype +} + +// Supported request types +public enum HTTPMethod: String { + case delete = "DELETE" + case get = "GET" + case head = "HEAD" + case options = "OPTIONS" + case patch = "PATCH" + case post = "POST" + case put = "PUT" +} + +extension URLResponse { + var HTTPHeaders: [String: String] { + return (self as? HTTPURLResponse)?.allHeaderFields as? [String: String] + ?? [:] + } +} + +public protocol URLComponentsConvertible { + var urlComponents: URLComponents? { get } +} + +extension String: URLComponentsConvertible { + public var urlComponents: URLComponents? { + return URLComponents(string: self) + } +} + +extension URL: URLComponentsConvertible { + public var urlComponents: URLComponents? { + return URLComponents(url: self, resolvingAgainstBaseURL: true) + } +} + +/// The only reason this is not a struct is the requirements for +/// lazy evaluation of `headers` and `cookies`, which is mutating the +/// struct. This would make those properties unusable with `HTTPResult`s +/// declared with `let` +public final class HTTPResult : NSObject { + public final var content: Data? + public var response: URLResponse? + public var error: Error? + public var request: URLRequest? { return task?.originalRequest } + public var task: URLSessionTask? + public var encoding = String.Encoding.utf8 + public var JSONReadingOptions = JSONSerialization.ReadingOptions(rawValue: 0) + + public var reason: String { + if let code = self.statusCode, let text = statusCodeDescriptions[code] { + return text + } + + if let error = self.error { + return error.localizedDescription + } + return "Unknown" + } + + public var isRedirect: Bool { + if let code = self.statusCode { + return code >= 300 && code < 400 + } + return false + } + + public var isPermanentRedirect: Bool { + return self.statusCode == 301 + } + + public override var description: String { + if let status = statusCode, + let urlString = request?.url?.absoluteString, + let method = request?.httpMethod + { + return "\(method) \(urlString) \(status)" + } else { + return "" + } + } + + public init(data: Data?, response: URLResponse?, error: Error?, + task: URLSessionTask?) + { + self.content = data + self.response = response + self.error = error + self.task = task + } + + public var json: Any? { + return content.flatMap { + try? JSONSerialization.jsonObject(with: $0, options: JSONReadingOptions) + } + } + + public var statusCode: Int? { + return (self.response as? HTTPURLResponse)?.statusCode + } + + public var text: String? { + return content.flatMap { String(data: $0, encoding: encoding) } + } + + public lazy var headers: CaseInsensitiveDictionary = { + return CaseInsensitiveDictionary( + dictionary: self.response?.HTTPHeaders ?? [:]) + }() + + public lazy var cookies: [String: HTTPCookie] = { + let foundCookies: [HTTPCookie] + if let headers = self.response?.HTTPHeaders, let url = self.response?.url { + foundCookies = HTTPCookie.cookies(withResponseHeaderFields: headers, + for: url) + } else { + foundCookies = [] + } + var result: [String: HTTPCookie] = [:] + for cookie in foundCookies { + result[cookie.name] = cookie + } + return result + }() + + public var ok: Bool { + return statusCode != nil && !(statusCode! >= 400 && statusCode! < 600) + } + + public var url: URL? { + return response?.url + } + + public lazy var links: [String: [String: String]] = { + var result = [String: [String: String]]() + guard let content = self.headers["link"] else { + return result + } + content.components(separatedBy: ", ").forEach { s in + let linkComponents = s.components(separatedBy: ";") + .map { $0.trimmingCharacters(in: CharacterSet.whitespaces) } + // although a link without a rel is valid, there's no way to reference it. + if linkComponents.count > 1 { + let url = linkComponents.first! + let start = url.index(url.startIndex, offsetBy: 1) + let end = url.index(url.endIndex, offsetBy: -1) + let urlRange = start..: Collection, + ExpressibleByDictionaryLiteral +{ + private var _data: [Key: Value] = [:] + private var _keyMap: [String: Key] = [:] + + public typealias Element = (key: Key, value: Value) + public typealias Index = DictionaryIndex + public var startIndex: Index { + return _data.startIndex + } + public var endIndex: Index { + return _data.endIndex + } + public func index(after: Index) -> Index { + return _data.index(after: after) + } + + public var count: Int { + assert(_data.count == _keyMap.count, "internal keys out of sync") + return _data.count + } + + public var isEmpty: Bool { + return _data.isEmpty + } + + public init(dictionaryLiteral elements: (Key, Value)...) { + for (key, value) in elements { + _keyMap["\(key)".lowercased()] = key + _data[key] = value + } + } + + public init(dictionary: [Key: Value]) { + for (key, value) in dictionary { + _keyMap["\(key)".lowercased()] = key + _data[key] = value + } + } + + public subscript (position: Index) -> Element { + return _data[position] + } + + public subscript (key: Key) -> Value? { + get { + if let realKey = _keyMap["\(key)".lowercased()] { + return _data[realKey] + } + return nil + } + set(newValue) { + let lowerKey = "\(key)".lowercased() + if _keyMap[lowerKey] == nil { + _keyMap[lowerKey] = key + } + _data[_keyMap[lowerKey]!] = newValue + } + } + + public func makeIterator() -> DictionaryIterator { + return _data.makeIterator() + } + + public var keys: Dictionary.Keys { + return _data.keys + } + public var values: Dictionary.Values { + return _data.values + } +} + +typealias TaskID = Int +public typealias Credentials = (username: String, password: String) +public typealias TaskProgressHandler = (HTTPProgress) -> Void +typealias TaskCompletionHandler = (HTTPResult) -> Void + +struct TaskConfiguration { + let credential: Credentials? + let redirects: Bool + let originalRequest: URLRequest? + var data: Data + let progressHandler: TaskProgressHandler? + let completionHandler: TaskCompletionHandler? +} + +public struct JustSessionDefaults { + public var JSONReadingOptions: JSONSerialization.ReadingOptions + public var JSONWritingOptions: JSONSerialization.WritingOptions + public var headers: [String: String] + public var multipartBoundary: String + public var credentialPersistence: URLCredential.Persistence + public var encoding: String.Encoding + public var cachePolicy: NSURLRequest.CachePolicy + public init( + JSONReadingOptions: JSONSerialization.ReadingOptions = + JSONSerialization.ReadingOptions(rawValue: 0), + JSONWritingOptions: JSONSerialization.WritingOptions = + JSONSerialization.WritingOptions(rawValue: 0), + headers: [String: String] = [:], + multipartBoundary: String = "Ju5tH77P15Aw350m3", + credentialPersistence: URLCredential.Persistence = .forSession, + encoding: String.Encoding = String.Encoding.utf8, + cachePolicy: NSURLRequest.CachePolicy = .reloadIgnoringLocalCacheData) + { + self.JSONReadingOptions = JSONReadingOptions + self.JSONWritingOptions = JSONWritingOptions + self.headers = headers + self.multipartBoundary = multipartBoundary + self.encoding = encoding + self.credentialPersistence = credentialPersistence + self.cachePolicy = cachePolicy + } +} + + +public struct HTTPProgress { + public enum `Type` { + case upload + case download + } + + public let type: Type + public let bytesProcessed: Int64 + public let bytesExpectedToProcess: Int64 + public var chunk: Data? + public var percent: Float { + return Float(bytesProcessed) / Float(bytesExpectedToProcess) + } +} + +let errorDomain = "net.justhttp.Just" + +public protocol JustAdaptor { + func request( + _ method: HTTPMethod, + url: URLComponentsConvertible, + params: [String: Any], + data: [String: Any], + json: Any?, + headers: [String: String], + files: [String: HTTPFile], + auth: Credentials?, + cookies: [String: String], + redirects: Bool, + timeout: Double?, + urlQuery: String?, + requestBody: Data?, + asyncProgressHandler: TaskProgressHandler?, + asyncCompletionHandler: ((HTTPResult) -> Void)? + ) -> HTTPResult + + init(session: URLSession?, defaults: JustSessionDefaults?) +} + +public struct JustOf { + let adaptor: Adaptor + public init(session: URLSession? = nil, + defaults: JustSessionDefaults? = nil) + { + adaptor = Adaptor(session: session, defaults: defaults) + } +} + +extension JustOf { + + @discardableResult + public func request( + _ method: HTTPMethod, + url: URLComponentsConvertible, + params: [String: Any] = [:], + data: [String: Any] = [:], + json: Any? = nil, + headers: [String: String] = [:], + files: [String: HTTPFile] = [:], + auth: (String, String)? = nil, + cookies: [String: String] = [:], + allowRedirects: Bool = true, + timeout: Double? = nil, + urlQuery: String? = nil, + requestBody: Data? = nil, + asyncProgressHandler: (TaskProgressHandler)? = nil, + asyncCompletionHandler: ((HTTPResult) -> Void)? = nil + ) -> HTTPResult { + return adaptor.request( + method, + url: url, + params: params, + data: data, + json: json, + headers: headers, + files: files, + auth: auth, + cookies: cookies, + redirects: allowRedirects, + timeout: timeout, + urlQuery: urlQuery, + requestBody: requestBody, + asyncProgressHandler: asyncProgressHandler, + asyncCompletionHandler: asyncCompletionHandler + ) + } + + @discardableResult + public func delete( + _ url: URLComponentsConvertible, + params: [String: Any] = [:], + data: [String: Any] = [:], + json: Any? = nil, + headers: [String: String] = [:], + files: [String: HTTPFile] = [:], + auth: (String, String)? = nil, + cookies: [String: String] = [:], + allowRedirects: Bool = true, + timeout: Double? = nil, + urlQuery: String? = nil, + requestBody: Data? = nil, + asyncProgressHandler: (TaskProgressHandler)? = nil, + asyncCompletionHandler: ((HTTPResult) -> Void)? = nil + ) -> HTTPResult { + + return adaptor.request( + .delete, + url: url, + params: params, + data: data, + json: json, + headers: headers, + files: files, + auth: auth, + cookies: cookies, + redirects: allowRedirects, + timeout: timeout, + urlQuery: urlQuery, + requestBody: requestBody, + asyncProgressHandler: asyncProgressHandler, + asyncCompletionHandler: asyncCompletionHandler + ) + } + + @discardableResult + public func get( + _ url: URLComponentsConvertible, + params: [String: Any] = [:], + data: [String: Any] = [:], + json: Any? = nil, + headers: [String: String] = [:], + files: [String: HTTPFile] = [:], + auth: (String, String)? = nil, + cookies: [String: String] = [:], + allowRedirects: Bool = true, + timeout: Double? = nil, + urlQuery: String? = nil, + requestBody: Data? = nil, + asyncProgressHandler: (TaskProgressHandler)? = nil, + asyncCompletionHandler: ((HTTPResult) -> Void)? = nil + ) -> HTTPResult { + + return adaptor.request( + .get, + url: url, + params: params, + data: data, + json: json, + headers: headers, + files: files, + auth: auth, + cookies: cookies, + redirects: allowRedirects, + timeout: timeout, + urlQuery: urlQuery, + requestBody: requestBody, + asyncProgressHandler: asyncProgressHandler, + asyncCompletionHandler: asyncCompletionHandler + ) + } + + @discardableResult + public func head( + _ url: URLComponentsConvertible, + params: [String: Any] = [:], + data: [String: Any] = [:], + json: Any? = nil, + headers: [String: String] = [:], + files: [String: HTTPFile] = [:], + auth: (String, String)? = nil, + cookies: [String: String] = [:], + allowRedirects: Bool = true, + timeout: Double? = nil, + urlQuery: String? = nil, + requestBody: Data? = nil, + asyncProgressHandler: (TaskProgressHandler)? = nil, + asyncCompletionHandler: ((HTTPResult) -> Void)? = nil + ) -> HTTPResult { + + return adaptor.request( + .head, + url: url, + params: params, + data: data, + json: json, + headers: headers, + files: files, + auth: auth, + cookies: cookies, + redirects: allowRedirects, + timeout: timeout, + urlQuery: urlQuery, + requestBody: requestBody, + asyncProgressHandler: asyncProgressHandler, + asyncCompletionHandler: asyncCompletionHandler + ) + } + + @discardableResult + public func options( + _ url: URLComponentsConvertible, + params: [String: Any] = [:], + data: [String: Any] = [:], + json: Any? = nil, + headers: [String: String] = [:], + files: [String: HTTPFile] = [:], + auth: (String, String)? = nil, + cookies: [String: String] = [:], + allowRedirects: Bool = true, + timeout: Double? = nil, + urlQuery: String? = nil, + requestBody: Data? = nil, + asyncProgressHandler: (TaskProgressHandler)? = nil, + asyncCompletionHandler: ((HTTPResult) -> Void)? = nil + ) -> HTTPResult { + return adaptor.request( + .options, + url: url, + params: params, + data: data, + json: json, + headers: headers, + files: files, + auth: auth, + cookies: cookies, + redirects: allowRedirects, + timeout: timeout, + urlQuery: urlQuery, + requestBody: requestBody, + asyncProgressHandler: asyncProgressHandler, + asyncCompletionHandler: asyncCompletionHandler + ) + } + + @discardableResult + public func patch( + _ url: URLComponentsConvertible, + params: [String: Any] = [:], + data: [String: Any] = [:], + json: Any? = nil, + headers: [String: String] = [:], + files: [String: HTTPFile] = [:], + auth: (String, String)? = nil, + cookies: [String: String] = [:], + allowRedirects: Bool = true, + timeout: Double? = nil, + urlQuery: String? = nil, + requestBody: Data? = nil, + asyncProgressHandler: (TaskProgressHandler)? = nil, + asyncCompletionHandler: ((HTTPResult) -> Void)? = nil + ) -> HTTPResult { + + return adaptor.request( + .patch, + url: url, + params: params, + data: data, + json: json, + headers: headers, + files: files, + auth: auth, + cookies: cookies, + redirects: allowRedirects, + timeout: timeout, + urlQuery: urlQuery, + requestBody: requestBody, + asyncProgressHandler: asyncProgressHandler, + asyncCompletionHandler: asyncCompletionHandler + ) + } + + @discardableResult + public func post( + _ url: URLComponentsConvertible, + params: [String: Any] = [:], + data: [String: Any] = [:], + json: Any? = nil, + headers: [String: String] = [:], + files: [String: HTTPFile] = [:], + auth: (String, String)? = nil, + cookies: [String: String] = [:], + allowRedirects: Bool = true, + timeout: Double? = nil, + urlQuery: String? = nil, + requestBody: Data? = nil, + asyncProgressHandler: (TaskProgressHandler)? = nil, + asyncCompletionHandler: ((HTTPResult) -> Void)? = nil + ) -> HTTPResult { + + return adaptor.request( + .post, + url: url, + params: params, + data: data, + json: json, + headers: headers, + files: files, + auth: auth, + cookies: cookies, + redirects: allowRedirects, + timeout: timeout, + urlQuery: urlQuery, + requestBody: requestBody, + asyncProgressHandler: asyncProgressHandler, + asyncCompletionHandler: asyncCompletionHandler + ) + } + + @discardableResult + public func put( + _ url: URLComponentsConvertible, + params: [String: Any] = [:], + data: [String: Any] = [:], + json: Any? = nil, + headers: [String: String] = [:], + files: [String: HTTPFile] = [:], + auth: (String, String)? = nil, + cookies: [String: String] = [:], + allowRedirects: Bool = true, + timeout: Double? = nil, + urlQuery: String? = nil, + requestBody: Data? = nil, + asyncProgressHandler: (TaskProgressHandler)? = nil, + asyncCompletionHandler: ((HTTPResult) -> Void)? = nil + ) -> HTTPResult { + + return adaptor.request( + .put, + url: url, + params: params, + data: data, + json: json, + headers: headers, + files: files, + auth: auth, + cookies: cookies, + redirects: allowRedirects, + timeout: timeout, + urlQuery: urlQuery, + requestBody: requestBody, + asyncProgressHandler: asyncProgressHandler, + asyncCompletionHandler: asyncCompletionHandler + ) + } +} + +public final class HTTP: NSObject, URLSessionDelegate, JustAdaptor { + + public init(session: URLSession? = nil, + defaults: JustSessionDefaults? = nil) + { + super.init() + if let initialSession = session { + self.session = initialSession + } else { + self.session = URLSession(configuration: URLSessionConfiguration.default, + delegate: self, delegateQueue: nil) + } + + if let initialDefaults = defaults { + self.defaults = initialDefaults + } else { + self.defaults = JustSessionDefaults() + } + } + + var taskConfigs: [TaskID: TaskConfiguration]=[:] + var defaults: JustSessionDefaults! + var session: URLSession! + var invalidURLError = NSError( + domain: errorDomain, + code: 0, + userInfo: [NSLocalizedDescriptionKey: "[Just] URL is invalid"] + ) + + var syncResultAccessError = NSError( + domain: errorDomain, + code: 1, + userInfo: [ + NSLocalizedDescriptionKey: + "[Just] You are accessing asynchronous result synchronously." + ] + ) + + func queryComponents(_ key: String, _ value: Any) -> [(String, String)] { + var components: [(String, String)] = [] + if let dictionary = value as? [String: Any] { + for (nestedKey, value) in dictionary { + components += queryComponents("\(key)[\(nestedKey)]", value) + } + } else if let array = value as? [Any] { + for value in array { + components += queryComponents("\(key)", value) + } + } else { + components.append(( + percentEncodeString(key), + percentEncodeString("\(value)")) + ) + } + + return components + } + + func query(_ parameters: [String: Any]) -> String { + var components: [(String, String)] = [] + for (key, value) in parameters.sorted(by: { $0.key < $1.key }) { + components += self.queryComponents(key, value) + } + + return (components.map { "\($0)=\($1)" }).joined(separator: "&") + } + + func percentEncodeString(_ originalObject: Any) -> String { + if originalObject is NSNull { + return "null" + } else { + var reserved = CharacterSet.urlQueryAllowed + reserved.remove(charactersIn: ": #[]@!$&'()*+, ;=") + return String(describing: originalObject) + .addingPercentEncoding(withAllowedCharacters: reserved) ?? "" + } + } + + + func makeTask(_ request: URLRequest, configuration: TaskConfiguration) + -> URLSessionDataTask? + { + let task = session.dataTask(with: request) + taskConfigs[task.taskIdentifier] = configuration + return task + } + + func synthesizeMultipartBody(_ data: [String: Any], files: [String: HTTPFile]) + -> Data? + { + var body = Data() + let boundary = "--\(self.defaults.multipartBoundary)\r\n" + .data(using: defaults.encoding)! + for (k, v) in data { + let valueToSend: Any = v is NSNull ? "null" : v + body.append(boundary) + body.append("Content-Disposition: form-data; name=\"\(k)\"\r\n\r\n" + .data(using: defaults.encoding)!) + body.append("\(valueToSend)\r\n".data(using: defaults.encoding)!) + } + + for (k, v) in files { + body.append(boundary) + var partContent: Data? = nil + var partFilename: String? = nil + var partMimetype: String? = nil + switch v { + case let .url(URL, mimetype): + partFilename = URL.lastPathComponent + if let URLContent = try? Data(contentsOf: URL) { + partContent = URLContent + } + partMimetype = mimetype + case let .text(filename, text, mimetype): + partFilename = filename + if let textData = text.data(using: defaults.encoding) { + partContent = textData + } + partMimetype = mimetype + case let .data(filename, data, mimetype): + partFilename = filename + partContent = data + partMimetype = mimetype + } + if let content = partContent, let filename = partFilename { + let dispose = "Content-Disposition: form-data; name=\"\(k)\"; filename=\"\(filename)\"\r\n" + body.append(dispose.data(using: defaults.encoding)!) + if let type = partMimetype { + body.append( + "Content-Type: \(type)\r\n\r\n".data(using: defaults.encoding)!) + } else { + body.append("\r\n".data(using: defaults.encoding)!) + } + body.append(content) + body.append("\r\n".data(using: defaults.encoding)!) + } + } + + if body.count > 0 { + body.append("--\(self.defaults.multipartBoundary)--\r\n" + .data(using: defaults.encoding)!) + } + + return body + } + + public func synthesizeRequest( + _ method: HTTPMethod, + url: URLComponentsConvertible, + params: [String: Any], + data: [String: Any], + json: Any?, + headers: CaseInsensitiveDictionary, + files: [String: HTTPFile], + auth: Credentials?, + timeout: Double?, + urlQuery: String?, + requestBody: Data? + ) -> URLRequest? { + if var urlComponents = url.urlComponents { + let queryString = query(params) + + if queryString.count > 0 { + urlComponents.percentEncodedQuery = queryString + } + + var finalHeaders = headers + var contentType: String? = nil + var body: Data? + + if let requestData = requestBody { + body = requestData + } else if files.count > 0 { + body = synthesizeMultipartBody(data, files: files) + let bound = self.defaults.multipartBoundary + contentType = "multipart/form-data; boundary=\(bound)" + } else { + if let requestJSON = json { + contentType = "application/json" + body = try? JSONSerialization.data(withJSONObject: requestJSON, + options: defaults.JSONWritingOptions) + } else { + if data.count > 0 { + // assume user wants JSON if she is using this header + if headers["content-type"]?.lowercased() == "application/json" { + body = try? JSONSerialization.data(withJSONObject: data, + options: defaults.JSONWritingOptions) + } else { + contentType = "application/x-www-form-urlencoded" + body = query(data).data(using: defaults.encoding) + } + } + } + } + + if let contentTypeValue = contentType { + finalHeaders["Content-Type"] = contentTypeValue + } + + if let auth = auth, + let utf8 = "\(auth.0):\(auth.1)".data(using: String.Encoding.utf8) + { + finalHeaders["Authorization"] = "Basic \(utf8.base64EncodedString())" + } + if let URL = urlComponents.url { + var request = URLRequest(url: URL) + request.cachePolicy = defaults.cachePolicy + request.httpBody = body + request.httpMethod = method.rawValue + if let requestTimeout = timeout { + request.timeoutInterval = requestTimeout + } + + for (k, v) in defaults.headers { + request.addValue(v, forHTTPHeaderField: k) + } + + for (k, v) in finalHeaders { + request.addValue(v, forHTTPHeaderField: k) + } + return request + } + + } + return nil + } + + public func request( + _ method: HTTPMethod, + url: URLComponentsConvertible, + params: [String: Any], + data: [String: Any], + json: Any?, + headers: [String: String], + files: [String: HTTPFile], + auth: Credentials?, + cookies: [String: String], + redirects: Bool, + timeout: Double?, + urlQuery: String?, + requestBody: Data?, + asyncProgressHandler: TaskProgressHandler?, + asyncCompletionHandler: ((HTTPResult) -> Void)?) -> HTTPResult { + + let isSynchronous = asyncCompletionHandler == nil + let semaphore = DispatchSemaphore(value: 0) + var requestResult: HTTPResult = HTTPResult(data: nil, response: nil, + error: syncResultAccessError, task: nil) + + let caseInsensitiveHeaders = CaseInsensitiveDictionary( + dictionary: headers) + guard let request = synthesizeRequest(method, url: url, + params: params, data: data, json: json, headers: caseInsensitiveHeaders, + files: files, auth: auth, timeout: timeout, urlQuery: urlQuery, + requestBody: requestBody) else + { + let erronousResult = HTTPResult(data: nil, response: nil, + error: invalidURLError, task: nil) + if let handler = asyncCompletionHandler { + handler(erronousResult) + } + return erronousResult + } + addCookies(request.url!, newCookies: cookies) + let config = TaskConfiguration( + credential: auth, + redirects: redirects, + originalRequest: request, + data: Data(), + progressHandler: asyncProgressHandler) + { result in + if let handler = asyncCompletionHandler { + handler(result) + } + if isSynchronous { + requestResult = result + semaphore.signal() + } + } + + if let task = makeTask(request, configuration: config) { + task.resume() + } + + if isSynchronous { + let timeout = timeout.flatMap { DispatchTime.now() + $0 } + ?? DispatchTime.distantFuture + _ = semaphore.wait(timeout: timeout) + return requestResult + } + return requestResult + } + + func addCookies(_ URL: Foundation.URL, newCookies: [String: String]) { + for (k, v) in newCookies { + if let cookie = HTTPCookie(properties: [ + HTTPCookiePropertyKey.name: k, + HTTPCookiePropertyKey.value: v, + HTTPCookiePropertyKey.originURL: URL, + HTTPCookiePropertyKey.path: "/" + ]) + { + session.configuration.httpCookieStorage?.setCookie(cookie) + } + } + } +} + +extension HTTP: URLSessionTaskDelegate, URLSessionDataDelegate { + public func urlSession(_ session: URLSession, task: URLSessionTask, + didReceive challenge: URLAuthenticationChallenge, + completionHandler: @escaping (URLSession.AuthChallengeDisposition, + URLCredential?) -> Void) + { + var endCredential: URLCredential? = nil + + if let taskConfig = taskConfigs[task.taskIdentifier], + let credential = taskConfig.credential + { + if !(challenge.previousFailureCount > 0) { + endCredential = URLCredential( + user: credential.0, + password: credential.1, + persistence: self.defaults.credentialPersistence + ) + } + } + + completionHandler(.useCredential, endCredential) + } + + public func urlSession(_ session: URLSession, task: URLSessionTask, + willPerformHTTPRedirection response: HTTPURLResponse, + newRequest request: URLRequest, + completionHandler: @escaping (URLRequest?) -> Void) + { + if let allowRedirects = taskConfigs[task.taskIdentifier]?.redirects { + if !allowRedirects { + completionHandler(nil) + return + } + completionHandler(request) + } else { + completionHandler(request) + } + } + + public func urlSession(_ session: URLSession, task: URLSessionTask, + didSendBodyData bytesSent: Int64, totalBytesSent: Int64, + totalBytesExpectedToSend: Int64) + { + if let handler = taskConfigs[task.taskIdentifier]?.progressHandler { + handler( + HTTPProgress( + type: .upload, + bytesProcessed: totalBytesSent, + bytesExpectedToProcess: totalBytesExpectedToSend, + chunk: nil + ) + ) + } + } + + public func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, + didReceive data: Data) + { + if let handler = taskConfigs[dataTask.taskIdentifier]?.progressHandler { + handler( + HTTPProgress( + type: .download, + bytesProcessed: dataTask.countOfBytesReceived, + bytesExpectedToProcess: dataTask.countOfBytesExpectedToReceive, + chunk: data + ) + ) + } + if taskConfigs[dataTask.taskIdentifier]?.data != nil { + taskConfigs[dataTask.taskIdentifier]?.data.append(data) + } + } + + public func urlSession(_ session: URLSession, task: URLSessionTask, + didCompleteWithError error: Error?) + { + if let config = taskConfigs[task.taskIdentifier], + let handler = config.completionHandler + { + let result = HTTPResult( + data: config.data, + response: task.response, + error: error, + task: task + ) + result.JSONReadingOptions = self.defaults.JSONReadingOptions + result.encoding = self.defaults.encoding + handler(result) + } + taskConfigs.removeValue(forKey: task.taskIdentifier) + } +} + +public let Just = JustOf() diff --git a/Pods/Manifest.lock b/Pods/Manifest.lock index ad11e35..032d067 100644 --- a/Pods/Manifest.lock +++ b/Pods/Manifest.lock @@ -1,16 +1,16 @@ PODS: - - SwiftSoup (2.2.0) + - Just (0.8.0) DEPENDENCIES: - - SwiftSoup + - Just SPEC REPOS: - https://github.com/cocoapods/specs.git: - - SwiftSoup + trunk: + - Just SPEC CHECKSUMS: - SwiftSoup: 230991361c5ba249d140161860a3864a28b63860 + Just: aef5105fb2c7069b65aa6f21aec8f429057f9c19 -PODFILE CHECKSUM: d5db68a23a6fb36f3d94717563c9d5199d9f3bdf +PODFILE CHECKSUM: 0ed9277c30181dde6c0bb4a7b18f37dca46c8ec9 -COCOAPODS: 1.7.5 +COCOAPODS: 1.8.0.beta.2 diff --git a/Pods/Pods.xcodeproj/project.pbxproj b/Pods/Pods.xcodeproj/project.pbxproj index db2da27..657c8f8 100644 --- a/Pods/Pods.xcodeproj/project.pbxproj +++ b/Pods/Pods.xcodeproj/project.pbxproj @@ -7,183 +7,95 @@ objects = { /* Begin PBXBuildFile section */ - 0323040E0BAAB427F131B8B7593C1823 /* QueryParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7FBEE42EAA661E6389FF98A8F7258F4A /* QueryParser.swift */; }; - 07DC1E76B4AC8D6F706C134BE25BFCB6 /* HttpStatusException.swift in Sources */ = {isa = PBXBuildFile; fileRef = 99D90FA8A6E0EE945BE59B43E11F1991 /* HttpStatusException.swift */; }; - 08F669849B088847C5391DCA0D21EBCA /* XmlDeclaration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 268ADCD2947926FB1316F8C94FEFA5A8 /* XmlDeclaration.swift */; }; - 0ACC881DFA0D90EFAFA203F57BCABF31 /* OrderedDictionary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49ACA67A55E4015D418EE108533FFE7F /* OrderedDictionary.swift */; }; - 0BD1BBE195BAC934A71711B53A7F020C /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F940C819049CFF8741C0F5E3E075E607 /* Cocoa.framework */; }; - 13646ECCC236443CE369AC3AB04C85A2 /* CombiningEvaluator.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC000E9275D38311D281B82C5AC7DF99 /* CombiningEvaluator.swift */; }; - 138730EAB95463CBD4F489B2F0C237E0 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F940C819049CFF8741C0F5E3E075E607 /* Cocoa.framework */; }; - 182563AFC01AAB5F8010B109A379109D /* Pods-RSwitch-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 4F000B9DE332C7D2340B760411896249 /* Pods-RSwitch-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 184FEFB86BB797EC34B8245B2448C9B1 /* StreamReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6E94E3D85C69197A8639760C6AD6133 /* StreamReader.swift */; }; - 1B1E44407BA5AB6B543BFD609D48FB4D /* Whitelist.swift in Sources */ = {isa = PBXBuildFile; fileRef = 22288D13FA0694E7A5E908C1CC9DE5BF /* Whitelist.swift */; }; - 1F6A5C0F3BEF9084C8E9066D3F8AD4F1 /* TokeniserState.swift in Sources */ = {isa = PBXBuildFile; fileRef = E3E019DBDCCCD70EFC6949EAE2EFD465 /* TokeniserState.swift */; }; - 212095A3D1CE5571B351D4999B2D72F7 /* ParseError.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC1722C7DA6C7AADB6E9D3FF2DAC741D /* ParseError.swift */; }; - 23605B9E6B3F4C6849BEB2995B8D5CC9 /* Node.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7144D15083381AAD10E032BFC539087D /* Node.swift */; }; - 268BA1DBE8391AF20EE9D562480A2040 /* StructuralEvaluator.swift in Sources */ = {isa = PBXBuildFile; fileRef = EBCB49D29F5DBB2E4E7C01BF9B286B42 /* StructuralEvaluator.swift */; }; - 2B29E96B4BEEE65DA4760B9E2070433C /* Pods-RSwitch-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = F0D5168CB259AAB643C8297DEDFBA2A3 /* Pods-RSwitch-dummy.m */; }; - 3A85CBC090CD9016F473398DEBBBC4D9 /* Element.swift in Sources */ = {isa = PBXBuildFile; fileRef = 78E39FD18511DFB98B97795AF070BAE8 /* Element.swift */; }; - 3DD15E341B2A822AE4170B66EF84785B /* FormElement.swift in Sources */ = {isa = PBXBuildFile; fileRef = E5AE07EC09DF0A0222B828F0110686DE /* FormElement.swift */; }; - 45AE0479CEA0DCD1CC289FAC7A0D74CD /* Tokeniser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AC2EF2D2470B5A55A2C5462E28A9246 /* Tokeniser.swift */; }; - 48061A6A40378AA49349A4E8E6E815D5 /* Comment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01B345D614BE0463ECFFCDAF8AE1D959 /* Comment.swift */; }; - 4860E1263F573B4EEA7BDF236A1199D0 /* SimpleDictionary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58F9B9738C02AF58D1D5DE8834759899 /* SimpleDictionary.swift */; }; - 4B2DC0B5E57666B3222AD7F24E579353 /* DocumentType.swift in Sources */ = {isa = PBXBuildFile; fileRef = AD297727E87AF4BEBB6DE15799DB2903 /* DocumentType.swift */; }; - 51C521B58C9C7F3E55CBBF64231CAD92 /* Entities.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9DC1F45FA2EFC6FD203B16A40D787A7 /* Entities.swift */; }; - 59CCEF0DB3257C3791FB7FEF729656A1 /* SwiftSoup-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 29FE73A05C9903FA27E5023421D500A9 /* SwiftSoup-dummy.m */; }; - 5EA9213700B4A83923FE1F76199D7478 /* TextNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 884E4622C66FF5ECF8A9CE1702E69CEB /* TextNode.swift */; }; - 5F4C6190E5A08291473F5C0E88FC3739 /* SwiftSoup-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 783742B9F3C0D7789BF1936E5320633D /* SwiftSoup-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 605E6909CF08E0DAD68A675C92906264 /* String.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D7E478CFFA3AD51798EFA5D2B48C5E5 /* String.swift */; }; - 6307C9763A4BF4AD4A57596F5756E3D6 /* Selector.swift in Sources */ = {isa = PBXBuildFile; fileRef = 049DA62C981D7D8B1F9AA7F2E8E13327 /* Selector.swift */; }; - 6400A9389A0A3E67315FA4FD500FB283 /* SwiftSoup.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4FE0E2E1E5641AB6B4DAB08F044186C3 /* SwiftSoup.swift */; }; - 64641F162787638B7319C71A2986F2D1 /* Document.swift in Sources */ = {isa = PBXBuildFile; fileRef = 484565425B7A00B867BFA9497B1BEC2C /* Document.swift */; }; - 68912B01B6D7D4021137BF72C32294F0 /* Collector.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4DF6771C707E52E16626CEC16E3C3B8 /* Collector.swift */; }; - 6D755DA0247FE8D37B6D95D48B8D1697 /* NodeVisitor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53EA4EB8183ACC0A1C56FAB0D1003783 /* NodeVisitor.swift */; }; - 6E8C2F72232BD8D69C06FD9BD135B0E0 /* HtmlTreeBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = F474D4B15BF04A79EDF6D540A62342C7 /* HtmlTreeBuilder.swift */; }; - 717A618E1185ED3073BF6557DAD82429 /* UnicodeScalar.swift in Sources */ = {isa = PBXBuildFile; fileRef = D96EEA325686C991085438AA5B69502C /* UnicodeScalar.swift */; }; - 7383E209342B658049AAC2F6A47CD54E /* Token.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8EDDABBCE4809A2F836AA605B7E1B11C /* Token.swift */; }; - 74ED1DAD719312ED2E1EAB6BB0BBFF71 /* BooleanAttribute.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAF631AD5246CE61C5DEFD7C3E3CD6B7 /* BooleanAttribute.swift */; }; - 787BA99F9006B790A7E2775CF4371A15 /* Exception.swift in Sources */ = {isa = PBXBuildFile; fileRef = B35D8D6D3BC418C508B79C61D6BC9615 /* Exception.swift */; }; - 7B5C603DF6AE98590BD5043DEE6533D2 /* StringBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8100EBE612516CD2A52C839A5B99AFD1 /* StringBuilder.swift */; }; - 8A156E7D9F56597ABF006024CE5A38B2 /* Parser.swift in Sources */ = {isa = PBXBuildFile; fileRef = F559860F6D0AAE454911A1EF3C0B668B /* Parser.swift */; }; - 8CCF800901928887AA517E01C12E7AA4 /* CharacterExt.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8948246B3834F8A3FEB030C74E3A2AB5 /* CharacterExt.swift */; }; - 96D271E1F3B86DABCAFBF96FA0F2EC03 /* Attributes.swift in Sources */ = {isa = PBXBuildFile; fileRef = E376FAE2C865C86BA8BCA7E9FC980FD4 /* Attributes.swift */; }; - 984F3128934C6FF64C4681754628FF0C /* CharacterReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1773A4068A9764EE8D86DF4EC7366AAC /* CharacterReader.swift */; }; - 9C390892DA03BA76F8078B5E9F1EE971 /* ArrayExt.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42D54DB54E3520B11C07EFA4EE4F3031 /* ArrayExt.swift */; }; - 9D9E42B84863721085CB2C0EE1467CA6 /* TokenQueue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 22E36ED5E17B02508428258D46A39FAE /* TokenQueue.swift */; }; - 9E2E92CA61302CFAA8D2F97AC088C5C3 /* Attribute.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6ECF0F75FB8E7DB14833337F209943C6 /* Attribute.swift */; }; - 9F0612E3E2BD1F85D7620321BEFBE2DC /* StringUtil.swift in Sources */ = {isa = PBXBuildFile; fileRef = E58D58E2454CF9D510F70E0FF2A412E7 /* StringUtil.swift */; }; - A072BEECFC9A659AC25573E82E8E0D65 /* Validate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1748F4905B4FC87B2F3D346E5B84B616 /* Validate.swift */; }; - A815B081D1C20E722584BEDC86E1BA5C /* OrderedSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48FD3F1F6B0CD6E7482B19ECFAABE244 /* OrderedSet.swift */; }; - AE698A9FA4B6EDA81A7F68DB435E3309 /* DataNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 94DC1B26DF1845449C7B42D5A166B937 /* DataNode.swift */; }; - AE993559119E69F0C50BCC2EBBF77E61 /* SerializationException.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5A7F2AF32CB0CBEDD6D5F4B84B632F5A /* SerializationException.swift */; }; - AF50D130B49C380ED075104BB7671FAB /* Tag.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C98DEADFC55406419E8F91EAEA86E8F /* Tag.swift */; }; - B22E0A04FCA9C46583CDE32FD83CFE1E /* ParseSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 94EC1C8CEA4EE1B55C08F9562A8E8307 /* ParseSettings.swift */; }; - BF10823605FA7A0062852CA043794186 /* Connection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0353C7EAAB2DCCB4166955D1F016296B /* Connection.swift */; }; - C88398AADEBDF75E34AEF8564807EBBA /* TreeBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9301E32BA67B6E5429D48C0AB38851AE /* TreeBuilder.swift */; }; - CCCB6C8A300C9117E119983C5E693781 /* Cleaner.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2DEA4C6C21E89636AA601430CFF5504 /* Cleaner.swift */; }; - D44EE0B232CCEDE658102DE87A02DAD2 /* NodeTraversor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 024F0251E1CBA4811918382B6D98DC5A /* NodeTraversor.swift */; }; - DB16F4FC1AC7BEFE72972A8B7F7629B1 /* XmlTreeBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A29168DA5AF77F67441271215C9DC6E /* XmlTreeBuilder.swift */; }; - E18636DA726A4EB4566C30DC572CEF30 /* ParseErrorList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DF72B46DECD390354841E0957556D49 /* ParseErrorList.swift */; }; - E25940181A204C2DDDE31DC346035755 /* HtmlTreeBuilderState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 152E999AE7B211A8286E727F84405191 /* HtmlTreeBuilderState.swift */; }; - EC2ADA20DC4D6D68A1CED448533F7987 /* Pattern.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6E92ECF1E721371A67F4871B34E6820 /* Pattern.swift */; }; - F17880FE84897581A0353EA6C49E8909 /* Evaluator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49796846D7023B6FE722096F05F3BC42 /* Evaluator.swift */; }; - F8C0CA7AF2CC574511A5C8C02DEDCF43 /* Elements.swift in Sources */ = {isa = PBXBuildFile; fileRef = 40D6C27F273357660198C2275EDB9B3F /* Elements.swift */; }; - FAF882C254A4D68E3B8DB2F392F5AE8D /* DataUtil.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4171FA64A1D37689A75BB082317E6E65 /* DataUtil.swift */; }; + 1642FF2CBDC0D5DE293557BAC7483330 /* Just.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8F0FBF810ECE65109C95E0C8BBB893F /* Just.swift */; }; + 183F65FE3A9F053B826D0BE6F6FD4976 /* Just-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 6B076A7E6A9514F7BC8853C054606452 /* Just-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 3319EB536901C1505EA1E0A74CA48C36 /* Pods-RSwitch-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = F0D5168CB259AAB643C8297DEDFBA2A3 /* Pods-RSwitch-dummy.m */; }; + 6E52FCF9BA1CABB3FE89003AA31BF40D /* Just-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 5A65C21E7E55D2FB16F3F2767B0063C7 /* Just-dummy.m */; }; + 833AEF1B4D51758EBA3E9E05B3C07743 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F940C819049CFF8741C0F5E3E075E607 /* Cocoa.framework */; }; + CE397D843966A9C8A318E053B323901E /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F940C819049CFF8741C0F5E3E075E607 /* Cocoa.framework */; }; + CF264F96F9FC03520BF4AEE09521E7C3 /* Pods-RSwitch-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 4F000B9DE332C7D2340B760411896249 /* Pods-RSwitch-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ - B77095034AB3D02A24C74888527C265D /* PBXContainerItemProxy */ = { + E0B9423F4CC99D0A13E90EE927936CDD /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; proxyType = 1; - remoteGlobalIDString = D89F48405DFAFEF441B4E758A15117A5; - remoteInfo = SwiftSoup; + remoteGlobalIDString = CE86A5B255D405184FBF7B919824D937; + remoteInfo = Just; }; /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ - 01B345D614BE0463ECFFCDAF8AE1D959 /* Comment.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Comment.swift; path = Sources/Comment.swift; sourceTree = ""; }; - 024F0251E1CBA4811918382B6D98DC5A /* NodeTraversor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = NodeTraversor.swift; path = Sources/NodeTraversor.swift; sourceTree = ""; }; - 0353C7EAAB2DCCB4166955D1F016296B /* Connection.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Connection.swift; path = Sources/Connection.swift; sourceTree = ""; }; - 049DA62C981D7D8B1F9AA7F2E8E13327 /* Selector.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Selector.swift; path = Sources/Selector.swift; sourceTree = ""; }; - 0A29168DA5AF77F67441271215C9DC6E /* XmlTreeBuilder.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = XmlTreeBuilder.swift; path = Sources/XmlTreeBuilder.swift; sourceTree = ""; }; - 152E999AE7B211A8286E727F84405191 /* HtmlTreeBuilderState.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = HtmlTreeBuilderState.swift; path = Sources/HtmlTreeBuilderState.swift; sourceTree = ""; }; - 1748F4905B4FC87B2F3D346E5B84B616 /* Validate.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Validate.swift; path = Sources/Validate.swift; sourceTree = ""; }; - 1773A4068A9764EE8D86DF4EC7366AAC /* CharacterReader.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = CharacterReader.swift; path = Sources/CharacterReader.swift; sourceTree = ""; }; - 1DF72B46DECD390354841E0957556D49 /* ParseErrorList.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ParseErrorList.swift; path = Sources/ParseErrorList.swift; sourceTree = ""; }; - 22288D13FA0694E7A5E908C1CC9DE5BF /* Whitelist.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Whitelist.swift; path = Sources/Whitelist.swift; sourceTree = ""; }; - 22E36ED5E17B02508428258D46A39FAE /* TokenQueue.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = TokenQueue.swift; path = Sources/TokenQueue.swift; sourceTree = ""; }; - 268ADCD2947926FB1316F8C94FEFA5A8 /* XmlDeclaration.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = XmlDeclaration.swift; path = Sources/XmlDeclaration.swift; sourceTree = ""; }; - 29FE73A05C9903FA27E5023421D500A9 /* SwiftSoup-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "SwiftSoup-dummy.m"; sourceTree = ""; }; - 3AC2EF2D2470B5A55A2C5462E28A9246 /* Tokeniser.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Tokeniser.swift; path = Sources/Tokeniser.swift; sourceTree = ""; }; - 40D6C27F273357660198C2275EDB9B3F /* Elements.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Elements.swift; path = Sources/Elements.swift; sourceTree = ""; }; - 4171FA64A1D37689A75BB082317E6E65 /* DataUtil.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = DataUtil.swift; path = Sources/DataUtil.swift; sourceTree = ""; }; - 42D54DB54E3520B11C07EFA4EE4F3031 /* ArrayExt.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ArrayExt.swift; path = Sources/ArrayExt.swift; sourceTree = ""; }; - 484565425B7A00B867BFA9497B1BEC2C /* Document.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Document.swift; path = Sources/Document.swift; sourceTree = ""; }; - 48FD3F1F6B0CD6E7482B19ECFAABE244 /* OrderedSet.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = OrderedSet.swift; path = Sources/OrderedSet.swift; sourceTree = ""; }; - 49796846D7023B6FE722096F05F3BC42 /* Evaluator.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Evaluator.swift; path = Sources/Evaluator.swift; sourceTree = ""; }; - 49ACA67A55E4015D418EE108533FFE7F /* OrderedDictionary.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = OrderedDictionary.swift; path = Sources/OrderedDictionary.swift; sourceTree = ""; }; 4F000B9DE332C7D2340B760411896249 /* Pods-RSwitch-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Pods-RSwitch-umbrella.h"; sourceTree = ""; }; - 4FE0E2E1E5641AB6B4DAB08F044186C3 /* SwiftSoup.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SwiftSoup.swift; path = Sources/SwiftSoup.swift; sourceTree = ""; }; - 53EA4EB8183ACC0A1C56FAB0D1003783 /* NodeVisitor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = NodeVisitor.swift; path = Sources/NodeVisitor.swift; sourceTree = ""; }; - 58F9B9738C02AF58D1D5DE8834759899 /* SimpleDictionary.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SimpleDictionary.swift; path = Sources/SimpleDictionary.swift; sourceTree = ""; }; - 5A7F2AF32CB0CBEDD6D5F4B84B632F5A /* SerializationException.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SerializationException.swift; path = Sources/SerializationException.swift; sourceTree = ""; }; - 5D52FFF81A1E26634DAD54B2BE7CBA99 /* Pods_RSwitch.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RSwitch.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 5F38EF8DCE7D46A354D1D1BBAC952903 /* SwiftSoup.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SwiftSoup.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 653737F57003A332C4E6F80EA2E55DA6 /* SwiftSoup.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = SwiftSoup.xcconfig; sourceTree = ""; }; + 574603E2D7597AEEB79587D7C3889AA1 /* Just.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = Just.xcconfig; sourceTree = ""; }; + 5A65C21E7E55D2FB16F3F2767B0063C7 /* Just-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "Just-dummy.m"; sourceTree = ""; }; + 5D52FFF81A1E26634DAD54B2BE7CBA99 /* Pods_RSwitch.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = Pods_RSwitch.framework; path = "Pods-RSwitch.framework"; sourceTree = BUILT_PRODUCTS_DIR; }; + 614B6A9B3F94B8D815819AA921D78D95 /* Just-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Just-prefix.pch"; sourceTree = ""; }; + 6848EDAB880F7E2D2B180B0D25F67504 /* Just.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = Just.modulemap; sourceTree = ""; }; + 6B076A7E6A9514F7BC8853C054606452 /* Just-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Just-umbrella.h"; sourceTree = ""; }; 6B5F1D02B43D15E9D5752784305E1A5D /* Pods-RSwitch.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-RSwitch.debug.xcconfig"; sourceTree = ""; }; - 6C98DEADFC55406419E8F91EAEA86E8F /* Tag.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Tag.swift; path = Sources/Tag.swift; sourceTree = ""; }; - 6ECF0F75FB8E7DB14833337F209943C6 /* Attribute.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Attribute.swift; path = Sources/Attribute.swift; sourceTree = ""; }; - 7144D15083381AAD10E032BFC539087D /* Node.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Node.swift; path = Sources/Node.swift; sourceTree = ""; }; - 783742B9F3C0D7789BF1936E5320633D /* SwiftSoup-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "SwiftSoup-umbrella.h"; sourceTree = ""; }; - 78E39FD18511DFB98B97795AF070BAE8 /* Element.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Element.swift; path = Sources/Element.swift; sourceTree = ""; }; 7B194431FBE08FAA54D43A7D8C27124C /* Pods-RSwitch-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Pods-RSwitch-Info.plist"; sourceTree = ""; }; - 7FBEE42EAA661E6389FF98A8F7258F4A /* QueryParser.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = QueryParser.swift; path = Sources/QueryParser.swift; sourceTree = ""; }; - 8100EBE612516CD2A52C839A5B99AFD1 /* StringBuilder.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = StringBuilder.swift; path = Sources/StringBuilder.swift; sourceTree = ""; }; - 884E4622C66FF5ECF8A9CE1702E69CEB /* TextNode.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = TextNode.swift; path = Sources/TextNode.swift; sourceTree = ""; }; - 8948246B3834F8A3FEB030C74E3A2AB5 /* CharacterExt.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = CharacterExt.swift; path = Sources/CharacterExt.swift; sourceTree = ""; }; - 8EDDABBCE4809A2F836AA605B7E1B11C /* Token.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Token.swift; path = Sources/Token.swift; sourceTree = ""; }; - 9301E32BA67B6E5429D48C0AB38851AE /* TreeBuilder.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = TreeBuilder.swift; path = Sources/TreeBuilder.swift; sourceTree = ""; }; - 94DC1B26DF1845449C7B42D5A166B937 /* DataNode.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = DataNode.swift; path = Sources/DataNode.swift; sourceTree = ""; }; - 94EC1C8CEA4EE1B55C08F9562A8E8307 /* ParseSettings.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ParseSettings.swift; path = Sources/ParseSettings.swift; sourceTree = ""; }; - 99D90FA8A6E0EE945BE59B43E11F1991 /* HttpStatusException.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = HttpStatusException.swift; path = Sources/HttpStatusException.swift; sourceTree = ""; }; - 9D7E478CFFA3AD51798EFA5D2B48C5E5 /* String.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = String.swift; path = Sources/String.swift; sourceTree = ""; }; - 9D940727FF8FB9C785EB98E56350EF41 /* Podfile */ = {isa = PBXFileReference; explicitFileType = text.script.ruby; includeInIndex = 1; indentWidth = 2; name = Podfile; path = ../Podfile; sourceTree = SOURCE_ROOT; tabWidth = 2; xcLanguageSpecificationIdentifier = xcode.lang.ruby; }; - A1E1DF856B2F4607BD0F2A365D1D9FD3 /* SwiftSoup-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "SwiftSoup-prefix.pch"; sourceTree = ""; }; - A9DC1F45FA2EFC6FD203B16A40D787A7 /* Entities.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Entities.swift; path = Sources/Entities.swift; sourceTree = ""; }; + 9A212383B73C76EDF23FB6126214CAB4 /* Just.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = Just.framework; path = Just.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 9D940727FF8FB9C785EB98E56350EF41 /* Podfile */ = {isa = PBXFileReference; explicitFileType = text.script.ruby; includeInIndex = 1; indentWidth = 2; lastKnownFileType = text; name = Podfile; path = ../Podfile; sourceTree = SOURCE_ROOT; tabWidth = 2; xcLanguageSpecificationIdentifier = xcode.lang.ruby; }; ACB677C58AE332368BBEB1AF0A6918B1 /* Pods-RSwitch-acknowledgements.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Pods-RSwitch-acknowledgements.plist"; sourceTree = ""; }; - AD297727E87AF4BEBB6DE15799DB2903 /* DocumentType.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = DocumentType.swift; path = Sources/DocumentType.swift; sourceTree = ""; }; - B35D8D6D3BC418C508B79C61D6BC9615 /* Exception.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Exception.swift; path = Sources/Exception.swift; sourceTree = ""; }; B39AAB51B4D348DDE0A772879510BD57 /* Pods-RSwitch-frameworks.sh */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.script.sh; path = "Pods-RSwitch-frameworks.sh"; sourceTree = ""; }; - C06313BA3ECCC78CBFABC9763DF22594 /* SwiftSoup-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "SwiftSoup-Info.plist"; sourceTree = ""; }; - C4DF6771C707E52E16626CEC16E3C3B8 /* Collector.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Collector.swift; path = Sources/Collector.swift; sourceTree = ""; }; - C6E94E3D85C69197A8639760C6AD6133 /* StreamReader.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = StreamReader.swift; path = Sources/StreamReader.swift; sourceTree = ""; }; - CC1722C7DA6C7AADB6E9D3FF2DAC741D /* ParseError.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ParseError.swift; path = Sources/ParseError.swift; sourceTree = ""; }; - D6E92ECF1E721371A67F4871B34E6820 /* Pattern.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Pattern.swift; path = Sources/Pattern.swift; sourceTree = ""; }; + B8F0FBF810ECE65109C95E0C8BBB893F /* Just.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Just.swift; path = Sources/Just/Just.swift; sourceTree = ""; }; D722B0A61F22FDFBDEF11F24016B4D1D /* Pods-RSwitch.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-RSwitch.release.xcconfig"; sourceTree = ""; }; - D96EEA325686C991085438AA5B69502C /* UnicodeScalar.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = UnicodeScalar.swift; path = Sources/UnicodeScalar.swift; sourceTree = ""; }; DB428D92F1F877A57EBAE4039884D744 /* Pods-RSwitch-acknowledgements.markdown */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; path = "Pods-RSwitch-acknowledgements.markdown"; sourceTree = ""; }; DCFA50DE569F3B468BACF6ECDE5DDBA8 /* Pods-RSwitch.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = "Pods-RSwitch.modulemap"; sourceTree = ""; }; - E2DEA4C6C21E89636AA601430CFF5504 /* Cleaner.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Cleaner.swift; path = Sources/Cleaner.swift; sourceTree = ""; }; - E376FAE2C865C86BA8BCA7E9FC980FD4 /* Attributes.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Attributes.swift; path = Sources/Attributes.swift; sourceTree = ""; }; - E3E019DBDCCCD70EFC6949EAE2EFD465 /* TokeniserState.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = TokeniserState.swift; path = Sources/TokeniserState.swift; sourceTree = ""; }; - E58D58E2454CF9D510F70E0FF2A412E7 /* StringUtil.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = StringUtil.swift; path = Sources/StringUtil.swift; sourceTree = ""; }; - E5AE07EC09DF0A0222B828F0110686DE /* FormElement.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = FormElement.swift; path = Sources/FormElement.swift; sourceTree = ""; }; - EAF631AD5246CE61C5DEFD7C3E3CD6B7 /* BooleanAttribute.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = BooleanAttribute.swift; path = Sources/BooleanAttribute.swift; sourceTree = ""; }; - EBCB49D29F5DBB2E4E7C01BF9B286B42 /* StructuralEvaluator.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = StructuralEvaluator.swift; path = Sources/StructuralEvaluator.swift; sourceTree = ""; }; - EC000E9275D38311D281B82C5AC7DF99 /* CombiningEvaluator.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = CombiningEvaluator.swift; path = Sources/CombiningEvaluator.swift; sourceTree = ""; }; - EFC11670D004E932C92C144DAC577866 /* SwiftSoup.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = SwiftSoup.modulemap; sourceTree = ""; }; F0D5168CB259AAB643C8297DEDFBA2A3 /* Pods-RSwitch-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "Pods-RSwitch-dummy.m"; sourceTree = ""; }; - F474D4B15BF04A79EDF6D540A62342C7 /* HtmlTreeBuilder.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = HtmlTreeBuilder.swift; path = Sources/HtmlTreeBuilder.swift; sourceTree = ""; }; - F559860F6D0AAE454911A1EF3C0B668B /* Parser.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Parser.swift; path = Sources/Parser.swift; sourceTree = ""; }; + F167994BDDD437D52AE2F7A9A702D838 /* Just-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Just-Info.plist"; sourceTree = ""; }; F940C819049CFF8741C0F5E3E075E607 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.14.sdk/System/Library/Frameworks/Cocoa.framework; sourceTree = DEVELOPER_DIR; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ - 1387CD09AAD2DE1E81F58DA4273382DF /* Frameworks */ = { + 992CF3B53A220E5FFE23E37882E06283 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 0BD1BBE195BAC934A71711B53A7F020C /* Cocoa.framework in Frameworks */, + CE397D843966A9C8A318E053B323901E /* Cocoa.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; - DB40808C3408552D3CD8A71C3992A07C /* Frameworks */ = { + E711F5EAC29CAB34E00E66AC2DB29C84 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 138730EAB95463CBD4F489B2F0C237E0 /* Cocoa.framework in Frameworks */, + 833AEF1B4D51758EBA3E9E05B3C07743 /* Cocoa.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ - 099C0EBCE1385C461569E1E3FC5B58C5 /* Products */ = { + 345EEEBE9381D91220155A959CF832C0 /* Pods */ = { isa = PBXGroup; children = ( + 9E03303A3E700793D80ED305328EEB37 /* Just */, + ); + name = Pods; + sourceTree = ""; + }; + 46872DBB8C34D63DE630A92868138E93 /* Support Files */ = { + isa = PBXGroup; + children = ( + 6848EDAB880F7E2D2B180B0D25F67504 /* Just.modulemap */, + 574603E2D7597AEEB79587D7C3889AA1 /* Just.xcconfig */, + 5A65C21E7E55D2FB16F3F2767B0063C7 /* Just-dummy.m */, + F167994BDDD437D52AE2F7A9A702D838 /* Just-Info.plist */, + 614B6A9B3F94B8D815819AA921D78D95 /* Just-prefix.pch */, + 6B076A7E6A9514F7BC8853C054606452 /* Just-umbrella.h */, + ); + name = "Support Files"; + path = "../Target Support Files/Just"; + sourceTree = ""; + }; + 623DD1C81238D9DB831E4CF39661DBBE /* Products */ = { + isa = PBXGroup; + children = ( + 9A212383B73C76EDF23FB6126214CAB4 /* Just.framework */, 5D52FFF81A1E26634DAD54B2BE7CBA99 /* Pods_RSwitch.framework */, - 5F38EF8DCE7D46A354D1D1BBAC952903 /* SwiftSoup.framework */, ); name = Products; sourceTree = ""; @@ -213,68 +125,14 @@ name = "Targets Support Files"; sourceTree = ""; }; - B67502FE5D481268EEE7772D16B9AFC4 /* SwiftSoup */ = { + 9E03303A3E700793D80ED305328EEB37 /* Just */ = { isa = PBXGroup; children = ( - 42D54DB54E3520B11C07EFA4EE4F3031 /* ArrayExt.swift */, - 6ECF0F75FB8E7DB14833337F209943C6 /* Attribute.swift */, - E376FAE2C865C86BA8BCA7E9FC980FD4 /* Attributes.swift */, - EAF631AD5246CE61C5DEFD7C3E3CD6B7 /* BooleanAttribute.swift */, - 8948246B3834F8A3FEB030C74E3A2AB5 /* CharacterExt.swift */, - 1773A4068A9764EE8D86DF4EC7366AAC /* CharacterReader.swift */, - E2DEA4C6C21E89636AA601430CFF5504 /* Cleaner.swift */, - C4DF6771C707E52E16626CEC16E3C3B8 /* Collector.swift */, - EC000E9275D38311D281B82C5AC7DF99 /* CombiningEvaluator.swift */, - 01B345D614BE0463ECFFCDAF8AE1D959 /* Comment.swift */, - 0353C7EAAB2DCCB4166955D1F016296B /* Connection.swift */, - 94DC1B26DF1845449C7B42D5A166B937 /* DataNode.swift */, - 4171FA64A1D37689A75BB082317E6E65 /* DataUtil.swift */, - 484565425B7A00B867BFA9497B1BEC2C /* Document.swift */, - AD297727E87AF4BEBB6DE15799DB2903 /* DocumentType.swift */, - 78E39FD18511DFB98B97795AF070BAE8 /* Element.swift */, - 40D6C27F273357660198C2275EDB9B3F /* Elements.swift */, - A9DC1F45FA2EFC6FD203B16A40D787A7 /* Entities.swift */, - 49796846D7023B6FE722096F05F3BC42 /* Evaluator.swift */, - B35D8D6D3BC418C508B79C61D6BC9615 /* Exception.swift */, - E5AE07EC09DF0A0222B828F0110686DE /* FormElement.swift */, - F474D4B15BF04A79EDF6D540A62342C7 /* HtmlTreeBuilder.swift */, - 152E999AE7B211A8286E727F84405191 /* HtmlTreeBuilderState.swift */, - 99D90FA8A6E0EE945BE59B43E11F1991 /* HttpStatusException.swift */, - 7144D15083381AAD10E032BFC539087D /* Node.swift */, - 024F0251E1CBA4811918382B6D98DC5A /* NodeTraversor.swift */, - 53EA4EB8183ACC0A1C56FAB0D1003783 /* NodeVisitor.swift */, - 49ACA67A55E4015D418EE108533FFE7F /* OrderedDictionary.swift */, - 48FD3F1F6B0CD6E7482B19ECFAABE244 /* OrderedSet.swift */, - CC1722C7DA6C7AADB6E9D3FF2DAC741D /* ParseError.swift */, - 1DF72B46DECD390354841E0957556D49 /* ParseErrorList.swift */, - F559860F6D0AAE454911A1EF3C0B668B /* Parser.swift */, - 94EC1C8CEA4EE1B55C08F9562A8E8307 /* ParseSettings.swift */, - D6E92ECF1E721371A67F4871B34E6820 /* Pattern.swift */, - 7FBEE42EAA661E6389FF98A8F7258F4A /* QueryParser.swift */, - 049DA62C981D7D8B1F9AA7F2E8E13327 /* Selector.swift */, - 5A7F2AF32CB0CBEDD6D5F4B84B632F5A /* SerializationException.swift */, - 58F9B9738C02AF58D1D5DE8834759899 /* SimpleDictionary.swift */, - C6E94E3D85C69197A8639760C6AD6133 /* StreamReader.swift */, - 9D7E478CFFA3AD51798EFA5D2B48C5E5 /* String.swift */, - 8100EBE612516CD2A52C839A5B99AFD1 /* StringBuilder.swift */, - E58D58E2454CF9D510F70E0FF2A412E7 /* StringUtil.swift */, - EBCB49D29F5DBB2E4E7C01BF9B286B42 /* StructuralEvaluator.swift */, - 4FE0E2E1E5641AB6B4DAB08F044186C3 /* SwiftSoup.swift */, - 6C98DEADFC55406419E8F91EAEA86E8F /* Tag.swift */, - 884E4622C66FF5ECF8A9CE1702E69CEB /* TextNode.swift */, - 8EDDABBCE4809A2F836AA605B7E1B11C /* Token.swift */, - 3AC2EF2D2470B5A55A2C5462E28A9246 /* Tokeniser.swift */, - E3E019DBDCCCD70EFC6949EAE2EFD465 /* TokeniserState.swift */, - 22E36ED5E17B02508428258D46A39FAE /* TokenQueue.swift */, - 9301E32BA67B6E5429D48C0AB38851AE /* TreeBuilder.swift */, - D96EEA325686C991085438AA5B69502C /* UnicodeScalar.swift */, - 1748F4905B4FC87B2F3D346E5B84B616 /* Validate.swift */, - 22288D13FA0694E7A5E908C1CC9DE5BF /* Whitelist.swift */, - 268ADCD2947926FB1316F8C94FEFA5A8 /* XmlDeclaration.swift */, - 0A29168DA5AF77F67441271215C9DC6E /* XmlTreeBuilder.swift */, - E1B5BB6304CFDA3D036CDE4281FF4070 /* Support Files */, + B8F0FBF810ECE65109C95E0C8BBB893F /* Just.swift */, + 46872DBB8C34D63DE630A92868138E93 /* Support Files */, ); - path = SwiftSoup; + name = Just; + path = Just; sourceTree = ""; }; CBD43E0947D94E318A0ED1350CFF29ED /* OS X */ = { @@ -290,20 +148,12 @@ children = ( 9D940727FF8FB9C785EB98E56350EF41 /* Podfile */, E0A1E60606E0BF6E2E10F1F01350DFE8 /* Frameworks */, - CFB4ABEAEAFCDB4587FF6BE5A683746C /* Pods */, - 099C0EBCE1385C461569E1E3FC5B58C5 /* Products */, + 345EEEBE9381D91220155A959CF832C0 /* Pods */, + 623DD1C81238D9DB831E4CF39661DBBE /* Products */, 9A32C13F6CC4CEB61BBDD444CD90E386 /* Targets Support Files */, ); sourceTree = ""; }; - CFB4ABEAEAFCDB4587FF6BE5A683746C /* Pods */ = { - isa = PBXGroup; - children = ( - B67502FE5D481268EEE7772D16B9AFC4 /* SwiftSoup */, - ); - name = Pods; - sourceTree = ""; - }; E0A1E60606E0BF6E2E10F1F01350DFE8 /* Frameworks */ = { isa = PBXGroup; children = ( @@ -312,36 +162,22 @@ name = Frameworks; sourceTree = ""; }; - E1B5BB6304CFDA3D036CDE4281FF4070 /* Support Files */ = { - isa = PBXGroup; - children = ( - EFC11670D004E932C92C144DAC577866 /* SwiftSoup.modulemap */, - 653737F57003A332C4E6F80EA2E55DA6 /* SwiftSoup.xcconfig */, - 29FE73A05C9903FA27E5023421D500A9 /* SwiftSoup-dummy.m */, - C06313BA3ECCC78CBFABC9763DF22594 /* SwiftSoup-Info.plist */, - A1E1DF856B2F4607BD0F2A365D1D9FD3 /* SwiftSoup-prefix.pch */, - 783742B9F3C0D7789BF1936E5320633D /* SwiftSoup-umbrella.h */, - ); - name = "Support Files"; - path = "../Target Support Files/SwiftSoup"; - sourceTree = ""; - }; /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ - 45226E43EF0BCD4D807D13B063AED550 /* Headers */ = { + 21756C5F361BBD3F898F752B5FC5280B /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( - 182563AFC01AAB5F8010B109A379109D /* Pods-RSwitch-umbrella.h in Headers */, + CF264F96F9FC03520BF4AEE09521E7C3 /* Pods-RSwitch-umbrella.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; - BEB4C428105AE2B5F04B887EA6FB77BA /* Headers */ = { + A012C3164E69047E3F0F8E2A30BFD809 /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( - 5F4C6190E5A08291473F5C0E88FC3739 /* SwiftSoup-umbrella.h in Headers */, + 183F65FE3A9F053B826D0BE6F6FD4976 /* Just-umbrella.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -350,39 +186,39 @@ /* Begin PBXNativeTarget section */ 36D714ADB141D512E7387D09CD1BF199 /* Pods-RSwitch */ = { isa = PBXNativeTarget; - buildConfigurationList = 96487669C0D0E8C89F8460652C8D1EA6 /* Build configuration list for PBXNativeTarget "Pods-RSwitch" */; + buildConfigurationList = 338659363A374BA154D8B72A03CAB0FD /* Build configuration list for PBXNativeTarget "Pods-RSwitch" */; buildPhases = ( - 45226E43EF0BCD4D807D13B063AED550 /* Headers */, - CBAEEE521B01B8038F1ECD057D96D45D /* Sources */, - DB40808C3408552D3CD8A71C3992A07C /* Frameworks */, - EDB54ECC04F10737C0F8B0D48488AE87 /* Resources */, + 21756C5F361BBD3F898F752B5FC5280B /* Headers */, + 98D24086F94BD93279491A23481B9646 /* Sources */, + 992CF3B53A220E5FFE23E37882E06283 /* Frameworks */, + 56F8E51A5CD786E480D2E399AD98C4C6 /* Resources */, ); buildRules = ( ); dependencies = ( - 7B277E72C2BDA768D527D230E005F952 /* PBXTargetDependency */, + 77D947801AA4E2D5978E29F77C5511CD /* PBXTargetDependency */, ); name = "Pods-RSwitch"; productName = "Pods-RSwitch"; productReference = 5D52FFF81A1E26634DAD54B2BE7CBA99 /* Pods_RSwitch.framework */; productType = "com.apple.product-type.framework"; }; - D89F48405DFAFEF441B4E758A15117A5 /* SwiftSoup */ = { + CE86A5B255D405184FBF7B919824D937 /* Just */ = { isa = PBXNativeTarget; - buildConfigurationList = 58C662AE5354AFF1184BB5205EAFAD64 /* Build configuration list for PBXNativeTarget "SwiftSoup" */; + buildConfigurationList = 63262DFBECA49AB0DB89612107EBDE33 /* Build configuration list for PBXNativeTarget "Just" */; buildPhases = ( - BEB4C428105AE2B5F04B887EA6FB77BA /* Headers */, - 2B35B20F754B9B73D4B17E77AE7B68D9 /* Sources */, - 1387CD09AAD2DE1E81F58DA4273382DF /* Frameworks */, - EC434C17106FD2518CB3618747654313 /* Resources */, + A012C3164E69047E3F0F8E2A30BFD809 /* Headers */, + 97F5F2B366C744A49770C2246E9ADFDB /* Sources */, + E711F5EAC29CAB34E00E66AC2DB29C84 /* Frameworks */, + DCA62D207B545086813B397BFAF10193 /* Resources */, ); buildRules = ( ); dependencies = ( ); - name = SwiftSoup; - productName = SwiftSoup; - productReference = 5F38EF8DCE7D46A354D1D1BBAC952903 /* SwiftSoup.framework */; + name = Just; + productName = Just; + productReference = 9A212383B73C76EDF23FB6126214CAB4 /* Just.framework */; productType = "com.apple.product-type.framework"; }; /* End PBXNativeTarget section */ @@ -402,25 +238,25 @@ en, ); mainGroup = CF1408CF629C7361332E53B88F7BD30C; - productRefGroup = 099C0EBCE1385C461569E1E3FC5B58C5 /* Products */; + productRefGroup = 623DD1C81238D9DB831E4CF39661DBBE /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( + CE86A5B255D405184FBF7B919824D937 /* Just */, 36D714ADB141D512E7387D09CD1BF199 /* Pods-RSwitch */, - D89F48405DFAFEF441B4E758A15117A5 /* SwiftSoup */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ - EC434C17106FD2518CB3618747654313 /* Resources */ = { + 56F8E51A5CD786E480D2E399AD98C4C6 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; - EDB54ECC04F10737C0F8B0D48488AE87 /* Resources */ = { + DCA62D207B545086813B397BFAF10193 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( @@ -430,174 +266,35 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ - 2B35B20F754B9B73D4B17E77AE7B68D9 /* Sources */ = { + 97F5F2B366C744A49770C2246E9ADFDB /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 9C390892DA03BA76F8078B5E9F1EE971 /* ArrayExt.swift in Sources */, - 9E2E92CA61302CFAA8D2F97AC088C5C3 /* Attribute.swift in Sources */, - 96D271E1F3B86DABCAFBF96FA0F2EC03 /* Attributes.swift in Sources */, - 74ED1DAD719312ED2E1EAB6BB0BBFF71 /* BooleanAttribute.swift in Sources */, - 8CCF800901928887AA517E01C12E7AA4 /* CharacterExt.swift in Sources */, - 984F3128934C6FF64C4681754628FF0C /* CharacterReader.swift in Sources */, - CCCB6C8A300C9117E119983C5E693781 /* Cleaner.swift in Sources */, - 68912B01B6D7D4021137BF72C32294F0 /* Collector.swift in Sources */, - 13646ECCC236443CE369AC3AB04C85A2 /* CombiningEvaluator.swift in Sources */, - 48061A6A40378AA49349A4E8E6E815D5 /* Comment.swift in Sources */, - BF10823605FA7A0062852CA043794186 /* Connection.swift in Sources */, - AE698A9FA4B6EDA81A7F68DB435E3309 /* DataNode.swift in Sources */, - FAF882C254A4D68E3B8DB2F392F5AE8D /* DataUtil.swift in Sources */, - 64641F162787638B7319C71A2986F2D1 /* Document.swift in Sources */, - 4B2DC0B5E57666B3222AD7F24E579353 /* DocumentType.swift in Sources */, - 3A85CBC090CD9016F473398DEBBBC4D9 /* Element.swift in Sources */, - F8C0CA7AF2CC574511A5C8C02DEDCF43 /* Elements.swift in Sources */, - 51C521B58C9C7F3E55CBBF64231CAD92 /* Entities.swift in Sources */, - F17880FE84897581A0353EA6C49E8909 /* Evaluator.swift in Sources */, - 787BA99F9006B790A7E2775CF4371A15 /* Exception.swift in Sources */, - 3DD15E341B2A822AE4170B66EF84785B /* FormElement.swift in Sources */, - 6E8C2F72232BD8D69C06FD9BD135B0E0 /* HtmlTreeBuilder.swift in Sources */, - E25940181A204C2DDDE31DC346035755 /* HtmlTreeBuilderState.swift in Sources */, - 07DC1E76B4AC8D6F706C134BE25BFCB6 /* HttpStatusException.swift in Sources */, - 23605B9E6B3F4C6849BEB2995B8D5CC9 /* Node.swift in Sources */, - D44EE0B232CCEDE658102DE87A02DAD2 /* NodeTraversor.swift in Sources */, - 6D755DA0247FE8D37B6D95D48B8D1697 /* NodeVisitor.swift in Sources */, - 0ACC881DFA0D90EFAFA203F57BCABF31 /* OrderedDictionary.swift in Sources */, - A815B081D1C20E722584BEDC86E1BA5C /* OrderedSet.swift in Sources */, - 212095A3D1CE5571B351D4999B2D72F7 /* ParseError.swift in Sources */, - E18636DA726A4EB4566C30DC572CEF30 /* ParseErrorList.swift in Sources */, - 8A156E7D9F56597ABF006024CE5A38B2 /* Parser.swift in Sources */, - B22E0A04FCA9C46583CDE32FD83CFE1E /* ParseSettings.swift in Sources */, - EC2ADA20DC4D6D68A1CED448533F7987 /* Pattern.swift in Sources */, - 0323040E0BAAB427F131B8B7593C1823 /* QueryParser.swift in Sources */, - 6307C9763A4BF4AD4A57596F5756E3D6 /* Selector.swift in Sources */, - AE993559119E69F0C50BCC2EBBF77E61 /* SerializationException.swift in Sources */, - 4860E1263F573B4EEA7BDF236A1199D0 /* SimpleDictionary.swift in Sources */, - 184FEFB86BB797EC34B8245B2448C9B1 /* StreamReader.swift in Sources */, - 605E6909CF08E0DAD68A675C92906264 /* String.swift in Sources */, - 7B5C603DF6AE98590BD5043DEE6533D2 /* StringBuilder.swift in Sources */, - 9F0612E3E2BD1F85D7620321BEFBE2DC /* StringUtil.swift in Sources */, - 268BA1DBE8391AF20EE9D562480A2040 /* StructuralEvaluator.swift in Sources */, - 59CCEF0DB3257C3791FB7FEF729656A1 /* SwiftSoup-dummy.m in Sources */, - 6400A9389A0A3E67315FA4FD500FB283 /* SwiftSoup.swift in Sources */, - AF50D130B49C380ED075104BB7671FAB /* Tag.swift in Sources */, - 5EA9213700B4A83923FE1F76199D7478 /* TextNode.swift in Sources */, - 7383E209342B658049AAC2F6A47CD54E /* Token.swift in Sources */, - 45AE0479CEA0DCD1CC289FAC7A0D74CD /* Tokeniser.swift in Sources */, - 1F6A5C0F3BEF9084C8E9066D3F8AD4F1 /* TokeniserState.swift in Sources */, - 9D9E42B84863721085CB2C0EE1467CA6 /* TokenQueue.swift in Sources */, - C88398AADEBDF75E34AEF8564807EBBA /* TreeBuilder.swift in Sources */, - 717A618E1185ED3073BF6557DAD82429 /* UnicodeScalar.swift in Sources */, - A072BEECFC9A659AC25573E82E8E0D65 /* Validate.swift in Sources */, - 1B1E44407BA5AB6B543BFD609D48FB4D /* Whitelist.swift in Sources */, - 08F669849B088847C5391DCA0D21EBCA /* XmlDeclaration.swift in Sources */, - DB16F4FC1AC7BEFE72972A8B7F7629B1 /* XmlTreeBuilder.swift in Sources */, + 6E52FCF9BA1CABB3FE89003AA31BF40D /* Just-dummy.m in Sources */, + 1642FF2CBDC0D5DE293557BAC7483330 /* Just.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; - CBAEEE521B01B8038F1ECD057D96D45D /* Sources */ = { + 98D24086F94BD93279491A23481B9646 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 2B29E96B4BEEE65DA4760B9E2070433C /* Pods-RSwitch-dummy.m in Sources */, + 3319EB536901C1505EA1E0A74CA48C36 /* Pods-RSwitch-dummy.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ - 7B277E72C2BDA768D527D230E005F952 /* PBXTargetDependency */ = { + 77D947801AA4E2D5978E29F77C5511CD /* PBXTargetDependency */ = { isa = PBXTargetDependency; - name = SwiftSoup; - target = D89F48405DFAFEF441B4E758A15117A5 /* SwiftSoup */; - targetProxy = B77095034AB3D02A24C74888527C265D /* PBXContainerItemProxy */; + name = Just; + target = CE86A5B255D405184FBF7B919824D937 /* Just */; + targetProxy = E0B9423F4CC99D0A13E90EE927936CDD /* PBXContainerItemProxy */; }; /* End PBXTargetDependency section */ /* Begin XCBuildConfiguration section */ - 28937119401B98869866251E32C12494 /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 6B5F1D02B43D15E9D5752784305E1A5D /* Pods-RSwitch.debug.xcconfig */; - buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO; - ARCHS = "$(ARCHS_STANDARD_64_BIT)"; - CLANG_ENABLE_OBJC_WEAK = NO; - CODE_SIGN_IDENTITY = "Developer ID Application"; - "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; - "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; - CODE_SIGN_STYLE = Manual; - COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 1; - DEFINES_MODULE = YES; - DEVELOPMENT_TEAM = CBY22P58G8; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - FRAMEWORK_VERSION = A; - INFOPLIST_FILE = "Target Support Files/Pods-RSwitch/Pods-RSwitch-Info.plist"; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/../Frameworks", - "@loader_path/Frameworks", - ); - MACH_O_TYPE = staticlib; - MACOSX_DEPLOYMENT_TARGET = 10.14; - MODULEMAP_FILE = "Target Support Files/Pods-RSwitch/Pods-RSwitch.modulemap"; - OTHER_LDFLAGS = ""; - OTHER_LIBTOOLFLAGS = ""; - PODS_ROOT = "$(SRCROOT)"; - PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}"; - PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; - PROVISIONING_PROFILE_SPECIFIER = ""; - SDKROOT = macosx; - SKIP_INSTALL = YES; - VERSIONING_SYSTEM = "apple-generic"; - VERSION_INFO_PREFIX = ""; - }; - name = Debug; - }; - 30E1CB02BB5209911271753062F04733 /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 653737F57003A332C4E6F80EA2E55DA6 /* SwiftSoup.xcconfig */; - buildSettings = { - ARCHS = "$(ARCHS_STANDARD_64_BIT)"; - CLANG_ENABLE_OBJC_WEAK = NO; - CODE_SIGN_IDENTITY = "Developer ID Application"; - "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; - "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; - CODE_SIGN_STYLE = Manual; - COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 1; - DEFINES_MODULE = YES; - DEVELOPMENT_TEAM = CBY22P58G8; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - FRAMEWORK_VERSION = A; - GCC_PREFIX_HEADER = "Target Support Files/SwiftSoup/SwiftSoup-prefix.pch"; - INFOPLIST_FILE = "Target Support Files/SwiftSoup/SwiftSoup-Info.plist"; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/../Frameworks", - "@loader_path/Frameworks", - ); - MACOSX_DEPLOYMENT_TARGET = 10.10; - MODULEMAP_FILE = "Target Support Files/SwiftSoup/SwiftSoup.modulemap"; - PRODUCT_MODULE_NAME = SwiftSoup; - PRODUCT_NAME = SwiftSoup; - PROVISIONING_PROFILE_SPECIFIER = ""; - SDKROOT = macosx; - SKIP_INSTALL = YES; - SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; - SWIFT_VERSION = 5.0; - VERSIONING_SYSTEM = "apple-generic"; - VERSION_INFO_PREFIX = ""; - }; - name = Release; - }; 430C0A1F2A9CB52955BEC7CE69B7B629 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -662,6 +359,44 @@ }; name = Debug; }; + 434E5D3509C83A8B996D60E6BEDA6C77 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 574603E2D7597AEEB79587D7C3889AA1 /* Just.xcconfig */; + buildSettings = { + ARCHS = "$(ARCHS_STANDARD_64_BIT)"; + CLANG_ENABLE_OBJC_WEAK = NO; + CODE_SIGN_IDENTITY = ""; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + COMBINE_HIDPI_IMAGES = YES; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + FRAMEWORK_VERSION = A; + GCC_PREFIX_HEADER = "Target Support Files/Just/Just-prefix.pch"; + INFOPLIST_FILE = "Target Support Files/Just/Just-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + "@loader_path/Frameworks", + ); + MACOSX_DEPLOYMENT_TARGET = 10.10; + MODULEMAP_FILE = "Target Support Files/Just/Just.modulemap"; + PRODUCT_MODULE_NAME = Just; + PRODUCT_NAME = Just; + SDKROOT = macosx; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; 597E092427DF423992C59C814880FE96 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { @@ -716,33 +451,31 @@ PRODUCT_NAME = "$(TARGET_NAME)"; STRIP_INSTALLED_PRODUCT = NO; SWIFT_COMPILATION_MODE = wholemodule; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_OPTIMIZATION_LEVEL = "-O"; SWIFT_VERSION = 5.0; SYMROOT = "${SRCROOT}/../build"; }; name = Release; }; - CE1E7DB9F3C040366A3496455A8B24BD /* Debug */ = { + ABCA764BDF2BC6B0A9DA9B8EAB2149ED /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 653737F57003A332C4E6F80EA2E55DA6 /* SwiftSoup.xcconfig */; + baseConfigurationReference = 574603E2D7597AEEB79587D7C3889AA1 /* Just.xcconfig */; buildSettings = { ARCHS = "$(ARCHS_STANDARD_64_BIT)"; CLANG_ENABLE_OBJC_WEAK = NO; - CODE_SIGN_IDENTITY = "Developer ID Application"; + CODE_SIGN_IDENTITY = ""; "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; - CODE_SIGN_STYLE = Manual; COMBINE_HIDPI_IMAGES = YES; CURRENT_PROJECT_VERSION = 1; DEFINES_MODULE = YES; - DEVELOPMENT_TEAM = CBY22P58G8; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; FRAMEWORK_VERSION = A; - GCC_PREFIX_HEADER = "Target Support Files/SwiftSoup/SwiftSoup-prefix.pch"; - INFOPLIST_FILE = "Target Support Files/SwiftSoup/SwiftSoup-Info.plist"; + GCC_PREFIX_HEADER = "Target Support Files/Just/Just-prefix.pch"; + INFOPLIST_FILE = "Target Support Files/Just/Just-Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -750,10 +483,9 @@ "@loader_path/Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 10.10; - MODULEMAP_FILE = "Target Support Files/SwiftSoup/SwiftSoup.modulemap"; - PRODUCT_MODULE_NAME = SwiftSoup; - PRODUCT_NAME = SwiftSoup; - PROVISIONING_PROFILE_SPECIFIER = ""; + MODULEMAP_FILE = "Target Support Files/Just/Just.modulemap"; + PRODUCT_MODULE_NAME = Just; + PRODUCT_NAME = Just; SDKROOT = macosx; SKIP_INSTALL = YES; SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; @@ -763,22 +495,20 @@ }; name = Debug; }; - D7F84BF4AD9212BB6A99F6519EC528A6 /* Release */ = { + D5BF4F3585D5CD8FE3C69B5C29C7A323 /* Release */ = { isa = XCBuildConfiguration; baseConfigurationReference = D722B0A61F22FDFBDEF11F24016B4D1D /* Pods-RSwitch.release.xcconfig */; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO; ARCHS = "$(ARCHS_STANDARD_64_BIT)"; CLANG_ENABLE_OBJC_WEAK = NO; - CODE_SIGN_IDENTITY = "Developer ID Application"; + CODE_SIGN_IDENTITY = ""; "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; - CODE_SIGN_STYLE = Manual; COMBINE_HIDPI_IMAGES = YES; CURRENT_PROJECT_VERSION = 1; DEFINES_MODULE = YES; - DEVELOPMENT_TEAM = CBY22P58G8; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; @@ -798,7 +528,6 @@ PODS_ROOT = "$(SRCROOT)"; PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; - PROVISIONING_PROFILE_SPECIFIER = ""; SDKROOT = macosx; SKIP_INSTALL = YES; VERSIONING_SYSTEM = "apple-generic"; @@ -806,32 +535,72 @@ }; name = Release; }; + F956E996BCA181F8AAFAB802C831FAB9 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 6B5F1D02B43D15E9D5752784305E1A5D /* Pods-RSwitch.debug.xcconfig */; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO; + ARCHS = "$(ARCHS_STANDARD_64_BIT)"; + CLANG_ENABLE_OBJC_WEAK = NO; + CODE_SIGN_IDENTITY = ""; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + COMBINE_HIDPI_IMAGES = YES; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + FRAMEWORK_VERSION = A; + INFOPLIST_FILE = "Target Support Files/Pods-RSwitch/Pods-RSwitch-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + "@loader_path/Frameworks", + ); + MACH_O_TYPE = staticlib; + MACOSX_DEPLOYMENT_TARGET = 10.14; + MODULEMAP_FILE = "Target Support Files/Pods-RSwitch/Pods-RSwitch.modulemap"; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PODS_ROOT = "$(SRCROOT)"; + PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}"; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SDKROOT = macosx; + SKIP_INSTALL = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ - 4821239608C13582E20E6DA73FD5F1F9 /* Build configuration list for PBXProject "Pods" */ = { + 338659363A374BA154D8B72A03CAB0FD /* Build configuration list for PBXNativeTarget "Pods-RSwitch" */ = { isa = XCConfigurationList; buildConfigurations = ( - 430C0A1F2A9CB52955BEC7CE69B7B629 /* Debug */, - 597E092427DF423992C59C814880FE96 /* Release */, + F956E996BCA181F8AAFAB802C831FAB9 /* Debug */, + D5BF4F3585D5CD8FE3C69B5C29C7A323 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - 58C662AE5354AFF1184BB5205EAFAD64 /* Build configuration list for PBXNativeTarget "SwiftSoup" */ = { + 4821239608C13582E20E6DA73FD5F1F9 /* Build configuration list for PBXProject "Pods" */ = { isa = XCConfigurationList; buildConfigurations = ( - CE1E7DB9F3C040366A3496455A8B24BD /* Debug */, - 30E1CB02BB5209911271753062F04733 /* Release */, + 430C0A1F2A9CB52955BEC7CE69B7B629 /* Debug */, + 597E092427DF423992C59C814880FE96 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - 96487669C0D0E8C89F8460652C8D1EA6 /* Build configuration list for PBXNativeTarget "Pods-RSwitch" */ = { + 63262DFBECA49AB0DB89612107EBDE33 /* Build configuration list for PBXNativeTarget "Just" */ = { isa = XCConfigurationList; buildConfigurations = ( - 28937119401B98869866251E32C12494 /* Debug */, - D7F84BF4AD9212BB6A99F6519EC528A6 /* Release */, + ABCA764BDF2BC6B0A9DA9B8EAB2149ED /* Debug */, + 434E5D3509C83A8B996D60E6BEDA6C77 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; diff --git a/Pods/Pods.xcodeproj/xcuserdata/hrbrmstr.xcuserdatad/xcschemes/Just.xcscheme b/Pods/Pods.xcodeproj/xcuserdata/hrbrmstr.xcuserdatad/xcschemes/Just.xcscheme new file mode 100644 index 0000000..35289a1 --- /dev/null +++ b/Pods/Pods.xcodeproj/xcuserdata/hrbrmstr.xcuserdatad/xcschemes/Just.xcscheme @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Pods/Pods.xcodeproj/xcuserdata/hrbrmstr.xcuserdatad/xcschemes/SwiftSoup.xcscheme b/Pods/Pods.xcodeproj/xcuserdata/hrbrmstr.xcuserdatad/xcschemes/SwiftSoup.xcscheme deleted file mode 100644 index 6234ac1..0000000 --- a/Pods/Pods.xcodeproj/xcuserdata/hrbrmstr.xcuserdatad/xcschemes/SwiftSoup.xcscheme +++ /dev/null @@ -1,60 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Pods/Pods.xcodeproj/xcuserdata/hrbrmstr.xcuserdatad/xcschemes/xcschememanagement.plist b/Pods/Pods.xcodeproj/xcuserdata/hrbrmstr.xcuserdatad/xcschemes/xcschememanagement.plist index 08c80c1..92b2918 100644 --- a/Pods/Pods.xcodeproj/xcuserdata/hrbrmstr.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Pods/Pods.xcodeproj/xcuserdata/hrbrmstr.xcuserdatad/xcschemes/xcschememanagement.plist @@ -4,14 +4,14 @@ SchemeUserState - Pods-RSwitch.xcscheme + Just.xcscheme isShown orderHint 0 - SwiftSoup.xcscheme + Pods-RSwitch.xcscheme isShown diff --git a/Pods/SwiftSoup/LICENSE b/Pods/SwiftSoup/LICENSE deleted file mode 100644 index ddeb6c9..0000000 --- a/Pods/SwiftSoup/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2016 Nabil Chatbi - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/Pods/SwiftSoup/README.md b/Pods/SwiftSoup/README.md deleted file mode 100644 index e33a692..0000000 --- a/Pods/SwiftSoup/README.md +++ /dev/null @@ -1,595 +0,0 @@ -

- SwiftSoup -

- - -![Platform OS X | iOS | tvOS | watchOS | Linux](https://img.shields.io/badge/platform-Linux%20%7C%20OS%20X%20%7C%20iOS%20%7C%20tvOS%20%7C%20watchOS-orange.svg) -[![SPM compatible](https://img.shields.io/badge/SPM-compatible-4BC51D.svg?style=flat)](https://github.com/apple/swift-package-manager) -![🐧 linux: ready](https://img.shields.io/badge/%F0%9F%90%A7%20linux-ready-red.svg) -![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat) -[![Build Status](https://travis-ci.org/scinfu/SwiftSoup.svg?branch=master)](https://travis-ci.org/scinfu/SwiftSoup) -[![Version](https://img.shields.io/cocoapods/v/SwiftSoup.svg?style=flat)](http://cocoapods.org/pods/SwiftSoup) -[![License](https://img.shields.io/cocoapods/l/SwiftSoup.svg?style=flat)](http://cocoapods.org/pods/SwiftSoup) -[![Twitter](https://img.shields.io/badge/twitter-@scinfu-blue.svg?style=flat)](http://twitter.com/scinfu) - -`SwiftSoup` is a pure Swift library, cross-platform (macOS, iOS, tvOS, watchOS and Linux!), for working with real-world HTML. It provides a very convenient API for extracting and manipulating data, using the best of DOM, CSS, and jQuery-like methods. -`SwiftSoup` implements the WHATWG HTML5 specification, and parses HTML to the same DOM as modern browsers do. -* Scrape and parse HTML from a URL, file, or string -* Find and extract data, using DOM traversal or CSS selectors -* Manipulate the HTML elements, attributes, and text -* Clean user-submitted content against a safe white-list, to prevent XSS attacks -* Output tidy HTML -`SwiftSoup` is designed to deal with all varieties of HTML found in the wild; from pristine and validating, to invalid tag-soup; `SwiftSoup` will create a sensible parse tree. -## Swift -Swift 5 ```>=2.0.0``` - -Swift 4.2 ```1.7.4``` - -## Installation - -### Cocoapods -SwiftSoup is available through [CocoaPods](http://cocoapods.org). To install -it, simply add the following line to your Podfile: - -```ruby -pod 'SwiftSoup' -``` -### Carthage -SwiftSoup is also available through [Carthage](https://github.com/Carthage/Carthage). To install -it, simply add the following line to your Cartfile: - -```ruby -github "scinfu/SwiftSoup" -``` -### Swift Package Manager -SwiftSoup is also available through [Swift Package Manager](https://github.com/apple/swift-package-manager). -To install it, simply add the dependency to your Package.Swift file: - -```swift -... -dependencies: [ - .package(url: "https://github.com/scinfu/SwiftSoup.git", from: "1.7.4"), -], -targets: [ - .target( name: "YourTarget", dependencies: ["SwiftSoup"]), -] -... -``` - -## Try -### Try out the simple online CSS selectors site: -[SwiftSoup Test Site](https://swiftsoup.herokuapp.com/) - -### Try out the example project opening Terminal and type: -```shell -pod try SwiftSoup -``` -

- SwiftSoup - SwiftSoup -

- -# To parse an HTML document: - -```swift -do { - let html = "First parse" - + "

Parsed HTML into a doc.

" - let doc: Document = try SwiftSoup.parse(html) - return try doc.text() -} catch Exception.Error(let type, let message) { - print(message) -} catch { - print("error") -} -``` - -* Unclosed tags (e.g. `

Lorem

Ipsum` parses to `

Lorem

Ipsum

`) -* Implicit tags (e.g. a naked `Table data` is wrapped into a `
...`) -* Reliably creating the document structure (`html` containing a `head` and `body`, and only appropriate elements within the head) - - -### The object model of a document -* Documents consist of Elements and TextNodes -* The inheritance chain is: `Document` extends `Element` extends `Node.TextNode` extends `Node`. -* An Element contains a list of children Nodes, and has one parent Element. They also have provide a filtered list of child Elements only. - - - - -# Extract attributes, text, and HTML from elements -### Problem -After parsing a document, and finding some elements, you'll want to get at the data inside those elements. -### Solution -- To get the value of an attribute, use the `Node.attr(_ String key)` method -- For the text on an element (and its combined children), use `Element.text()` -- For HTML, use `Element.html()`, or `Node.outerHtml()` as appropriate - -```swift -do { - let html: String = "

An example link.

"; - let doc: Document = try SwiftSoup.parse(html) - let link: Element = try doc.select("a").first()! - - let text: String = try doc.body()!.text(); // "An example link" - let linkHref: String = try link.attr("href"); // "http://example.com/" - let linkText: String = try link.text(); // "example"" - - let linkOuterH: String = try link.outerHtml(); // "example" - let linkInnerH: String = try link.html(); // "example" -} catch Exception.Error(let type, let message) { - print(message) -} catch { - print("error") -} -``` - -### Description -The methods above are the core of the element data access methods. There are additional others: -- `Element.id()` -- `Element.tagName()` -- `Element.className()` and `Element.hasClass(_ String className)` - -All of these accessor methods have corresponding setter methods to change the data. - - - - - -# Parse a document from a String -### Problem -You have HTML in a Swift String, and you want to parse that HTML to get at its contents, or to make sure it's well formed, or to modify it. The String may have come from user input, a file, or from the web. -### Solution -Use the static `SwiftSoup.parse(_ html: String)` method, or `SwiftSoup.parse(_ html: String, _ baseUri: String)`. - -```swift -do { - let html = "First parse" - + "

Parsed HTML into a doc.

" - let doc: Document = try SwiftSoup.parse(html) - return try doc.text() -} catch Exception.Error(let type, let message) { - print("") -} catch { - print("") -} -``` -### Description -The `parse(_ html: String, _ baseUri: String)` method parses the input HTML into a new `Document`. The base URI argument is used to resolve relative URLs into absolute URLs, and should be set to the URL where the document was fetched from. If that's not applicable, or if you know the HTML has a base element, you can use the `parse(_ html: String)` method. - -As long as you pass in a non-null string, you're guaranteed to have a successful, sensible parse, with a Document containing (at least) a `head` and a `body` element. - -Once you have a `Document`, you can get at the data using the appropriate methods in `Document` and its supers `Element` and `Node`. - - - -# Parsing a body fragment -### Problem -You have a fragment of body HTML (e.g. `div` containing a couple of p tags; as opposed to a full HTML document) that you want to parse. Perhaps it was provided by a user submitting a comment, or editing the body of a page in a CMS. -### Solution -Use the `SwiftSoup.parseBodyFragment(_ html: String)` method. - -```swift -do { - let html: String = "

Lorem ipsum.

" - let doc: Document = try SwiftSoup.parseBodyFragment(html) - let body: Element? = doc.body() -} catch Exception.Error(let type, let message) { - print(message) -} catch { - print("error") -} -``` - -### Description -The `parseBodyFragment` method creates an empty shell document, and inserts the parsed HTML into the `body` element. If you used the normal `SwiftSoup(_ html: String)` method, you would generally get the same result, but explicitly treating the input as a body fragment ensures that any bozo HTML provided by the user is parsed into the `body` element. - -The `Document.body()` method retrieves the element children of the document's `body` element; it is equivalent to `doc.getElementsByTag("body")`. - -### Stay safe -If you are going to accept HTML input from a user, you need to be careful to avoid cross-site scripting attacks. See the documentation for the `Whitelist` based cleaner, and clean the input with `clean(String bodyHtml, Whitelist whitelist)`. - - - - - -# Sanitize untrusted HTML (to prevent XSS) -### Problem -You want to allow untrusted users to supply HTML for output on your website (e.g. as comment submission). You need to clean this HTML to avoid [cross-site scripting](https://en.wikipedia.org/wiki/Cross-site_scripting) (XSS) attacks. -### Solution -Use the SwiftSoup HTML `Cleaner` with a configuration specified by a `Whitelist`. - -```swift -do { - let unsafe: String = "

Link

" - let safe: String = try SwiftSoup.clean(unsafe, Whitelist.basic())! - // now:

Link

-} catch Exception.Error(let type, let message) { - print(message) -} catch { - print("error") -} -``` - -### Discussion -A cross-site scripting attack against your site can really ruin your day, not to mention your users'. Many sites avoid XSS attacks by not allowing HTML in user submitted content: they enforce plain text only, or use an alternative markup syntax like wiki-text or Markdown. These are seldom optimal solutions for the user, as they lower expressiveness, and force the user to learn a new syntax. - -A better solution may be to use a rich text WYSIWYG editor (like [CKEditor](http://ckeditor.com) or [TinyMCE](https://www.tinymce.com)). These output HTML, and allow the user to work visually. However, their validation is done on the client side: you need to apply a server-side validation to clean up the input and ensure the HTML is safe to place on your site. Otherwise, an attacker can avoid the client-side Javascript validation and inject unsafe HMTL directly into your site - -The SwiftSoup whitelist sanitizer works by parsing the input HTML (in a safe, sand-boxed environment), and then iterating through the parse tree and only allowing known-safe tags and attributes (and values) through into the cleaned output. - -It does not use regular expressions, which are inappropriate for this task. - -SwiftSoup provides a range of `Whitelist` configurations to suit most requirements; they can be modified if necessary, but take care. - -The cleaner is useful not only for avoiding XSS, but also in limiting the range of elements the user can provide: you may be OK with textual `a`, `strong` elements, but not structural `div` or `table` elements. - -### See also -- See the [XSS cheat sheet](http://ha.ckers.org/xss.html) and filter evasion guide, as an example of how regular-expression filters don't work, and why a safe whitelist parser-based sanitizer is the correct approach. -- See the `Cleaner` reference if you want to get a `Document` instead of a String return -- See the `Whitelist` reference for the different canned options, and to create a custom whitelist -- The [nofollow](https://en.wikipedia.org/wiki/Nofollow) link attribute - - - - -# Set attribute values -### Problem -You have a parsed document that you would like to update attribute values on, before saving it out to disk, or sending it on as a HTTP response. - -### Solution -Use the attribute setter methods `Element.attr(_ key: String, _ value: String)`, and `Elements.attr(_ key: String, _ value: String)`. - -If you need to modify the class attribute of an element, use the `Element.addClass(_ className: String)` and `Element.removeClass(_ className: String)` methods. - -The `Elements` collection has bulk attribute and class methods. For example, to add a `rel="nofollow"` attribute to every `a` element inside a div: - -```swift -do { - try doc.select("div.comments a").attr("rel", "nofollow") -} catch Exception.Error(let type, let message) { - print(message) -} catch { - print("error") -} -``` -### Description -Like the other methods in `Element`, the attr methods return the current `Element` (or `Elements` when working on a collection from a select). This allows convenient method chaining: - -```swift -do { - try doc.select("div.masthead").attr("title", "swiftsoup").addClass("round-box"); -} catch Exception.Error(let type, let message) { - print(message) -} catch { - print("error") -} -``` - - -# Set the HTML of an element -### Problem -You need to modify the HTML of an element. -### Solution -Use the HTML setter methods in `Element`: -```swift -do { - let doc: Document = try SwiftSoup.parse("
One
One") - let div: Element = try doc.select("div").first()! //
- try div.html("

lorem ipsum

") //

lorem ipsum

- try div.prepend("

First

") - try div.append("

Last

") - print(div) - // now div is:

First

lorem ipsum

Last

- - let span: Element = try doc.select("span").first()! // One - try span.wrap("
  • ") - print(doc) - // now:
  • One
  • -} catch Exception.Error(let type, let message) { - print(message) -} catch { - print("error") -} -``` -### Discussion -- `Element.html(_ html: String)` clears any existing inner HTML in an element, and replaces it with parsed HTML. -- `Element.prepend(_ first: String)` and `Element.append(_ last: String)` add HTML to the start or end of an element's inner HTML, respectively -- `Element.wrap(_ around: String)` wraps HTML around the outer HTML of an element. - -### See also -You can also use the `Element.prependElement(_ tag: String)` and `Element.appendElement(_ tag: String)` methods to create new elements and insert them into the document flow as a child element. - - - - - -# Setting the text content of elements -### Problem -You need to modify the text content of an HTML document. -# Solution -Use the text setter methods of `Element`: - -```swift -do { - let doc: Document = try SwiftSoup.parse("") - let div: Element = try doc.select("div").first()! //
    - try div.text("five > four") //
    five > four
    - try div.prepend("First ") - try div.append(" Last") - // now:
    First five > four Last
    -} catch Exception.Error(let type, let message) { - print(message) -} catch { - print("error") -} -``` - -### Discussion -The text setter methods mirror the [[HTML setter|Set the HTML of an element]] methods: -- `Element.text(_ text: String)` clears any existing inner HTML in an element, and replaces it with the supplied text. -- `Element.prepend(_ first: String)` and `Element.append(_ last: String)` add text nodes to the start or end of an element's inner HTML, respectively -The text should be supplied unencoded: characters like `<`, `>` etc will be treated as literals, not HTML. - - - - - -# Use DOM methods to navigate a document -### Problem -You have a HTML document that you want to extract data from. You know generally the structure of the HTML document. - -### Solution -Use the DOM-like methods available after parsing HTML into a `Document`. - -```swift -do { - let html: String = "One Two" - let els: Elements = try SwiftSoup.parse(html).select("a") - for link: Element in els.array() { - let linkHref: String = try link.attr("href") - let linkText: String = try link.text() - } -} catch Exception.Error(let type, let message) { - print(message) -} catch { - print("error") -} -``` -### Description -Elements provide a range of DOM-like methods to find elements, and extract and manipulate their data. The DOM getters are contextual: called on a parent Document they find matching elements under the document; called on a child element they find elements under that child. In this way you can window in on the data you want. -### Finding elements -* `getElementById(_ id: String)` -* `getElementsByTag(_ tag:String)` -* `getElementsByClass(_ className: String)` -* `getElementsByAttribute(_ key: String)` (and related methods) -* Element siblings: `siblingElements()`, `firstElementSibling()`, `lastElementSibling()`, `nextElementSibling()`, `previousElementSibling()` -* Graph: `parent()`, `children()`, `child(_ index: Int)` - -# Element data -* `attr(_ key: Strin)` to get and `attr(_ key: String, _ value: String)` to set attributes -* `attributes()` to get all attributes -* `id()`, `className()` and `classNames()` -* `text()` to get and `text(_ value: String)` to set the text content -* `html()` to get and `html(_ value: String)` to set the inner HTML content -* `outerHtml()` to get the outer HTML value -* `data()` to get data content (e.g. of script and style tags) -* `tag()` and `tagName()` - -### Manipulating HTML and text -* `append(_ html: String)`, `prepend(html: String)` -* `appendText(text: String)`, `prependText(text: String)` -* `appendElement(tagName: String)`, `prependElement(tagName: String)` -* `html(_ value: String)` - - - - - - - - - - - - -# Use selector syntax to find elements -### Problem -You want to find or manipulate elements using a CSS or jQuery-like selector syntax. -### Solution -Use the `Element.select(_ selector: String)` and `Elements.select(_ selector: String)` methods: - -```swift -do { - let doc: Document = try SwiftSoup.parse("...") - let links: Elements = try doc.select("a[href]") // a with href - let pngs: Elements = try doc.select("img[src$=.png]") - // img with src ending .png - let masthead: Element? = try doc.select("div.masthead").first() - // div with class=masthead - let resultLinks: Elements? = try doc.select("h3.r > a") // direct a after h3 -} catch Exception.Error(let type, let message) { - print(message) -} catch { - print("error") -} -``` -### Description -SwiftSoup elements support a [CSS](https://www.w3.org/TR/2009/PR-css3-selectors-20091215/) (or [jQuery](http://jquery.com)) like selector syntax to find matching elements, that allows very powerful and robust queries. - -The `select` method is available in a `Document`, `Element`, or in `Elements`. It is contextual, so you can filter by selecting from a specific element, or by chaining select calls. - -Select returns a list of `Elements` (as `Elements`), which provides a range of methods to extract and manipulate the results. -### Selector overview -* `tagname`: find elements by tag, e.g. `a` -* `ns|tag`: find elements by tag in a namespace, e.g. `fb|name` finds `` elements -* `#id`: find elements by ID, e.g. `#logo` -* `.class`: find elements by class name, e.g. `.masthead` -* `[attribute]`: elements with attribute, e.g. `[href]` -* `[^attr]`: elements with an attribute name prefix, e.g. `[^data-]` finds elements with HTML5 dataset attributes -* `[attr=value]`: elements with attribute value, e.g. `[width=500]` (also quotable, like `[data-name='launch sequence']`) -* `[attr^=value]`, `[attr$=value]`, `[attr*=value]`: elements with attributes that start with, end with, or contain the value, e.g. `[href*=/path/]` -* `[attr~=regex]`: elements with attribute values that match the regular expression; e.g. `img[src~=(?i)\.(png|jpe?g)]` -* `*`: all elements, e.g. `*` -### Selector combinations -* `el#id`: elements with ID, e.g. `div#logo` -* `el.class`: elements with class, e.g. `div.masthead` -* `el[attr]`: elements with attribute, e.g. `a[href]` -* Any combination, e.g. `a[href].highlight` -* Ancestor `child`: child elements that descend from ancestor, e.g. `.body p` finds `p` elements anywhere under a block with class "body" -* `parent > child`: child elements that descend directly from parent, e.g. `div.content > p` finds p elements; and `body > *` finds the direct children of the body tag -* `siblingA + siblingB`: finds sibling B element immediately preceded by sibling A, e.g. `div.head + div` -* `siblingA ~ siblingX`: finds sibling X element preceded by sibling A, e.g. `h1 ~ p` -* `el`, `el`, `el`: group multiple selectors, find unique elements that match any of the selectors; e.g. `div.masthead`, `div.logo` - -### Pseudo selectors -* `:lt(n)`: find elements whose sibling index (i.e. its position in the DOM tree relative to its parent) is less than n; e.g. `td:lt(3)` -* `:gt(n)`: find elements whose sibling index is greater than n; e.g. `div p:gt(2)` -* `:eq(n)`: find elements whose sibling index is equal to n; e.g. `form input:eq(1)` -* `:has(seletor)`: find elements that contain elements matching the selector; e.g. `div:has(p)` -* `:not(selector)`: find elements that do not match the selector; e.g. `div:not(.logo)` -* `:contains(text)`: find elements that contain the given text. The search is case-insensitive; e.g. `p:contains(swiftsoup)` -* `:containsOwn(text)`: find elements that directly contain the given text -* `:matches(regex)`: find elements whose text matches the specified regular expression; e.g. `div:matches((?i)login)` -* `:matchesOwn(regex)`: find elements whose own text matches the specified regular expression -* Note that the above indexed pseudo-selectors are 0-based, that is, the first element is at index 0, the second at 1, etc - -# Examples -## To parse an HTML document from String: - -```swift -let html = "First parse

    Parsed HTML into a doc.

    " -guard let doc: Document = try? SwiftSoup.parse(html) else { return } -``` - -## Get all text nodes: - -```swift -guard let elements = try? doc.getAllElements() else { return html } -for element in elements { - for textNode in element.textNodes() { - [...] - } -} -``` - -## Set CSS using SwiftSoup: - -```swift -try doc.head()?.append("") -``` - -## Get HTML value -```swift -let html = "
    " - + "
    " - + "
    " - + "
    " - + "" - + "" - + "" - + "
    " - + "" - + "" - + "" - + "" - + "
    " - + "
    " - + "
    " - + "
    " -guard let doc: Document = try? SwiftSoup.parse(html) else { return } // parse html -let elements = try doc.select("[name=transaction_id]") // query -let transaction_id = try elements.get(0) // select first element -let value = try transaction_id.val() // get value -print(value) // 4245 -``` -## How to remove all the html from a string - -```swift -guard let doc: Document = try? SwiftSoup.parse(html) else { return } // parse html -guard let txt = try? doc.text() else { return } -print(txt) -``` - -## How to get and update XML values - -```swift -let xml = "One" -guard let doc = try? SwiftSoup.parse(xml, "", Parser.xmlParser()) else { return } -guard let element = try? doc.getElementsByTag("val").first() // Find first element -element.text("NewValue") // Edit Value -let valueString = element.text() // "NewValue" -``` - -## How to get all `` - -```swift -do { - let doc: Document = try SwiftSoup.parse(html) - let srcs: Elements = try doc.select("img[src]") - let srcsStringArray: [String?] = srcs.array().map { try? $0.attr("src").description } - // do something with srcsStringArray -} catch Exception.Error(_, let message) { - print(message) -} catch { - print("error") -} -``` - -## Get all `href` of `` - -```swift -let html = "One Two" -guard let els: Elements = try? SwiftSoup.parse(html).select("a") else { return } -for element: Element in els.array() { - print(try? element.attr("href")) -} -``` -Output: -``` -"?foo=bar&mid<=true" -"?foo=bar Å å π 新 there ¾ © »" - - -"Hello &<> Å å π 新 there ¾ © »" -"Hello &<> Å å π 新 there ¾ © »" -"Hello &<> Å å π 新 there ¾ © »" -"Hello &<> Å å π 新 there ¾ © »" -"Hello &<> Å å π 新 there ¾ © »" - -``` - - - -## Author - -Nabil Chatbi, scinfu@gmail.com - -## Note -SwiftSoup was ported to Swift from Java [Jsoup](https://jsoup.org/) library. - -## License - -SwiftSoup is available under the MIT license. See the LICENSE file for more info. diff --git a/Pods/SwiftSoup/Sources/ArrayExt.swift b/Pods/SwiftSoup/Sources/ArrayExt.swift deleted file mode 100644 index a3b329f..0000000 --- a/Pods/SwiftSoup/Sources/ArrayExt.swift +++ /dev/null @@ -1,21 +0,0 @@ -// -// ArrayExt.swift -// SwifSoup -// -// Created by Nabil Chatbi on 05/10/16. -// Copyright © 2016 Nabil Chatbi.. All rights reserved. -// - -import Foundation - -extension Array where Element : Equatable { - func lastIndexOf(_ e: Element) -> Int { - for pos in (0.. String { - return key - } - - /** - Set the attribute key; case is preserved. - @param key the new key; must not be null - */ - open func setKey(key: String) throws { - try Validate.notEmpty(string: key) - self.key = key.trim() - } - - /** - Get the attribute value. - @return the attribute value - */ - open func getValue() -> String { - return value - } - - /** - Set the attribute value. - @param value the new attribute value; must not be null - */ - @discardableResult - open func setValue(value: String) -> String { - let old = self.value - self.value = value - return old - } - - /** - Get the HTML representation of this attribute; e.g. {@code href="index.html"}. - @return HTML - */ - public func html() -> String { - let accum = StringBuilder() - html(accum: accum, out: (Document("")).outputSettings()) - return accum.toString() - } - - public func html(accum: StringBuilder, out: OutputSettings ) { - accum.append(key) - if (!shouldCollapseAttribute(out: out)) { - accum.append("=\"") - Entities.escape(accum, value, out, true, false, false) - accum.append("\"") - } - } - - /** - Get the string representation of this attribute, implemented as {@link #html()}. - @return string - */ - open func toString() -> String { - return html() - } - - /** - * Create a new Attribute from an unencoded key and a HTML attribute encoded value. - * @param unencodedKey assumes the key is not encoded, as can be only run of simple \w chars. - * @param encodedValue HTML attribute encoded value - * @return attribute - */ - public static func createFromEncoded(unencodedKey: String, encodedValue: String) throws ->Attribute { - let value = try Entities.unescape(string: encodedValue, strict: true) - return try Attribute(key: unencodedKey, value: value) - } - - public func isDataAttribute() -> Bool { - return key.startsWith(Attributes.dataPrefix) && key.count > Attributes.dataPrefix.count - } - - /** - * Collapsible if it's a boolean attribute and value is empty or same as name - * - * @param out Outputsettings - * @return Returns whether collapsible or not - */ - public final func shouldCollapseAttribute(out: OutputSettings) -> Bool { - return ("" == value || value.equalsIgnoreCase(string: key)) - && out.syntax() == OutputSettings.Syntax.html - && isBooleanAttribute() - } - - public func isBooleanAttribute() -> Bool { - return Attribute.booleanAttributes.contains(key) - } - - public func hashCode() -> Int { - var result = key.hashValue - result = 31 * result + value.hashValue - return result - } - - public func clone() -> Attribute { - do { - return try Attribute(key: key, value: value) - } catch Exception.Error( _, let msg) { - print(msg) - } catch { - - } - return try! Attribute(key: "", value: "") - } -} - -extension Attribute: Equatable { - static public func == (lhs: Attribute, rhs: Attribute) -> Bool { - return lhs.value == rhs.value && lhs.key == rhs.key - } - -} diff --git a/Pods/SwiftSoup/Sources/Attributes.swift b/Pods/SwiftSoup/Sources/Attributes.swift deleted file mode 100644 index 46c6098..0000000 --- a/Pods/SwiftSoup/Sources/Attributes.swift +++ /dev/null @@ -1,264 +0,0 @@ -// -// Attributes.swift -// SwifSoup -// -// Created by Nabil Chatbi on 29/09/16. -// Copyright © 2016 Nabil Chatbi.. All rights reserved. -// - -import Foundation - -/** - * The attributes of an Element. - *

    - * Attributes are treated as a map: there can be only one value associated with an attribute key/name. - *

    - *

    - * Attribute name and value comparisons are case sensitive. By default for HTML, attribute names are - * normalized to lower-case on parsing. That means you should use lower-case strings when referring to attributes by - * name. - *

    - * - * - */ -open class Attributes: NSCopying { - - public static var dataPrefix: String = "data-" - - var attributes: OrderedDictionary = OrderedDictionary() - // linked hash map to preserve insertion order. - // null be default as so many elements have no attributes -- saves a good chunk of memory - - public init() {} - - /** - Get an attribute value by key. - @param key the (case-sensitive) attribute key - @return the attribute value if set; or empty string if not set. - @see #hasKey(String) - */ - open func get(key: String) -> String { - let attr: Attribute? = attributes.get(key: key) - return attr != nil ? attr!.getValue() : "" - } - - /** - * Get an attribute's value by case-insensitive key - * @param key the attribute name - * @return the first matching attribute value if set; or empty string if not set. - */ - open func getIgnoreCase(key: String )throws -> String { - try Validate.notEmpty(string: key) - - for attrKey in (attributes.keySet()) { - if attrKey.equalsIgnoreCase(string: key) { - return attributes.get(key: attrKey)!.getValue() - } - } - return "" - } - - /** - Set a new attribute, or replace an existing one by key. - @param key attribute key - @param value attribute value - */ - open func put(_ key: String, _ value: String) throws { - let attr = try Attribute(key: key, value: value) - put(attribute: attr) - } - - /** - Set a new boolean attribute, remove attribute if value is false. - @param key attribute key - @param value attribute value - */ - open func put(_ key: String, _ value: Bool) throws { - if (value) { - try put(attribute: BooleanAttribute(key: key)) - } else { - try remove(key: key) - } - } - - /** - Set a new attribute, or replace an existing one by key. - @param attribute attribute - */ - open func put(attribute: Attribute) { - attributes.put(value: attribute, forKey: attribute.getKey()) - } - - /** - Remove an attribute by key. Case sensitive. - @param key attribute key to remove - */ - open func remove(key: String)throws { - try Validate.notEmpty(string: key) - attributes.remove(key: key) - } - - /** - Remove an attribute by key. Case insensitive. - @param key attribute key to remove - */ - open func removeIgnoreCase(key: String ) throws { - try Validate.notEmpty(string: key) - for attrKey in attributes.keySet() { - if (attrKey.equalsIgnoreCase(string: key)) { - attributes.remove(key: attrKey) - } - } - } - - /** - Tests if these attributes contain an attribute with this key. - @param key case-sensitive key to check for - @return true if key exists, false otherwise - */ - open func hasKey(key: String) -> Bool { - return attributes.containsKey(key: key) - } - - /** - Tests if these attributes contain an attribute with this key. - @param key key to check for - @return true if key exists, false otherwise - */ - open func hasKeyIgnoreCase(key: String) -> Bool { - for attrKey in attributes.keySet() { - if (attrKey.equalsIgnoreCase(string: key)) { - return true - } - } - return false - } - - /** - Get the number of attributes in this set. - @return size - */ - open func size() -> Int { - return attributes.count//TODO: check retyrn right size - } - - /** - Add all the attributes from the incoming set to this set. - @param incoming attributes to add to these attributes. - */ - open func addAll(incoming: Attributes?) { - guard let incoming = incoming else { - return - } - - if (incoming.size() == 0) { - return - } - attributes.putAll(all: incoming.attributes) - } - -// open func iterator() -> IndexingIterator> { -// if (attributes.isEmpty) { -// let args: [Attribute] = [] -// return args.makeIterator() -// } -// return attributes.orderedValues.makeIterator() -// } - - /** - Get the attributes as a List, for iteration. Do not modify the keys of the attributes via this view, as changes - to keys will not be recognised in the containing set. - @return an view of the attributes as a List. - */ - open func asList() -> Array { - var list: Array = Array(/*attributes.size()*/) - for entry in attributes.orderedValues { - list.append(entry) - } - return list - } - - /** - * Retrieves a filtered view of attributes that are HTML5 custom data attributes; that is, attributes with keys - * starting with {@code data-}. - * @return map of custom data attributes. - */ - //Map - open func dataset() -> Dictionary { - var dataset = Dictionary() - for attribute in attributes { - let attr = attribute.1 - if(attr.isDataAttribute()) { - let key = attr.getKey().substring(Attributes.dataPrefix.count) - dataset[key] = attribute.1.getValue() - } - } - return dataset - } - - /** - Get the HTML representation of these attributes. - @return HTML - @throws SerializationException if the HTML representation of the attributes cannot be constructed. - */ - open func html()throws -> String { - let accum = StringBuilder() - try html(accum: accum, out: Document("").outputSettings()) // output settings a bit funky, but this html() seldom used - return accum.toString() - } - - public func html(accum: StringBuilder, out: OutputSettings ) throws { - for attribute in attributes.orderedValues { - accum.append(" ") - attribute.html(accum: accum, out: out) - } - } - - open func toString()throws -> String { - return try html() - } - - /** - * Checks if these attributes are equal to another set of attributes, by comparing the two sets - * @param o attributes to compare with - * @return if both sets of attributes have the same content - */ - open func equals(o: AnyObject?) -> Bool { - if(o == nil) {return false} - if (self === o.self) {return true} - guard let that: Attributes = o as? Attributes else {return false} - return (attributes == that.attributes) - } - - /** - * Calculates the hashcode of these attributes, by iterating all attributes and summing their hashcodes. - * @return calculated hashcode - */ - open func hashCode() -> Int { - return attributes.hashCode() - } - - public func copy(with zone: NSZone? = nil) -> Any { - let clone = Attributes() - clone.attributes = attributes.clone() - return clone - } - - open func clone() -> Attributes { - return self.copy() as! Attributes - } - - fileprivate static func dataKey(key: String) -> String { - return dataPrefix + key - } - -} - -extension Attributes: Sequence { - public func makeIterator() -> AnyIterator { - var list = attributes.orderedValues - return AnyIterator { - return list.count > 0 ? list.removeFirst() : nil - } - } -} diff --git a/Pods/SwiftSoup/Sources/BooleanAttribute.swift b/Pods/SwiftSoup/Sources/BooleanAttribute.swift deleted file mode 100644 index 793490d..0000000 --- a/Pods/SwiftSoup/Sources/BooleanAttribute.swift +++ /dev/null @@ -1,26 +0,0 @@ -// -// BooleanAttribute.swift -// SwifSoup -// -// Created by Nabil Chatbi on 29/09/16. -// Copyright © 2016 Nabil Chatbi.. All rights reserved. -// - -import Foundation - -/** - * A boolean attribute that is written out without any value. - */ -open class BooleanAttribute: Attribute { - /** - * Create a new boolean attribute from unencoded (raw) key. - * @param key attribute key - */ - init(key: String) throws { - try super.init(key: key, value: "") - } - - override public func isBooleanAttribute() -> Bool { - return true - } -} diff --git a/Pods/SwiftSoup/Sources/CharacterExt.swift b/Pods/SwiftSoup/Sources/CharacterExt.swift deleted file mode 100644 index 2cab2b5..0000000 --- a/Pods/SwiftSoup/Sources/CharacterExt.swift +++ /dev/null @@ -1,81 +0,0 @@ -// -// CharacterExt.swift -// SwifSoup -// -// Created by Nabil Chatbi on 08/10/16. -// Copyright © 2016 Nabil Chatbi.. All rights reserved. -// - -import Foundation - -extension Character { - - public static let space: Character = " " - public static let BackslashT: Character = "\t" - public static let BackslashN: Character = "\n" - public static let BackslashF: Character = Character(UnicodeScalar(12)) - public static let BackslashR: Character = "\r" - public static let BackshashRBackslashN: Character = "\r\n" - - //http://www.unicode.org/glossary/#supplementary_code_point - public static let MIN_SUPPLEMENTARY_CODE_POINT: UInt32 = 0x010000 - - /// True for any space character, and the control characters \t, \n, \r, \f, \v. - - var isWhitespace: Bool { - switch self { - case Character.space, Character.BackslashT, Character.BackslashN, Character.BackslashF, Character.BackslashR: return true - case Character.BackshashRBackslashN: return true - default: return false - - } - } - - /// `true` if `self` normalized contains a single code unit that is in the category of Decimal Numbers. - var isDigit: Bool { - - return isMemberOfCharacterSet(CharacterSet.decimalDigits) - - } - - /// Lowercase `self`. - var lowercase: Character { - - let str = String(self).lowercased() - return str[str.startIndex] - - } - - /// Return `true` if `self` normalized contains a single code unit that is a member of the supplied character set. - /// - /// - parameter set: The `NSCharacterSet` used to test for membership. - /// - returns: `true` if `self` normalized contains a single code unit that is a member of the supplied character set. - func isMemberOfCharacterSet(_ set: CharacterSet) -> Bool { - - let normalized = String(self).precomposedStringWithCanonicalMapping - let unicodes = normalized.unicodeScalars - - guard unicodes.count == 1 else { return false } - return set.contains(UnicodeScalar(unicodes.first!.value)!) - - } - - static func convertFromIntegerLiteral(value: IntegerLiteralType) -> Character { - return Character(UnicodeScalar(value)!) - } - - static func isLetter(_ char: Character) -> Bool { - return char.isLetter() - } - func isLetter() -> Bool { - return self.isMemberOfCharacterSet(CharacterSet.letters) - } - - static func isLetterOrDigit(_ char: Character) -> Bool { - return char.isLetterOrDigit() - } - func isLetterOrDigit() -> Bool { - if(self.isLetter()) {return true} - return self.isDigit - } -} diff --git a/Pods/SwiftSoup/Sources/CharacterReader.swift b/Pods/SwiftSoup/Sources/CharacterReader.swift deleted file mode 100644 index ff81a80..0000000 --- a/Pods/SwiftSoup/Sources/CharacterReader.swift +++ /dev/null @@ -1,463 +0,0 @@ -// -// CharacterReader.swift -// SwiftSoup -// -// Created by Nabil Chatbi on 10/10/16. -// Copyright © 2016 Nabil Chatbi.. All rights reserved. -// - -import Foundation - -/** - CharacterReader consumes tokens off a string. To replace the old TokenQueue. - */ -public final class CharacterReader { - private static let empty = "" - public static let EOF: UnicodeScalar = "\u{FFFF}"//65535 - private let input: [UnicodeScalar] - private let length: Int - private var pos: Int = 0 - private var mark: Int = 0 - //private let stringCache: Array // holds reused strings in this doc, to lessen garbage - - public init(_ input: String) { - self.input = Array(input.unicodeScalars) - self.length = self.input.count - //stringCache = Array(repeating:nil, count:512) - } - - public func getPos() -> Int { - return self.pos - } - - public func isEmpty() -> Bool { - return pos >= length - } - - public func current() -> UnicodeScalar { - return (pos >= length) ? CharacterReader.EOF : input[pos] - } - - @discardableResult - public func consume() -> UnicodeScalar { - let val = (pos >= length) ? CharacterReader.EOF : input[pos] - pos += 1 - return val - } - - public func unconsume() { - pos -= 1 - } - - public func advance() { - pos += 1 - } - - public func markPos() { - mark = pos - } - - public func rewindToMark() { - pos = mark - } - - public func consumeAsString() -> String { - let p = pos - pos+=1 - return String(input[p]) - //return String(input, pos+=1, 1) - } - - /** - * Returns the number of characters between the current position and the next instance of the input char - * @param c scan target - * @return offset between current position and next instance of target. -1 if not found. - */ - public func nextIndexOf(_ c: UnicodeScalar) -> Int { - // doesn't handle scanning for surrogates - for i in pos.. Int { - // doesn't handle scanning for surrogates - if(seq.isEmpty) {return -1} - let startChar: UnicodeScalar = seq.unicodeScalar(0) - for var offset in pos.. String { - let offset = nextIndexOf(c) - if (offset != -1) { - let consumed = cacheString(pos, offset) - pos += offset - return consumed - } else { - return consumeToEnd() - } - } - - public func consumeTo(_ seq: String) -> String { - let offset = nextIndexOf(seq) - if (offset != -1) { - let consumed = cacheString(pos, offset) - pos += offset - return consumed - } else { - return consumeToEnd() - } - } - - public func consumeToAny(_ chars: UnicodeScalar...) -> String { - return consumeToAny(chars) - } - public func consumeToAny(_ chars: [UnicodeScalar]) -> String { - let start: Int = pos - let remaining: Int = length - let val = input - OUTER: while (pos < remaining) { - if chars.contains(val[pos]) { - break OUTER - } -// for c in chars { -// if (val[pos] == c){ -// break OUTER -// } -// } - pos += 1 - } - - return pos > start ? cacheString(start, pos-start) : CharacterReader.empty - } - - public func consumeToAnySorted(_ chars: UnicodeScalar...) -> String { - return consumeToAnySorted(chars) - } - public func consumeToAnySorted(_ chars: [UnicodeScalar]) -> String { - let start = pos - let remaining = length - let val = input - - while (pos < remaining) { - - if chars.contains(val[pos]) { - break - } - pos += 1 - } - - return pos > start ? cacheString(start, pos-start) : CharacterReader.empty - } - - public func consumeData() -> String { - // &, <, null - let start = pos - let remaining = length - let val = input - - while (pos < remaining) { - let c: UnicodeScalar = val[pos] - if (c == UnicodeScalar.Ampersand || c == UnicodeScalar.LessThan || c == TokeniserStateVars.nullScalr) { - break - } - pos += 1 - } - - return pos > start ? cacheString(start, pos-start) : CharacterReader.empty - } - - public func consumeTagName() -> String { - // '\t', '\n', '\r', '\f', ' ', '/', '>', nullChar - let start = pos - let remaining = length - let val = input - - while (pos < remaining) { - let c: UnicodeScalar = val[pos] - if (c == UnicodeScalar.BackslashT || c == UnicodeScalar.BackslashN || c == UnicodeScalar.BackslashR || c == UnicodeScalar.BackslashF || c == UnicodeScalar.Space || c == UnicodeScalar.Slash || c == UnicodeScalar.GreaterThan || c == TokeniserStateVars.nullScalr) { - break - } - pos += 1 - } - return pos > start ? cacheString(start, pos-start) : CharacterReader.empty - } - - public func consumeToEnd() -> String { - let data = cacheString(pos, length-pos) - pos = length - return data - } - - public func consumeLetterSequence() -> String { - let start = pos - while (pos < length) { - let c: UnicodeScalar = input[pos] - if ((c >= "A" && c <= "Z") || (c >= "a" && c <= "z") || c.isMemberOfCharacterSet(CharacterSet.letters)) { - pos += 1 - } else { - break - } - } - return cacheString(start, pos - start) - } - - public func consumeLetterThenDigitSequence() -> String { - let start = pos - while (pos < length) { - let c = input[pos] - if ((c >= "A" && c <= "Z") || (c >= "a" && c <= "z") || c.isMemberOfCharacterSet(CharacterSet.letters)) { - pos += 1 - } else { - break - } - } - while (!isEmpty()) { - let c = input[pos] - if (c >= "0" && c <= "9") { - pos += 1 - } else { - break - } - } - - return cacheString(start, pos - start) - } - - public func consumeHexSequence() -> String { - let start = pos - while (pos < length) { - let c = input[pos] - if ((c >= "0" && c <= "9") || (c >= "A" && c <= "F") || (c >= "a" && c <= "f")) { - pos+=1 - } else { - break - } - } - return cacheString(start, pos - start) - } - - public func consumeDigitSequence() -> String { - let start = pos - while (pos < length) { - let c = input[pos] - if (c >= "0" && c <= "9") { - pos+=1 - } else { - break - } - } - return cacheString(start, pos - start) - } - - public func matches(_ c: UnicodeScalar) -> Bool { - return !isEmpty() && input[pos] == c - - } - - public func matches(_ seq: String) -> Bool { - let scanLength = seq.unicodeScalars.count - if (scanLength > length - pos) { - return false - } - - for offset in 0.. Bool { - - let scanLength = seq.unicodeScalars.count - if(scanLength == 0) { - return false - } - if (scanLength > length - pos) { - return false - } - - for offset in 0.. Bool { - if (isEmpty()) { - return false - } - - let c: UnicodeScalar = input[pos] - for seek in seq { - if (seek == c) { - return true - } - } - return false - } - - public func matchesAnySorted(_ seq: [UnicodeScalar]) -> Bool { - return !isEmpty() && seq.contains(input[pos]) - } - - public func matchesLetter() -> Bool { - if (isEmpty()) { - return false - } - let c = input[pos] - return (c >= "A" && c <= "Z") || (c >= "a" && c <= "z") || c.isMemberOfCharacterSet(CharacterSet.letters) - } - - public func matchesDigit() -> Bool { - if (isEmpty()) { - return false - } - let c = input[pos] - return (c >= "0" && c <= "9") - } - - @discardableResult - public func matchConsume(_ seq: String) -> Bool { - if (matches(seq)) { - pos += seq.unicodeScalars.count - return true - } else { - return false - } - } - - @discardableResult - public func matchConsumeIgnoreCase(_ seq: String) -> Bool { - if (matchesIgnoreCase(seq)) { - pos += seq.unicodeScalars.count - return true - } else { - return false - } - } - - public func containsIgnoreCase(_ seq: String ) -> Bool { - // used to check presence of , . only finds consistent case. - let loScan = seq.lowercased(with: Locale(identifier: "en")) - let hiScan = seq.uppercased(with: Locale(identifier: "eng")) - return (nextIndexOf(loScan) > -1) || (nextIndexOf(hiScan) > -1) - } - - public func toString() -> String { - return String(input[pos.. - * Simplistic, and on hash collisions just falls back to creating a new string, vs a full HashMap with Entry list. - * That saves both having to create objects as hash keys, and running through the entry list, at the expense of - * some more duplicates. - */ - private func cacheString(_ start: Int, _ count: Int) -> String { - return String(input[start.. CharacterReader.maxCacheLen) { -// return String(val[start.. Bool { -// if (count == cached.unicodeScalars.count) { -// var count = count -// let one = input -// var i = start -// var j = 0 -// while (count != 0) { -// count -= 1 -// if (one[i] != cached.unicodeScalar(j) ) { -// return false -// } -// j += 1 -// i += 1 -// } -// return true -// } -// return false -// } -} - -extension CharacterReader: CustomDebugStringConvertible { - public var debugDescription: String { - return self.toString() - } -} diff --git a/Pods/SwiftSoup/Sources/Cleaner.swift b/Pods/SwiftSoup/Sources/Cleaner.swift deleted file mode 100644 index 6c16c76..0000000 --- a/Pods/SwiftSoup/Sources/Cleaner.swift +++ /dev/null @@ -1,150 +0,0 @@ -// -// Cleaner.swift -// SwiftSoup -// -// Created by Nabil Chatbi on 15/10/16. -// Copyright © 2016 Nabil Chatbi.. All rights reserved. -// - -import Foundation - -open class Cleaner { - fileprivate let whitelist: Whitelist - - /** - Create a new cleaner, that sanitizes documents using the supplied whitelist. - @param whitelist white-list to clean with - */ - public init(_ whitelist: Whitelist) { - self.whitelist = whitelist - } - - /** - Creates a new, clean document, from the original dirty document, containing only elements allowed by the whitelist. - The original document is not modified. Only elements from the dirt document's body are used. - @param dirtyDocument Untrusted base document to clean. - @return cleaned document. - */ - public func clean(_ dirtyDocument: Document)throws->Document { - //Validate.notNull(dirtyDocument) - let clean: Document = Document.createShell(dirtyDocument.getBaseUri()) - if (dirtyDocument.body() != nil && clean.body() != nil) // frameset documents won't have a body. the clean doc will have empty body. - { - try copySafeNodes(dirtyDocument.body()!, clean.body()!) - } - return clean - } - - /** - Determines if the input document is valid, against the whitelist. It is considered valid if all the tags and attributes - in the input HTML are allowed by the whitelist. -

    - This method can be used as a validator for user input forms. An invalid document will still be cleaned successfully - using the {@link #clean(Document)} document. If using as a validator, it is recommended to still clean the document - to ensure enforced attributes are set correctly, and that the output is tidied. -

    - @param dirtyDocument document to test - @return true if no tags or attributes need to be removed; false if they do - */ - public func isValid(_ dirtyDocument: Document)throws->Bool { - //Validate.notNull(dirtyDocument) - let clean: Document = Document.createShell(dirtyDocument.getBaseUri()) - let numDiscarded: Int = try copySafeNodes(dirtyDocument.body()!, clean.body()!) - return numDiscarded == 0 - } - - @discardableResult - fileprivate func copySafeNodes(_ source: Element, _ dest: Element)throws->Int { - let cleaningVisitor: Cleaner.CleaningVisitor = Cleaner.CleaningVisitor(source, dest, self) - let traversor: NodeTraversor = NodeTraversor(cleaningVisitor) - try traversor.traverse(source) - return cleaningVisitor.numDiscarded - } - - fileprivate func createSafeElement(_ sourceEl: Element)throws->ElementMeta { - let sourceTag: String = sourceEl.tagName() - let destAttrs: Attributes = Attributes() - let dest: Element = try Element(Tag.valueOf(sourceTag), sourceEl.getBaseUri(), destAttrs) - var numDiscarded: Int = 0 - - if let sourceAttrs = sourceEl.getAttributes() { - for sourceAttr: Attribute in sourceAttrs { - if (try whitelist.isSafeAttribute(sourceTag, sourceEl, sourceAttr)) { - destAttrs.put(attribute: sourceAttr) - } else { - numDiscarded+=1 - } - } - } - let enforcedAttrs: Attributes = try whitelist.getEnforcedAttributes(sourceTag) - destAttrs.addAll(incoming: enforcedAttrs) - - return ElementMeta(dest, numDiscarded) - } - -} - -extension Cleaner { - fileprivate final class CleaningVisitor: NodeVisitor { - var numDiscarded: Int = 0 - let root: Element - var destination: Element? // current element to append nodes to - - private var cleaner: Cleaner - - public init(_ root: Element, _ destination: Element, _ cleaner: Cleaner) { - self.root = root - self.destination = destination - self.cleaner = cleaner - } - - public func head(_ source: Node, _ depth: Int)throws { - if let sourceEl = (source as? Element) { - if (cleaner.whitelist.isSafeTag(sourceEl.tagName())) { // safe, clone and copy safe attrs - let meta: Cleaner.ElementMeta = try cleaner.createSafeElement(sourceEl) - let destChild: Element = meta.el - try destination?.appendChild(destChild) - - numDiscarded += meta.numAttribsDiscarded - destination = destChild - } else if (source != root) { // not a safe tag, so don't add. don't count root against discarded. - numDiscarded+=1 - } - } else if let sourceText = (source as? TextNode) { - let destText: TextNode = TextNode(sourceText.getWholeText(), source.getBaseUri()) - try destination?.appendChild(destText) - } else if let sourceData = (source as? DataNode) { - if sourceData.parent() != nil && cleaner.whitelist.isSafeTag(sourceData.parent()!.nodeName()) { - //let sourceData: DataNode = (DataNode) source - let destData: DataNode = DataNode(sourceData.getWholeData(), source.getBaseUri()) - try destination?.appendChild(destData) - } else { - numDiscarded+=1 - } - } else { // else, we don't care about comments, xml proc instructions, etc - numDiscarded+=1 - } - } - - public func tail(_ source: Node, _ depth: Int)throws { - if let x = (source as? Element) { - if cleaner.whitelist.isSafeTag(x.nodeName()) { - // would have descended, so pop destination stack - destination = destination?.parent() - } - } - } - } -} - -extension Cleaner { - fileprivate struct ElementMeta { - let el: Element - let numAttribsDiscarded: Int - - init(_ el: Element, _ numAttribsDiscarded: Int) { - self.el = el - self.numAttribsDiscarded = numAttribsDiscarded - } - } -} diff --git a/Pods/SwiftSoup/Sources/Collector.swift b/Pods/SwiftSoup/Sources/Collector.swift deleted file mode 100644 index 7bb6feb..0000000 --- a/Pods/SwiftSoup/Sources/Collector.swift +++ /dev/null @@ -1,59 +0,0 @@ -// -// Collector.swift -// SwiftSoup -// -// Created by Nabil Chatbi on 22/10/16. -// Copyright © 2016 Nabil Chatbi.. All rights reserved. -// - -import Foundation - -/** - * Collects a list of elements that match the supplied criteria. - * - */ -open class Collector { - - private init() { - } - - /** - Build a list of elements, by visiting root and every descendant of root, and testing it against the evaluator. - @param eval Evaluator to test elements against - @param root root of tree to descend - @return list of matches; empty if none - */ - public static func collect (_ eval: Evaluator, _ root: Element)throws->Elements { - let elements: Elements = Elements() - try NodeTraversor(Accumulator(root, elements, eval)).traverse(root) - return elements - } - -} - -private final class Accumulator: NodeVisitor { - private let root: Element - private let elements: Elements - private let eval: Evaluator - - init(_ root: Element, _ elements: Elements, _ eval: Evaluator) { - self.root = root - self.elements = elements - self.eval = eval - } - - public func head(_ node: Node, _ depth: Int) { - guard let el = node as? Element else { - return - } - do { - if try eval.matches(root, el) { - elements.add(el) - } - } catch {} - } - - public func tail(_ node: Node, _ depth: Int) { - // void - } -} diff --git a/Pods/SwiftSoup/Sources/CombiningEvaluator.swift b/Pods/SwiftSoup/Sources/CombiningEvaluator.swift deleted file mode 100644 index fdeb0ae..0000000 --- a/Pods/SwiftSoup/Sources/CombiningEvaluator.swift +++ /dev/null @@ -1,127 +0,0 @@ -// -// CombiningEvaluator.swift -// SwiftSoup -// -// Created by Nabil Chatbi on 23/10/16. -// Copyright © 2016 Nabil Chatbi.. All rights reserved. -// - -import Foundation - -/** - * Base combining (and, or) evaluator. - */ -public class CombiningEvaluator: Evaluator { - - public private(set) var evaluators: Array - var num: Int = 0 - - public override init() { - evaluators = Array() - super.init() - } - - public init(_ evaluators: Array) { - self.evaluators = evaluators - super.init() - updateNumEvaluators() - } - - public init(_ evaluators: Evaluator...) { - self.evaluators = evaluators - super.init() - updateNumEvaluators() - } - - func rightMostEvaluator() -> Evaluator? { - return num > 0 && evaluators.count > 0 ? evaluators[num - 1] : nil - } - - func replaceRightMostEvaluator(_ replacement: Evaluator) { - evaluators[num - 1] = replacement - } - - func updateNumEvaluators() { - // used so we don't need to bash on size() for every match test - num = evaluators.count - } - - public final class And: CombiningEvaluator { - public override init(_ evaluators: [Evaluator]) { - super.init(evaluators) - } - - public override init(_ evaluators: Evaluator...) { - super.init(evaluators) - } - - public override func matches(_ root: Element, _ node: Element) -> Bool { - for index in 0.. String { - let array: [String] = evaluators.map { String($0.toString()) } - return StringUtil.join(array, sep: " ") - } - } - - public final class Or: CombiningEvaluator { - /** - * Create a new Or evaluator. The initial evaluators are ANDed together and used as the first clause of the OR. - * @param evaluators initial OR clause (these are wrapped into an AND evaluator). - */ - public override init(_ evaluators: [Evaluator]) { - super.init() - if num > 1 { - self.evaluators.append(And(evaluators)) - } else { // 0 or 1 - self.evaluators.append(contentsOf: evaluators) - } - updateNumEvaluators() - } - - override init(_ evaluators: Evaluator...) { - super.init() - if num > 1 { - self.evaluators.append(And(evaluators)) - } else { // 0 or 1 - self.evaluators.append(contentsOf: evaluators) - } - updateNumEvaluators() - } - - override init() { - super.init() - } - - public func add(_ evaluator: Evaluator) { - evaluators.append(evaluator) - updateNumEvaluators() - } - - public override func matches(_ root: Element, _ node: Element) -> Bool { - for index in 0.. String { - return ":or\(evaluators.map {String($0.toString())})" - } - } -} diff --git a/Pods/SwiftSoup/Sources/Comment.swift b/Pods/SwiftSoup/Sources/Comment.swift deleted file mode 100644 index 0892cad..0000000 --- a/Pods/SwiftSoup/Sources/Comment.swift +++ /dev/null @@ -1,66 +0,0 @@ -// -// Comment.swift -// SwiftSoup -// -// Created by Nabil Chatbi on 22/10/16. -// Copyright © 2016 Nabil Chatbi.. All rights reserved. -// - -import Foundation - -/** - A comment node. - */ -public class Comment: Node { - private static let COMMENT_KEY: String = "comment" - - /** - Create a new comment node. - @param data The contents of the comment - @param baseUri base URI - */ - public init(_ data: String, _ baseUri: String) { - super.init(baseUri) - do { - try attributes?.put(Comment.COMMENT_KEY, data) - } catch {} - } - - public override func nodeName() -> String { - return "#comment" - } - - /** - Get the contents of the comment. - @return comment content - */ - public func getData() -> String { - return attributes!.get(key: Comment.COMMENT_KEY) - } - - override func outerHtmlHead(_ accum: StringBuilder, _ depth: Int, _ out: OutputSettings) { - if (out.prettyPrint()) { - indent(accum, depth, out) - } - accum - .append("") - } - - override func outerHtmlTail(_ accum: StringBuilder, _ depth: Int, _ out: OutputSettings) {} - - public override func copy(with zone: NSZone? = nil) -> Any { - let clone = Comment(attributes!.get(key: Comment.COMMENT_KEY), baseUri!) - return copy(clone: clone) - } - - public override func copy(parent: Node?) -> Node { - let clone = Comment(attributes!.get(key: Comment.COMMENT_KEY), baseUri!) - return copy(clone: clone, parent: parent) - } - - public override func copy(clone: Node, parent: Node?) -> Node { - return super.copy(clone: clone, parent: parent) - } -} diff --git a/Pods/SwiftSoup/Sources/Connection.swift b/Pods/SwiftSoup/Sources/Connection.swift deleted file mode 100644 index 7b309a5..0000000 --- a/Pods/SwiftSoup/Sources/Connection.swift +++ /dev/null @@ -1,10 +0,0 @@ -// -// Connection.swift -// SwifSoup -// -// Created by Nabil Chatbi on 29/09/16. -// Copyright © 2016 Nabil Chatbi.. All rights reserved. -// - -import Foundation -//TODO: diff --git a/Pods/SwiftSoup/Sources/DataNode.swift b/Pods/SwiftSoup/Sources/DataNode.swift deleted file mode 100644 index 37f7199..0000000 --- a/Pods/SwiftSoup/Sources/DataNode.swift +++ /dev/null @@ -1,85 +0,0 @@ -// -// DataNode.swift -// SwifSoup -// -// Created by Nabil Chatbi on 29/09/16. -// Copyright © 2016 Nabil Chatbi.. All rights reserved. -// - -import Foundation - -/** - A data node, for contents of style, script tags etc, where contents should not show in text(). - */ -open class DataNode: Node { - private static let DATA_KEY: String = "data" - - /** - Create a new DataNode. - @param data data contents - @param baseUri base URI - */ - public init(_ data: String, _ baseUri: String) { - super.init(baseUri) - do { - try attributes?.put(DataNode.DATA_KEY, data) - } catch {} - - } - - open override func nodeName() -> String { - return "#data" - } - - /** - Get the data contents of this node. Will be unescaped and with original new lines, space etc. - @return data - */ - open func getWholeData() -> String { - return attributes!.get(key: DataNode.DATA_KEY) - } - - /** - * Set the data contents of this node. - * @param data unencoded data - * @return this node, for chaining - */ - @discardableResult - open func setWholeData(_ data: String) -> DataNode { - do { - try attributes?.put(DataNode.DATA_KEY, data) - } catch {} - return self - } - - override func outerHtmlHead(_ accum: StringBuilder, _ depth: Int, _ out: OutputSettings)throws { - accum.append(getWholeData()) // data is not escaped in return from data nodes, so " in script, style is plain - } - - override func outerHtmlTail(_ accum: StringBuilder, _ depth: Int, _ out: OutputSettings) {} - - /** - Create a new DataNode from HTML encoded data. - @param encodedData encoded data - @param baseUri bass URI - @return new DataNode - */ - public static func createFromEncoded(_ encodedData: String, _ baseUri: String)throws->DataNode { - let data = try Entities.unescape(encodedData) - return DataNode(data, baseUri) - } - - public override func copy(with zone: NSZone? = nil) -> Any { - let clone = DataNode(attributes!.get(key: DataNode.DATA_KEY), baseUri!) - return copy(clone: clone) - } - - public override func copy(parent: Node?) -> Node { - let clone = DataNode(attributes!.get(key: DataNode.DATA_KEY), baseUri!) - return copy(clone: clone, parent: parent) - } - - public override func copy(clone: Node, parent: Node?) -> Node { - return super.copy(clone: clone, parent: parent) - } -} diff --git a/Pods/SwiftSoup/Sources/DataUtil.swift b/Pods/SwiftSoup/Sources/DataUtil.swift deleted file mode 100644 index f2d0dee..0000000 --- a/Pods/SwiftSoup/Sources/DataUtil.swift +++ /dev/null @@ -1,24 +0,0 @@ -// -// DataUtil.swift -// SwifSoup -// -// Created by Nabil Chatbi on 02/10/16. -// Copyright © 2016 Nabil Chatbi.. All rights reserved. -// - -import Foundation - -/** - * Internal static utilities for handling data. - * - */ -class DataUtil { - - static let charsetPattern = "(?i)\\bcharset=\\s*(?:\"|')?([^\\s,;\"']*)" - static let defaultCharset = "UTF-8" // used if not found in header or meta charset - static let bufferSize = 0x20000 // ~130K. - static let UNICODE_BOM = 0xFEFF - static let mimeBoundaryChars = "-_1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" - static let boundaryLength = 32 - -} diff --git a/Pods/SwiftSoup/Sources/Document.swift b/Pods/SwiftSoup/Sources/Document.swift deleted file mode 100644 index a47a867..0000000 --- a/Pods/SwiftSoup/Sources/Document.swift +++ /dev/null @@ -1,562 +0,0 @@ -// -// Document.swift -// SwifSoup -// -// Created by Nabil Chatbi on 29/09/16. -// Copyright © 2016 Nabil Chatbi.. All rights reserved. -// - -import Foundation - -open class Document: Element { - public enum QuirksMode { - case noQuirks, quirks, limitedQuirks - } - - private var _outputSettings: OutputSettings = OutputSettings() - private var _quirksMode: Document.QuirksMode = QuirksMode.noQuirks - private let _location: String - private var updateMetaCharset: Bool = false - - /** - Create a new, empty Document. - @param baseUri base URI of document - @see org.jsoup.Jsoup#parse - @see #createShell - */ - public init(_ baseUri: String) { - self._location = baseUri - super.init(try! Tag.valueOf("#root", ParseSettings.htmlDefault), baseUri) - } - - /** - Create a valid, empty shell of a document, suitable for adding more elements to. - @param baseUri baseUri of document - @return document with html, head, and body elements. - */ - static public func createShell(_ baseUri: String) -> Document { - let doc: Document = Document(baseUri) - let html: Element = try! doc.appendElement("html") - try! html.appendElement("head") - try! html.appendElement("body") - - return doc - } - - /** - * Get the URL this Document was parsed from. If the starting URL is a redirect, - * this will return the final URL from which the document was served from. - * @return location - */ - public func location() -> String { - return _location - } - - /** - Accessor to the document's {@code head} element. - @return {@code head} - */ - public func head() -> Element? { - return findFirstElementByTagName("head", self) - } - - /** - Accessor to the document's {@code body} element. - @return {@code body} - */ - public func body() -> Element? { - return findFirstElementByTagName("body", self) - } - - /** - Get the string contents of the document's {@code title} element. - @return Trimmed title, or empty string if none set. - */ - public func title()throws->String { - // title is a preserve whitespace tag (for document output), but normalised here - let titleEl: Element? = try getElementsByTag("title").first() - return titleEl != nil ? try StringUtil.normaliseWhitespace(titleEl!.text()).trim() : "" - } - - /** - Set the document's {@code title} element. Updates the existing element, or adds {@code title} to {@code head} if - not present - @param title string to set as title - */ - public func title(_ title: String)throws { - let titleEl: Element? = try getElementsByTag("title").first() - if (titleEl == nil) { // add to head - try head()?.appendElement("title").text(title) - } else { - try titleEl?.text(title) - } - } - - /** - Create a new Element, with this document's base uri. Does not make the new element a child of this document. - @param tagName element tag name (e.g. {@code a}) - @return new element - */ - public func createElement(_ tagName: String)throws->Element { - return try Element(Tag.valueOf(tagName, ParseSettings.preserveCase), self.getBaseUri()) - } - - /** - Normalise the document. This happens after the parse phase so generally does not need to be called. - Moves any text content that is not in the body element into the body. - @return this document after normalisation - */ - @discardableResult - public func normalise()throws->Document { - var htmlE: Element? = findFirstElementByTagName("html", self) - if (htmlE == nil) { - htmlE = try appendElement("html") - } - let htmlEl: Element = htmlE! - - if (head() == nil) { - try htmlEl.prependElement("head") - } - if (body() == nil) { - try htmlEl.appendElement("body") - } - - // pull text nodes out of root, html, and head els, and push into body. non-text nodes are already taken care - // of. do in inverse order to maintain text order. - try normaliseTextNodes(head()!) - try normaliseTextNodes(htmlEl) - try normaliseTextNodes(self) - - try normaliseStructure("head", htmlEl) - try normaliseStructure("body", htmlEl) - - try ensureMetaCharsetElement() - - return self - } - - // does not recurse. - private func normaliseTextNodes(_ element: Element)throws { - var toMove: Array = Array() - for node: Node in element.childNodes { - if let tn = (node as? TextNode) { - if (!tn.isBlank()) { - toMove.append(tn) - } - } - } - - for i in (0.. or contents into one, delete the remainder, and ensure they are owned by - private func normaliseStructure(_ tag: String, _ htmlEl: Element)throws { - let elements: Elements = try self.getElementsByTag(tag) - let master: Element? = elements.first() // will always be available as created above if not existent - if (elements.size() > 1) { // dupes, move contents to master - var toMove: Array = Array() - for i in 1.. - if (!(master != nil && master!.parent() != nil && master!.parent()!.equals(htmlEl))) { - try htmlEl.appendChild(master!) // includes remove() - } - } - - // fast method to get first by tag name, used for html, head, body finders - private func findFirstElementByTagName(_ tag: String, _ node: Node) -> Element? { - if (node.nodeName()==tag) { - return node as? Element - } else { - for child: Node in node.childNodes { - let found: Element? = findFirstElementByTagName(tag, child) - if (found != nil) { - return found - } - } - } - return nil - } - - open override func outerHtml()throws->String { - return try super.html() // no outer wrapper tag - } - - /** - Set the text of the {@code body} of this document. Any existing nodes within the body will be cleared. - @param text unencoded text - @return this document - */ - @discardableResult - public override func text(_ text: String)throws->Element { - try body()?.text(text) // overridden to not nuke doc structure - return self - } - - open override func nodeName() -> String { - return "#document" - } - - /** - * Sets the charset used in this document. This method is equivalent - * to {@link OutputSettings#charset(java.nio.charset.Charset) - * OutputSettings.charset(Charset)} but in addition it updates the - * charset / encoding element within the document. - * - *

    This enables - * {@link #updateMetaCharsetElement(boolean) meta charset update}.

    - * - *

    If there's no element with charset / encoding information yet it will - * be created. Obsolete charset / encoding definitions are removed!

    - * - *

    Elements used:

    - * - *
      - *
    • Html: <meta charset="CHARSET">
    • - *
    • Xml: <?xml version="1.0" encoding="CHARSET">
    • - *
    - * - * @param charset Charset - * - * @see #updateMetaCharsetElement(boolean) - * @see OutputSettings#charset(java.nio.charset.Charset) - */ - public func charset(_ charset: String.Encoding)throws { - updateMetaCharsetElement(true) - _outputSettings.charset(charset) - try ensureMetaCharsetElement() - } - - /** - * Returns the charset used in this document. This method is equivalent - * to {@link OutputSettings#charset()}. - * - * @return Current Charset - * - * @see OutputSettings#charset() - */ - public func charset()->String.Encoding { - return _outputSettings.charset() - } - - /** - * Sets whether the element with charset information in this document is - * updated on changes through {@link #charset(java.nio.charset.Charset) - * Document.charset(Charset)} or not. - * - *

    If set to false (default) there are no elements - * modified.

    - * - * @param update If true the element updated on charset - * changes, false if not - * - * @see #charset(java.nio.charset.Charset) - */ - public func updateMetaCharsetElement(_ update: Bool) { - self.updateMetaCharset = update - } - - /** - * Returns whether the element with charset information in this document is - * updated on changes through {@link #charset(java.nio.charset.Charset) - * Document.charset(Charset)} or not. - * - * @return Returns true if the element is updated on charset - * changes, false if not - */ - public func updateMetaCharsetElement() -> Bool { - return updateMetaCharset - } - - /** - * Ensures a meta charset (html) or xml declaration (xml) with the current - * encoding used. This only applies with - * {@link #updateMetaCharsetElement(boolean) updateMetaCharset} set to - * true, otherwise this method does nothing. - * - *
      - *
    • An exsiting element gets updated with the current charset
    • - *
    • If there's no element yet it will be inserted
    • - *
    • Obsolete elements are removed
    • - *
    - * - *

    Elements used:

    - * - *
      - *
    • Html: <meta charset="CHARSET">
    • - *
    • Xml: <?xml version="1.0" encoding="CHARSET">
    • - *
    - */ - private func ensureMetaCharsetElement()throws { - if (updateMetaCharset) { - let syntax: OutputSettings.Syntax = outputSettings().syntax() - - if (syntax == OutputSettings.Syntax.html) { - let metaCharset: Element? = try select("meta[charset]").first() - - if (metaCharset != nil) { - try metaCharset?.attr("charset", charset().displayName()) - } else { - let head: Element? = self.head() - - if (head != nil) { - try head?.appendElement("meta").attr("charset", charset().displayName()) - } - } - - // Remove obsolete elements - let s = try select("meta[name=charset]") - try s.remove() - - } else if (syntax == OutputSettings.Syntax.xml) { - let node: Node = getChildNodes()[0] - - if let decl = (node as? XmlDeclaration) { - - if (decl.name()=="xml") { - try decl.attr("encoding", charset().displayName()) - - _ = try decl.attr("version") - try decl.attr("version", "1.0") - } else { - try Validate.notNull(obj: baseUri) - let decl = XmlDeclaration("xml", baseUri!, false) - try decl.attr("version", "1.0") - try decl.attr("encoding", charset().displayName()) - - try prependChild(decl) - } - } else { - try Validate.notNull(obj: baseUri) - let decl = XmlDeclaration("xml", baseUri!, false) - try decl.attr("version", "1.0") - try decl.attr("encoding", charset().displayName()) - - try prependChild(decl) - } - } - } - } - - /** - * Get the document's current output settings. - * @return the document's current output settings. - */ - public func outputSettings() -> OutputSettings { - return _outputSettings - } - - /** - * Set the document's output settings. - * @param outputSettings new output settings. - * @return this document, for chaining. - */ - @discardableResult - public func outputSettings(_ outputSettings: OutputSettings) -> Document { - self._outputSettings = outputSettings - return self - } - - public func quirksMode()->Document.QuirksMode { - return _quirksMode - } - - @discardableResult - public func quirksMode(_ quirksMode: Document.QuirksMode) -> Document { - self._quirksMode = quirksMode - return self - } - - public override func copy(with zone: NSZone? = nil) -> Any { - let clone = Document(_location) - return copy(clone: clone) - } - - public override func copy(parent: Node?) -> Node { - let clone = Document(_location) - return copy(clone: clone, parent: parent) - } - - public override func copy(clone: Node, parent: Node?) -> Node { - let clone = clone as! Document - clone._outputSettings = _outputSettings.copy() as! OutputSettings - clone._quirksMode = _quirksMode - clone.updateMetaCharset = updateMetaCharset - return super.copy(clone: clone, parent: parent) - } - -} - -public class OutputSettings: NSCopying { - /** - * The output serialization syntax. - */ - public enum Syntax {case html, xml} - - private var _escapeMode: Entities.EscapeMode = Entities.EscapeMode.base - private var _encoder: String.Encoding = String.Encoding.utf8 // Charset.forName("UTF-8") - private var _prettyPrint: Bool = true - private var _outline: Bool = false - private var _indentAmount: UInt = 1 - private var _syntax = Syntax.html - - public init() {} - - /** - * Get the document's current HTML escape mode: base, which provides a limited set of named HTML - * entities and escapes other characters as numbered entities for maximum compatibility; or extended, - * which uses the complete set of HTML named entities. - *

    - * The default escape mode is base. - * @return the document's current escape mode - */ - public func escapeMode() -> Entities.EscapeMode { - return _escapeMode - } - - /** - * Set the document's escape mode, which determines how characters are escaped when the output character set - * does not support a given character:- using either a named or a numbered escape. - * @param escapeMode the new escape mode to use - * @return the document's output settings, for chaining - */ - @discardableResult - public func escapeMode(_ escapeMode: Entities.EscapeMode) -> OutputSettings { - self._escapeMode = escapeMode - return self - } - - /** - * Get the document's current output charset, which is used to control which characters are escaped when - * generating HTML (via the html() methods), and which are kept intact. - *

    - * Where possible (when parsing from a URL or File), the document's output charset is automatically set to the - * input charset. Otherwise, it defaults to UTF-8. - * @return the document's current charset. - */ - public func encoder() -> String.Encoding { - return _encoder - } - public func charset() -> String.Encoding { - return _encoder - } - - /** - * Update the document's output charset. - * @param charset the new charset to use. - * @return the document's output settings, for chaining - */ - @discardableResult - public func encoder(_ encoder: String.Encoding) -> OutputSettings { - self._encoder = encoder - return self - } - - @discardableResult - public func charset(_ e: String.Encoding) -> OutputSettings { - return encoder(e) - } - - /** - * Get the document's current output syntax. - * @return current syntax - */ - public func syntax() -> Syntax { - return _syntax - } - - /** - * Set the document's output syntax. Either {@code html}, with empty tags and boolean attributes (etc), or - * {@code xml}, with self-closing tags. - * @param syntax serialization syntax - * @return the document's output settings, for chaining - */ - @discardableResult - public func syntax(syntax: Syntax) -> OutputSettings { - _syntax = syntax - return self - } - - /** - * Get if pretty printing is enabled. Default is true. If disabled, the HTML output methods will not re-format - * the output, and the output will generally look like the input. - * @return if pretty printing is enabled. - */ - public func prettyPrint() -> Bool { - return _prettyPrint - } - - /** - * Enable or disable pretty printing. - * @param pretty new pretty print setting - * @return this, for chaining - */ - @discardableResult - public func prettyPrint(pretty: Bool) -> OutputSettings { - _prettyPrint = pretty - return self - } - - /** - * Get if outline mode is enabled. Default is false. If enabled, the HTML output methods will consider - * all tags as block. - * @return if outline mode is enabled. - */ - public func outline() -> Bool { - return _outline - } - - /** - * Enable or disable HTML outline mode. - * @param outlineMode new outline setting - * @return this, for chaining - */ - @discardableResult - public func outline(outlineMode: Bool) -> OutputSettings { - _outline = outlineMode - return self - } - - /** - * Get the current tag indent amount, used when pretty printing. - * @return the current indent amount - */ - public func indentAmount() -> UInt { - return _indentAmount - } - - /** - * Set the indent amount for pretty printing - * @param indentAmount number of spaces to use for indenting each level. Must be {@literal >=} 0. - * @return this, for chaining - */ - @discardableResult - public func indentAmount(indentAmount: UInt) -> OutputSettings { - _indentAmount = indentAmount - return self - } - - public func copy(with zone: NSZone? = nil) -> Any { - let clone: OutputSettings = OutputSettings() - clone.charset(_encoder) // new charset and charset encoder - clone._escapeMode = _escapeMode//Entities.EscapeMode.valueOf(escapeMode.name()) - // indentAmount, prettyPrint are primitives so object.clone() will handle - return clone - } - -} diff --git a/Pods/SwiftSoup/Sources/DocumentType.swift b/Pods/SwiftSoup/Sources/DocumentType.swift deleted file mode 100644 index 95f9b10..0000000 --- a/Pods/SwiftSoup/Sources/DocumentType.swift +++ /dev/null @@ -1,129 +0,0 @@ -// -// DocumentType.swift -// SwifSoup -// -// Created by Nabil Chatbi on 29/09/16. -// Copyright © 2016 Nabil Chatbi.. All rights reserved. -// - -import Foundation - -/** - * A {@code } node. - */ -public class DocumentType: Node { - static let PUBLIC_KEY: String = "PUBLIC" - static let SYSTEM_KEY: String = "SYSTEM" - private static let NAME: String = "name" - private static let PUB_SYS_KEY: String = "pubSysKey"; // PUBLIC or SYSTEM - private static let PUBLIC_ID: String = "publicId" - private static let SYSTEM_ID: String = "systemId" - // todo: quirk mode from publicId and systemId - - /** - * Create a new doctype element. - * @param name the doctype's name - * @param publicId the doctype's public ID - * @param systemId the doctype's system ID - * @param baseUri the doctype's base URI - */ - public init(_ name: String, _ publicId: String, _ systemId: String, _ baseUri: String) { - super.init(baseUri) - do { - try attr(DocumentType.NAME, name) - try attr(DocumentType.PUBLIC_ID, publicId) - if (has(DocumentType.PUBLIC_ID)) { - try attr(DocumentType.PUB_SYS_KEY, DocumentType.PUBLIC_KEY) - } - try attr(DocumentType.SYSTEM_ID, systemId) - } catch {} - } - - /** - * Create a new doctype element. - * @param name the doctype's name - * @param publicId the doctype's public ID - * @param systemId the doctype's system ID - * @param baseUri the doctype's base URI - */ - public init(_ name: String, _ pubSysKey: String?, _ publicId: String, _ systemId: String, _ baseUri: String) { - super.init(baseUri) - do { - try attr(DocumentType.NAME, name) - if(pubSysKey != nil) { - try attr(DocumentType.PUB_SYS_KEY, pubSysKey!) - } - try attr(DocumentType.PUBLIC_ID, publicId) - try attr(DocumentType.SYSTEM_ID, systemId) - } catch {} - } - - public override func nodeName() -> String { - return "#doctype" - } - - override func outerHtmlHead(_ accum: StringBuilder, _ depth: Int, _ out: OutputSettings) { - if (out.syntax() == OutputSettings.Syntax.html && !has(DocumentType.PUBLIC_ID) && !has(DocumentType.SYSTEM_ID)) { - // looks like a html5 doctype, go lowercase for aesthetics - accum.append("") - } - - override func outerHtmlTail(_ accum: StringBuilder, _ depth: Int, _ out: OutputSettings) { - } - - private func has(_ attribute: String) -> Bool { - do { - return !StringUtil.isBlank(try attr(attribute)) - } catch {return false} - } - - public override func copy(with zone: NSZone? = nil) -> Any { - let clone = DocumentType(attributes!.get(key: DocumentType.NAME), - attributes!.get(key: DocumentType.PUBLIC_ID), - attributes!.get(key: DocumentType.SYSTEM_ID), - baseUri!) - return copy(clone: clone) - } - - public override func copy(parent: Node?) -> Node { - let clone = DocumentType(attributes!.get(key: DocumentType.NAME), - attributes!.get(key: DocumentType.PUBLIC_ID), - attributes!.get(key: DocumentType.SYSTEM_ID), - baseUri!) - return copy(clone: clone, parent: parent) - } - - public override func copy(clone: Node, parent: Node?) -> Node { - return super.copy(clone: clone, parent: parent) - } - -} diff --git a/Pods/SwiftSoup/Sources/Element.swift b/Pods/SwiftSoup/Sources/Element.swift deleted file mode 100644 index 4ec5b23..0000000 --- a/Pods/SwiftSoup/Sources/Element.swift +++ /dev/null @@ -1,1295 +0,0 @@ -// -// Element.swift -// SwifSoup -// -// Created by Nabil Chatbi on 29/09/16. -// Copyright © 2016 Nabil Chatbi.. All rights reserved. -// - -import Foundation - -open class Element: Node { - var _tag: Tag - - private static let classString = "class" - private static let emptyString = "" - private static let idString = "id" - private static let rootString = "#root" - - //private static let classSplit : Pattern = Pattern("\\s+") - private static let classSplit = "\\s+" - - /** - * Create a new, standalone Element. (Standalone in that is has no parent.) - * - * @param tag tag of this element - * @param baseUri the base URI - * @param attributes initial attributes - * @see #appendChild(Node) - * @see #appendElement(String) - */ - public init(_ tag: Tag, _ baseUri: String, _ attributes: Attributes) { - self._tag = tag - super.init(baseUri, attributes) - } - /** - * Create a new Element from a tag and a base URI. - * - * @param tag element tag - * @param baseUri the base URI of this element. It is acceptable for the base URI to be an empty - * string, but not null. - * @see Tag#valueOf(String, ParseSettings) - */ - public init(_ tag: Tag, _ baseUri: String) { - self._tag = tag - super.init(baseUri, Attributes()) - } - - open override func nodeName() -> String { - return _tag.getName() - } - /** - * Get the name of the tag for this element. E.g. {@code div} - * - * @return the tag name - */ - open func tagName() -> String { - return _tag.getName() - } - open func tagNameNormal() -> String { - return _tag.getNameNormal() - } - - /** - * Change the tag of this element. For example, convert a {@code } to a {@code

    } with - * {@code el.tagName("div")}. - * - * @param tagName new tag name for this element - * @return this element, for chaining - */ - @discardableResult - public func tagName(_ tagName: String)throws->Element { - try Validate.notEmpty(string: tagName, msg: "Tag name must not be empty.") - _tag = try Tag.valueOf(tagName, ParseSettings.preserveCase) // preserve the requested tag case - return self - } - - /** - * Get the Tag for this element. - * - * @return the tag object - */ - open func tag() -> Tag { - return _tag - } - - /** - * Test if this element is a block-level element. (E.g. {@code
    == true} or an inline element - * {@code

    == false}). - * - * @return true if block, false if not (and thus inline) - */ - open func isBlock() -> Bool { - return _tag.isBlock() - } - - /** - * Get the {@code id} attribute of this element. - * - * @return The id attribute, if present, or an empty string if not. - */ - open func id() -> String { - guard let attributes = attributes else {return Element.emptyString} - do { - return try attributes.getIgnoreCase(key: Element.idString) - } catch {} - return Element.emptyString - } - - /** - * Set an attribute value on this element. If this element already has an attribute with the - * key, its value is updated; otherwise, a new attribute is added. - * - * @return this element - */ - @discardableResult - open override func attr(_ attributeKey: String, _ attributeValue: String)throws->Element { - try super.attr(attributeKey, attributeValue) - return self - } - - /** - * Set a boolean attribute value on this element. Setting to true sets the attribute value to "" and - * marks the attribute as boolean so no value is written out. Setting to false removes the attribute - * with the same key if it exists. - * - * @param attributeKey the attribute key - * @param attributeValue the attribute value - * - * @return this element - */ - @discardableResult - open func attr(_ attributeKey: String, _ attributeValue: Bool)throws->Element { - try attributes?.put(attributeKey, attributeValue) - return self - } - - /** - * Get this element's HTML5 custom data attributes. Each attribute in the element that has a key - * starting with "data-" is included the dataset. - *

    - * E.g., the element {@code

    ...} has the dataset - * {@code package=jsoup, language=java}. - *

    - * This map is a filtered view of the element's attribute map. Changes to one map (add, remove, update) are reflected - * in the other map. - *

    - * You can find elements that have data attributes using the {@code [^data-]} attribute key prefix selector. - * @return a map of {@code key=value} custom data attributes. - */ - open func dataset()->Dictionary { - return attributes!.dataset() - } - - open override func parent() -> Element? { - return parentNode as? Element - } - - /** - * Get this element's parent and ancestors, up to the document root. - * @return this element's stack of parents, closest first. - */ - open func parents() -> Elements { - let parents: Elements = Elements() - Element.accumulateParents(self, parents) - return parents - } - - private static func accumulateParents(_ el: Element, _ parents: Elements) { - let parent: Element? = el.parent() - if (parent != nil && !(parent!.tagName() == Element.rootString)) { - parents.add(parent!) - accumulateParents(parent!, parents) - } - } - - /** - * Get a child element of this element, by its 0-based index number. - *

    - * Note that an element can have both mixed Nodes and Elements as children. This method inspects - * a filtered list of children that are elements, and the index is based on that filtered list. - *

    - * - * @param index the index number of the element to retrieve - * @return the child element, if it exists, otherwise throws an {@code IndexOutOfBoundsException} - * @see #childNode(int) - */ - open func child(_ index: Int) -> Element { - return children().get(index) - } - - /** - * Get this element's child elements. - *

    - * This is effectively a filter on {@link #childNodes()} to get Element nodes. - *

    - * @return child elements. If this element has no children, returns an - * empty list. - * @see #childNodes() - */ - open func children() -> Elements { - // create on the fly rather than maintaining two lists. if gets slow, memoize, and mark dirty on change - var elements = Array() - for node in childNodes { - if let n = node as? Element { - elements.append(n) - } - } - return Elements(elements) - } - - /** - * Get this element's child text nodes. The list is unmodifiable but the text nodes may be manipulated. - *

    - * This is effectively a filter on {@link #childNodes()} to get Text nodes. - * @return child text nodes. If this element has no text nodes, returns an - * empty list. - *

    - * For example, with the input HTML: {@code

    One Two Three
    Four

    } with the {@code p} element selected: - *
      - *
    • {@code p.text()} = {@code "One Two Three Four"}
    • - *
    • {@code p.ownText()} = {@code "One Three Four"}
    • - *
    • {@code p.children()} = {@code Elements[,
      ]}
    • - *
    • {@code p.childNodes()} = {@code List["One ", , " Three ",
      , " Four"]}
    • - *
    • {@code p.textNodes()} = {@code List["One ", " Three ", " Four"]}
    • - *
    - */ - open func textNodes()->Array { - var textNodes = Array() - for node in childNodes { - if let n = node as? TextNode { - textNodes.append(n) - } - } - return textNodes - } - - /** - * Get this element's child data nodes. The list is unmodifiable but the data nodes may be manipulated. - *

    - * This is effectively a filter on {@link #childNodes()} to get Data nodes. - *

    - * @return child data nodes. If this element has no data nodes, returns an - * empty list. - * @see #data() - */ - open func dataNodes()->Array { - var dataNodes = Array() - for node in childNodes { - if let n = node as? DataNode { - dataNodes.append(n) - } - } - return dataNodes - } - - /** - * Find elements that match the {@link Selector} CSS query, with this element as the starting context. Matched elements - * may include this element, or any of its children. - *

    - * This method is generally more powerful to use than the DOM-type {@code getElementBy*} methods, because - * multiple filters can be combined, e.g.: - *

    - *
      - *
    • {@code el.select("a[href]")} - finds links ({@code a} tags with {@code href} attributes) - *
    • {@code el.select("a[href*=example.com]")} - finds links pointing to example.com (loosely) - *
    - *

    - * See the query syntax documentation in {@link org.jsoup.select.Selector}. - *

    - * - * @param cssQuery a {@link Selector} CSS-like query - * @return elements that match the query (empty if none match) - * @see org.jsoup.select.Selector - * @throws Selector.SelectorParseException (unchecked) on an invalid CSS query. - */ - public func select(_ cssQuery: String)throws->Elements { - return try Selector.select(cssQuery, self) - } - - /** - * Check if this element matches the given {@link Selector} CSS query. - * @param cssQuery a {@link Selector} CSS query - * @return if this element matches the query - */ - public func iS(_ cssQuery: String)throws->Bool { - return try iS(QueryParser.parse(cssQuery)) - } - - /** - * Check if this element matches the given {@link Selector} CSS query. - * @param cssQuery a {@link Selector} CSS query - * @return if this element matches the query - */ - public func iS(_ evaluator: Evaluator)throws->Bool { - guard let od = self.ownerDocument() else { - return false - } - return try evaluator.matches(od, self) - } - - /** - * Add a node child node to this element. - * - * @param child node to add. - * @return this element, so that you can add more child nodes or elements. - */ - @discardableResult - public func appendChild(_ child: Node)throws->Element { - // was - Node#addChildren(child). short-circuits an array create and a loop. - try reparentChild(child) - ensureChildNodes() - childNodes.append(child) - child.setSiblingIndex(childNodes.count - 1) - return self - } - - /** - * Add a node to the start of this element's children. - * - * @param child node to add. - * @return this element, so that you can add more child nodes or elements. - */ - @discardableResult - public func prependChild(_ child: Node)throws->Element { - try addChildren(0, child) - return self - } - - /** - * Inserts the given child nodes into this element at the specified index. Current nodes will be shifted to the - * right. The inserted nodes will be moved from their current parent. To prevent moving, copy the nodes first. - * - * @param index 0-based index to insert children at. Specify {@code 0} to insert at the start, {@code -1} at the - * end - * @param children child nodes to insert - * @return this element, for chaining. - */ - @discardableResult - public func insertChildren(_ index: Int, _ children: Array)throws->Element { - //Validate.notNull(children, "Children collection to be inserted must not be null.") - var index = index - let currentSize: Int = childNodeSize() - if (index < 0) { index += currentSize + 1} // roll around - try Validate.isTrue(val: index >= 0 && index <= currentSize, msg: "Insert position out of bounds.") - - try addChildren(index, children) - return self - } - - /** - * Create a new element by tag name, and add it as the last child. - * - * @param tagName the name of the tag (e.g. {@code div}). - * @return the new element, to allow you to add content to it, e.g.: - * {@code parent.appendElement("h1").attr("id", "header").text("Welcome")} - */ - @discardableResult - public func appendElement(_ tagName: String)throws->Element { - let child: Element = Element(try Tag.valueOf(tagName), getBaseUri()) - try appendChild(child) - return child - } - - /** - * Create a new element by tag name, and add it as the first child. - * - * @param tagName the name of the tag (e.g. {@code div}). - * @return the new element, to allow you to add content to it, e.g.: - * {@code parent.prependElement("h1").attr("id", "header").text("Welcome")} - */ - @discardableResult - public func prependElement(_ tagName: String)throws->Element { - let child: Element = Element(try Tag.valueOf(tagName), getBaseUri()) - try prependChild(child) - return child - } - - /** - * Create and append a new TextNode to this element. - * - * @param text the unencoded text to add - * @return this element - */ - @discardableResult - public func appendText(_ text: String)throws->Element { - let node: TextNode = TextNode(text, getBaseUri()) - try appendChild(node) - return self - } - - /** - * Create and prepend a new TextNode to this element. - * - * @param text the unencoded text to add - * @return this element - */ - @discardableResult - public func prependText(_ text: String)throws->Element { - let node: TextNode = TextNode(text, getBaseUri()) - try prependChild(node) - return self - } - - /** - * Add inner HTML to this element. The supplied HTML will be parsed, and each node appended to the end of the children. - * @param html HTML to add inside this element, after the existing HTML - * @return this element - * @see #html(String) - */ - @discardableResult - public func append(_ html: String)throws->Element { - let nodes: Array = try Parser.parseFragment(html, self, getBaseUri()) - try addChildren(nodes) - return self - } - - /** - * Add inner HTML into this element. The supplied HTML will be parsed, and each node prepended to the start of the element's children. - * @param html HTML to add inside this element, before the existing HTML - * @return this element - * @see #html(String) - */ - @discardableResult - public func prepend(_ html: String)throws->Element { - let nodes: Array = try Parser.parseFragment(html, self, getBaseUri()) - try addChildren(0, nodes) - return self - } - - /** - * Insert the specified HTML into the DOM before this element (as a preceding sibling). - * - * @param html HTML to add before this element - * @return this element, for chaining - * @see #after(String) - */ - @discardableResult - open override func before(_ html: String)throws->Element { - return try super.before(html) as! Element - } - - /** - * Insert the specified node into the DOM before this node (as a preceding sibling). - * @param node to add before this element - * @return this Element, for chaining - * @see #after(Node) - */ - @discardableResult - open override func before(_ node: Node)throws->Element { - return try super.before(node) as! Element - } - - /** - * Insert the specified HTML into the DOM after this element (as a following sibling). - * - * @param html HTML to add after this element - * @return this element, for chaining - * @see #before(String) - */ - @discardableResult - open override func after(_ html: String)throws->Element { - return try super.after(html) as! Element - } - - /** - * Insert the specified node into the DOM after this node (as a following sibling). - * @param node to add after this element - * @return this element, for chaining - * @see #before(Node) - */ - open override func after(_ node: Node)throws->Element { - return try super.after(node) as! Element - } - - /** - * Remove all of the element's child nodes. Any attributes are left as-is. - * @return this element - */ - @discardableResult - public func empty() -> Element { - childNodes.removeAll() - return self - } - - /** - * Wrap the supplied HTML around this element. - * - * @param html HTML to wrap around this element, e.g. {@code
    }. Can be arbitrarily deep. - * @return this element, for chaining. - */ - @discardableResult - open override func wrap(_ html: String)throws->Element { - return try super.wrap(html) as! Element - } - - /** - * Get a CSS selector that will uniquely select this element. - *

    - * If the element has an ID, returns #id; - * otherwise returns the parent (if any) CSS selector, followed by {@literal '>'}, - * followed by a unique selector for the element (tag.class.class:nth-child(n)). - *

    - * - * @return the CSS Path that can be used to retrieve the element in a selector. - */ - public func cssSelector()throws->String { - let elementId = id() - if (elementId.count > 0) { - return "#" + elementId - } - - // Translate HTML namespace ns:tag to CSS namespace syntax ns|tag - let tagName: String = self.tagName().replacingOccurrences(of: ":", with: "|") - var selector: String = tagName - let cl = try classNames() - let classes: String = cl.joined(separator: ".") - if (classes.count > 0) { - selector.append(".") - selector.append(classes) - } - - if (parent() == nil || ((parent() as? Document) != nil)) // don't add Document to selector, as will always have a html node - { - return selector - } - - selector.insert(contentsOf: " > ", at: selector.startIndex) - if (try parent()!.select(selector).array().count > 1) { - selector.append(":nth-child(\(try elementSiblingIndex() + 1))") - } - - return try parent()!.cssSelector() + (selector) - } - - /** - * Get sibling elements. If the element has no sibling elements, returns an empty list. An element is not a sibling - * of itself, so will not be included in the returned list. - * @return sibling elements - */ - public func siblingElements() -> Elements { - if (parentNode == nil) {return Elements()} - - let elements: Array? = parent()?.children().array() - let siblings: Elements = Elements() - if let elements = elements { - for el: Element in elements { - if (el != self) { - siblings.add(el) - } - } - } - return siblings - } - - /** - * Gets the next sibling element of this element. E.g., if a {@code div} contains two {@code p}s, - * the {@code nextElementSibling} of the first {@code p} is the second {@code p}. - *

    - * This is similar to {@link #nextSibling()}, but specifically finds only Elements - *

    - * @return the next element, or null if there is no next element - * @see #previousElementSibling() - */ - public func nextElementSibling()throws->Element? { - if (parentNode == nil) {return nil} - let siblings: Array? = parent()?.children().array() - let index: Int? = try Element.indexInList(self, siblings) - try Validate.notNull(obj: index) - if let siblings = siblings { - if (siblings.count > index!+1) { - return siblings[index!+1] - } else { - return nil} - } - return nil - } - - /** - * Gets the previous element sibling of this element. - * @return the previous element, or null if there is no previous element - * @see #nextElementSibling() - */ - public func previousElementSibling()throws->Element? { - if (parentNode == nil) {return nil} - let siblings: Array? = parent()?.children().array() - let index: Int? = try Element.indexInList(self, siblings) - try Validate.notNull(obj: index) - if (index! > 0) { - return siblings?[index!-1] - } else { - return nil - } - } - - /** - * Gets the first element sibling of this element. - * @return the first sibling that is an element (aka the parent's first element child) - */ - public func firstElementSibling() -> Element? { - // todo: should firstSibling() exclude this? - let siblings: Array? = parent()?.children().array() - return (siblings != nil && siblings!.count > 1) ? siblings![0] : nil - } - - /* - * Get the list index of this element in its element sibling list. I.e. if this is the first element - * sibling, returns 0. - * @return position in element sibling list - */ - public func elementSiblingIndex()throws->Int { - if (parent() == nil) {return 0} - let x = try Element.indexInList(self, parent()?.children().array()) - return x == nil ? 0 : x! - } - - /** - * Gets the last element sibling of this element - * @return the last sibling that is an element (aka the parent's last element child) - */ - public func lastElementSibling() -> Element? { - let siblings: Array? = parent()?.children().array() - return (siblings != nil && siblings!.count > 1) ? siblings![siblings!.count - 1] : nil - } - - private static func indexInList(_ search: Element, _ elements: Array?)throws->Int? { - try Validate.notNull(obj: elements) - if let elements = elements { - for i in 0..Elements { - try Validate.notEmpty(string: tagName) - let tagName = tagName.lowercased().trim() - - return try Collector.collect(Evaluator.Tag(tagName), self) - } - - /** - * Find an element by ID, including or under this element. - *

    - * Note that this finds the first matching ID, starting with this element. If you search down from a different - * starting point, it is possible to find a different element by ID. For unique element by ID within a Document, - * use {@link Document#getElementById(String)} - * @param id The ID to search for. - * @return The first matching element by ID, starting with this element, or null if none found. - */ - public func getElementById(_ id: String)throws->Element? { - try Validate.notEmpty(string: id) - - let elements: Elements = try Collector.collect(Evaluator.Id(id), self) - if (elements.array().count > 0) { - return elements.get(0) - } else { - return nil - } - } - - /** - * Find elements that have this class, including or under this element. Case insensitive. - *

    - * Elements can have multiple classes (e.g. {@code

    }. This method - * checks each class, so you can find the above with {@code el.getElementsByClass("header")}. - * - * @param className the name of the class to search for. - * @return elements with the supplied class name, empty if none - * @see #hasClass(String) - * @see #classNames() - */ - public func getElementsByClass(_ className: String)throws->Elements { - try Validate.notEmpty(string: className) - - return try Collector.collect(Evaluator.Class(className), self) - } - - /** - * Find elements that have a named attribute set. Case insensitive. - * - * @param key name of the attribute, e.g. {@code href} - * @return elements that have this attribute, empty if none - */ - public func getElementsByAttribute(_ key: String)throws->Elements { - try Validate.notEmpty(string: key) - let key = key.trim() - - return try Collector.collect(Evaluator.Attribute(key), self) - } - - /** - * Find elements that have an attribute name starting with the supplied prefix. Use {@code data-} to find elements - * that have HTML5 datasets. - * @param keyPrefix name prefix of the attribute e.g. {@code data-} - * @return elements that have attribute names that start with with the prefix, empty if none. - */ - public func getElementsByAttributeStarting(_ keyPrefix: String)throws->Elements { - try Validate.notEmpty(string: keyPrefix) - let keyPrefix = keyPrefix.trim() - - return try Collector.collect(Evaluator.AttributeStarting(keyPrefix), self) - } - - /** - * Find elements that have an attribute with the specific value. Case insensitive. - * - * @param key name of the attribute - * @param value value of the attribute - * @return elements that have this attribute with this value, empty if none - */ - public func getElementsByAttributeValue(_ key: String, _ value: String)throws->Elements { - return try Collector.collect(Evaluator.AttributeWithValue(key, value), self) - } - - /** - * Find elements that either do not have this attribute, or have it with a different value. Case insensitive. - * - * @param key name of the attribute - * @param value value of the attribute - * @return elements that do not have a matching attribute - */ - public func getElementsByAttributeValueNot(_ key: String, _ value: String)throws->Elements { - return try Collector.collect(Evaluator.AttributeWithValueNot(key, value), self) - } - - /** - * Find elements that have attributes that start with the value prefix. Case insensitive. - * - * @param key name of the attribute - * @param valuePrefix start of attribute value - * @return elements that have attributes that start with the value prefix - */ - public func getElementsByAttributeValueStarting(_ key: String, _ valuePrefix: String)throws->Elements { - return try Collector.collect(Evaluator.AttributeWithValueStarting(key, valuePrefix), self) - } - - /** - * Find elements that have attributes that end with the value suffix. Case insensitive. - * - * @param key name of the attribute - * @param valueSuffix end of the attribute value - * @return elements that have attributes that end with the value suffix - */ - public func getElementsByAttributeValueEnding(_ key: String, _ valueSuffix: String)throws->Elements { - return try Collector.collect(Evaluator.AttributeWithValueEnding(key, valueSuffix), self) - } - - /** - * Find elements that have attributes whose value contains the match string. Case insensitive. - * - * @param key name of the attribute - * @param match substring of value to search for - * @return elements that have attributes containing this text - */ - public func getElementsByAttributeValueContaining(_ key: String, _ match: String)throws->Elements { - return try Collector.collect(Evaluator.AttributeWithValueContaining(key, match), self) - } - - /** - * Find elements that have attributes whose values match the supplied regular expression. - * @param key name of the attribute - * @param pattern compiled regular expression to match against attribute values - * @return elements that have attributes matching this regular expression - */ - public func getElementsByAttributeValueMatching(_ key: String, _ pattern: Pattern)throws->Elements { - return try Collector.collect(Evaluator.AttributeWithValueMatching(key, pattern), self) - - } - - /** - * Find elements that have attributes whose values match the supplied regular expression. - * @param key name of the attribute - * @param regex regular expression to match against attribute values. You can use embedded flags (such as (?i) and (?m) to control regex options. - * @return elements that have attributes matching this regular expression - */ - public func getElementsByAttributeValueMatching(_ key: String, _ regex: String)throws->Elements { - var pattern: Pattern - do { - pattern = Pattern.compile(regex) - try pattern.validate() - } catch { - throw Exception.Error(type: ExceptionType.IllegalArgumentException, Message: "Pattern syntax error: \(regex)") - } - return try getElementsByAttributeValueMatching(key, pattern) - } - - /** - * Find elements whose sibling index is less than the supplied index. - * @param index 0-based index - * @return elements less than index - */ - public func getElementsByIndexLessThan(_ index: Int)throws->Elements { - return try Collector.collect(Evaluator.IndexLessThan(index), self) - } - - /** - * Find elements whose sibling index is greater than the supplied index. - * @param index 0-based index - * @return elements greater than index - */ - public func getElementsByIndexGreaterThan(_ index: Int)throws->Elements { - return try Collector.collect(Evaluator.IndexGreaterThan(index), self) - } - - /** - * Find elements whose sibling index is equal to the supplied index. - * @param index 0-based index - * @return elements equal to index - */ - public func getElementsByIndexEquals(_ index: Int)throws->Elements { - return try Collector.collect(Evaluator.IndexEquals(index), self) - } - - /** - * Find elements that contain the specified string. The search is case insensitive. The text may appear directly - * in the element, or in any of its descendants. - * @param searchText to look for in the element's text - * @return elements that contain the string, case insensitive. - * @see Element#text() - */ - public func getElementsContainingText(_ searchText: String)throws->Elements { - return try Collector.collect(Evaluator.ContainsText(searchText), self) - } - - /** - * Find elements that directly contain the specified string. The search is case insensitive. The text must appear directly - * in the element, not in any of its descendants. - * @param searchText to look for in the element's own text - * @return elements that contain the string, case insensitive. - * @see Element#ownText() - */ - public func getElementsContainingOwnText(_ searchText: String)throws->Elements { - return try Collector.collect(Evaluator.ContainsOwnText(searchText), self) - } - - /** - * Find elements whose text matches the supplied regular expression. - * @param pattern regular expression to match text against - * @return elements matching the supplied regular expression. - * @see Element#text() - */ - public func getElementsMatchingText(_ pattern: Pattern)throws->Elements { - return try Collector.collect(Evaluator.Matches(pattern), self) - } - - /** - * Find elements whose text matches the supplied regular expression. - * @param regex regular expression to match text against. You can use embedded flags (such as (?i) and (?m) to control regex options. - * @return elements matching the supplied regular expression. - * @see Element#text() - */ - public func getElementsMatchingText(_ regex: String)throws->Elements { - let pattern: Pattern - do { - pattern = Pattern.compile(regex) - try pattern.validate() - } catch { - throw Exception.Error(type: ExceptionType.IllegalArgumentException, Message: "Pattern syntax error: \(regex)") - } - return try getElementsMatchingText(pattern) - } - - /** - * Find elements whose own text matches the supplied regular expression. - * @param pattern regular expression to match text against - * @return elements matching the supplied regular expression. - * @see Element#ownText() - */ - public func getElementsMatchingOwnText(_ pattern: Pattern)throws->Elements { - return try Collector.collect(Evaluator.MatchesOwn(pattern), self) - } - - /** - * Find elements whose text matches the supplied regular expression. - * @param regex regular expression to match text against. You can use embedded flags (such as (?i) and (?m) to control regex options. - * @return elements matching the supplied regular expression. - * @see Element#ownText() - */ - public func getElementsMatchingOwnText(_ regex: String)throws->Elements { - let pattern: Pattern - do { - pattern = Pattern.compile(regex) - try pattern.validate() - } catch { - throw Exception.Error(type: ExceptionType.IllegalArgumentException, Message: "Pattern syntax error: \(regex)") - } - return try getElementsMatchingOwnText(pattern) - } - - /** - * Find all elements under this element (including self, and children of children). - * - * @return all elements - */ - public func getAllElements()throws->Elements { - return try Collector.collect(Evaluator.AllElements(), self) - } - - /** - * Gets the combined text of this element and all its children. Whitespace is normalized and trimmed. - *

    - * For example, given HTML {@code

    Hello there now!

    }, {@code p.text()} returns {@code "Hello there now!"} - * - * @return unencoded text, or empty string if none. - * @see #ownText() - * @see #textNodes() - */ - class textNodeVisitor: NodeVisitor { - let accum: StringBuilder - init(_ accum: StringBuilder) { - self.accum = accum - } - public func head(_ node: Node, _ depth: Int) { - if let textNode = (node as? TextNode) { - Element.appendNormalisedText(accum, textNode) - } else if let element = (node as? Element) { - if (accum.length > 0 && - (element.isBlock() || element._tag.getName() == "br") && - !TextNode.lastCharIsWhitespace(accum)) { - accum.append(" ") - } - } - } - - public func tail(_ node: Node, _ depth: Int) { - } - } - public func text()throws->String { - let accum: StringBuilder = StringBuilder() - try NodeTraversor(textNodeVisitor(accum)).traverse(self) - return accum.toString().trim() - } - - /** - * Gets the text owned by this element only; does not get the combined text of all children. - *

    - * For example, given HTML {@code

    Hello there now!

    }, {@code p.ownText()} returns {@code "Hello now!"}, - * whereas {@code p.text()} returns {@code "Hello there now!"}. - * Note that the text within the {@code b} element is not returned, as it is not a direct child of the {@code p} element. - * - * @return unencoded text, or empty string if none. - * @see #text() - * @see #textNodes() - */ - public func ownText() -> String { - let sb: StringBuilder = StringBuilder() - ownText(sb) - return sb.toString().trim() - } - - private func ownText(_ accum: StringBuilder) { - for child: Node in childNodes { - if let textNode = (child as? TextNode) { - Element.appendNormalisedText(accum, textNode) - } else if let child = (child as? Element) { - Element.appendWhitespaceIfBr(child, accum) - } - } - } - - private static func appendNormalisedText(_ accum: StringBuilder, _ textNode: TextNode) { - let text: String = textNode.getWholeText() - - if (Element.preserveWhitespace(textNode.parentNode)) { - accum.append(text) - } else { - StringUtil.appendNormalisedWhitespace(accum, string: text, stripLeading: TextNode.lastCharIsWhitespace(accum)) - } - } - - private static func appendWhitespaceIfBr(_ element: Element, _ accum: StringBuilder) { - if (element._tag.getName() == "br" && !TextNode.lastCharIsWhitespace(accum)) { - accum.append(" ") - } - } - - static func preserveWhitespace(_ node: Node?) -> Bool { - // looks only at this element and one level up, to prevent recursion & needless stack searches - if let element = (node as? Element) { - return element._tag.preserveWhitespace() || element.parent() != nil && element.parent()!._tag.preserveWhitespace() - } - return false - } - - /** - * Set the text of this element. Any existing contents (text or elements) will be cleared - * @param text unencoded text - * @return this element - */ - @discardableResult - public func text(_ text: String)throws->Element { - empty() - let textNode: TextNode = TextNode(text, baseUri) - try appendChild(textNode) - return self - } - - /** - Test if this element has any text content (that is not just whitespace). - @return true if element has non-blank text content. - */ - public func hasText() -> Bool { - for child: Node in childNodes { - if let textNode = (child as? TextNode) { - if (!textNode.isBlank()) { - return true - } - } else if let el = (child as? Element) { - if (el.hasText()) { - return true - } - } - } - return false - } - - /** - * Get the combined data of this element. Data is e.g. the inside of a {@code script} tag. - * @return the data, or empty string if none - * - * @see #dataNodes() - */ - public func data() -> String { - let sb: StringBuilder = StringBuilder() - - for childNode: Node in childNodes { - if let data = (childNode as? DataNode) { - sb.append(data.getWholeData()) - } else if let element = (childNode as? Element) { - let elementData: String = element.data() - sb.append(elementData) - } - } - return sb.toString() - } - - /** - * Gets the literal value of this element's "class" attribute, which may include multiple class names, space - * separated. (E.g. on <div class="header gray"> returns, "header gray") - * @return The literal class attribute, or empty string if no class attribute set. - */ - public func className()throws->String { - return try attr(Element.classString).trim() - } - - /** - * Get all of the element's class names. E.g. on element {@code
    }, - * returns a set of two elements {@code "header", "gray"}. Note that modifications to this set are not pushed to - * the backing {@code class} attribute; use the {@link #classNames(java.util.Set)} method to persist them. - * @return set of classnames, empty if no class attribute - */ - public func classNames()throws->OrderedSet { - let fitted = try className().replaceAll(of: Element.classSplit, with: " ", options: .caseInsensitive) - let names: [String] = fitted.components(separatedBy: " ") - let classNames: OrderedSet = OrderedSet(sequence: names) - classNames.remove(Element.emptyString) // if classNames() was empty, would include an empty class - return classNames - } - - /** - Set the element's {@code class} attribute to the supplied class names. - @param classNames set of classes - @return this element, for chaining - */ - @discardableResult - public func classNames(_ classNames: OrderedSet)throws->Element { - try attributes?.put(Element.classString, StringUtil.join(classNames, sep: " ")) - return self - } - - /** - * Tests if this element has a class. Case insensitive. - * @param className name of class to check for - * @return true if it does, false if not - */ - // performance sensitive - public func hasClass(_ className: String) -> Bool { - let classAtt: String? = attributes?.get(key: Element.classString) - let len: Int = (classAtt != nil) ? classAtt!.count : 0 - let wantLen: Int = className.count - - if (len == 0 || len < wantLen) { - return false - } - let classAttr = classAtt! - - // if both lengths are equal, only need compare the className with the attribute - if (len == wantLen) { - return className.equalsIgnoreCase(string: classAttr) - } - - // otherwise, scan for whitespace and compare regions (with no string or arraylist allocations) - var inClass: Bool = false - var start: Int = 0 - for i in 0..Element { - let classes: OrderedSet = try classNames() - classes.append(className) - try classNames(classes) - return self - } - - /** - Remove a class name from this element's {@code class} attribute. - @param className class name to remove - @return this element - */ - @discardableResult - public func removeClass(_ className: String)throws->Element { - let classes: OrderedSet = try classNames() - classes.remove(className) - try classNames(classes) - return self - } - - /** - Toggle a class name on this element's {@code class} attribute: if present, remove it; otherwise add it. - @param className class name to toggle - @return this element - */ - @discardableResult - public func toggleClass(_ className: String)throws->Element { - let classes: OrderedSet = try classNames() - if (classes.contains(className)) {classes.remove(className) - } else { - classes.append(className) - } - try classNames(classes) - - return self - } - - /** - * Get the value of a form element (input, textarea, etc). - * @return the value of the form element, or empty string if not set. - */ - public func val()throws->String { - if (tagName()=="textarea") { - return try text() - } else { - return try attr("value") - } - } - - /** - * Set the value of a form element (input, textarea, etc). - * @param value value to set - * @return this element (for chaining) - */ - @discardableResult - public func val(_ value: String)throws->Element { - if (tagName() == "textarea") { - try text(value) - } else { - try attr("value", value) - } - return self - } - - override func outerHtmlHead(_ accum: StringBuilder, _ depth: Int, _ out: OutputSettings)throws { - if (out.prettyPrint() && (_tag.formatAsBlock() || (parent() != nil && parent()!.tag().formatAsBlock()) || out.outline())) { - if (accum.length > 0) { - indent(accum, depth, out) - } - } - accum - .append("<") - .append(tagName()) - try attributes?.html(accum: accum, out: out) - - // selfclosing includes unknown tags, isEmpty defines tags that are always empty - if (childNodes.isEmpty && _tag.isSelfClosing()) { - if (out.syntax() == OutputSettings.Syntax.html && _tag.isEmpty()) { - accum.append(">") - } else { - accum.append(" />") // in html, in xml - } - } else { - accum.append(">") - } - } - - override func outerHtmlTail(_ accum: StringBuilder, _ depth: Int, _ out: OutputSettings) { - if (!(childNodes.isEmpty && _tag.isSelfClosing())) { - if (out.prettyPrint() && (!childNodes.isEmpty && ( - _tag.formatAsBlock() || (out.outline() && (childNodes.count>1 || (childNodes.count==1 && !(((childNodes[0] as? TextNode) != nil))))) - ))) { - indent(accum, depth, out) - } - accum.append("") - } - } - - /** - * Retrieves the element's inner HTML. E.g. on a {@code
    } with one empty {@code

    }, would return - * {@code

    }. (Whereas {@link #outerHtml()} would return {@code

    }.) - * - * @return String of HTML. - * @see #outerHtml() - */ - public func html()throws->String { - let accum: StringBuilder = StringBuilder() - try html2(accum) - return getOutputSettings().prettyPrint() ? accum.toString().trim() : accum.toString() - } - - private func html2(_ accum: StringBuilder)throws { - for node in childNodes { - try node.outerHtml(accum) - } - } - - /** - * {@inheritDoc} - */ - open override func html(_ appendable: StringBuilder)throws->StringBuilder { - for node in childNodes { - try node.outerHtml(appendable) - } - return appendable - } - - /** - * Set this element's inner HTML. Clears the existing HTML first. - * @param html HTML to parse and set into this element - * @return this element - * @see #append(String) - */ - @discardableResult - public func html(_ html: String)throws->Element { - empty() - try append(html) - return self - } - - public override func copy(with zone: NSZone? = nil) -> Any { - let clone = Element(_tag, baseUri!, attributes!) - return copy(clone: clone) - } - - public override func copy(parent: Node?) -> Node { - let clone = Element(_tag, baseUri!, attributes!) - return copy(clone: clone, parent: parent) - } - public override func copy(clone: Node, parent: Node?) -> Node { - return super.copy(clone: clone, parent: parent) - } - - override public func hash(into hasher: inout Hasher) { - super.hash(into: &hasher) - hasher.combine(_tag) - } -} diff --git a/Pods/SwiftSoup/Sources/Elements.swift b/Pods/SwiftSoup/Sources/Elements.swift deleted file mode 100644 index 7bcda28..0000000 --- a/Pods/SwiftSoup/Sources/Elements.swift +++ /dev/null @@ -1,602 +0,0 @@ -// -// Elements.swift -// SwiftSoup -// -// Created by Nabil Chatbi on 20/10/16. -// Copyright © 2016 Nabil Chatbi.. All rights reserved. -// -/** -A list of {@link Element}s, with methods that act on every element in the list. -

    -To get an {@code Elements} object, use the {@link Element#select(String)} method. -

    -*/ - -import Foundation - -//open typealias Elements = Array -//typealias E = Element -open class Elements: NSCopying { - fileprivate var this: Array = Array() - - ///base init - public init() { - } - ///Initialized with an array - public init(_ a: Array) { - this = a - } - ///Initialized with an order set - public init(_ a: OrderedSet) { - this.append(contentsOf: a) - } - - /** - * Creates a deep copy of these elements. - * @return a deep copy - */ - public func copy(with zone: NSZone? = nil) -> Any { - let clone: Elements = Elements() - for e: Element in this { - clone.add(e.copy() as! Element) - } - return clone - } - - // attribute methods - /** - Get an attribute value from the first matched element that has the attribute. - @param attributeKey The attribute key. - @return The attribute value from the first matched element that has the attribute.. If no elements were matched (isEmpty() == true), - or if the no elements have the attribute, returns empty string. - @see #hasAttr(String) - */ - open func attr(_ attributeKey: String)throws->String { - for element in this { - if (element.hasAttr(attributeKey)) { - return try element.attr(attributeKey) - } - } - return "" - } - - /** - Checks if any of the matched elements have this attribute set. - @param attributeKey attribute key - @return true if any of the elements have the attribute; false if none do. - */ - open func hasAttr(_ attributeKey: String) -> Bool { - for element in this { - if element.hasAttr(attributeKey) {return true} - } - return false - } - - /** - * Set an attribute on all matched elements. - * @param attributeKey attribute key - * @param attributeValue attribute value - * @return this - */ - @discardableResult - open func attr(_ attributeKey: String, _ attributeValue: String)throws->Elements { - for element in this { - try element.attr(attributeKey, attributeValue) - } - return self - } - - /** - * Remove an attribute from every matched element. - * @param attributeKey The attribute to remove. - * @return this (for chaining) - */ - @discardableResult - open func removeAttr(_ attributeKey: String)throws->Elements { - for element in this { - try element.removeAttr(attributeKey) - } - return self - } - - /** - Add the class name to every matched element's {@code class} attribute. - @param className class name to add - @return this - */ - @discardableResult - open func addClass(_ className: String)throws->Elements { - for element in this { - try element.addClass(className) - } - return self - } - - /** - Remove the class name from every matched element's {@code class} attribute, if present. - @param className class name to remove - @return this - */ - @discardableResult - open func removeClass(_ className: String)throws->Elements { - for element: Element in this { - try element.removeClass(className) - } - return self - } - - /** - Toggle the class name on every matched element's {@code class} attribute. - @param className class name to add if missing, or remove if present, from every element. - @return this - */ - @discardableResult - open func toggleClass(_ className: String)throws->Elements { - for element: Element in this { - try element.toggleClass(className) - } - return self - } - - /** - Determine if any of the matched elements have this class name set in their {@code class} attribute. - @param className class name to check for - @return true if any do, false if none do - */ - - open func hasClass(_ className: String) -> Bool { - for element: Element in this { - if (element.hasClass(className)) { - return true - } - } - return false - } - - /** - * Get the form element's value of the first matched element. - * @return The form element's value, or empty if not set. - * @see Element#val() - */ - open func val()throws->String { - if (size() > 0) { - return try first()!.val() - } - return "" - } - - /** - * Set the form element's value in each of the matched elements. - * @param value The value to set into each matched element - * @return this (for chaining) - */ - @discardableResult - open func val(_ value: String)throws->Elements { - for element: Element in this { - try element.val(value) - } - return self - } - - /** - * Get the combined text of all the matched elements. - *

    - * Note that it is possible to get repeats if the matched elements contain both parent elements and their own - * children, as the Element.text() method returns the combined text of a parent and all its children. - * @return string of all text: unescaped and no HTML. - * @see Element#text() - */ - open func text()throws->String { - let sb: StringBuilder = StringBuilder() - for element: Element in this { - if (sb.length != 0) { - sb.append(" ") - } - sb.append(try element.text()) - } - return sb.toString() - } - - /// Check if an element has text - open func hasText() -> Bool { - for element: Element in this { - if (element.hasText()) { - return true - } - } - return false - } - - /** - * Get the combined inner HTML of all matched elements. - * @return string of all element's inner HTML. - * @see #text() - * @see #outerHtml() - */ - open func html()throws->String { - var text = try this.reduce("") {result, name in "\(result)\(try name.html())\n"} - text.removeLast() - return text - } - - /** - * Get the combined outer HTML of all matched elements. - * @return string of all element's outer HTML. - * @see #text() - * @see #html() - */ - open func outerHtml()throws->String { - let sb: StringBuilder = StringBuilder() - for element in this { - if (sb.length != 0) { - sb.append("\n") - } - sb.append(try element.outerHtml()) - } - return sb.toString() - } - - /** - * Get the combined outer HTML of all matched elements. Alias of {@link #outerHtml()}. - * @return string of all element's outer HTML. - * @see #text() - * @see #html() - */ - - open func toString()throws->String { - return try outerHtml() - } - - /** - * Update the tag name of each matched element. For example, to change each {@code } to a {@code }, do - * {@code doc.select("i").tagName("em");} - * @param tagName the new tag name - * @return this, for chaining - * @see Element#tagName(String) - */ - @discardableResult - open func tagName(_ tagName: String)throws->Elements { - for element: Element in this { - try element.tagName(tagName) - } - return self - } - - /** - * Set the inner HTML of each matched element. - * @param html HTML to parse and set into each matched element. - * @return this, for chaining - * @see Element#html(String) - */ - @discardableResult - open func html(_ html: String)throws->Elements { - for element: Element in this { - try element.html(html) - } - return self - } - - /** - * Add the supplied HTML to the start of each matched element's inner HTML. - * @param html HTML to add inside each element, before the existing HTML - * @return this, for chaining - * @see Element#prepend(String) - */ - @discardableResult - open func prepend(_ html: String)throws->Elements { - for element: Element in this { - try element.prepend(html) - } - return self - } - - /** - * Add the supplied HTML to the end of each matched element's inner HTML. - * @param html HTML to add inside each element, after the existing HTML - * @return this, for chaining - * @see Element#append(String) - */ - @discardableResult - open func append(_ html: String)throws->Elements { - for element: Element in this { - try element.append(html) - } - return self - } - - /** - * Insert the supplied HTML before each matched element's outer HTML. - * @param html HTML to insert before each element - * @return this, for chaining - * @see Element#before(String) - */ - @discardableResult - open func before(_ html: String)throws->Elements { - for element: Element in this { - try element.before(html) - } - return self - } - - /** - * Insert the supplied HTML after each matched element's outer HTML. - * @param html HTML to insert after each element - * @return this, for chaining - * @see Element#after(String) - */ - @discardableResult - open func after(_ html: String)throws->Elements { - for element: Element in this { - try element.after(html) - } - return self - } - - /** - Wrap the supplied HTML around each matched elements. For example, with HTML - {@code

    This is Jsoup

    }, - doc.select("b").wrap("<i></i>"); - becomes {@code

    This is jsoup

    } - @param html HTML to wrap around each element, e.g. {@code
    }. Can be arbitrarily deep. - @return this (for chaining) - @see Element#wrap - */ - @discardableResult - open func wrap(_ html: String)throws->Elements { - try Validate.notEmpty(string: html) - for element: Element in this { - try element.wrap(html) - } - return self - } - - /** - * Removes the matched elements from the DOM, and moves their children up into their parents. This has the effect of - * dropping the elements but keeping their children. - *

    - * This is useful for e.g removing unwanted formatting elements but keeping their contents. - *

    - * - * E.g. with HTML:

    {@code

    One Two
    }

    - *

    {@code doc.select("font").unwrap();}

    - *

    HTML = {@code

    One Two
    }

    - * - * @return this (for chaining) - * @see Node#unwrap - */ - @discardableResult - open func unwrap()throws->Elements { - for element: Element in this { - try element.unwrap() - } - return self - } - - /** - * Empty (remove all child nodes from) each matched element. This is similar to setting the inner HTML of each - * element to nothing. - *

    - * E.g. HTML: {@code

    Hello there

    now

    }
    - * doc.select("p").empty();
    - * HTML = {@code

    } - * @return this, for chaining - * @see Element#empty() - * @see #remove() - */ - @discardableResult - open func empty() -> Elements { - for element: Element in this { - element.empty() - } - return self - } - - /** - * Remove each matched element from the DOM. This is similar to setting the outer HTML of each element to nothing. - *

    - * E.g. HTML: {@code

    Hello

    there

    }
    - * doc.select("p").remove();
    - * HTML = {@code
    } - *

    - * Note that this method should not be used to clean user-submitted HTML; rather, use {@link org.jsoup.safety.Cleaner} to clean HTML. - * @return this, for chaining - * @see Element#empty() - * @see #empty() - */ - @discardableResult - open func remove()throws->Elements { - for element in this { - try element.remove() - } - return self - } - - // filters - - /** - * Find matching elements within this element list. - * @param query A {@link Selector} query - * @return the filtered list of elements, or an empty list if none match. - */ - open func select(_ query: String)throws->Elements { - return try Selector.select(query, this) - } - - /** - * Remove elements from this list that match the {@link Selector} query. - *

    - * E.g. HTML: {@code

    Two
    }
    - * Elements divs = doc.select("div").not(".logo");
    - * Result: {@code divs: [
    Two
    ]} - *

    - * @param query the selector query whose results should be removed from these elements - * @return a new elements list that contains only the filtered results - */ - open func not(_ query: String)throws->Elements { - let out: Elements = try Selector.select(query, this) - return Selector.filterOut(this, out.this) - } - - /** - * Get the nth matched element as an Elements object. - *

    - * See also {@link #get(int)} to retrieve an Element. - * @param index the (zero-based) index of the element in the list to retain - * @return Elements containing only the specified element, or, if that element did not exist, an empty list. - */ - open func eq(_ index: Int) -> Elements { - return size() > index ? Elements([get(index)]) : Elements() - } - - /** - * Test if any of the matched elements match the supplied query. - * @param query A selector - * @return true if at least one element in the list matches the query. - */ - open func iS(_ query: String)throws->Bool { - let eval: Evaluator = try QueryParser.parse(query) - for e: Element in this { - if (try e.iS(eval)) { - return true - } - } - return false - - } - - /** - * Get all of the parents and ancestor elements of the matched elements. - * @return all of the parents and ancestor elements of the matched elements - */ - - open func parents() -> Elements { - let combo: OrderedSet = OrderedSet() - for e: Element in this { - combo.append(contentsOf: e.parents().array()) - } - return Elements(combo) - } - - // list-like methods - /** - Get the first matched element. - @return The first matched element, or null if contents is empty. - */ - open func first() -> Element? { - return isEmpty() ? nil : get(0) - } - - /// Check if no element stored - open func isEmpty() -> Bool { - return array().count == 0 - } - - /// Count - open func size() -> Int { - return array().count - } - - /** - Get the last matched element. - @return The last matched element, or null if contents is empty. - */ - open func last() -> Element? { - return isEmpty() ? nil : get(size() - 1) - } - - /** - * Perform a depth-first traversal on each of the selected elements. - * @param nodeVisitor the visitor callbacks to perform on each node - * @return this, for chaining - */ - @discardableResult - open func traverse(_ nodeVisitor: NodeVisitor)throws->Elements { - let traversor: NodeTraversor = NodeTraversor(nodeVisitor) - for el: Element in this { - try traversor.traverse(el) - } - return self - } - - /** - * Get the {@link FormElement} forms from the selected elements, if any. - * @return a list of {@link FormElement}s pulled from the matched elements. The list will be empty if the elements contain - * no forms. - */ - open func forms()->Array { - var forms: Array = Array() - for el: Element in this { - if let el = el as? FormElement { - forms.append(el) - } - } - return forms - } - - /** - * Appends the specified element to the end of this list. - * - * @param e element to be appended to this list - * @return true (as specified by {@link Collection#add}) - */ - open func add(_ e: Element) { - this.append(e) - } - - /** - * Insert the specified element at index. - */ - open func add(_ index: Int, _ element: Element) { - this.insert(element, at: index) - } - - /// Return element at index - open func get(_ i: Int) -> Element { - return this[i] - } - - /// Returns all elements - open func array()->Array { - return this - } -} - -/** -* Elements extension Equatable. -*/ -extension Elements: Equatable { - /// Returns a Boolean value indicating whether two values are equal. - /// - /// Equality is the inverse of inequality. For any values `a` and `b`, - /// `a == b` implies that `a != b` is `false`. - /// - /// - Parameters: - /// - lhs: A value to compare. - /// - rhs: Another value to compare. - public static func ==(lhs: Elements, rhs: Elements) -> Bool { - return lhs.this == rhs.this - } -} - -/** -* Elements RandomAccessCollection -*/ -extension Elements: RandomAccessCollection { - public subscript(position: Int) -> Element { - return this[position] - } - - public var startIndex: Int { - return this.startIndex - } - - public var endIndex: Int { - return this.endIndex - } - - /// The number of Element objects in the collection. - /// Equivalent to `size()` - public var count: Int { - return this.count - } -} diff --git a/Pods/SwiftSoup/Sources/Entities.swift b/Pods/SwiftSoup/Sources/Entities.swift deleted file mode 100644 index 44aa03f..0000000 --- a/Pods/SwiftSoup/Sources/Entities.swift +++ /dev/null @@ -1,382 +0,0 @@ -// -// Entities.swift -// SwifSoup -// -// Created by Nabil Chatbi on 29/09/16. -// Copyright © 2016 Nabil Chatbi.. All rights reserved. -// - -import Foundation - -/** - * HTML entities, and escape routines. - * Source: W3C HTML - * named character references. - */ -public class Entities { - private static let empty = -1 - private static let emptyName = "" - private static let codepointRadix: Int = 36 - - public struct EscapeMode: Equatable { - - /** Restricted entities suitable for XHTML output: lt, gt, amp, and quot only. */ - public static let xhtml: EscapeMode = EscapeMode(string: Entities.xhtml, size: 4, id: 0) - /** Default HTML output entities. */ - public static let base: EscapeMode = EscapeMode(string: Entities.base, size: 106, id: 1) - /** Complete HTML entities. */ - public static let extended: EscapeMode = EscapeMode(string: Entities.full, size: 2125, id: 2) - - fileprivate let value: Int - - // table of named references to their codepoints. sorted so we can binary search. built by BuildEntities. - fileprivate var nameKeys: [String] - fileprivate var codeVals: [Int] // limitation is the few references with multiple characters; those go into multipoints. - - // table of codepoints to named entities. - fileprivate var codeKeys: [Int] // we don' support multicodepoints to single named value currently - fileprivate var nameVals: [String] - - public static func == (left: EscapeMode, right: EscapeMode) -> Bool { - return left.value == right.value - } - - static func != (left: EscapeMode, right: EscapeMode) -> Bool { - return left.value != right.value - } - - private static let codeDelims: [UnicodeScalar] = [",", ";"] - - init(string: String, size: Int, id: Int) { - nameKeys = [String](repeating: "", count: size) - codeVals = [Int](repeating: 0, count: size) - codeKeys = [Int](repeating: 0, count: size) - nameVals = [String](repeating: "", count: size) - value = id - - //Load() - - var i = 0 - - let reader: CharacterReader = CharacterReader(string) - - while (!reader.isEmpty()) { - // NotNestedLessLess=10913,824;1887 - - let name: String = reader.consumeTo("=") - reader.advance() - let cp1: Int = Int(reader.consumeToAny(EscapeMode.codeDelims), radix: codepointRadix) ?? 0 - let codeDelim: UnicodeScalar = reader.current() - reader.advance() - let cp2: Int - if (codeDelim == ",") { - cp2 = Int(reader.consumeTo(";"), radix: codepointRadix) ?? 0 - reader.advance() - } else { - cp2 = empty - } - let index: Int = Int(reader.consumeTo("\n"), radix: codepointRadix) ?? 0 - reader.advance() - - nameKeys[i] = name - codeVals[i] = cp1 - codeKeys[index] = cp1 - nameVals[index] = name - - if (cp2 != empty) { - var s = String() - s.append(Character(UnicodeScalar(cp1)!)) - s.append(Character(UnicodeScalar(cp2)!)) - multipoints[name] = s - } - i = i + 1 - } - } - -// init(string: String, size: Int, id: Int) { -// nameKeys = [String](repeating: "", count: size) -// codeVals = [Int](repeating: 0, count: size) -// codeKeys = [Int](repeating: 0, count: size) -// nameVals = [String](repeating: "", count: size) -// value = id -// -// let components = string.components(separatedBy: "\n") -// -// var i = 0 -// for entry in components { -// let match = Entities.entityPattern.matcher(in: entry) -// if (match.find()) { -// let name = match.group(1)! -// let cp1 = Int(match.group(2)!, radix: codepointRadix) -// //let cp2 = Int(Int.parseInt(s: match.group(3), radix: codepointRadix)) -// let cp2 = match.group(3) != nil ? Int(match.group(3)!, radix: codepointRadix) : empty -// let index = Int(match.group(4)!, radix: codepointRadix) -// -// nameKeys[i] = name -// codeVals[i] = cp1! -// codeKeys[index!] = cp1! -// nameVals[index!] = name -// -// if (cp2 != empty) { -// var s = String() -// s.append(Character(UnicodeScalar(cp1!)!)) -// s.append(Character(UnicodeScalar(cp2!)!)) -// multipoints[name] = s -// } -// i += 1 -// } -// } -// } - - public func codepointForName(_ name: String) -> Int { -// for s in nameKeys { -// if s == name { -// return codeVals[nameKeys.index(of: s)!] -// } -// } - guard let index = nameKeys.firstIndex(of: name) else { - return empty - } - return codeVals[index] - } - - public func nameForCodepoint(_ codepoint: Int ) -> String { - //let ss = codeKeys.index(of: codepoint) - - var index = -1 - for s in codeKeys { - if s == codepoint { - index = codeKeys.firstIndex(of: codepoint)! - } - } - - if (index >= 0) { - // the results are ordered so lower case versions of same codepoint come after uppercase, and we prefer to emit lower - // (and binary search for same item with multi results is undefined - return (index < nameVals.count-1 && codeKeys[index+1] == codepoint) ? - nameVals[index+1] : nameVals[index] - } - return emptyName - } - - private func size() -> Int { - return nameKeys.count - } - - } - - private static var multipoints: Dictionary = Dictionary() // name -> multiple character references - - private init() { - } - - /** - * Check if the input is a known named entity - * @param name the possible entity name (e.g. "lt" or "amp") - * @return true if a known named entity - */ - public static func isNamedEntity(_ name: String ) -> Bool { - return (EscapeMode.extended.codepointForName(name) != empty) - } - - /** - * Check if the input is a known named entity in the base entity set. - * @param name the possible entity name (e.g. "lt" or "amp") - * @return true if a known named entity in the base set - * @see #isNamedEntity(String) - */ - public static func isBaseNamedEntity(_ name: String) -> Bool { - return EscapeMode.base.codepointForName(name) != empty - } - - /** - * Get the Character value of the named entity - * @param name named entity (e.g. "lt" or "amp") - * @return the Character value of the named entity (e.g. '{@literal <}' or '{@literal &}') - * @deprecated does not support characters outside the BMP or multiple character names - */ - public static func getCharacterByName(name: String) -> Character { - return Character.convertFromIntegerLiteral(value: EscapeMode.extended.codepointForName(name)) - } - - /** - * Get the character(s) represented by the named entitiy - * @param name entity (e.g. "lt" or "amp") - * @return the string value of the character(s) represented by this entity, or "" if not defined - */ - public static func getByName(name: String) -> String { - let val = multipoints[name] - if (val != nil) {return val!} - let codepoint = EscapeMode.extended.codepointForName(name) - if (codepoint != empty) { - return String(Character(UnicodeScalar(codepoint)!)) - } - return emptyName - } - - public static func codepointsForName(_ name: String, codepoints: inout [UnicodeScalar]) -> Int { - - if let val: String = multipoints[name] { - codepoints[0] = val.unicodeScalar(0) - codepoints[1] = val.unicodeScalar(1) - return 2 - } - - let codepoint = EscapeMode.extended.codepointForName(name) - if (codepoint != empty) { - codepoints[0] = UnicodeScalar(codepoint)! - return 1 - } - return 0 - } - - public static func escape(_ string: String, _ encode: String.Encoding = .utf8 ) -> String { - return Entities.escape(string, OutputSettings().charset(encode).escapeMode(Entities.EscapeMode.extended)) - } - - public static func escape(_ string: String, _ out: OutputSettings) -> String { - let accum = StringBuilder()//string.characters.count * 2 - escape(accum, string, out, false, false, false) - // try { - // - // } catch (IOException e) { - // throw new SerializationException(e) // doesn't happen - // } - return accum.toString() - } - - // this method is ugly, and does a lot. but other breakups cause rescanning and stringbuilder generations - static func escape(_ accum: StringBuilder, _ string: String, _ out: OutputSettings, _ inAttribute: Bool, _ normaliseWhite: Bool, _ stripLeadingWhite: Bool ) { - var lastWasWhite = false - var reachedNonWhite = false - let escapeMode: EscapeMode = out.escapeMode() - let encoder: String.Encoding = out.encoder() - //let length = UInt32(string.characters.count) - - var codePoint: UnicodeScalar - for ch in string.unicodeScalars { - codePoint = ch - - if (normaliseWhite) { - if (codePoint.isWhitespace) { - if ((stripLeadingWhite && !reachedNonWhite) || lastWasWhite) { - continue - } - accum.append(UnicodeScalar.Space) - lastWasWhite = true - continue - } else { - lastWasWhite = false - reachedNonWhite = true - } - } - - // surrogate pairs, split implementation for efficiency on single char common case (saves creating strings, char[]): - if (codePoint.value < Character.MIN_SUPPLEMENTARY_CODE_POINT) { - let c = codePoint - // html specific and required escapes: - switch (codePoint) { - case UnicodeScalar.Ampersand: - accum.append("&") - break - case UnicodeScalar(UInt32(0xA0))!: - if (escapeMode != EscapeMode.xhtml) { - accum.append(" ") - } else { - accum.append(" ") - } - break - case UnicodeScalar.LessThan: - // escape when in character data or when in a xml attribue val; not needed in html attr val - if (!inAttribute || escapeMode == EscapeMode.xhtml) { - accum.append("<") - } else { - accum.append(c) - } - break - case UnicodeScalar.GreaterThan: - if (!inAttribute) { - accum.append(">") - } else { - accum.append(c)} - break - case "\"": - if (inAttribute) { - accum.append(""") - } else { - accum.append(c) - } - break - default: - if (canEncode(c, encoder)) { - accum.append(c) - } else { - appendEncoded(accum: accum, escapeMode: escapeMode, codePoint: codePoint) - } - } - } else { - if (encoder.canEncode(String(codePoint))) // uses fallback encoder for simplicity - { - accum.append(String(codePoint)) - } else { - appendEncoded(accum: accum, escapeMode: escapeMode, codePoint: codePoint) - } - } - } - } - - private static func appendEncoded(accum: StringBuilder, escapeMode: EscapeMode, codePoint: UnicodeScalar) { - let name = escapeMode.nameForCodepoint(Int(codePoint.value)) - if (name != emptyName) // ok for identity check - {accum.append(UnicodeScalar.Ampersand).append(name).append(";") - } else { - accum.append("&#x").append(String.toHexString(n: Int(codePoint.value)) ).append(";") - } - } - - public static func unescape(_ string: String)throws-> String { - return try unescape(string: string, strict: false) - } - - /** - * Unescape the input string. - * @param string to un-HTML-escape - * @param strict if "strict" (that is, requires trailing ';' char, otherwise that's optional) - * @return unescaped string - */ - public static func unescape(string: String, strict: Bool)throws -> String { - return try Parser.unescapeEntities(string, strict) - } - - /* - * Provides a fast-path for Encoder.canEncode, which drastically improves performance on Android post JellyBean. - * After KitKat, the implementation of canEncode degrades to the point of being useless. For non ASCII or UTF, - * performance may be bad. We can add more encoders for common character sets that are impacted by performance - * issues on Android if required. - * - * Benchmarks: * - * OLD toHtml() impl v New (fastpath) in millis - * Wiki: 1895, 16 - * CNN: 6378, 55 - * Alterslash: 3013, 28 - * Jsoup: 167, 2 - */ - private static func canEncode(_ c: UnicodeScalar, _ fallback: String.Encoding) -> Bool { - // todo add more charset tests if impacted by Android's bad perf in canEncode - switch (fallback) { - case String.Encoding.ascii: - return c.value < 0x80 - case String.Encoding.utf8: - return true // real is:!(Character.isLowSurrogate(c) || Character.isHighSurrogate(c)) - but already check above - default: - return fallback.canEncode(String(Character(c))) - } - } - - static let xhtml: String = "amp=12;1\ngt=1q;3\nlt=1o;2\nquot=y;0" - - static let base: String = "AElig=5i;1c\nAMP=12;2\nAacute=5d;17\nAcirc=5e;18\nAgrave=5c;16\nAring=5h;1b\nAtilde=5f;19\nAuml=5g;1a\nCOPY=4p;h\nCcedil=5j;1d\nETH=5s;1m\nEacute=5l;1f\nEcirc=5m;1g\nEgrave=5k;1e\nEuml=5n;1h\nGT=1q;6\nIacute=5p;1j\nIcirc=5q;1k\nIgrave=5o;1i\nIuml=5r;1l\nLT=1o;4\nNtilde=5t;1n\nOacute=5v;1p\nOcirc=5w;1q\nOgrave=5u;1o\nOslash=60;1u\nOtilde=5x;1r\nOuml=5y;1s\nQUOT=y;0\nREG=4u;n\nTHORN=66;20\nUacute=62;1w\nUcirc=63;1x\nUgrave=61;1v\nUuml=64;1y\nYacute=65;1z\naacute=69;23\nacirc=6a;24\nacute=50;u\naelig=6e;28\nagrave=68;22\namp=12;3\naring=6d;27\natilde=6b;25\nauml=6c;26\nbrvbar=4m;e\nccedil=6f;29\ncedil=54;y\ncent=4i;a\ncopy=4p;i\ncurren=4k;c\ndeg=4w;q\ndivide=6v;2p\neacute=6h;2b\necirc=6i;2c\negrave=6g;2a\neth=6o;2i\neuml=6j;2d\nfrac12=59;13\nfrac14=58;12\nfrac34=5a;14\ngt=1q;7\niacute=6l;2f\nicirc=6m;2g\niexcl=4h;9\nigrave=6k;2e\niquest=5b;15\niuml=6n;2h\nlaquo=4r;k\nlt=1o;5\nmacr=4v;p\nmicro=51;v\nmiddot=53;x\nnbsp=4g;8\nnot=4s;l\nntilde=6p;2j\noacute=6r;2l\nocirc=6s;2m\nograve=6q;2k\nordf=4q;j\nordm=56;10\noslash=6w;2q\notilde=6t;2n\nouml=6u;2o\npara=52;w\nplusmn=4x;r\npound=4j;b\nquot=y;1\nraquo=57;11\nreg=4u;o\nsect=4n;f\nshy=4t;m\nsup1=55;z\nsup2=4y;s\nsup3=4z;t\nszlig=67;21\nthorn=72;2w\ntimes=5z;1t\nuacute=6y;2s\nucirc=6z;2t\nugrave=6x;2r\numl=4o;g\nuuml=70;2u\nyacute=71;2v\nyen=4l;d\nyuml=73;2x" - - static let full: String = "AElig=5i;2v\nAMP=12;8\nAacute=5d;2p\nAbreve=76;4k\nAcirc=5e;2q\nAcy=sw;av\nAfr=2kn8;1kh\nAgrave=5c;2o\nAlpha=pd;8d\nAmacr=74;4i\nAnd=8cz;1e1\nAogon=78;4m\nAopf=2koo;1ls\nApplyFunction=6e9;ew\nAring=5h;2t\nAscr=2kkc;1jc\nAssign=6s4;s6\nAtilde=5f;2r\nAuml=5g;2s\nBackslash=6qe;o1\nBarv=8h3;1it\nBarwed=6x2;120\nBcy=sx;aw\nBecause=6r9;pw\nBernoullis=6jw;gn\nBeta=pe;8e\nBfr=2kn9;1ki\nBopf=2kop;1lt\nBreve=k8;82\nBscr=6jw;gp\nBumpeq=6ry;ro\nCHcy=tj;bi\nCOPY=4p;1q\nCacute=7a;4o\nCap=6vm;zz\nCapitalDifferentialD=6kl;h8\nCayleys=6jx;gq\nCcaron=7g;4u\nCcedil=5j;2w\nCcirc=7c;4q\nCconint=6r4;pn\nCdot=7e;4s\nCedilla=54;2e\nCenterDot=53;2b\nCfr=6jx;gr\nChi=pz;8y\nCircleDot=6u1;x8\nCircleMinus=6ty;x3\nCirclePlus=6tx;x1\nCircleTimes=6tz;x5\nClockwiseContourIntegral=6r6;pp\nCloseCurlyDoubleQuote=6cd;e0\nCloseCurlyQuote=6c9;dt\nColon=6rb;q1\nColone=8dw;1en\nCongruent=6sh;sn\nConint=6r3;pm\nContourIntegral=6r2;pi\nCopf=6iq;f7\nCoproduct=6q8;nq\nCounterClockwiseContourIntegral=6r7;pr\nCross=8bz;1d8\nCscr=2kke;1jd\nCup=6vn;100\nCupCap=6rx;rk\nDD=6kl;h9\nDDotrahd=841;184\nDJcy=si;ai\nDScy=sl;al\nDZcy=sv;au\nDagger=6ch;e7\nDarr=6n5;j5\nDashv=8h0;1ir\nDcaron=7i;4w\nDcy=t0;az\nDel=6pz;n9\nDelta=pg;8g\nDfr=2knb;1kj\nDiacriticalAcute=50;27\nDiacriticalDot=k9;84\nDiacriticalDoubleAcute=kd;8a\nDiacriticalGrave=2o;13\nDiacriticalTilde=kc;88\nDiamond=6v8;za\nDifferentialD=6km;ha\nDopf=2kor;1lu\nDot=4o;1n\nDotDot=6ho;f5\nDotEqual=6s0;rw\nDoubleContourIntegral=6r3;pl\nDoubleDot=4o;1m\nDoubleDownArrow=6oj;m0\nDoubleLeftArrow=6og;lq\nDoubleLeftRightArrow=6ok;m3\nDoubleLeftTee=8h0;1iq\nDoubleLongLeftArrow=7w8;17g\nDoubleLongLeftRightArrow=7wa;17m\nDoubleLongRightArrow=7w9;17j\nDoubleRightArrow=6oi;lw\nDoubleRightTee=6ug;xz\nDoubleUpArrow=6oh;lt\nDoubleUpDownArrow=6ol;m7\nDoubleVerticalBar=6qt;ov\nDownArrow=6mr;i8\nDownArrowBar=843;186\nDownArrowUpArrow=6ph;mn\nDownBreve=lt;8c\nDownLeftRightVector=85s;198\nDownLeftTeeVector=866;19m\nDownLeftVector=6nx;ke\nDownLeftVectorBar=85y;19e\nDownRightTeeVector=867;19n\nDownRightVector=6o1;kq\nDownRightVectorBar=85z;19f\nDownTee=6uc;xs\nDownTeeArrow=6nb;jh\nDownarrow=6oj;m1\nDscr=2kkf;1je\nDstrok=7k;4y\nENG=96;6g\nETH=5s;35\nEacute=5l;2y\nEcaron=7u;56\nEcirc=5m;2z\nEcy=tp;bo\nEdot=7q;52\nEfr=2knc;1kk\nEgrave=5k;2x\nElement=6q0;na\nEmacr=7m;50\nEmptySmallSquare=7i3;15x\nEmptyVerySmallSquare=7fv;150\nEogon=7s;54\nEopf=2kos;1lv\nEpsilon=ph;8h\nEqual=8dx;1eo\nEqualTilde=6rm;qp\nEquilibrium=6oc;li\nEscr=6k0;gu\nEsim=8dv;1em\nEta=pj;8j\nEuml=5n;30\nExists=6pv;mz\nExponentialE=6kn;hc\nFcy=tg;bf\nFfr=2knd;1kl\nFilledSmallSquare=7i4;15y\nFilledVerySmallSquare=7fu;14w\nFopf=2kot;1lw\nForAll=6ps;ms\nFouriertrf=6k1;gv\nFscr=6k1;gw\nGJcy=sj;aj\nGT=1q;r\nGamma=pf;8f\nGammad=rg;a5\nGbreve=7y;5a\nGcedil=82;5e\nGcirc=7w;58\nGcy=sz;ay\nGdot=80;5c\nGfr=2kne;1km\nGg=6vt;10c\nGopf=2kou;1lx\nGreaterEqual=6sl;sv\nGreaterEqualLess=6vv;10i\nGreaterFullEqual=6sn;t6\nGreaterGreater=8f6;1gh\nGreaterLess=6t3;ul\nGreaterSlantEqual=8e6;1f5\nGreaterTilde=6sz;ub\nGscr=2kki;1jf\nGt=6sr;tr\nHARDcy=tm;bl\nHacek=jr;80\nHat=2m;10\nHcirc=84;5f\nHfr=6j0;fe\nHilbertSpace=6iz;fa\nHopf=6j1;fg\nHorizontalLine=7b4;13i\nHscr=6iz;fc\nHstrok=86;5h\nHumpDownHump=6ry;rn\nHumpEqual=6rz;rs\nIEcy=t1;b0\nIJlig=8i;5s\nIOcy=sh;ah\nIacute=5p;32\nIcirc=5q;33\nIcy=t4;b3\nIdot=8g;5p\nIfr=6j5;fq\nIgrave=5o;31\nIm=6j5;fr\nImacr=8a;5l\nImaginaryI=6ko;hf\nImplies=6oi;ly\nInt=6r0;pf\nIntegral=6qz;pd\nIntersection=6v6;z4\nInvisibleComma=6eb;f0\nInvisibleTimes=6ea;ey\nIogon=8e;5n\nIopf=2kow;1ly\nIota=pl;8l\nIscr=6j4;fn\nItilde=88;5j\nIukcy=sm;am\nIuml=5r;34\nJcirc=8k;5u\nJcy=t5;b4\nJfr=2knh;1kn\nJopf=2kox;1lz\nJscr=2kkl;1jg\nJsercy=so;ao\nJukcy=sk;ak\nKHcy=th;bg\nKJcy=ss;as\nKappa=pm;8m\nKcedil=8m;5w\nKcy=t6;b5\nKfr=2kni;1ko\nKopf=2koy;1m0\nKscr=2kkm;1jh\nLJcy=sp;ap\nLT=1o;m\nLacute=8p;5z\nLambda=pn;8n\nLang=7vu;173\nLaplacetrf=6j6;fs\nLarr=6n2;j1\nLcaron=8t;63\nLcedil=8r;61\nLcy=t7;b6\nLeftAngleBracket=7vs;16x\nLeftArrow=6mo;hu\nLeftArrowBar=6p0;mj\nLeftArrowRightArrow=6o6;l3\nLeftCeiling=6x4;121\nLeftDoubleBracket=7vq;16t\nLeftDownTeeVector=869;19p\nLeftDownVector=6o3;kw\nLeftDownVectorBar=861;19h\nLeftFloor=6x6;125\nLeftRightArrow=6ms;ib\nLeftRightVector=85q;196\nLeftTee=6ub;xq\nLeftTeeArrow=6n8;ja\nLeftTeeVector=862;19i\nLeftTriangle=6uq;ya\nLeftTriangleBar=89b;1c0\nLeftTriangleEqual=6us;yg\nLeftUpDownVector=85t;199\nLeftUpTeeVector=868;19o\nLeftUpVector=6nz;kk\nLeftUpVectorBar=860;19g\nLeftVector=6nw;kb\nLeftVectorBar=85u;19a\nLeftarrow=6og;lr\nLeftrightarrow=6ok;m4\nLessEqualGreater=6vu;10e\nLessFullEqual=6sm;t0\nLessGreater=6t2;ui\nLessLess=8f5;1gf\nLessSlantEqual=8e5;1ez\nLessTilde=6sy;u8\nLfr=2knj;1kp\nLl=6vs;109\nLleftarrow=6oq;me\nLmidot=8v;65\nLongLeftArrow=7w5;177\nLongLeftRightArrow=7w7;17d\nLongRightArrow=7w6;17a\nLongleftarrow=7w8;17h\nLongleftrightarrow=7wa;17n\nLongrightarrow=7w9;17k\nLopf=2koz;1m1\nLowerLeftArrow=6mx;iq\nLowerRightArrow=6mw;in\nLscr=6j6;fu\nLsh=6nk;jv\nLstrok=8x;67\nLt=6sq;tl\nMap=83p;17v\nMcy=t8;b7\nMediumSpace=6e7;eu\nMellintrf=6k3;gx\nMfr=2knk;1kq\nMinusPlus=6qb;nv\nMopf=2kp0;1m2\nMscr=6k3;gz\nMu=po;8o\nNJcy=sq;aq\nNacute=8z;69\nNcaron=93;6d\nNcedil=91;6b\nNcy=t9;b8\nNegativeMediumSpace=6bv;dc\nNegativeThickSpace=6bv;dd\nNegativeThinSpace=6bv;de\nNegativeVeryThinSpace=6bv;db\nNestedGreaterGreater=6sr;tq\nNestedLessLess=6sq;tk\nNewLine=a;1\nNfr=2knl;1kr\nNoBreak=6e8;ev\nNonBreakingSpace=4g;1d\nNopf=6j9;fx\nNot=8h8;1ix\nNotCongruent=6si;sp\nNotCupCap=6st;tv\nNotDoubleVerticalBar=6qu;p0\nNotElement=6q1;ne\nNotEqual=6sg;sk\nNotEqualTilde=6rm,mw;qn\nNotExists=6pw;n1\nNotGreater=6sv;tz\nNotGreaterEqual=6sx;u5\nNotGreaterFullEqual=6sn,mw;t3\nNotGreaterGreater=6sr,mw;tn\nNotGreaterLess=6t5;uq\nNotGreaterSlantEqual=8e6,mw;1f2\nNotGreaterTilde=6t1;ug\nNotHumpDownHump=6ry,mw;rl\nNotHumpEqual=6rz,mw;rq\nNotLeftTriangle=6wa;113\nNotLeftTriangleBar=89b,mw;1bz\nNotLeftTriangleEqual=6wc;119\nNotLess=6su;tw\nNotLessEqual=6sw;u2\nNotLessGreater=6t4;uo\nNotLessLess=6sq,mw;th\nNotLessSlantEqual=8e5,mw;1ew\nNotLessTilde=6t0;ue\nNotNestedGreaterGreater=8f6,mw;1gg\nNotNestedLessLess=8f5,mw;1ge\nNotPrecedes=6tc;vb\nNotPrecedesEqual=8fj,mw;1gv\nNotPrecedesSlantEqual=6w0;10p\nNotReverseElement=6q4;nl\nNotRightTriangle=6wb;116\nNotRightTriangleBar=89c,mw;1c1\nNotRightTriangleEqual=6wd;11c\nNotSquareSubset=6tr,mw;wh\nNotSquareSubsetEqual=6w2;10t\nNotSquareSuperset=6ts,mw;wl\nNotSquareSupersetEqual=6w3;10v\nNotSubset=6te,6he;vh\nNotSubsetEqual=6tk;w0\nNotSucceeds=6td;ve\nNotSucceedsEqual=8fk,mw;1h1\nNotSucceedsSlantEqual=6w1;10r\nNotSucceedsTilde=6tb,mw;v7\nNotSuperset=6tf,6he;vm\nNotSupersetEqual=6tl;w3\nNotTilde=6rl;ql\nNotTildeEqual=6ro;qv\nNotTildeFullEqual=6rr;r1\nNotTildeTilde=6rt;r9\nNotVerticalBar=6qs;or\nNscr=2kkp;1ji\nNtilde=5t;36\nNu=pp;8p\nOElig=9e;6m\nOacute=5v;38\nOcirc=5w;39\nOcy=ta;b9\nOdblac=9c;6k\nOfr=2knm;1ks\nOgrave=5u;37\nOmacr=98;6i\nOmega=q1;90\nOmicron=pr;8r\nOopf=2kp2;1m3\nOpenCurlyDoubleQuote=6cc;dy\nOpenCurlyQuote=6c8;dr\nOr=8d0;1e2\nOscr=2kkq;1jj\nOslash=60;3d\nOtilde=5x;3a\nOtimes=8c7;1df\nOuml=5y;3b\nOverBar=6da;em\nOverBrace=732;13b\nOverBracket=71w;134\nOverParenthesis=730;139\nPartialD=6pu;mx\nPcy=tb;ba\nPfr=2knn;1kt\nPhi=py;8x\nPi=ps;8s\nPlusMinus=4x;22\nPoincareplane=6j0;fd\nPopf=6jd;g3\nPr=8fv;1hl\nPrecedes=6t6;us\nPrecedesEqual=8fj;1gy\nPrecedesSlantEqual=6t8;uy\nPrecedesTilde=6ta;v4\nPrime=6cz;eg\nProduct=6q7;no\nProportion=6rb;q0\nProportional=6ql;oa\nPscr=2kkr;1jk\nPsi=q0;8z\nQUOT=y;3\nQfr=2kno;1ku\nQopf=6je;g5\nQscr=2kks;1jl\nRBarr=840;183\nREG=4u;1x\nRacute=9g;6o\nRang=7vv;174\nRarr=6n4;j4\nRarrtl=846;187\nRcaron=9k;6s\nRcedil=9i;6q\nRcy=tc;bb\nRe=6jg;gb\nReverseElement=6q3;nh\nReverseEquilibrium=6ob;le\nReverseUpEquilibrium=86n;1a4\nRfr=6jg;ga\nRho=pt;8t\nRightAngleBracket=7vt;170\nRightArrow=6mq;i3\nRightArrowBar=6p1;ml\nRightArrowLeftArrow=6o4;ky\nRightCeiling=6x5;123\nRightDoubleBracket=7vr;16v\nRightDownTeeVector=865;19l\nRightDownVector=6o2;kt\nRightDownVectorBar=85x;19d\nRightFloor=6x7;127\nRightTee=6ua;xo\nRightTeeArrow=6na;je\nRightTeeVector=863;19j\nRightTriangle=6ur;yd\nRightTriangleBar=89c;1c2\nRightTriangleEqual=6ut;yk\nRightUpDownVector=85r;197\nRightUpTeeVector=864;19k\nRightUpVector=6ny;kh\nRightUpVectorBar=85w;19c\nRightVector=6o0;kn\nRightVectorBar=85v;19b\nRightarrow=6oi;lx\nRopf=6jh;gd\nRoundImplies=86o;1a6\nRrightarrow=6or;mg\nRscr=6jf;g7\nRsh=6nl;jx\nRuleDelayed=8ac;1cb\nSHCHcy=tl;bk\nSHcy=tk;bj\nSOFTcy=to;bn\nSacute=9m;6u\nSc=8fw;1hm\nScaron=9s;70\nScedil=9q;6y\nScirc=9o;6w\nScy=td;bc\nSfr=2knq;1kv\nShortDownArrow=6mr;i7\nShortLeftArrow=6mo;ht\nShortRightArrow=6mq;i2\nShortUpArrow=6mp;hy\nSigma=pv;8u\nSmallCircle=6qg;o6\nSopf=2kp6;1m4\nSqrt=6qi;o9\nSquare=7fl;14t\nSquareIntersection=6tv;ww\nSquareSubset=6tr;wi\nSquareSubsetEqual=6tt;wp\nSquareSuperset=6ts;wm\nSquareSupersetEqual=6tu;ws\nSquareUnion=6tw;wz\nSscr=2kku;1jm\nStar=6va;zf\nSub=6vk;zw\nSubset=6vk;zv\nSubsetEqual=6ti;vu\nSucceeds=6t7;uv\nSucceedsEqual=8fk;1h4\nSucceedsSlantEqual=6t9;v1\nSucceedsTilde=6tb;v8\nSuchThat=6q3;ni\nSum=6q9;ns\nSup=6vl;zy\nSuperset=6tf;vp\nSupersetEqual=6tj;vx\nSupset=6vl;zx\nTHORN=66;3j\nTRADE=6jm;gf\nTSHcy=sr;ar\nTScy=ti;bh\nTab=9;0\nTau=pw;8v\nTcaron=9w;74\nTcedil=9u;72\nTcy=te;bd\nTfr=2knr;1kw\nTherefore=6r8;pt\nTheta=pk;8k\nThickSpace=6e7,6bu;et\nThinSpace=6bt;d7\nTilde=6rg;q9\nTildeEqual=6rn;qs\nTildeFullEqual=6rp;qy\nTildeTilde=6rs;r4\nTopf=2kp7;1m5\nTripleDot=6hn;f3\nTscr=2kkv;1jn\nTstrok=9y;76\nUacute=62;3f\nUarr=6n3;j2\nUarrocir=85l;193\nUbrcy=su;at\nUbreve=a4;7c\nUcirc=63;3g\nUcy=tf;be\nUdblac=a8;7g\nUfr=2kns;1kx\nUgrave=61;3e\nUmacr=a2;7a\nUnderBar=2n;11\nUnderBrace=733;13c\nUnderBracket=71x;136\nUnderParenthesis=731;13a\nUnion=6v7;z8\nUnionPlus=6tq;wf\nUogon=aa;7i\nUopf=2kp8;1m6\nUpArrow=6mp;hz\nUpArrowBar=842;185\nUpArrowDownArrow=6o5;l1\nUpDownArrow=6mt;ie\nUpEquilibrium=86m;1a2\nUpTee=6ud;xv\nUpTeeArrow=6n9;jc\nUparrow=6oh;lu\nUpdownarrow=6ol;m8\nUpperLeftArrow=6mu;ih\nUpperRightArrow=6mv;ik\nUpsi=r6;9z\nUpsilon=px;8w\nUring=a6;7e\nUscr=2kkw;1jo\nUtilde=a0;78\nUuml=64;3h\nVDash=6uj;y3\nVbar=8h7;1iw\nVcy=sy;ax\nVdash=6uh;y1\nVdashl=8h2;1is\nVee=6v5;z3\nVerbar=6c6;dp\nVert=6c6;dq\nVerticalBar=6qr;on\nVerticalLine=3g;18\nVerticalSeparator=7rs;16o\nVerticalTilde=6rk;qi\nVeryThinSpace=6bu;d9\nVfr=2knt;1ky\nVopf=2kp9;1m7\nVscr=2kkx;1jp\nVvdash=6ui;y2\nWcirc=ac;7k\nWedge=6v4;z0\nWfr=2knu;1kz\nWopf=2kpa;1m8\nWscr=2kky;1jq\nXfr=2knv;1l0\nXi=pq;8q\nXopf=2kpb;1m9\nXscr=2kkz;1jr\nYAcy=tr;bq\nYIcy=sn;an\nYUcy=tq;bp\nYacute=65;3i\nYcirc=ae;7m\nYcy=tn;bm\nYfr=2knw;1l1\nYopf=2kpc;1ma\nYscr=2kl0;1js\nYuml=ag;7o\nZHcy=t2;b1\nZacute=ah;7p\nZcaron=al;7t\nZcy=t3;b2\nZdot=aj;7r\nZeroWidthSpace=6bv;df\nZeta=pi;8i\nZfr=6js;gl\nZopf=6jo;gi\nZscr=2kl1;1jt\naacute=69;3m\nabreve=77;4l\nac=6ri;qg\nacE=6ri,mr;qe\nacd=6rj;qh\nacirc=6a;3n\nacute=50;28\nacy=ts;br\naelig=6e;3r\naf=6e9;ex\nafr=2kny;1l2\nagrave=68;3l\nalefsym=6k5;h3\naleph=6k5;h4\nalpha=q9;92\namacr=75;4j\namalg=8cf;1dm\namp=12;9\nand=6qv;p6\nandand=8d1;1e3\nandd=8d8;1e9\nandslope=8d4;1e6\nandv=8d6;1e7\nang=6qo;oj\nange=884;1b1\nangle=6qo;oi\nangmsd=6qp;ol\nangmsdaa=888;1b5\nangmsdab=889;1b6\nangmsdac=88a;1b7\nangmsdad=88b;1b8\nangmsdae=88c;1b9\nangmsdaf=88d;1ba\nangmsdag=88e;1bb\nangmsdah=88f;1bc\nangrt=6qn;og\nangrtvb=6v2;yw\nangrtvbd=87x;1b0\nangsph=6qq;om\nangst=5h;2u\nangzarr=70c;12z\naogon=79;4n\naopf=2kpe;1mb\nap=6rs;r8\napE=8ds;1ej\napacir=8dr;1eh\nape=6ru;rd\napid=6rv;rf\napos=13;a\napprox=6rs;r5\napproxeq=6ru;rc\naring=6d;3q\nascr=2kl2;1ju\nast=16;e\nasymp=6rs;r6\nasympeq=6rx;rj\natilde=6b;3o\nauml=6c;3p\nawconint=6r7;ps\nawint=8b5;1cr\nbNot=8h9;1iy\nbackcong=6rw;rg\nbackepsilon=s6;af\nbackprime=6d1;ei\nbacksim=6rh;qc\nbacksimeq=6vh;zp\nbarvee=6v1;yv\nbarwed=6x1;11y\nbarwedge=6x1;11x\nbbrk=71x;137\nbbrktbrk=71y;138\nbcong=6rw;rh\nbcy=tt;bs\nbdquo=6ce;e4\nbecaus=6r9;py\nbecause=6r9;px\nbemptyv=88g;1bd\nbepsi=s6;ag\nbernou=6jw;go\nbeta=qa;93\nbeth=6k6;h5\nbetween=6ss;tt\nbfr=2knz;1l3\nbigcap=6v6;z5\nbigcirc=7hr;15s\nbigcup=6v7;z7\nbigodot=8ao;1cd\nbigoplus=8ap;1cf\nbigotimes=8aq;1ch\nbigsqcup=8au;1cl\nbigstar=7id;15z\nbigtriangledown=7gd;15e\nbigtriangleup=7g3;154\nbiguplus=8as;1cj\nbigvee=6v5;z1\nbigwedge=6v4;yy\nbkarow=83x;17x\nblacklozenge=8a3;1c9\nblacksquare=7fu;14x\nblacktriangle=7g4;156\nblacktriangledown=7ge;15g\nblacktriangleleft=7gi;15k\nblacktriangleright=7g8;15a\nblank=74z;13f\nblk12=7f6;14r\nblk14=7f5;14q\nblk34=7f7;14s\nblock=7ew;14p\nbne=1p,6hx;o\nbnequiv=6sh,6hx;sm\nbnot=6xc;12d\nbopf=2kpf;1mc\nbot=6ud;xx\nbottom=6ud;xu\nbowtie=6vc;zi\nboxDL=7dj;141\nboxDR=7dg;13y\nboxDl=7di;140\nboxDr=7df;13x\nboxH=7dc;13u\nboxHD=7dy;14g\nboxHU=7e1;14j\nboxHd=7dw;14e\nboxHu=7dz;14h\nboxUL=7dp;147\nboxUR=7dm;144\nboxUl=7do;146\nboxUr=7dl;143\nboxV=7dd;13v\nboxVH=7e4;14m\nboxVL=7dv;14d\nboxVR=7ds;14a\nboxVh=7e3;14l\nboxVl=7du;14c\nboxVr=7dr;149\nboxbox=895;1bw\nboxdL=7dh;13z\nboxdR=7de;13w\nboxdl=7bk;13m\nboxdr=7bg;13l\nboxh=7b4;13j\nboxhD=7dx;14f\nboxhU=7e0;14i\nboxhd=7cc;13r\nboxhu=7ck;13s\nboxminus=6u7;xi\nboxplus=6u6;xg\nboxtimes=6u8;xk\nboxuL=7dn;145\nboxuR=7dk;142\nboxul=7bs;13o\nboxur=7bo;13n\nboxv=7b6;13k\nboxvH=7e2;14k\nboxvL=7dt;14b\nboxvR=7dq;148\nboxvh=7cs;13t\nboxvl=7c4;13q\nboxvr=7bw;13p\nbprime=6d1;ej\nbreve=k8;83\nbrvbar=4m;1k\nbscr=2kl3;1jv\nbsemi=6dr;er\nbsim=6rh;qd\nbsime=6vh;zq\nbsol=2k;x\nbsolb=891;1bv\nbsolhsub=7uw;16r\nbull=6ci;e9\nbullet=6ci;e8\nbump=6ry;rp\nbumpE=8fi;1gu\nbumpe=6rz;ru\nbumpeq=6rz;rt\ncacute=7b;4p\ncap=6qx;pa\ncapand=8ck;1dq\ncapbrcup=8cp;1dv\ncapcap=8cr;1dx\ncapcup=8cn;1dt\ncapdot=8cg;1dn\ncaps=6qx,1e68;p9\ncaret=6dd;eo\ncaron=jr;81\nccaps=8ct;1dz\nccaron=7h;4v\nccedil=6f;3s\nccirc=7d;4r\nccups=8cs;1dy\nccupssm=8cw;1e0\ncdot=7f;4t\ncedil=54;2f\ncemptyv=88i;1bf\ncent=4i;1g\ncenterdot=53;2c\ncfr=2ko0;1l4\nchcy=uf;ce\ncheck=7pv;16j\ncheckmark=7pv;16i\nchi=qv;9s\ncir=7gr;15q\ncirE=88z;1bt\ncirc=jq;7z\ncirceq=6s7;sc\ncirclearrowleft=6nu;k6\ncirclearrowright=6nv;k8\ncircledR=4u;1w\ncircledS=79k;13g\ncircledast=6u3;xc\ncircledcirc=6u2;xa\ncircleddash=6u5;xe\ncire=6s7;sd\ncirfnint=8b4;1cq\ncirmid=8hb;1j0\ncirscir=88y;1bs\nclubs=7kz;168\nclubsuit=7kz;167\ncolon=1m;j\ncolone=6s4;s7\ncoloneq=6s4;s5\ncomma=18;g\ncommat=1s;u\ncomp=6pt;mv\ncompfn=6qg;o7\ncomplement=6pt;mu\ncomplexes=6iq;f6\ncong=6rp;qz\ncongdot=8dp;1ef\nconint=6r2;pj\ncopf=2kpg;1md\ncoprod=6q8;nr\ncopy=4p;1r\ncopysr=6jb;fz\ncrarr=6np;k1\ncross=7pz;16k\ncscr=2kl4;1jw\ncsub=8gf;1id\ncsube=8gh;1if\ncsup=8gg;1ie\ncsupe=8gi;1ig\nctdot=6wf;11g\ncudarrl=854;18x\ncudarrr=851;18u\ncuepr=6vy;10m\ncuesc=6vz;10o\ncularr=6nq;k3\ncularrp=859;190\ncup=6qy;pc\ncupbrcap=8co;1du\ncupcap=8cm;1ds\ncupcup=8cq;1dw\ncupdot=6tp;we\ncupor=8cl;1dr\ncups=6qy,1e68;pb\ncurarr=6nr;k5\ncurarrm=858;18z\ncurlyeqprec=6vy;10l\ncurlyeqsucc=6vz;10n\ncurlyvee=6vi;zr\ncurlywedge=6vj;zt\ncurren=4k;1i\ncurvearrowleft=6nq;k2\ncurvearrowright=6nr;k4\ncuvee=6vi;zs\ncuwed=6vj;zu\ncwconint=6r6;pq\ncwint=6r5;po\ncylcty=6y5;12u\ndArr=6oj;m2\ndHar=86d;19t\ndagger=6cg;e5\ndaleth=6k8;h7\ndarr=6mr;ia\ndash=6c0;dl\ndashv=6ub;xr\ndbkarow=83z;180\ndblac=kd;8b\ndcaron=7j;4x\ndcy=tw;bv\ndd=6km;hb\nddagger=6ch;e6\nddarr=6oa;ld\nddotseq=8dz;1ep\ndeg=4w;21\ndelta=qc;95\ndemptyv=88h;1be\ndfisht=873;1aj\ndfr=2ko1;1l5\ndharl=6o3;kx\ndharr=6o2;ku\ndiam=6v8;zc\ndiamond=6v8;zb\ndiamondsuit=7l2;16b\ndiams=7l2;16c\ndie=4o;1o\ndigamma=rh;a6\ndisin=6wi;11j\ndiv=6v;49\ndivide=6v;48\ndivideontimes=6vb;zg\ndivonx=6vb;zh\ndjcy=uq;co\ndlcorn=6xq;12n\ndlcrop=6x9;12a\ndollar=10;6\ndopf=2kph;1me\ndot=k9;85\ndoteq=6s0;rx\ndoteqdot=6s1;rz\ndotminus=6rc;q2\ndotplus=6qc;ny\ndotsquare=6u9;xm\ndoublebarwedge=6x2;11z\ndownarrow=6mr;i9\ndowndownarrows=6oa;lc\ndownharpoonleft=6o3;kv\ndownharpoonright=6o2;ks\ndrbkarow=840;182\ndrcorn=6xr;12p\ndrcrop=6x8;129\ndscr=2kl5;1jx\ndscy=ut;cr\ndsol=8ae;1cc\ndstrok=7l;4z\ndtdot=6wh;11i\ndtri=7gf;15j\ndtrif=7ge;15h\nduarr=6ph;mo\nduhar=86n;1a5\ndwangle=886;1b3\ndzcy=v3;d0\ndzigrarr=7wf;17r\neDDot=8dz;1eq\neDot=6s1;s0\neacute=6h;3u\neaster=8dq;1eg\necaron=7v;57\necir=6s6;sb\necirc=6i;3v\necolon=6s5;s9\necy=ul;ck\nedot=7r;53\nee=6kn;he\nefDot=6s2;s2\nefr=2ko2;1l6\neg=8ey;1g9\negrave=6g;3t\negs=8eu;1g5\negsdot=8ew;1g7\nel=8ex;1g8\nelinters=73b;13e\nell=6j7;fv\nels=8et;1g3\nelsdot=8ev;1g6\nemacr=7n;51\nempty=6px;n7\nemptyset=6px;n5\nemptyv=6px;n6\nemsp=6bn;d2\nemsp13=6bo;d3\nemsp14=6bp;d4\neng=97;6h\nensp=6bm;d1\neogon=7t;55\neopf=2kpi;1mf\nepar=6vp;103\neparsl=89v;1c6\neplus=8dt;1ek\nepsi=qd;97\nepsilon=qd;96\nepsiv=s5;ae\neqcirc=6s6;sa\neqcolon=6s5;s8\neqsim=6rm;qq\neqslantgtr=8eu;1g4\neqslantless=8et;1g2\nequals=1p;p\nequest=6sf;sj\nequiv=6sh;so\nequivDD=8e0;1er\neqvparsl=89x;1c8\nerDot=6s3;s4\nerarr=86p;1a7\nescr=6jz;gs\nesdot=6s0;ry\nesim=6rm;qr\neta=qf;99\neth=6o;41\neuml=6j;3w\neuro=6gc;f2\nexcl=x;2\nexist=6pv;n0\nexpectation=6k0;gt\nexponentiale=6kn;hd\nfallingdotseq=6s2;s1\nfcy=uc;cb\nfemale=7k0;163\nffilig=1dkz;1ja\nfflig=1dkw;1j7\nffllig=1dl0;1jb\nffr=2ko3;1l7\nfilig=1dkx;1j8\nfjlig=2u,2y;15\nflat=7l9;16e\nfllig=1dky;1j9\nfltns=7g1;153\nfnof=b6;7v\nfopf=2kpj;1mg\nforall=6ps;mt\nfork=6vo;102\nforkv=8gp;1in\nfpartint=8b1;1cp\nfrac12=59;2k\nfrac13=6kz;hh\nfrac14=58;2j\nfrac15=6l1;hj\nfrac16=6l5;hn\nfrac18=6l7;hp\nfrac23=6l0;hi\nfrac25=6l2;hk\nfrac34=5a;2m\nfrac35=6l3;hl\nfrac38=6l8;hq\nfrac45=6l4;hm\nfrac56=6l6;ho\nfrac58=6l9;hr\nfrac78=6la;hs\nfrasl=6dg;eq\nfrown=6xu;12r\nfscr=2kl7;1jy\ngE=6sn;t8\ngEl=8ek;1ft\ngacute=dx;7x\ngamma=qb;94\ngammad=rh;a7\ngap=8ee;1fh\ngbreve=7z;5b\ngcirc=7x;59\ngcy=tv;bu\ngdot=81;5d\nge=6sl;sx\ngel=6vv;10k\ngeq=6sl;sw\ngeqq=6sn;t7\ngeqslant=8e6;1f6\nges=8e6;1f7\ngescc=8fd;1gn\ngesdot=8e8;1f9\ngesdoto=8ea;1fb\ngesdotol=8ec;1fd\ngesl=6vv,1e68;10h\ngesles=8es;1g1\ngfr=2ko4;1l8\ngg=6sr;ts\nggg=6vt;10b\ngimel=6k7;h6\ngjcy=ur;cp\ngl=6t3;un\nglE=8eq;1fz\ngla=8f9;1gj\nglj=8f8;1gi\ngnE=6sp;tg\ngnap=8ei;1fp\ngnapprox=8ei;1fo\ngne=8eg;1fl\ngneq=8eg;1fk\ngneqq=6sp;tf\ngnsim=6w7;10y\ngopf=2kpk;1mh\ngrave=2o;14\ngscr=6iy;f9\ngsim=6sz;ud\ngsime=8em;1fv\ngsiml=8eo;1fx\ngt=1q;s\ngtcc=8fb;1gl\ngtcir=8e2;1et\ngtdot=6vr;107\ngtlPar=87p;1aw\ngtquest=8e4;1ev\ngtrapprox=8ee;1fg\ngtrarr=86w;1ad\ngtrdot=6vr;106\ngtreqless=6vv;10j\ngtreqqless=8ek;1fs\ngtrless=6t3;um\ngtrsim=6sz;uc\ngvertneqq=6sp,1e68;td\ngvnE=6sp,1e68;te\nhArr=6ok;m5\nhairsp=6bu;da\nhalf=59;2l\nhamilt=6iz;fb\nhardcy=ui;ch\nharr=6ms;id\nharrcir=85k;192\nharrw=6nh;js\nhbar=6j3;fl\nhcirc=85;5g\nhearts=7l1;16a\nheartsuit=7l1;169\nhellip=6cm;eb\nhercon=6ux;yr\nhfr=2ko5;1l9\nhksearow=84l;18i\nhkswarow=84m;18k\nhoarr=6pr;mr\nhomtht=6rf;q5\nhookleftarrow=6nd;jj\nhookrightarrow=6ne;jl\nhopf=2kpl;1mi\nhorbar=6c5;do\nhscr=2kl9;1jz\nhslash=6j3;fi\nhstrok=87;5i\nhybull=6df;ep\nhyphen=6c0;dk\niacute=6l;3y\nic=6eb;f1\nicirc=6m;3z\nicy=u0;bz\niecy=tx;bw\niexcl=4h;1f\niff=6ok;m6\nifr=2ko6;1la\nigrave=6k;3x\nii=6ko;hg\niiiint=8b0;1cn\niiint=6r1;pg\niinfin=89o;1c3\niiota=6jt;gm\nijlig=8j;5t\nimacr=8b;5m\nimage=6j5;fp\nimagline=6j4;fm\nimagpart=6j5;fo\nimath=8h;5r\nimof=6uv;yo\nimped=c5;7w\nin=6q0;nd\nincare=6it;f8\ninfin=6qm;of\ninfintie=89p;1c4\ninodot=8h;5q\nint=6qz;pe\nintcal=6uy;yt\nintegers=6jo;gh\nintercal=6uy;ys\nintlarhk=8bb;1cx\nintprod=8cc;1dk\niocy=up;cn\niogon=8f;5o\niopf=2kpm;1mj\niota=qh;9b\niprod=8cc;1dl\niquest=5b;2n\niscr=2kla;1k0\nisin=6q0;nc\nisinE=6wp;11r\nisindot=6wl;11n\nisins=6wk;11l\nisinsv=6wj;11k\nisinv=6q0;nb\nit=6ea;ez\nitilde=89;5k\niukcy=uu;cs\niuml=6n;40\njcirc=8l;5v\njcy=u1;c0\njfr=2ko7;1lb\njmath=fr;7y\njopf=2kpn;1mk\njscr=2klb;1k1\njsercy=uw;cu\njukcy=us;cq\nkappa=qi;9c\nkappav=s0;a9\nkcedil=8n;5x\nkcy=u2;c1\nkfr=2ko8;1lc\nkgreen=8o;5y\nkhcy=ud;cc\nkjcy=v0;cy\nkopf=2kpo;1ml\nkscr=2klc;1k2\nlAarr=6oq;mf\nlArr=6og;ls\nlAtail=84b;18a\nlBarr=83y;17z\nlE=6sm;t2\nlEg=8ej;1fr\nlHar=86a;19q\nlacute=8q;60\nlaemptyv=88k;1bh\nlagran=6j6;ft\nlambda=qj;9d\nlang=7vs;16z\nlangd=87l;1as\nlangle=7vs;16y\nlap=8ed;1ff\nlaquo=4r;1t\nlarr=6mo;hx\nlarrb=6p0;mk\nlarrbfs=84f;18e\nlarrfs=84d;18c\nlarrhk=6nd;jk\nlarrlp=6nf;jo\nlarrpl=855;18y\nlarrsim=86r;1a9\nlarrtl=6n6;j7\nlat=8ff;1gp\nlatail=849;188\nlate=8fh;1gt\nlates=8fh,1e68;1gs\nlbarr=83w;17w\nlbbrk=7si;16p\nlbrace=3f;16\nlbrack=2j;v\nlbrke=87f;1am\nlbrksld=87j;1aq\nlbrkslu=87h;1ao\nlcaron=8u;64\nlcedil=8s;62\nlceil=6x4;122\nlcub=3f;17\nlcy=u3;c2\nldca=852;18v\nldquo=6cc;dz\nldquor=6ce;e3\nldrdhar=86f;19v\nldrushar=85n;195\nldsh=6nm;jz\nle=6sk;st\nleftarrow=6mo;hv\nleftarrowtail=6n6;j6\nleftharpoondown=6nx;kd\nleftharpoonup=6nw;ka\nleftleftarrows=6o7;l6\nleftrightarrow=6ms;ic\nleftrightarrows=6o6;l4\nleftrightharpoons=6ob;lf\nleftrightsquigarrow=6nh;jr\nleftthreetimes=6vf;zl\nleg=6vu;10g\nleq=6sk;ss\nleqq=6sm;t1\nleqslant=8e5;1f0\nles=8e5;1f1\nlescc=8fc;1gm\nlesdot=8e7;1f8\nlesdoto=8e9;1fa\nlesdotor=8eb;1fc\nlesg=6vu,1e68;10d\nlesges=8er;1g0\nlessapprox=8ed;1fe\nlessdot=6vq;104\nlesseqgtr=6vu;10f\nlesseqqgtr=8ej;1fq\nlessgtr=6t2;uj\nlesssim=6sy;u9\nlfisht=870;1ag\nlfloor=6x6;126\nlfr=2ko9;1ld\nlg=6t2;uk\nlgE=8ep;1fy\nlhard=6nx;kf\nlharu=6nw;kc\nlharul=86i;19y\nlhblk=7es;14o\nljcy=ux;cv\nll=6sq;tm\nllarr=6o7;l7\nllcorner=6xq;12m\nllhard=86j;19z\nlltri=7i2;15w\nlmidot=8w;66\nlmoust=71s;131\nlmoustache=71s;130\nlnE=6so;tc\nlnap=8eh;1fn\nlnapprox=8eh;1fm\nlne=8ef;1fj\nlneq=8ef;1fi\nlneqq=6so;tb\nlnsim=6w6;10x\nloang=7vw;175\nloarr=6pp;mp\nlobrk=7vq;16u\nlongleftarrow=7w5;178\nlongleftrightarrow=7w7;17e\nlongmapsto=7wc;17p\nlongrightarrow=7w6;17b\nlooparrowleft=6nf;jn\nlooparrowright=6ng;jp\nlopar=879;1ak\nlopf=2kpp;1mm\nloplus=8bx;1d6\nlotimes=8c4;1dc\nlowast=6qf;o5\nlowbar=2n;12\nloz=7gq;15p\nlozenge=7gq;15o\nlozf=8a3;1ca\nlpar=14;b\nlparlt=87n;1au\nlrarr=6o6;l5\nlrcorner=6xr;12o\nlrhar=6ob;lg\nlrhard=86l;1a1\nlrm=6by;di\nlrtri=6v3;yx\nlsaquo=6d5;ek\nlscr=2kld;1k3\nlsh=6nk;jw\nlsim=6sy;ua\nlsime=8el;1fu\nlsimg=8en;1fw\nlsqb=2j;w\nlsquo=6c8;ds\nlsquor=6ca;dw\nlstrok=8y;68\nlt=1o;n\nltcc=8fa;1gk\nltcir=8e1;1es\nltdot=6vq;105\nlthree=6vf;zm\nltimes=6vd;zj\nltlarr=86u;1ac\nltquest=8e3;1eu\nltrPar=87q;1ax\nltri=7gj;15n\nltrie=6us;yi\nltrif=7gi;15l\nlurdshar=85m;194\nluruhar=86e;19u\nlvertneqq=6so,1e68;t9\nlvnE=6so,1e68;ta\nmDDot=6re;q4\nmacr=4v;20\nmale=7k2;164\nmalt=7q8;16m\nmaltese=7q8;16l\nmap=6na;jg\nmapsto=6na;jf\nmapstodown=6nb;ji\nmapstoleft=6n8;jb\nmapstoup=6n9;jd\nmarker=7fy;152\nmcomma=8bt;1d4\nmcy=u4;c3\nmdash=6c4;dn\nmeasuredangle=6qp;ok\nmfr=2koa;1le\nmho=6jr;gj\nmicro=51;29\nmid=6qr;oq\nmidast=16;d\nmidcir=8hc;1j1\nmiddot=53;2d\nminus=6qa;nu\nminusb=6u7;xj\nminusd=6rc;q3\nminusdu=8bu;1d5\nmlcp=8gr;1ip\nmldr=6cm;ec\nmnplus=6qb;nw\nmodels=6uf;xy\nmopf=2kpq;1mn\nmp=6qb;nx\nmscr=2kle;1k4\nmstpos=6ri;qf\nmu=qk;9e\nmultimap=6uw;yp\nmumap=6uw;yq\nnGg=6vt,mw;10a\nnGt=6sr,6he;tp\nnGtv=6sr,mw;to\nnLeftarrow=6od;lk\nnLeftrightarrow=6oe;lm\nnLl=6vs,mw;108\nnLt=6sq,6he;tj\nnLtv=6sq,mw;ti\nnRightarrow=6of;lo\nnVDash=6un;y7\nnVdash=6um;y6\nnabla=6pz;n8\nnacute=90;6a\nnang=6qo,6he;oh\nnap=6rt;rb\nnapE=8ds,mw;1ei\nnapid=6rv,mw;re\nnapos=95;6f\nnapprox=6rt;ra\nnatur=7la;16g\nnatural=7la;16f\nnaturals=6j9;fw\nnbsp=4g;1e\nnbump=6ry,mw;rm\nnbumpe=6rz,mw;rr\nncap=8cj;1dp\nncaron=94;6e\nncedil=92;6c\nncong=6rr;r2\nncongdot=8dp,mw;1ee\nncup=8ci;1do\nncy=u5;c4\nndash=6c3;dm\nne=6sg;sl\nneArr=6on;mb\nnearhk=84k;18h\nnearr=6mv;im\nnearrow=6mv;il\nnedot=6s0,mw;rv\nnequiv=6si;sq\nnesear=84o;18n\nnesim=6rm,mw;qo\nnexist=6pw;n3\nnexists=6pw;n2\nnfr=2kob;1lf\nngE=6sn,mw;t4\nnge=6sx;u7\nngeq=6sx;u6\nngeqq=6sn,mw;t5\nngeqslant=8e6,mw;1f3\nnges=8e6,mw;1f4\nngsim=6t1;uh\nngt=6sv;u1\nngtr=6sv;u0\nnhArr=6oe;ln\nnharr=6ni;ju\nnhpar=8he;1j3\nni=6q3;nk\nnis=6ws;11u\nnisd=6wq;11s\nniv=6q3;nj\nnjcy=uy;cw\nnlArr=6od;ll\nnlE=6sm,mw;sy\nnlarr=6my;iu\nnldr=6cl;ea\nnle=6sw;u4\nnleftarrow=6my;it\nnleftrightarrow=6ni;jt\nnleq=6sw;u3\nnleqq=6sm,mw;sz\nnleqslant=8e5,mw;1ex\nnles=8e5,mw;1ey\nnless=6su;tx\nnlsim=6t0;uf\nnlt=6su;ty\nnltri=6wa;115\nnltrie=6wc;11b\nnmid=6qs;ou\nnopf=2kpr;1mo\nnot=4s;1u\nnotin=6q1;ng\nnotinE=6wp,mw;11q\nnotindot=6wl,mw;11m\nnotinva=6q1;nf\nnotinvb=6wn;11p\nnotinvc=6wm;11o\nnotni=6q4;nn\nnotniva=6q4;nm\nnotnivb=6wu;11w\nnotnivc=6wt;11v\nnpar=6qu;p4\nnparallel=6qu;p2\nnparsl=8hp,6hx;1j5\nnpart=6pu,mw;mw\nnpolint=8b8;1cu\nnpr=6tc;vd\nnprcue=6w0;10q\nnpre=8fj,mw;1gw\nnprec=6tc;vc\nnpreceq=8fj,mw;1gx\nnrArr=6of;lp\nnrarr=6mz;iw\nnrarrc=84z,mw;18s\nnrarrw=6n1,mw;ix\nnrightarrow=6mz;iv\nnrtri=6wb;118\nnrtrie=6wd;11e\nnsc=6td;vg\nnsccue=6w1;10s\nnsce=8fk,mw;1h2\nnscr=2klf;1k5\nnshortmid=6qs;os\nnshortparallel=6qu;p1\nnsim=6rl;qm\nnsime=6ro;qx\nnsimeq=6ro;qw\nnsmid=6qs;ot\nnspar=6qu;p3\nnsqsube=6w2;10u\nnsqsupe=6w3;10w\nnsub=6tg;vs\nnsubE=8g5,mw;1hv\nnsube=6tk;w2\nnsubset=6te,6he;vi\nnsubseteq=6tk;w1\nnsubseteqq=8g5,mw;1hw\nnsucc=6td;vf\nnsucceq=8fk,mw;1h3\nnsup=6th;vt\nnsupE=8g6,mw;1hz\nnsupe=6tl;w5\nnsupset=6tf,6he;vn\nnsupseteq=6tl;w4\nnsupseteqq=8g6,mw;1i0\nntgl=6t5;ur\nntilde=6p;42\nntlg=6t4;up\nntriangleleft=6wa;114\nntrianglelefteq=6wc;11a\nntriangleright=6wb;117\nntrianglerighteq=6wd;11d\nnu=ql;9f\nnum=z;5\nnumero=6ja;fy\nnumsp=6br;d5\nnvDash=6ul;y5\nnvHarr=83o;17u\nnvap=6rx,6he;ri\nnvdash=6uk;y4\nnvge=6sl,6he;su\nnvgt=1q,6he;q\nnvinfin=89q;1c5\nnvlArr=83m;17s\nnvle=6sk,6he;sr\nnvlt=1o,6he;l\nnvltrie=6us,6he;yf\nnvrArr=83n;17t\nnvrtrie=6ut,6he;yj\nnvsim=6rg,6he;q6\nnwArr=6om;ma\nnwarhk=84j;18g\nnwarr=6mu;ij\nnwarrow=6mu;ii\nnwnear=84n;18m\noS=79k;13h\noacute=6r;44\noast=6u3;xd\nocir=6u2;xb\nocirc=6s;45\nocy=u6;c5\nodash=6u5;xf\nodblac=9d;6l\nodiv=8c8;1dg\nodot=6u1;x9\nodsold=88s;1bn\noelig=9f;6n\nofcir=88v;1bp\nofr=2koc;1lg\nogon=kb;87\nograve=6q;43\nogt=88x;1br\nohbar=88l;1bi\nohm=q1;91\noint=6r2;pk\nolarr=6nu;k7\nolcir=88u;1bo\nolcross=88r;1bm\noline=6da;en\nolt=88w;1bq\nomacr=99;6j\nomega=qx;9u\nomicron=qn;9h\nomid=88m;1bj\nominus=6ty;x4\noopf=2kps;1mp\nopar=88n;1bk\noperp=88p;1bl\noplus=6tx;x2\nor=6qw;p8\norarr=6nv;k9\nord=8d9;1ea\norder=6k4;h1\norderof=6k4;h0\nordf=4q;1s\nordm=56;2h\norigof=6uu;yn\noror=8d2;1e4\norslope=8d3;1e5\norv=8d7;1e8\noscr=6k4;h2\noslash=6w;4a\nosol=6u0;x7\notilde=6t;46\notimes=6tz;x6\notimesas=8c6;1de\nouml=6u;47\novbar=6yl;12x\npar=6qt;oz\npara=52;2a\nparallel=6qt;ox\nparsim=8hf;1j4\nparsl=8hp;1j6\npart=6pu;my\npcy=u7;c6\npercnt=11;7\nperiod=1a;h\npermil=6cw;ed\nperp=6ud;xw\npertenk=6cx;ee\npfr=2kod;1lh\nphi=qu;9r\nphiv=r9;a2\nphmmat=6k3;gy\nphone=7im;162\npi=qo;9i\npitchfork=6vo;101\npiv=ra;a4\nplanck=6j3;fj\nplanckh=6j2;fh\nplankv=6j3;fk\nplus=17;f\nplusacir=8bn;1cz\nplusb=6u6;xh\npluscir=8bm;1cy\nplusdo=6qc;nz\nplusdu=8bp;1d1\npluse=8du;1el\nplusmn=4x;23\nplussim=8bq;1d2\nplustwo=8br;1d3\npm=4x;24\npointint=8b9;1cv\npopf=2kpt;1mq\npound=4j;1h\npr=6t6;uu\nprE=8fn;1h7\nprap=8fr;1he\nprcue=6t8;v0\npre=8fj;1h0\nprec=6t6;ut\nprecapprox=8fr;1hd\npreccurlyeq=6t8;uz\npreceq=8fj;1gz\nprecnapprox=8ft;1hh\nprecneqq=8fp;1h9\nprecnsim=6w8;10z\nprecsim=6ta;v5\nprime=6cy;ef\nprimes=6jd;g2\nprnE=8fp;1ha\nprnap=8ft;1hi\nprnsim=6w8;110\nprod=6q7;np\nprofalar=6y6;12v\nprofline=6xe;12e\nprofsurf=6xf;12f\nprop=6ql;oe\npropto=6ql;oc\nprsim=6ta;v6\nprurel=6uo;y8\npscr=2klh;1k6\npsi=qw;9t\npuncsp=6bs;d6\nqfr=2koe;1li\nqint=8b0;1co\nqopf=2kpu;1mr\nqprime=6dz;es\nqscr=2kli;1k7\nquaternions=6j1;ff\nquatint=8ba;1cw\nquest=1r;t\nquesteq=6sf;si\nquot=y;4\nrAarr=6or;mh\nrArr=6oi;lz\nrAtail=84c;18b\nrBarr=83z;181\nrHar=86c;19s\nrace=6rh,mp;qb\nracute=9h;6p\nradic=6qi;o8\nraemptyv=88j;1bg\nrang=7vt;172\nrangd=87m;1at\nrange=885;1b2\nrangle=7vt;171\nraquo=57;2i\nrarr=6mq;i6\nrarrap=86t;1ab\nrarrb=6p1;mm\nrarrbfs=84g;18f\nrarrc=84z;18t\nrarrfs=84e;18d\nrarrhk=6ne;jm\nrarrlp=6ng;jq\nrarrpl=85h;191\nrarrsim=86s;1aa\nrarrtl=6n7;j9\nrarrw=6n1;iz\nratail=84a;189\nratio=6ra;pz\nrationals=6je;g4\nrbarr=83x;17y\nrbbrk=7sj;16q\nrbrace=3h;1b\nrbrack=2l;y\nrbrke=87g;1an\nrbrksld=87i;1ap\nrbrkslu=87k;1ar\nrcaron=9l;6t\nrcedil=9j;6r\nrceil=6x5;124\nrcub=3h;1c\nrcy=u8;c7\nrdca=853;18w\nrdldhar=86h;19x\nrdquo=6cd;e2\nrdquor=6cd;e1\nrdsh=6nn;k0\nreal=6jg;g9\nrealine=6jf;g6\nrealpart=6jg;g8\nreals=6jh;gc\nrect=7fx;151\nreg=4u;1y\nrfisht=871;1ah\nrfloor=6x7;128\nrfr=2kof;1lj\nrhard=6o1;kr\nrharu=6o0;ko\nrharul=86k;1a0\nrho=qp;9j\nrhov=s1;ab\nrightarrow=6mq;i4\nrightarrowtail=6n7;j8\nrightharpoondown=6o1;kp\nrightharpoonup=6o0;km\nrightleftarrows=6o4;kz\nrightleftharpoons=6oc;lh\nrightrightarrows=6o9;la\nrightsquigarrow=6n1;iy\nrightthreetimes=6vg;zn\nring=ka;86\nrisingdotseq=6s3;s3\nrlarr=6o4;l0\nrlhar=6oc;lj\nrlm=6bz;dj\nrmoust=71t;133\nrmoustache=71t;132\nrnmid=8ha;1iz\nroang=7vx;176\nroarr=6pq;mq\nrobrk=7vr;16w\nropar=87a;1al\nropf=2kpv;1ms\nroplus=8by;1d7\nrotimes=8c5;1dd\nrpar=15;c\nrpargt=87o;1av\nrppolint=8b6;1cs\nrrarr=6o9;lb\nrsaquo=6d6;el\nrscr=2klj;1k8\nrsh=6nl;jy\nrsqb=2l;z\nrsquo=6c9;dv\nrsquor=6c9;du\nrthree=6vg;zo\nrtimes=6ve;zk\nrtri=7g9;15d\nrtrie=6ut;ym\nrtrif=7g8;15b\nrtriltri=89a;1by\nruluhar=86g;19w\nrx=6ji;ge\nsacute=9n;6v\nsbquo=6ca;dx\nsc=6t7;ux\nscE=8fo;1h8\nscap=8fs;1hg\nscaron=9t;71\nsccue=6t9;v3\nsce=8fk;1h6\nscedil=9r;6z\nscirc=9p;6x\nscnE=8fq;1hc\nscnap=8fu;1hk\nscnsim=6w9;112\nscpolint=8b7;1ct\nscsim=6tb;va\nscy=u9;c8\nsdot=6v9;zd\nsdotb=6u9;xn\nsdote=8di;1ec\nseArr=6oo;mc\nsearhk=84l;18j\nsearr=6mw;ip\nsearrow=6mw;io\nsect=4n;1l\nsemi=1n;k\nseswar=84p;18p\nsetminus=6qe;o2\nsetmn=6qe;o4\nsext=7qu;16n\nsfr=2kog;1lk\nsfrown=6xu;12q\nsharp=7lb;16h\nshchcy=uh;cg\nshcy=ug;cf\nshortmid=6qr;oo\nshortparallel=6qt;ow\nshy=4t;1v\nsigma=qr;9n\nsigmaf=qq;9l\nsigmav=qq;9m\nsim=6rg;qa\nsimdot=8dm;1ed\nsime=6rn;qu\nsimeq=6rn;qt\nsimg=8f2;1gb\nsimgE=8f4;1gd\nsiml=8f1;1ga\nsimlE=8f3;1gc\nsimne=6rq;r0\nsimplus=8bo;1d0\nsimrarr=86q;1a8\nslarr=6mo;hw\nsmallsetminus=6qe;o0\nsmashp=8c3;1db\nsmeparsl=89w;1c7\nsmid=6qr;op\nsmile=6xv;12t\nsmt=8fe;1go\nsmte=8fg;1gr\nsmtes=8fg,1e68;1gq\nsoftcy=uk;cj\nsol=1b;i\nsolb=890;1bu\nsolbar=6yn;12y\nsopf=2kpw;1mt\nspades=7kw;166\nspadesuit=7kw;165\nspar=6qt;oy\nsqcap=6tv;wx\nsqcaps=6tv,1e68;wv\nsqcup=6tw;x0\nsqcups=6tw,1e68;wy\nsqsub=6tr;wk\nsqsube=6tt;wr\nsqsubset=6tr;wj\nsqsubseteq=6tt;wq\nsqsup=6ts;wo\nsqsupe=6tu;wu\nsqsupset=6ts;wn\nsqsupseteq=6tu;wt\nsqu=7fl;14v\nsquare=7fl;14u\nsquarf=7fu;14y\nsquf=7fu;14z\nsrarr=6mq;i5\nsscr=2klk;1k9\nssetmn=6qe;o3\nssmile=6xv;12s\nsstarf=6va;ze\nstar=7ie;161\nstarf=7id;160\nstraightepsilon=s5;ac\nstraightphi=r9;a0\nstrns=4v;1z\nsub=6te;vl\nsubE=8g5;1hy\nsubdot=8fx;1hn\nsube=6ti;vw\nsubedot=8g3;1ht\nsubmult=8g1;1hr\nsubnE=8gb;1i8\nsubne=6tm;w9\nsubplus=8fz;1hp\nsubrarr=86x;1ae\nsubset=6te;vk\nsubseteq=6ti;vv\nsubseteqq=8g5;1hx\nsubsetneq=6tm;w8\nsubsetneqq=8gb;1i7\nsubsim=8g7;1i3\nsubsub=8gl;1ij\nsubsup=8gj;1ih\nsucc=6t7;uw\nsuccapprox=8fs;1hf\nsucccurlyeq=6t9;v2\nsucceq=8fk;1h5\nsuccnapprox=8fu;1hj\nsuccneqq=8fq;1hb\nsuccnsim=6w9;111\nsuccsim=6tb;v9\nsum=6q9;nt\nsung=7l6;16d\nsup=6tf;vr\nsup1=55;2g\nsup2=4y;25\nsup3=4z;26\nsupE=8g6;1i2\nsupdot=8fy;1ho\nsupdsub=8go;1im\nsupe=6tj;vz\nsupedot=8g4;1hu\nsuphsol=7ux;16s\nsuphsub=8gn;1il\nsuplarr=86z;1af\nsupmult=8g2;1hs\nsupnE=8gc;1ic\nsupne=6tn;wd\nsupplus=8g0;1hq\nsupset=6tf;vq\nsupseteq=6tj;vy\nsupseteqq=8g6;1i1\nsupsetneq=6tn;wc\nsupsetneqq=8gc;1ib\nsupsim=8g8;1i4\nsupsub=8gk;1ii\nsupsup=8gm;1ik\nswArr=6op;md\nswarhk=84m;18l\nswarr=6mx;is\nswarrow=6mx;ir\nswnwar=84q;18r\nszlig=67;3k\ntarget=6xi;12h\ntau=qs;9o\ntbrk=71w;135\ntcaron=9x;75\ntcedil=9v;73\ntcy=ua;c9\ntdot=6hn;f4\ntelrec=6xh;12g\ntfr=2koh;1ll\nthere4=6r8;pv\ntherefore=6r8;pu\ntheta=qg;9a\nthetasym=r5;9v\nthetav=r5;9x\nthickapprox=6rs;r3\nthicksim=6rg;q7\nthinsp=6bt;d8\nthkap=6rs;r7\nthksim=6rg;q8\nthorn=72;4g\ntilde=kc;89\ntimes=5z;3c\ntimesb=6u8;xl\ntimesbar=8c1;1da\ntimesd=8c0;1d9\ntint=6r1;ph\ntoea=84o;18o\ntop=6uc;xt\ntopbot=6ye;12w\ntopcir=8hd;1j2\ntopf=2kpx;1mu\ntopfork=8gq;1io\ntosa=84p;18q\ntprime=6d0;eh\ntrade=6jm;gg\ntriangle=7g5;158\ntriangledown=7gf;15i\ntriangleleft=7gj;15m\ntrianglelefteq=6us;yh\ntriangleq=6sc;sg\ntriangleright=7g9;15c\ntrianglerighteq=6ut;yl\ntridot=7ho;15r\ntrie=6sc;sh\ntriminus=8ca;1di\ntriplus=8c9;1dh\ntrisb=899;1bx\ntritime=8cb;1dj\ntrpezium=736;13d\ntscr=2kll;1ka\ntscy=ue;cd\ntshcy=uz;cx\ntstrok=9z;77\ntwixt=6ss;tu\ntwoheadleftarrow=6n2;j0\ntwoheadrightarrow=6n4;j3\nuArr=6oh;lv\nuHar=86b;19r\nuacute=6y;4c\nuarr=6mp;i1\nubrcy=v2;cz\nubreve=a5;7d\nucirc=6z;4d\nucy=ub;ca\nudarr=6o5;l2\nudblac=a9;7h\nudhar=86m;1a3\nufisht=872;1ai\nufr=2koi;1lm\nugrave=6x;4b\nuharl=6nz;kl\nuharr=6ny;ki\nuhblk=7eo;14n\nulcorn=6xo;12j\nulcorner=6xo;12i\nulcrop=6xb;12c\nultri=7i0;15u\numacr=a3;7b\numl=4o;1p\nuogon=ab;7j\nuopf=2kpy;1mv\nuparrow=6mp;i0\nupdownarrow=6mt;if\nupharpoonleft=6nz;kj\nupharpoonright=6ny;kg\nuplus=6tq;wg\nupsi=qt;9q\nupsih=r6;9y\nupsilon=qt;9p\nupuparrows=6o8;l8\nurcorn=6xp;12l\nurcorner=6xp;12k\nurcrop=6xa;12b\nuring=a7;7f\nurtri=7i1;15v\nuscr=2klm;1kb\nutdot=6wg;11h\nutilde=a1;79\nutri=7g5;159\nutrif=7g4;157\nuuarr=6o8;l9\nuuml=70;4e\nuwangle=887;1b4\nvArr=6ol;m9\nvBar=8h4;1iu\nvBarv=8h5;1iv\nvDash=6ug;y0\nvangrt=87w;1az\nvarepsilon=s5;ad\nvarkappa=s0;a8\nvarnothing=6px;n4\nvarphi=r9;a1\nvarpi=ra;a3\nvarpropto=6ql;ob\nvarr=6mt;ig\nvarrho=s1;aa\nvarsigma=qq;9k\nvarsubsetneq=6tm,1e68;w6\nvarsubsetneqq=8gb,1e68;1i5\nvarsupsetneq=6tn,1e68;wa\nvarsupsetneqq=8gc,1e68;1i9\nvartheta=r5;9w\nvartriangleleft=6uq;y9\nvartriangleright=6ur;yc\nvcy=tu;bt\nvdash=6ua;xp\nvee=6qw;p7\nveebar=6uz;yu\nveeeq=6sa;sf\nvellip=6we;11f\nverbar=3g;19\nvert=3g;1a\nvfr=2koj;1ln\nvltri=6uq;yb\nvnsub=6te,6he;vj\nvnsup=6tf,6he;vo\nvopf=2kpz;1mw\nvprop=6ql;od\nvrtri=6ur;ye\nvscr=2kln;1kc\nvsubnE=8gb,1e68;1i6\nvsubne=6tm,1e68;w7\nvsupnE=8gc,1e68;1ia\nvsupne=6tn,1e68;wb\nvzigzag=87u;1ay\nwcirc=ad;7l\nwedbar=8db;1eb\nwedge=6qv;p5\nwedgeq=6s9;se\nweierp=6jc;g0\nwfr=2kok;1lo\nwopf=2kq0;1mx\nwp=6jc;g1\nwr=6rk;qk\nwreath=6rk;qj\nwscr=2klo;1kd\nxcap=6v6;z6\nxcirc=7hr;15t\nxcup=6v7;z9\nxdtri=7gd;15f\nxfr=2kol;1lp\nxhArr=7wa;17o\nxharr=7w7;17f\nxi=qm;9g\nxlArr=7w8;17i\nxlarr=7w5;179\nxmap=7wc;17q\nxnis=6wr;11t\nxodot=8ao;1ce\nxopf=2kq1;1my\nxoplus=8ap;1cg\nxotime=8aq;1ci\nxrArr=7w9;17l\nxrarr=7w6;17c\nxscr=2klp;1ke\nxsqcup=8au;1cm\nxuplus=8as;1ck\nxutri=7g3;155\nxvee=6v5;z2\nxwedge=6v4;yz\nyacute=71;4f\nyacy=un;cm\nycirc=af;7n\nycy=uj;ci\nyen=4l;1j\nyfr=2kom;1lq\nyicy=uv;ct\nyopf=2kq2;1mz\nyscr=2klq;1kf\nyucy=um;cl\nyuml=73;4h\nzacute=ai;7q\nzcaron=am;7u\nzcy=tz;by\nzdot=ak;7s\nzeetrf=6js;gk\nzeta=qe;98\nzfr=2kon;1lr\nzhcy=ty;bx\nzigrarr=6ot;mi\nzopf=2kq3;1n0\nzscr=2klr;1kg\nzwj=6bx;dh\nzwnj=6bw;dg" - -} diff --git a/Pods/SwiftSoup/Sources/Evaluator.swift b/Pods/SwiftSoup/Sources/Evaluator.swift deleted file mode 100644 index b8882a6..0000000 --- a/Pods/SwiftSoup/Sources/Evaluator.swift +++ /dev/null @@ -1,720 +0,0 @@ -// -// Evaluator.swift -// SwiftSoup -// -// Created by Nabil Chatbi on 22/10/16. -// Copyright © 2016 Nabil Chatbi.. All rights reserved. -// - -import Foundation - -/** - * Evaluates that an element matches the selector. - */ -public class Evaluator { - init () {} - - /** - * Test if the element meets the evaluator's requirements. - * - * @param root Root of the matching subtree - * @param element tested element - * @return Returns true if the requirements are met or - * false otherwise - */ - open func matches(_ root: Element, _ element: Element)throws->Bool { - preconditionFailure("self method must be overridden") - } - - open func toString() -> String { - preconditionFailure("self method must be overridden") - } - - /** - * Evaluator for tag name - */ - public class Tag: Evaluator { - private let tagName: String - private let tagNameNormal: String - - public init(_ tagName: String) { - self.tagName = tagName - self.tagNameNormal = tagName.lowercased() - } - - open override func matches(_ root: Element, _ element: Element)throws->Bool { - return element.tagNameNormal() == tagNameNormal - } - - open override func toString() -> String { - return String(tagName) - } - } - - /** - * Evaluator for tag name that ends with - */ - public final class TagEndsWith: Evaluator { - private let tagName: String - - public init(_ tagName: String) { - self.tagName = tagName - } - - public override func matches(_ root: Element, _ element: Element)throws->Bool { - return (element.tagName().hasSuffix(tagName)) - } - - public override func toString() -> String { - return String(tagName) - } - } - - /** - * Evaluator for element id - */ - public final class Id: Evaluator { - private let id: String - - public init(_ id: String) { - self.id = id - } - - public override func matches(_ root: Element, _ element: Element)throws->Bool { - return (id == element.id()) - } - - public override func toString() -> String { - return "#\(id)" - } - - } - - /** - * Evaluator for element class - */ - public final class Class: Evaluator { - private let className: String - - public init(_ className: String) { - self.className = className - } - - public override func matches(_ root: Element, _ element: Element) -> Bool { - return (element.hasClass(className)) - } - - public override func toString() -> String { - return ".\(className)" - } - - } - - /** - * Evaluator for attribute name matching - */ - public final class Attribute: Evaluator { - private let key: String - - public init(_ key: String) { - self.key = key - } - - public override func matches(_ root: Element, _ element: Element)throws->Bool { - return element.hasAttr(key) - } - - public override func toString() -> String { - return "[\(key)]" - } - - } - - /** - * Evaluator for attribute name prefix matching - */ - public final class AttributeStarting: Evaluator { - private let keyPrefix: String - - public init(_ keyPrefix: String)throws { - try Validate.notEmpty(string: keyPrefix) - self.keyPrefix = keyPrefix.lowercased() - } - - public override func matches(_ root: Element, _ element: Element)throws->Bool { - if let values = element.getAttributes() { - for attribute in values where attribute.getKey().lowercased().hasPrefix(keyPrefix) { - return true - } - } - return false - } - - public override func toString() -> String { - return "[^\(keyPrefix)]" - } - - } - - /** - * Evaluator for attribute name/value matching - */ - public final class AttributeWithValue: AttributeKeyPair { - public override init(_ key: String, _ value: String)throws { - try super.init(key, value) - } - - public override func matches(_ root: Element, _ element: Element)throws->Bool { - if element.hasAttr(key) { - let string = try element.attr(key) - return value.equalsIgnoreCase(string: string.trim()) - } - return false - } - - public override func toString() -> String { - return "[\(key)=\(value)]" - } - - } - - /** - * Evaluator for attribute name != value matching - */ - public final class AttributeWithValueNot: AttributeKeyPair { - public override init(_ key: String, _ value: String)throws { - try super.init(key, value) - } - - public override func matches(_ root: Element, _ element: Element)throws->Bool { - let string = try element.attr(key) - return !value.equalsIgnoreCase(string: string) - } - - public override func toString() -> String { - return "[\(key)!=\(value)]" - } - - } - - /** - * Evaluator for attribute name/value matching (value prefix) - */ - public final class AttributeWithValueStarting: AttributeKeyPair { - public override init(_ key: String, _ value: String)throws { - try super.init(key, value) - } - - public override func matches(_ root: Element, _ element: Element)throws->Bool { - if element.hasAttr(key) { - return try element.attr(key).lowercased().hasPrefix(value) // value is lower case already - } - return false - } - - public override func toString() -> String { - return "[\(key)^=\(value)]" - } - - } - - /** - * Evaluator for attribute name/value matching (value ending) - */ - public final class AttributeWithValueEnding: AttributeKeyPair { - public override init(_ key: String, _ value: String)throws { - try super.init(key, value) - } - - public override func matches(_ root: Element, _ element: Element)throws->Bool { - if element.hasAttr(key) { - return try element.attr(key).lowercased().hasSuffix(value) // value is lower case - } - return false - } - - public override func toString() -> String { - return "[\(key)$=\(value)]" - } - - } - - /** - * Evaluator for attribute name/value matching (value containing) - */ - public final class AttributeWithValueContaining: AttributeKeyPair { - public override init(_ key: String, _ value: String)throws { - try super.init(key, value) - } - - public override func matches(_ root: Element, _ element: Element)throws->Bool { - if element.hasAttr(key) { - return try element.attr(key).lowercased().contains(value) // value is lower case - } - return false - } - - public override func toString() -> String { - return "[\(key)*=\(value)]" - } - - } - - /** - * Evaluator for attribute name/value matching (value regex matching) - */ - public final class AttributeWithValueMatching: Evaluator { - let key: String - let pattern: Pattern - - public init(_ key: String, _ pattern: Pattern) { - self.key = key.trim().lowercased() - self.pattern = pattern - super.init() - } - - public override func matches(_ root: Element, _ element: Element)throws->Bool { - if element.hasAttr(key) { - let string = try element.attr(key) - return pattern.matcher(in: string).find() - } - return false - } - - public override func toString() -> String { - return "[\(key)~=\(pattern.toString())]" - } - - } - - /** - * Abstract evaluator for attribute name/value matching - */ - public class AttributeKeyPair: Evaluator { - let key: String - var value: String - - public init(_ key: String, _ value2: String)throws { - var value2 = value2 - try Validate.notEmpty(string: key) - try Validate.notEmpty(string: value2) - - self.key = key.trim().lowercased() - if value2.startsWith("\"") && value2.hasSuffix("\"") || value2.startsWith("'") && value2.hasSuffix("'") { - value2 = value2.substring(1, value2.count-2) - } - self.value = value2.trim().lowercased() - } - - open override func matches(_ root: Element, _ element: Element)throws->Bool { - preconditionFailure("self method must be overridden") - } - } - - /** - * Evaluator for any / all element matching - */ - public final class AllElements: Evaluator { - - public override func matches(_ root: Element, _ element: Element)throws->Bool { - return true - } - - public override func toString() -> String { - return "*" - } - } - - /** - * Evaluator for matching by sibling index number (e {@literal <} idx) - */ - public final class IndexLessThan: IndexEvaluator { - public override init(_ index: Int) { - super.init(index) - } - - public override func matches(_ root: Element, _ element: Element)throws->Bool { - return try element.elementSiblingIndex() < index - } - - public override func toString() -> String { - return ":lt(\(index))" - } - - } - - /** - * Evaluator for matching by sibling index number (e {@literal >} idx) - */ - public final class IndexGreaterThan: IndexEvaluator { - public override init(_ index: Int) { - super.init(index) - } - - public override func matches(_ root: Element, _ element: Element)throws->Bool { - return try element.elementSiblingIndex() > index - } - - public override func toString() -> String { - return ":gt(\(index))" - } - - } - - /** - * Evaluator for matching by sibling index number (e = idx) - */ - public final class IndexEquals: IndexEvaluator { - public override init(_ index: Int) { - super.init(index) - } - - public override func matches(_ root: Element, _ element: Element)throws->Bool { - return try element.elementSiblingIndex() == index - } - - public override func toString() -> String { - return ":eq(\(index))" - } - - } - - /** - * Evaluator for matching the last sibling (css :last-child) - */ - public final class IsLastChild: Evaluator { - public override func matches(_ root: Element, _ element: Element)throws->Bool { - - if let parent = element.parent() { - let index = try element.elementSiblingIndex() - return !(parent is Document) && index == (parent.getChildNodes().count - 1) - } - return false - } - - public override func toString() -> String { - return ":last-child" - } - } - - public final class IsFirstOfType: IsNthOfType { - public init() { - super.init(0, 1) - } - public override func toString() -> String { - return ":first-of-type" - } - } - - public final class IsLastOfType: IsNthLastOfType { - public init() { - super.init(0, 1) - } - public override func toString() -> String { - return ":last-of-type" - } - } - - public class CssNthEvaluator: Evaluator { - public let a: Int - public let b: Int - - public init(_ a: Int, _ b: Int) { - self.a = a - self.b = b - } - public init(_ b: Int) { - self.a = 0 - self.b = b - } - - open override func matches(_ root: Element, _ element: Element)throws->Bool { - let p: Element? = element.parent() - if (p == nil || (((p as? Document) != nil))) {return false} - - let pos: Int = try calculatePosition(root, element) - if (a == 0) {return pos == b} - - return (pos-b)*a >= 0 && (pos-b)%a==0 - } - - open override func toString() -> String { - if (a == 0) { - return ":\(getPseudoClass())(\(b))" - } - if (b == 0) { - return ":\(getPseudoClass())(\(a))" - } - return ":\(getPseudoClass())(\(a)\(b))" - } - - open func getPseudoClass() -> String { - preconditionFailure("self method must be overridden") - } - open func calculatePosition(_ root: Element, _ element: Element)throws->Int { - preconditionFailure("self method must be overridden") - } - } - - /** - * css-compatible Evaluator for :eq (css :nth-child) - * - * @see IndexEquals - */ - public final class IsNthChild: CssNthEvaluator { - - public override init(_ a: Int, _ b: Int) { - super.init(a, b) - } - - public override func calculatePosition(_ root: Element, _ element: Element)throws->Int { - return try element.elementSiblingIndex()+1 - } - - public override func getPseudoClass() -> String { - return "nth-child" - } - } - - /** - * css pseudo class :nth-last-child) - * - * @see IndexEquals - */ - public final class IsNthLastChild: CssNthEvaluator { - public override init(_ a: Int, _ b: Int) { - super.init(a, b) - } - - public override func calculatePosition(_ root: Element, _ element: Element)throws->Int { - var i = 0 - - if let l = element.parent() { - i = l.children().array().count - } - return i - (try element.elementSiblingIndex()) - } - - public override func getPseudoClass() -> String { - return "nth-last-child" - } - } - - /** - * css pseudo class nth-of-type - * - */ - public class IsNthOfType: CssNthEvaluator { - public override init(_ a: Int, _ b: Int) { - super.init(a, b) - } - - open override func calculatePosition(_ root: Element, _ element: Element) -> Int { - var pos = 0 - let family: Elements? = element.parent()?.children() - if let array = family?.array() { - for el in array { - if (el.tag() == element.tag()) {pos+=1} - if (el === element) {break} - } - } - - return pos - } - - open override func getPseudoClass() -> String { - return "nth-of-type" - } - } - - public class IsNthLastOfType: CssNthEvaluator { - - public override init(_ a: Int, _ b: Int) { - super.init(a, b) - } - - open override func calculatePosition(_ root: Element, _ element: Element)throws->Int { - var pos = 0 - if let family = element.parent()?.children() { - let x = try element.elementSiblingIndex() - for i in x.. String { - return "nth-last-of-type" - } - } - - /** - * Evaluator for matching the first sibling (css :first-child) - */ - public final class IsFirstChild: Evaluator { - public override func matches(_ root: Element, _ element: Element)throws->Bool { - let p = element.parent() - if(p != nil && !(((p as? Document) != nil))) { - return (try element.elementSiblingIndex()) == 0 - } - return false - } - - public override func toString() -> String { - return ":first-child" - } - } - - /** - * css3 pseudo-class :root - * @see :root selector - * - */ - public final class IsRoot: Evaluator { - public override func matches(_ root: Element, _ element: Element)throws->Bool { - let r: Element = ((root as? Document) != nil) ? root.child(0) : root - return element === r - } - public override func toString() -> String { - return ":root" - } - } - - public final class IsOnlyChild: Evaluator { - public override func matches(_ root: Element, _ element: Element)throws->Bool { - let p = element.parent() - return p != nil && !((p as? Document) != nil) && element.siblingElements().array().count == 0 - } - public override func toString() -> String { - return ":only-child" - } - } - - public final class IsOnlyOfType: Evaluator { - public override func matches(_ root: Element, _ element: Element)throws->Bool { - let p = element.parent() - if (p == nil || (p as? Document) != nil) {return false} - - var pos = 0 - if let family = p?.children().array() { - for el in family { - if (el.tag() == element.tag()) {pos+=1} - } - } - return pos == 1 - } - - public override func toString() -> String { - return ":only-of-type" - } - } - - public final class IsEmpty: Evaluator { - public override func matches(_ root: Element, _ element: Element)throws->Bool { - let family: Array = element.getChildNodes() - for n in family { - if (!((n as? Comment) != nil || (n as? XmlDeclaration) != nil || (n as? DocumentType) != nil)) {return false} - } - return true - } - - public override func toString() -> String { - return ":empty" - } - } - - /** - * Abstract evaluator for sibling index matching - * - * @author ant - */ - public class IndexEvaluator: Evaluator { - let index: Int - - public init(_ index: Int) { - self.index = index - } - } - - /** - * Evaluator for matching Element (and its descendants) text - */ - public final class ContainsText: Evaluator { - private let searchText: String - - public init(_ searchText: String) { - self.searchText = searchText.lowercased() - } - - public override func matches(_ root: Element, _ element: Element)throws->Bool { - return (try element.text().lowercased().contains(searchText)) - } - - public override func toString() -> String { - return ":contains(\(searchText)" - } - } - - /** - * Evaluator for matching Element's own text - */ - public final class ContainsOwnText: Evaluator { - private let searchText: String - - public init(_ searchText: String) { - self.searchText = searchText.lowercased() - } - - public override func matches(_ root: Element, _ element: Element)throws->Bool { - return (element.ownText().lowercased().contains(searchText)) - } - - public override func toString() -> String { - return ":containsOwn(\(searchText)" - } - } - - /** - * Evaluator for matching Element (and its descendants) text with regex - */ - public final class Matches: Evaluator { - private let pattern: Pattern - - public init(_ pattern: Pattern) { - self.pattern = pattern - } - - public override func matches(_ root: Element, _ element: Element)throws->Bool { - let m = try pattern.matcher(in: element.text()) - return m.find() - } - - public override func toString() -> String { - return ":matches(\(pattern)" - } - } - - /** - * Evaluator for matching Element's own text with regex - */ - public final class MatchesOwn: Evaluator { - private let pattern: Pattern - - public init(_ pattern: Pattern) { - self.pattern = pattern - } - - public override func matches(_ root: Element, _ element: Element)throws->Bool { - let m = pattern.matcher(in: element.ownText()) - return m.find() - } - - public override func toString() -> String { - return ":matchesOwn(\(pattern.toString())" - } - } -} diff --git a/Pods/SwiftSoup/Sources/Exception.swift b/Pods/SwiftSoup/Sources/Exception.swift deleted file mode 100644 index a4ab97a..0000000 --- a/Pods/SwiftSoup/Sources/Exception.swift +++ /dev/null @@ -1,22 +0,0 @@ -// -// Exception.swift -// SwifSoup -// -// Created by Nabil Chatbi on 02/10/16. -// Copyright © 2016 Nabil Chatbi.. All rights reserved. -// - -import Foundation - -public enum ExceptionType { - case IllegalArgumentException - case IOException - case XmlDeclaration - case MalformedURLException - case CloneNotSupportedException - case SelectorParseException -} - -public enum Exception: Error { - case Error(type:ExceptionType, Message: String) -} diff --git a/Pods/SwiftSoup/Sources/FormElement.swift b/Pods/SwiftSoup/Sources/FormElement.swift deleted file mode 100644 index a15754f..0000000 --- a/Pods/SwiftSoup/Sources/FormElement.swift +++ /dev/null @@ -1,125 +0,0 @@ -// -// FormElement.swift -// SwifSoup -// -// Created by Nabil Chatbi on 29/09/16. -// Copyright © 2016 Nabil Chatbi.. All rights reserved. -// - -import Foundation - -/** - * A HTML Form Element provides ready access to the form fields/controls that are associated with it. It also allows a - * form to easily be submitted. - */ -public class FormElement: Element { - private let _elements: Elements = Elements() - - /** - * Create a new, standalone form element. - * - * @param tag tag of this element - * @param baseUri the base URI - * @param attributes initial attributes - */ - public override init(_ tag: Tag, _ baseUri: String, _ attributes: Attributes) { - super.init(tag, baseUri, attributes) - } - - /** - * Get the list of form control elements associated with this form. - * @return form controls associated with this element. - */ - public func elements() -> Elements { - return _elements - } - - /** - * Add a form control element to this form. - * @param element form control to add - * @return this form element, for chaining - */ - @discardableResult - public func addElement(_ element: Element) -> FormElement { - _elements.add(element) - return self - } - - //todo: - /** - * Prepare to submit this form. A Connection object is created with the request set up from the form values. You - * can then set up other options (like user-agent, timeout, cookies), then execute it. - * @return a connection prepared from the values of this form. - * @throws IllegalArgumentException if the form's absolute action URL cannot be determined. Make sure you pass the - * document's base URI when parsing. - */ -// public func submit()throws->Connection { -// let action: String = hasAttr("action") ? try absUrl("action") : try baseUri() -// Validate.notEmpty(action, "Could not determine a form action URL for submit. Ensure you set a base URI when parsing.") -// Connection.Method method = attr("method").toUpperCase().equals("POST") ? -// Connection.Method.POST : Connection.Method.GET -// -// return Jsoup.connect(action) -// .data(formData()) -// .method(method) -// } - - //todo: - /** - * Get the data that this form submits. The returned list is a copy of the data, and changes to the contents of the - * list will not be reflected in the DOM. - * @return a list of key vals - */ -// public List formData() { -// ArrayList data = new ArrayList(); -// -// // iterate the form control elements and accumulate their values -// for (Element el: elements) { -// if (!el.tag().isFormSubmittable()) continue; // contents are form listable, superset of submitable -// if (el.hasAttr("disabled")) continue; // skip disabled form inputs -// String name = el.attr("name"); -// if (name.length() == 0) continue; -// String type = el.attr("type"); -// -// if ("select".equals(el.tagName())) { -// Elements options = el.select("option[selected]"); -// boolean set = false; -// for (Element option: options) { -// data.add(HttpConnection.KeyVal.create(name, option.val())); -// set = true; -// } -// if (!set) { -// Element option = el.select("option").first(); -// if (option != null) -// data.add(HttpConnection.KeyVal.create(name, option.val())); -// } -// } else if ("checkbox".equalsIgnoreCase(type) || "radio".equalsIgnoreCase(type)) { -// // only add checkbox or radio if they have the checked attribute -// if (el.hasAttr("checked")) { -// final String val = el.val().length() > 0 ? el.val() : "on"; -// data.add(HttpConnection.KeyVal.create(name, val)); -// } -// } else { -// data.add(HttpConnection.KeyVal.create(name, el.val())); -// } -// } -// return data; -// } - - public override func copy(with zone: NSZone? = nil) -> Any { - let clone = FormElement(_tag, baseUri!, attributes!) - return copy(clone: clone) - } - - public override func copy(parent: Node?) -> Node { - let clone = FormElement(_tag, baseUri!, attributes!) - return copy(clone: clone, parent: parent) - } - public override func copy(clone: Node, parent: Node?) -> Node { - let clone = clone as! FormElement - for att in _elements.array() { - clone._elements.add(att) - } - return super.copy(clone: clone, parent: parent) - } -} diff --git a/Pods/SwiftSoup/Sources/HtmlTreeBuilder.swift b/Pods/SwiftSoup/Sources/HtmlTreeBuilder.swift deleted file mode 100644 index 532fe34..0000000 --- a/Pods/SwiftSoup/Sources/HtmlTreeBuilder.swift +++ /dev/null @@ -1,771 +0,0 @@ -// -// HtmlTreeBuilder.swift -// SwiftSoup -// -// Created by Nabil Chatbi on 24/10/16. -// Copyright © 2016 Nabil Chatbi.. All rights reserved. -// - -import Foundation - -/** - * HTML Tree Builder; creates a DOM from Tokens. - */ -class HtmlTreeBuilder: TreeBuilder { - // tag searches - public static let TagsSearchInScope: [String] = ["applet", "caption", "html", "table", "td", "th", "marquee", "object"] - private static let TagSearchList: [String] = ["ol", "ul"] - private static let TagSearchButton: [String] = ["button"] - private static let TagSearchTableScope: [String] = ["html", "table"] - private static let TagSearchSelectScope: [String] = ["optgroup", "option"] - private static let TagSearchEndTags: [String] = ["dd", "dt", "li", "option", "optgroup", "p", "rp", "rt"] - private static let TagSearchSpecial: [String] = ["address", "applet", "area", "article", "aside", "base", "basefont", "bgsound", - "blockquote", "body", "br", "button", "caption", "center", "col", "colgroup", "command", "dd", - "details", "dir", "div", "dl", "dt", "embed", "fieldset", "figcaption", "figure", "footer", "form", - "frame", "frameset", "h1", "h2", "h3", "h4", "h5", "h6", "head", "header", "hgroup", "hr", "html", - "iframe", "img", "input", "isindex", "li", "link", "listing", "marquee", "menu", "meta", "nav", - "noembed", "noframes", "noscript", "object", "ol", "p", "param", "plaintext", "pre", "script", - "section", "select", "style", "summary", "table", "tbody", "td", "textarea", "tfoot", "th", "thead", - "title", "tr", "ul", "wbr", "xmp"] - - private var _state: HtmlTreeBuilderState = HtmlTreeBuilderState.Initial // the current state - private var _originalState: HtmlTreeBuilderState = HtmlTreeBuilderState.Initial // original / marked state - - private var baseUriSetFromDoc: Bool = false - private var headElement: Element? // the current head element - private var formElement: FormElement? // the current form element - private var contextElement: Element? // fragment parse context -- could be null even if fragment parsing - private var formattingElements: Array = Array() // active (open) formatting elements - private var pendingTableCharacters: Array = Array() // chars in table to be shifted out - private var emptyEnd: Token.EndTag = Token.EndTag() // reused empty end tag - - private var _framesetOk: Bool = true // if ok to go into frameset - private var fosterInserts: Bool = false // if next inserts should be fostered - private var fragmentParsing: Bool = false // if parsing a fragment of html - - public override init() { - super.init() - } - - public override func defaultSettings() -> ParseSettings { - return ParseSettings.htmlDefault - } - - override func parse(_ input: String, _ baseUri: String, _ errors: ParseErrorList, _ settings: ParseSettings)throws->Document { - _state = HtmlTreeBuilderState.Initial - baseUriSetFromDoc = false - return try super.parse(input, baseUri, errors, settings) - } - - func parseFragment(_ inputFragment: String, _ context: Element?, _ baseUri: String, _ errors: ParseErrorList, _ settings: ParseSettings)throws->Array { - // context may be null - _state = HtmlTreeBuilderState.Initial - initialiseParse(inputFragment, baseUri, errors, settings) - contextElement = context - fragmentParsing = true - var root: Element? = nil - - if let context = context { - if let d = context.ownerDocument() { // quirks setup: - doc.quirksMode(d.quirksMode()) - } - - // initialise the tokeniser state: - let contextTag: String = context.tagName() - if (StringUtil.inString(contextTag, haystack: "title", "textarea")) { - tokeniser.transition(TokeniserState.Rcdata) - } else if (StringUtil.inString(contextTag, haystack: "iframe", "noembed", "noframes", "style", "xmp")) { - tokeniser.transition(TokeniserState.Rawtext) - } else if (contextTag=="script") { - tokeniser.transition(TokeniserState.ScriptData) - } else if (contextTag==("noscript")) { - tokeniser.transition(TokeniserState.Data) // if scripting enabled, rawtext - } else if (contextTag=="plaintext") { - tokeniser.transition(TokeniserState.Data) - } else { - tokeniser.transition(TokeniserState.Data) // default - } - - root = try Element(Tag.valueOf("html", settings), baseUri) - try Validate.notNull(obj: root) - try doc.appendChild(root!) - stack.append(root!) - resetInsertionMode() - - // setup form element to nearest form on context (up ancestor chain). ensures form controls are associated - // with form correctly - let contextChain: Elements = context.parents() - contextChain.add(0, context) - for parent: Element in contextChain.array() { - if let x = (parent as? FormElement) { - formElement = x - break - } - } - } - - try runParser() - if (context != nil && root != nil) { - return root!.getChildNodes() - } else { - return doc.getChildNodes() - } - } - - @discardableResult - public override func process(_ token: Token)throws->Bool { - currentToken = token - return try self._state.process(token, self) - } - - @discardableResult - func process(_ token: Token, _ state: HtmlTreeBuilderState)throws->Bool { - currentToken = token - return try state.process(token, self) - } - - func transition(_ state: HtmlTreeBuilderState) { - self._state = state - } - - func state() -> HtmlTreeBuilderState { - return _state - } - - func markInsertionMode() { - _originalState = _state - } - - func originalState() -> HtmlTreeBuilderState { - return _originalState - } - - func framesetOk(_ framesetOk: Bool) { - self._framesetOk = framesetOk - } - - func framesetOk() -> Bool { - return _framesetOk - } - - func getDocument() -> Document { - return doc - } - - func getBaseUri() -> String { - return baseUri - } - - func maybeSetBaseUri(_ base: Element)throws { - if (baseUriSetFromDoc) { // only listen to the first in parse - return - } - - let href: String = try base.absUrl("href") - if (href.count != 0) { // ignore etc - baseUri = href - baseUriSetFromDoc = true - try doc.setBaseUri(href) // set on the doc so doc.createElement(Tag) will get updated base, and to update all descendants - } - } - - func isFragmentParsing() -> Bool { - return fragmentParsing - } - - func error(_ state: HtmlTreeBuilderState) { - if (errors.canAddError() && currentToken != nil) { - errors.add(ParseError(reader.getPos(), "Unexpected token [\(currentToken!.tokenType())] when in state [\(state.rawValue)]")) - } - } - - @discardableResult - func insert(_ startTag: Token.StartTag)throws->Element { - // handle empty unknown tags - // when the spec expects an empty tag, will directly hit insertEmpty, so won't generate this fake end tag. - if (startTag.isSelfClosing()) { - let el: Element = try insertEmpty(startTag) - stack.append(el) - tokeniser.transition(TokeniserState.Data) // handles - - var tagPending: Token.Tag = Token.Tag() // tag we are building up - let startPending: Token.StartTag = Token.StartTag() - let endPending: Token.EndTag = Token.EndTag() - let charPending: Token.Char = Token.Char() - let doctypePending: Token.Doctype = Token.Doctype() // doctype building up - let commentPending: Token.Comment = Token.Comment() // comment building up - private var lastStartTag: String? // the last start tag emitted, to test appropriate end tag - private var selfClosingFlagAcknowledged: Bool = true - - init(_ reader: CharacterReader, _ errors: ParseErrorList?) { - self.reader = reader - self.errors = errors - } - - func read()throws->Token { - if (!selfClosingFlagAcknowledged) { - error("Self closing flag not acknowledged") - selfClosingFlagAcknowledged = true - } - - while (!isEmitPending) { - try state.read(self, reader) - } - - // if emit is pending, a non-character token was found: return any chars in buffer, and leave token for next read: - if (charsBuilder.length > 0) { - let str: String = charsBuilder.toString() - charsBuilder.clear() - charsString = nil - return charPending.data(str) - } else if (charsString != nil) { - let token: Token = charPending.data(charsString!) - charsString = nil - return token - } else { - isEmitPending = false - return emitPending! - } - } - - func emit(_ token: Token)throws { - try Validate.isFalse(val: isEmitPending, msg: "There is an unread token pending!") - - emitPending = token - isEmitPending = true - - if (token.type == Token.TokenType.StartTag) { - let startTag: Token.StartTag = token as! Token.StartTag - lastStartTag = startTag._tagName! - if (startTag._selfClosing) { - selfClosingFlagAcknowledged = false - } - } else if (token.type == Token.TokenType.EndTag) { - let endTag: Token.EndTag = token as! Token.EndTag - if (endTag._attributes.size() != 0) { - error("Attributes incorrectly present on end tag") - } - } - } - - func emit(_ str: String ) { - // buffer strings up until last string token found, to emit only one token for a run of character refs etc. - // does not set isEmitPending; read checks that - if (charsString == nil) { - charsString = str - } else { - if (charsBuilder.length == 0) { // switching to string builder as more than one emit before read - charsBuilder.append(charsString!) - } - charsBuilder.append(str) - } - } - - func emit(_ chars: [UnicodeScalar]) { - emit(String(chars.map {Character($0)})) - } - - // func emit(_ codepoints: [Int]) { - // emit(String(codepoints, 0, codepoints.length)); - // } - - func emit(_ c: UnicodeScalar) { - emit(String(c)) - } - - func getState() -> TokeniserState { - return state - } - - func transition(_ state: TokeniserState) { - self.state = state - } - - func advanceTransition(_ state: TokeniserState) { - reader.advance() - self.state = state - } - - func acknowledgeSelfClosingFlag() { - selfClosingFlagAcknowledged = true - } - - private var codepointHolder: [UnicodeScalar] = [UnicodeScalar(0)!] // holder to not have to keep creating arrays - private var multipointHolder: [UnicodeScalar] = [UnicodeScalar(0)!, UnicodeScalar(0)!] - - func consumeCharacterReference(_ additionalAllowedCharacter: UnicodeScalar?, _ inAttribute: Bool)throws->[UnicodeScalar]? { - if (reader.isEmpty()) { - return nil - } - if (additionalAllowedCharacter != nil && additionalAllowedCharacter == reader.current()) { - return nil - } - if (reader.matchesAnySorted(Tokeniser.notCharRefCharsSorted)) { - return nil - } - - var codeRef: [UnicodeScalar] = codepointHolder - reader.markPos() - if (reader.matchConsume("#")) { // numbered - let isHexMode: Bool = reader.matchConsumeIgnoreCase("X") - let numRef: String = isHexMode ? reader.consumeHexSequence() : reader.consumeDigitSequence() - if (numRef.unicodeScalars.count == 0) { // didn't match anything - characterReferenceError("numeric reference with no numerals") - reader.rewindToMark() - return nil - } - if (!reader.matchConsume(";")) { - characterReferenceError("missing semicolon") // missing semi - } - var charval: Int = -1 - - let base: Int = isHexMode ? 16 : 10 - if let num = Int(numRef, radix: base) { - charval = num - } - - if (charval == -1 || (charval >= 0xD800 && charval <= 0xDFFF) || charval > 0x10FFFF) { - characterReferenceError("character outside of valid range") - codeRef[0] = Tokeniser.replacementChar - return codeRef - } else { - // todo: implement number replacement table - // todo: check for extra illegal unicode points as parse errors - codeRef[0] = UnicodeScalar(charval)! - return codeRef - } - } else { // named - // get as many letters as possible, and look for matching entities. - let nameRef: String = reader.consumeLetterThenDigitSequence() - let looksLegit: Bool = reader.matches(";") - // found if a base named entity without a ;, or an extended entity with the ;. - let found: Bool = (Entities.isBaseNamedEntity(nameRef) || (Entities.isNamedEntity(nameRef) && looksLegit)) - - if (!found) { - reader.rewindToMark() - if (looksLegit) { // named with semicolon - characterReferenceError("invalid named referenece '\(nameRef)'") - } - return nil - } - if (inAttribute && (reader.matchesLetter() || reader.matchesDigit() || reader.matchesAny("=", "-", "_"))) { - // don't want that to match - reader.rewindToMark() - return nil - } - if (!reader.matchConsume(";")) { - characterReferenceError("missing semicolon") // missing semi - } - let numChars: Int = Entities.codepointsForName(nameRef, codepoints: &multipointHolder) - if (numChars == 1) { - codeRef[0] = multipointHolder[0] - return codeRef - } else if (numChars == 2) { - return multipointHolder - } else { - try Validate.fail(msg: "Unexpected characters returned for \(nameRef) num: \(numChars)") - return multipointHolder - } - } - } - - @discardableResult - func createTagPending(_ start: Bool)->Token.Tag { - tagPending = start ? startPending.reset() : endPending.reset() - return tagPending - } - - func emitTagPending()throws { - try tagPending.finaliseTag() - try emit(tagPending) - } - - func createCommentPending() { - commentPending.reset() - } - - func emitCommentPending()throws { - try emit(commentPending) - } - - func createDoctypePending() { - doctypePending.reset() - } - - func emitDoctypePending()throws { - try emit(doctypePending) - } - - func createTempBuffer() { - Token.reset(dataBuffer) - } - - func isAppropriateEndTagToken()throws->Bool { - if(lastStartTag != nil) { - let s = try tagPending.name() - return s.equalsIgnoreCase(string: lastStartTag!) - } - return false - } - - func appropriateEndTagName() -> String? { - if (lastStartTag == nil) { - return nil - } - return lastStartTag - } - - func error(_ state: TokeniserState) { - if (errors != nil && errors!.canAddError()) { - errors?.add(ParseError(reader.getPos(), "Unexpected character '\(String(reader.current()))' in input state [\(state.description)]")) - } - } - - func eofError(_ state: TokeniserState) { - if (errors != nil && errors!.canAddError()) { - errors?.add(ParseError(reader.getPos(), "Unexpectedly reached end of file (EOF) in input state [\(state.description)]")) - } - } - - private func characterReferenceError(_ message: String) { - if (errors != nil && errors!.canAddError()) { - errors?.add(ParseError(reader.getPos(), "Invalid character reference: \(message)")) - } - } - - private func error(_ errorMsg: String) { - if (errors != nil && errors!.canAddError()) { - errors?.add(ParseError(reader.getPos(), errorMsg)) - } - } - - func currentNodeInHtmlNS() -> Bool { - // todo: implement namespaces correctly - return true - // Element currentNode = currentNode() - // return currentNode != null && currentNode.namespace().equals("HTML") - } - - /** - * Utility method to consume reader and unescape entities found within. - * @param inAttribute - * @return unescaped string from reader - */ - func unescapeEntities(_ inAttribute: Bool)throws->String { - let builder: StringBuilder = StringBuilder() - while (!reader.isEmpty()) { - builder.append(reader.consumeTo(UnicodeScalar.Ampersand)) - if (reader.matches(UnicodeScalar.Ampersand)) { - reader.consume() - if let c = try consumeCharacterReference(nil, inAttribute) { - if (c.count==0) { - builder.append(UnicodeScalar.Ampersand) - } else { - builder.appendCodePoint(c[0]) - if (c.count == 2) { - builder.appendCodePoint(c[1]) - } - } - } else { - builder.append(UnicodeScalar.Ampersand) - } - } - } - return builder.toString() - } - -} diff --git a/Pods/SwiftSoup/Sources/TokeniserState.swift b/Pods/SwiftSoup/Sources/TokeniserState.swift deleted file mode 100644 index 707248a..0000000 --- a/Pods/SwiftSoup/Sources/TokeniserState.swift +++ /dev/null @@ -1,1644 +0,0 @@ -// -// TokeniserState.swift -// SwiftSoup -// -// Created by Nabil Chatbi on 12/10/16. -// Copyright © 2016 Nabil Chatbi.. All rights reserved. -// - -import Foundation - -protocol TokeniserStateProtocol { - func read(_ t: Tokeniser, _ r: CharacterReader)throws -} - -public class TokeniserStateVars { - public static let nullScalr: UnicodeScalar = "\u{0000}" - - static let attributeSingleValueCharsSorted = ["'", UnicodeScalar.Ampersand, nullScalr].sorted() - static let attributeDoubleValueCharsSorted = ["\"", UnicodeScalar.Ampersand, nullScalr].sorted() - static let attributeNameCharsSorted = [UnicodeScalar.BackslashT, "\n", "\r", UnicodeScalar.BackslashF, " ", "/", "=", ">", nullScalr, "\"", "'", UnicodeScalar.LessThan].sorted() - static let attributeValueUnquoted = [UnicodeScalar.BackslashT, "\n", "\r", UnicodeScalar.BackslashF, " ", UnicodeScalar.Ampersand, ">", nullScalr, "\"", "'", UnicodeScalar.LessThan, "=", "`"].sorted() - - static let replacementChar: UnicodeScalar = Tokeniser.replacementChar - static let replacementStr: String = String(Tokeniser.replacementChar) - static let eof: UnicodeScalar = CharacterReader.EOF -} - -enum TokeniserState: TokeniserStateProtocol { - case Data - case CharacterReferenceInData - case Rcdata - case CharacterReferenceInRcdata - case Rawtext - case ScriptData - case PLAINTEXT - case TagOpen - case EndTagOpen - case TagName - case RcdataLessthanSign - case RCDATAEndTagOpen - case RCDATAEndTagName - case RawtextLessthanSign - case RawtextEndTagOpen - case RawtextEndTagName - case ScriptDataLessthanSign - case ScriptDataEndTagOpen - case ScriptDataEndTagName - case ScriptDataEscapeStart - case ScriptDataEscapeStartDash - case ScriptDataEscaped - case ScriptDataEscapedDash - case ScriptDataEscapedDashDash - case ScriptDataEscapedLessthanSign - case ScriptDataEscapedEndTagOpen - case ScriptDataEscapedEndTagName - case ScriptDataDoubleEscapeStart - case ScriptDataDoubleEscaped - case ScriptDataDoubleEscapedDash - case ScriptDataDoubleEscapedDashDash - case ScriptDataDoubleEscapedLessthanSign - case ScriptDataDoubleEscapeEnd - case BeforeAttributeName - case AttributeName - case AfterAttributeName - case BeforeAttributeValue - case AttributeValue_doubleQuoted - case AttributeValue_singleQuoted - case AttributeValue_unquoted - case AfterAttributeValue_quoted - case SelfClosingStartTag - case BogusComment - case MarkupDeclarationOpen - case CommentStart - case CommentStartDash - case Comment - case CommentEndDash - case CommentEnd - case CommentEndBang - case Doctype - case BeforeDoctypeName - case DoctypeName - case AfterDoctypeName - case AfterDoctypePublicKeyword - case BeforeDoctypePublicIdentifier - case DoctypePublicIdentifier_doubleQuoted - case DoctypePublicIdentifier_singleQuoted - case AfterDoctypePublicIdentifier - case BetweenDoctypePublicAndSystemIdentifiers - case AfterDoctypeSystemKeyword - case BeforeDoctypeSystemIdentifier - case DoctypeSystemIdentifier_doubleQuoted - case DoctypeSystemIdentifier_singleQuoted - case AfterDoctypeSystemIdentifier - case BogusDoctype - case CdataSection - - internal func read(_ t: Tokeniser, _ r: CharacterReader)throws { - switch self { - case .Data: - switch (r.current()) { - case UnicodeScalar.Ampersand: - t.advanceTransition(.CharacterReferenceInData) - break - case UnicodeScalar.LessThan: - t.advanceTransition(.TagOpen) - break - case TokeniserStateVars.nullScalr: - t.error(self) // NOT replacement character (oddly?) - t.emit(r.consume()) - break - case TokeniserStateVars.eof: - try t.emit(Token.EOF()) - break - default: - let data: String = r.consumeData() - t.emit(data) - break - } - break - case .CharacterReferenceInData: - try TokeniserState.readCharRef(t, .Data) - break - case .Rcdata: - switch (r.current()) { - case UnicodeScalar.Ampersand: - t.advanceTransition(.CharacterReferenceInRcdata) - break - case UnicodeScalar.LessThan: - t.advanceTransition(.RcdataLessthanSign) - break - case TokeniserStateVars.nullScalr: - t.error(self) - r.advance() - t.emit(TokeniserStateVars.replacementChar) - break - case TokeniserStateVars.eof: - try t.emit(Token.EOF()) - break - default: - let data = r.consumeToAny(UnicodeScalar.Ampersand, UnicodeScalar.LessThan, TokeniserStateVars.nullScalr) - t.emit(data) - break - } - break - case .CharacterReferenceInRcdata: - try TokeniserState.readCharRef(t, .Rcdata) - break - case .Rawtext: - try TokeniserState.readData(t, r, self, .RawtextLessthanSign) - break - case .ScriptData: - try TokeniserState.readData(t, r, self, .ScriptDataLessthanSign) - break - case .PLAINTEXT: - switch (r.current()) { - case TokeniserStateVars.nullScalr: - t.error(self) - r.advance() - t.emit(TokeniserStateVars.replacementChar) - break - case TokeniserStateVars.eof: - try t.emit(Token.EOF()) - break - default: - let data = r.consumeTo(TokeniserStateVars.nullScalr) - t.emit(data) - break - } - break - case .TagOpen: - // from < in data - switch (r.current()) { - case "!": - t.advanceTransition(.MarkupDeclarationOpen) - break - case "/": - t.advanceTransition(.EndTagOpen) - break - case "?": - t.advanceTransition(.BogusComment) - break - default: - if (r.matchesLetter()) { - t.createTagPending(true) - t.transition(.TagName) - } else { - t.error(self) - t.emit(UnicodeScalar.LessThan) // char that got us here - t.transition(.Data) - } - break - } - break - case .EndTagOpen: - if (r.isEmpty()) { - t.eofError(self) - t.emit("")) { - t.error(self) - t.advanceTransition(.Data) - } else { - t.error(self) - t.advanceTransition(.BogusComment) - } - break - case .TagName: - // from < or ": - try t.emitTagPending() - t.transition(.Data) - break - case TokeniserStateVars.nullScalr: // replacement - t.tagPending.appendTagName(TokeniserStateVars.replacementStr) - break - case TokeniserStateVars.eof: // should emit pending tag? - t.eofError(self) - t.transition(.Data) - // no default, as covered with above consumeToAny - default: - break - } - case .RcdataLessthanSign: - if (r.matches("/")) { - t.createTempBuffer() - t.advanceTransition(.RCDATAEndTagOpen) - } else if (r.matchesLetter() && t.appropriateEndTagName() != nil && !r.containsIgnoreCase("), so rather than - // consuming to EOF break out here - t.tagPending = t.createTagPending(false).name(t.appropriateEndTagName()!) - try t.emitTagPending() - r.unconsume() // undo UnicodeScalar.LessThan - t.transition(.Data) - } else { - t.emit(UnicodeScalar.LessThan) - t.transition(.Rcdata) - } - break - case .RCDATAEndTagOpen: - if (r.matchesLetter()) { - t.createTagPending(false) - t.tagPending.appendTagName(r.current()) - t.dataBuffer.append(r.current()) - t.advanceTransition(.RCDATAEndTagName) - } else { - t.emit("": - if (try t.isAppropriateEndTagToken()) { - try t.emitTagPending() - t.transition(.Data) - } else {anythingElse(t, r)} - break - default: - anythingElse(t, r) - break - } - break - case .RawtextLessthanSign: - if (r.matches("/")) { - t.createTempBuffer() - t.advanceTransition(.RawtextEndTagOpen) - } else { - t.emit(UnicodeScalar.LessThan) - t.transition(.Rawtext) - } - break - case .RawtextEndTagOpen: - TokeniserState.readEndTag(t, r, .RawtextEndTagName, .Rawtext) - break - case .RawtextEndTagName: - try TokeniserState.handleDataEndTag(t, r, .Rawtext) - break - case .ScriptDataLessthanSign: - switch (r.consume()) { - case "/": - t.createTempBuffer() - t.transition(.ScriptDataEndTagOpen) - break - case "!": - t.emit("": - t.emit(c) - t.transition(.ScriptData) - break - case TokeniserStateVars.nullScalr: - t.error(self) - t.emit(TokeniserStateVars.replacementChar) - t.transition(.ScriptDataEscaped) - break - default: - t.emit(c) - t.transition(.ScriptDataEscaped) - } - break - case .ScriptDataEscapedLessthanSign: - if (r.matchesLetter()) { - t.createTempBuffer() - t.dataBuffer.append(r.current()) - t.emit("<" + String(r.current())) - t.advanceTransition(.ScriptDataDoubleEscapeStart) - } else if (r.matches("/")) { - t.createTempBuffer() - t.advanceTransition(.ScriptDataEscapedEndTagOpen) - } else { - t.emit(UnicodeScalar.LessThan) - t.transition(.ScriptDataEscaped) - } - break - case .ScriptDataEscapedEndTagOpen: - if (r.matchesLetter()) { - t.createTagPending(false) - t.tagPending.appendTagName(r.current()) - t.dataBuffer.append(r.current()) - t.advanceTransition(.ScriptDataEscapedEndTagName) - } else { - t.emit("": - t.emit(c) - t.transition(.ScriptData) - break - case TokeniserStateVars.nullScalr: - t.error(self) - t.emit(TokeniserStateVars.replacementChar) - t.transition(.ScriptDataDoubleEscaped) - break - case TokeniserStateVars.eof: - t.eofError(self) - t.transition(.Data) - break - default: - t.emit(c) - t.transition(.ScriptDataDoubleEscaped) - } - break - case .ScriptDataDoubleEscapedLessthanSign: - if (r.matches("/")) { - t.emit("/") - t.createTempBuffer() - t.advanceTransition(.ScriptDataDoubleEscapeEnd) - } else { - t.transition(.ScriptDataDoubleEscaped) - } - break - case .ScriptDataDoubleEscapeEnd: - TokeniserState.handleDataDoubleEscapeTag(t, r, .ScriptDataEscaped, .ScriptDataDoubleEscaped) - break - case .BeforeAttributeName: - // from tagname ": - try t.emitTagPending() - t.transition(.Data) - break - case TokeniserStateVars.nullScalr: - t.error(self) - try t.tagPending.newAttribute() - r.unconsume() - t.transition(.AttributeName) - break - case TokeniserStateVars.eof: - t.eofError(self) - t.transition(.Data) - break - case "\"", "'", UnicodeScalar.LessThan, "=": - t.error(self) - try t.tagPending.newAttribute() - t.tagPending.appendAttributeName(c) - t.transition(.AttributeName) - break - default: // A-Z, anything else - try t.tagPending.newAttribute() - r.unconsume() - t.transition(.AttributeName) - } - break - case .AttributeName: - let name = r.consumeToAnySorted(TokeniserStateVars.attributeNameCharsSorted) - t.tagPending.appendAttributeName(name) - - let c = r.consume() - switch (c) { - case UnicodeScalar.BackslashT: - t.transition(.AfterAttributeName) - break - case "\n": - t.transition(.AfterAttributeName) - break - case "\r": - t.transition(.AfterAttributeName) - break - case UnicodeScalar.BackslashF: - t.transition(.AfterAttributeName) - break - case " ": - t.transition(.AfterAttributeName) - break - case "/": - t.transition(.SelfClosingStartTag) - break - case "=": - t.transition(.BeforeAttributeValue) - break - case ">": - try t.emitTagPending() - t.transition(.Data) - break - case TokeniserStateVars.nullScalr: - t.error(self) - t.tagPending.appendAttributeName(TokeniserStateVars.replacementChar) - break - case TokeniserStateVars.eof: - t.eofError(self) - t.transition(.Data) - break - case "\"": - t.error(self) - t.tagPending.appendAttributeName(c) - case "'": - t.error(self) - t.tagPending.appendAttributeName(c) - case UnicodeScalar.LessThan: - t.error(self) - t.tagPending.appendAttributeName(c) - // no default, as covered in consumeToAny - default: - break - } - break - case .AfterAttributeName: - let c = r.consume() - switch (c) { - case UnicodeScalar.BackslashT, "\n", "\r", UnicodeScalar.BackslashF, " ": - // ignore - break - case "/": - t.transition(.SelfClosingStartTag) - break - case "=": - t.transition(.BeforeAttributeValue) - break - case ">": - try t.emitTagPending() - t.transition(.Data) - break - case TokeniserStateVars.nullScalr: - t.error(self) - t.tagPending.appendAttributeName(TokeniserStateVars.replacementChar) - t.transition(.AttributeName) - break - case TokeniserStateVars.eof: - t.eofError(self) - t.transition(.Data) - break - case "\"", "'", UnicodeScalar.LessThan: - t.error(self) - try t.tagPending.newAttribute() - t.tagPending.appendAttributeName(c) - t.transition(.AttributeName) - break - default: // A-Z, anything else - try t.tagPending.newAttribute() - r.unconsume() - t.transition(.AttributeName) - } - break - case .BeforeAttributeValue: - let c = r.consume() - switch (c) { - case UnicodeScalar.BackslashT, "\n", "\r", UnicodeScalar.BackslashF, " ": - // ignore - break - case "\"": - t.transition(.AttributeValue_doubleQuoted) - break - case UnicodeScalar.Ampersand: - r.unconsume() - t.transition(.AttributeValue_unquoted) - break - case "'": - t.transition(.AttributeValue_singleQuoted) - break - case TokeniserStateVars.nullScalr: - t.error(self) - t.tagPending.appendAttributeValue(TokeniserStateVars.replacementChar) - t.transition(.AttributeValue_unquoted) - break - case TokeniserStateVars.eof: - t.eofError(self) - try t.emitTagPending() - t.transition(.Data) - break - case ">": - t.error(self) - try t.emitTagPending() - t.transition(.Data) - break - case UnicodeScalar.LessThan, "=", "`": - t.error(self) - t.tagPending.appendAttributeValue(c) - t.transition(.AttributeValue_unquoted) - break - default: - r.unconsume() - t.transition(.AttributeValue_unquoted) - } - break - case .AttributeValue_doubleQuoted: - let value = r.consumeToAny(TokeniserStateVars.attributeDoubleValueCharsSorted) - if (value.count > 0) { - t.tagPending.appendAttributeValue(value) - } else { - t.tagPending.setEmptyAttributeValue() - } - - let c = r.consume() - switch (c) { - case "\"": - t.transition(.AfterAttributeValue_quoted) - break - case UnicodeScalar.Ampersand: - - if let ref = try t.consumeCharacterReference("\"", true) { - t.tagPending.appendAttributeValue(ref) - } else { - t.tagPending.appendAttributeValue(UnicodeScalar.Ampersand) - } - break - case TokeniserStateVars.nullScalr: - t.error(self) - t.tagPending.appendAttributeValue(TokeniserStateVars.replacementChar) - break - case TokeniserStateVars.eof: - t.eofError(self) - t.transition(.Data) - break - // no default, handled in consume to any above - default: - break - } - break - case .AttributeValue_singleQuoted: - let value = r.consumeToAny(TokeniserStateVars.attributeSingleValueCharsSorted) - if (value.count > 0) { - t.tagPending.appendAttributeValue(value) - } else { - t.tagPending.setEmptyAttributeValue() - } - - let c = r.consume() - switch (c) { - case "'": - t.transition(.AfterAttributeValue_quoted) - break - case UnicodeScalar.Ampersand: - - if let ref = try t.consumeCharacterReference("'", true) { - t.tagPending.appendAttributeValue(ref) - } else { - t.tagPending.appendAttributeValue(UnicodeScalar.Ampersand) - } - break - case TokeniserStateVars.nullScalr: - t.error(self) - t.tagPending.appendAttributeValue(TokeniserStateVars.replacementChar) - break - case TokeniserStateVars.eof: - t.eofError(self) - t.transition(.Data) - break - // no default, handled in consume to any above - default: - break - } - break - case .AttributeValue_unquoted: - let value = r.consumeToAnySorted(TokeniserStateVars.attributeValueUnquoted) - if (value.count > 0) { - t.tagPending.appendAttributeValue(value) - } - - let c = r.consume() - switch (c) { - case UnicodeScalar.BackslashT, "\n", "\r", UnicodeScalar.BackslashF, " ": - t.transition(.BeforeAttributeName) - break - case UnicodeScalar.Ampersand: - if let ref = try t.consumeCharacterReference(">", true) { - t.tagPending.appendAttributeValue(ref) - } else { - t.tagPending.appendAttributeValue(UnicodeScalar.Ampersand) - } - break - case ">": - try t.emitTagPending() - t.transition(.Data) - break - case TokeniserStateVars.nullScalr: - t.error(self) - t.tagPending.appendAttributeValue(TokeniserStateVars.replacementChar) - break - case TokeniserStateVars.eof: - t.eofError(self) - t.transition(.Data) - break - case "\"", "'", UnicodeScalar.LessThan, "=", "`": - t.error(self) - t.tagPending.appendAttributeValue(c) - break - // no default, handled in consume to any above - default: - break - } - break - case .AfterAttributeValue_quoted: - // CharacterReferenceInAttributeValue state handled inline - let c = r.consume() - switch (c) { - case UnicodeScalar.BackslashT, "\n", "\r", UnicodeScalar.BackslashF, " ": - t.transition(.BeforeAttributeName) - break - case "/": - t.transition(.SelfClosingStartTag) - break - case ">": - try t.emitTagPending() - t.transition(.Data) - break - case TokeniserStateVars.eof: - t.eofError(self) - t.transition(.Data) - break - default: - t.error(self) - r.unconsume() - t.transition(.BeforeAttributeName) - } - break - case .SelfClosingStartTag: - let c = r.consume() - switch (c) { - case ">": - t.tagPending._selfClosing = true - try t.emitTagPending() - t.transition(.Data) - break - case TokeniserStateVars.eof: - t.eofError(self) - t.transition(.Data) - break - default: - t.error(self) - r.unconsume() - t.transition(.BeforeAttributeName) - } - break - case .BogusComment: - // todo: handle bogus comment starting from eof. when does that trigger? - // rewind to capture character that lead us here - r.unconsume() - let comment: Token.Comment = Token.Comment() - comment.bogus = true - comment.data.append(r.consumeTo(">")) - // todo: replace nullChar with replaceChar - try t.emit(comment) - t.advanceTransition(.Data) - break - case .MarkupDeclarationOpen: - if (r.matchConsume("--")) { - t.createCommentPending() - t.transition(.CommentStart) - } else if (r.matchConsumeIgnoreCase("DOCTYPE")) { - t.transition(.Doctype) - } else if (r.matchConsume("[CDATA[")) { - // todo: should actually check current namepspace, and only non-html allows cdata. until namespace - // is implemented properly, keep handling as cdata - //} else if (!t.currentNodeInHtmlNS() && r.matchConsume("[CDATA[")) { - t.transition(.CdataSection) - } else { - t.error(self) - t.advanceTransition(.BogusComment) // advance so self character gets in bogus comment data's rewind - } - break - case .CommentStart: - let c = r.consume() - switch (c) { - case "-": - t.transition(.CommentStartDash) - break - case TokeniserStateVars.nullScalr: - t.error(self) - t.commentPending.data.append(TokeniserStateVars.replacementChar) - t.transition(.Comment) - break - case ">": - t.error(self) - try t.emitCommentPending() - t.transition(.Data) - break - case TokeniserStateVars.eof: - t.eofError(self) - try t.emitCommentPending() - t.transition(.Data) - break - default: - t.commentPending.data.append(c) - t.transition(.Comment) - } - break - case .CommentStartDash: - let c = r.consume() - switch (c) { - case "-": - t.transition(.CommentStartDash) - break - case TokeniserStateVars.nullScalr: - t.error(self) - t.commentPending.data.append(TokeniserStateVars.replacementChar) - t.transition(.Comment) - break - case ">": - t.error(self) - try t.emitCommentPending() - t.transition(.Data) - break - case TokeniserStateVars.eof: - t.eofError(self) - try t.emitCommentPending() - t.transition(.Data) - break - default: - t.commentPending.data.append(c) - t.transition(.Comment) - } - break - case .Comment: - let c = r.current() - switch (c) { - case "-": - t.advanceTransition(.CommentEndDash) - break - case TokeniserStateVars.nullScalr: - t.error(self) - r.advance() - t.commentPending.data.append(TokeniserStateVars.replacementChar) - break - case TokeniserStateVars.eof: - t.eofError(self) - try t.emitCommentPending() - t.transition(.Data) - break - default: - t.commentPending.data.append(r.consumeToAny("-", TokeniserStateVars.nullScalr)) - } - break - case .CommentEndDash: - let c = r.consume() - switch (c) { - case "-": - t.transition(.CommentEnd) - break - case TokeniserStateVars.nullScalr: - t.error(self) - t.commentPending.data.append("-").append(TokeniserStateVars.replacementChar) - t.transition(.Comment) - break - case TokeniserStateVars.eof: - t.eofError(self) - try t.emitCommentPending() - t.transition(.Data) - break - default: - t.commentPending.data.append("-").append(c) - t.transition(.Comment) - } - break - case .CommentEnd: - let c = r.consume() - switch (c) { - case ">": - try t.emitCommentPending() - t.transition(.Data) - break - case TokeniserStateVars.nullScalr: - t.error(self) - t.commentPending.data.append("--").append(TokeniserStateVars.replacementChar) - t.transition(.Comment) - break - case "!": - t.error(self) - t.transition(.CommentEndBang) - break - case "-": - t.error(self) - t.commentPending.data.append("-") - break - case TokeniserStateVars.eof: - t.eofError(self) - try t.emitCommentPending() - t.transition(.Data) - break - default: - t.error(self) - t.commentPending.data.append("--").append(c) - t.transition(.Comment) - } - break - case .CommentEndBang: - let c = r.consume() - switch (c) { - case "-": - t.commentPending.data.append("--!") - t.transition(.CommentEndDash) - break - case ">": - try t.emitCommentPending() - t.transition(.Data) - break - case TokeniserStateVars.nullScalr: - t.error(self) - t.commentPending.data.append("--!").append(TokeniserStateVars.replacementChar) - t.transition(.Comment) - break - case TokeniserStateVars.eof: - t.eofError(self) - try t.emitCommentPending() - t.transition(.Data) - break - default: - t.commentPending.data.append("--!").append(c) - t.transition(.Comment) - } - break - case .Doctype: - let c = r.consume() - switch (c) { - case UnicodeScalar.BackslashT, "\n", "\r", UnicodeScalar.BackslashF, " ": - t.transition(.BeforeDoctypeName) - break - case TokeniserStateVars.eof: - t.eofError(self) - // note: fall through to > case - case ">": // catch invalid - t.error(self) - t.createDoctypePending() - t.doctypePending.forceQuirks = true - try t.emitDoctypePending() - t.transition(.Data) - break - default: - t.error(self) - t.transition(.BeforeDoctypeName) - } - break - case .BeforeDoctypeName: - if (r.matchesLetter()) { - t.createDoctypePending() - t.transition(.DoctypeName) - return - } - let c = r.consume() - switch (c) { - case UnicodeScalar.BackslashT, "\n", "\r", UnicodeScalar.BackslashF, " ": - break // ignore whitespace - case TokeniserStateVars.nullScalr: - t.error(self) - t.createDoctypePending() - t.doctypePending.name.append(TokeniserStateVars.replacementChar) - t.transition(.DoctypeName) - break - case TokeniserStateVars.eof: - t.eofError(self) - t.createDoctypePending() - t.doctypePending.forceQuirks = true - try t.emitDoctypePending() - t.transition(.Data) - break - default: - t.createDoctypePending() - t.doctypePending.name.append(c) - t.transition(.DoctypeName) - } - break - case .DoctypeName: - if (r.matchesLetter()) { - let name = r.consumeLetterSequence() - t.doctypePending.name.append(name) - return - } - let c = r.consume() - switch (c) { - case ">": - try t.emitDoctypePending() - t.transition(.Data) - break - case UnicodeScalar.BackslashT, "\n", "\r", UnicodeScalar.BackslashF, " ": - t.transition(.AfterDoctypeName) - break - case TokeniserStateVars.nullScalr: - t.error(self) - t.doctypePending.name.append(TokeniserStateVars.replacementChar) - break - case TokeniserStateVars.eof: - t.eofError(self) - t.doctypePending.forceQuirks = true - try t.emitDoctypePending() - t.transition(.Data) - break - default: - t.doctypePending.name.append(c) - } - break - case .AfterDoctypeName: - if (r.isEmpty()) { - t.eofError(self) - t.doctypePending.forceQuirks = true - try t.emitDoctypePending() - t.transition(.Data) - return - } - if (r.matchesAny(UnicodeScalar.BackslashT, "\n", "\r", UnicodeScalar.BackslashF, " ")) { - r.advance() // ignore whitespace - } else if (r.matches(">")) { - try t.emitDoctypePending() - t.advanceTransition(.Data) - } else if (r.matchConsumeIgnoreCase(DocumentType.PUBLIC_KEY)) { - t.doctypePending.pubSysKey = DocumentType.PUBLIC_KEY - t.transition(.AfterDoctypePublicKeyword) - } else if (r.matchConsumeIgnoreCase(DocumentType.SYSTEM_KEY)) { - t.doctypePending.pubSysKey = DocumentType.SYSTEM_KEY - t.transition(.AfterDoctypeSystemKeyword) - } else { - t.error(self) - t.doctypePending.forceQuirks = true - t.advanceTransition(.BogusDoctype) - } - break - case .AfterDoctypePublicKeyword: - let c = r.consume() - switch (c) { - case UnicodeScalar.BackslashT, "\n", "\r", UnicodeScalar.BackslashF, " ": - t.transition(.BeforeDoctypePublicIdentifier) - break - case "\"": - t.error(self) - // set public id to empty string - t.transition(.DoctypePublicIdentifier_doubleQuoted) - break - case "'": - t.error(self) - // set public id to empty string - t.transition(.DoctypePublicIdentifier_singleQuoted) - break - case ">": - t.error(self) - t.doctypePending.forceQuirks = true - try t.emitDoctypePending() - t.transition(.Data) - break - case TokeniserStateVars.eof: - t.eofError(self) - t.doctypePending.forceQuirks = true - try t.emitDoctypePending() - t.transition(.Data) - break - default: - t.error(self) - t.doctypePending.forceQuirks = true - t.transition(.BogusDoctype) - } - break - case .BeforeDoctypePublicIdentifier: - let c = r.consume() - switch (c) { - case UnicodeScalar.BackslashT, "\n", "\r", UnicodeScalar.BackslashF, " ": - break - case "\"": - // set public id to empty string - t.transition(.DoctypePublicIdentifier_doubleQuoted) - break - case "'": - // set public id to empty string - t.transition(.DoctypePublicIdentifier_singleQuoted) - break - case ">": - t.error(self) - t.doctypePending.forceQuirks = true - try t.emitDoctypePending() - t.transition(.Data) - break - case TokeniserStateVars.eof: - t.eofError(self) - t.doctypePending.forceQuirks = true - try t.emitDoctypePending() - t.transition(.Data) - break - default: - t.error(self) - t.doctypePending.forceQuirks = true - t.transition(.BogusDoctype) - } - break - case .DoctypePublicIdentifier_doubleQuoted: - let c = r.consume() - switch (c) { - case "\"": - t.transition(.AfterDoctypePublicIdentifier) - break - case TokeniserStateVars.nullScalr: - t.error(self) - t.doctypePending.publicIdentifier.append(TokeniserStateVars.replacementChar) - break - case ">": - t.error(self) - t.doctypePending.forceQuirks = true - try t.emitDoctypePending() - t.transition(.Data) - break - case TokeniserStateVars.eof: - t.eofError(self) - t.doctypePending.forceQuirks = true - try t.emitDoctypePending() - t.transition(.Data) - break - default: - t.doctypePending.publicIdentifier.append(c) - } - break - case .DoctypePublicIdentifier_singleQuoted: - let c = r.consume() - switch (c) { - case "'": - t.transition(.AfterDoctypePublicIdentifier) - break - case TokeniserStateVars.nullScalr: - t.error(self) - t.doctypePending.publicIdentifier.append(TokeniserStateVars.replacementChar) - break - case ">": - t.error(self) - t.doctypePending.forceQuirks = true - try t.emitDoctypePending() - t.transition(.Data) - break - case TokeniserStateVars.eof: - t.eofError(self) - t.doctypePending.forceQuirks = true - try t.emitDoctypePending() - t.transition(.Data) - break - default: - t.doctypePending.publicIdentifier.append(c) - } - break - case .AfterDoctypePublicIdentifier: - let c = r.consume() - switch (c) { - case UnicodeScalar.BackslashT, "\n", "\r", UnicodeScalar.BackslashF, " ": - t.transition(.BetweenDoctypePublicAndSystemIdentifiers) - break - case ">": - try t.emitDoctypePending() - t.transition(.Data) - break - case "\"": - t.error(self) - // system id empty - t.transition(.DoctypeSystemIdentifier_doubleQuoted) - break - case "'": - t.error(self) - // system id empty - t.transition(.DoctypeSystemIdentifier_singleQuoted) - break - case TokeniserStateVars.eof: - t.eofError(self) - t.doctypePending.forceQuirks = true - try t.emitDoctypePending() - t.transition(.Data) - break - default: - t.error(self) - t.doctypePending.forceQuirks = true - t.transition(.BogusDoctype) - } - break - case .BetweenDoctypePublicAndSystemIdentifiers: - let c = r.consume() - switch (c) { - case UnicodeScalar.BackslashT, "\n", "\r", UnicodeScalar.BackslashF, " ": - break - case ">": - try t.emitDoctypePending() - t.transition(.Data) - break - case "\"": - t.error(self) - // system id empty - t.transition(.DoctypeSystemIdentifier_doubleQuoted) - break - case "'": - t.error(self) - // system id empty - t.transition(.DoctypeSystemIdentifier_singleQuoted) - break - case TokeniserStateVars.eof: - t.eofError(self) - t.doctypePending.forceQuirks = true - try t.emitDoctypePending() - t.transition(.Data) - break - default: - t.error(self) - t.doctypePending.forceQuirks = true - t.transition(.BogusDoctype) - } - break - case .AfterDoctypeSystemKeyword: - let c = r.consume() - switch (c) { - case UnicodeScalar.BackslashT, "\n", "\r", UnicodeScalar.BackslashF, " ": - t.transition(.BeforeDoctypeSystemIdentifier) - break - case ">": - t.error(self) - t.doctypePending.forceQuirks = true - try t.emitDoctypePending() - t.transition(.Data) - break - case "\"": - t.error(self) - // system id empty - t.transition(.DoctypeSystemIdentifier_doubleQuoted) - break - case "'": - t.error(self) - // system id empty - t.transition(.DoctypeSystemIdentifier_singleQuoted) - break - case TokeniserStateVars.eof: - t.eofError(self) - t.doctypePending.forceQuirks = true - try t.emitDoctypePending() - t.transition(.Data) - break - default: - t.error(self) - t.doctypePending.forceQuirks = true - try t.emitDoctypePending() - } - break - case .BeforeDoctypeSystemIdentifier: - let c = r.consume() - switch (c) { - case UnicodeScalar.BackslashT, "\n", "\r", UnicodeScalar.BackslashF, " ": - break - case "\"": - // set system id to empty string - t.transition(.DoctypeSystemIdentifier_doubleQuoted) - break - case "'": - // set public id to empty string - t.transition(.DoctypeSystemIdentifier_singleQuoted) - break - case ">": - t.error(self) - t.doctypePending.forceQuirks = true - try t.emitDoctypePending() - t.transition(.Data) - break - case TokeniserStateVars.eof: - t.eofError(self) - t.doctypePending.forceQuirks = true - try t.emitDoctypePending() - t.transition(.Data) - break - default: - t.error(self) - t.doctypePending.forceQuirks = true - t.transition(.BogusDoctype) - } - break - case .DoctypeSystemIdentifier_doubleQuoted: - let c = r.consume() - switch (c) { - case "\"": - t.transition(.AfterDoctypeSystemIdentifier) - break - case TokeniserStateVars.nullScalr: - t.error(self) - t.doctypePending.systemIdentifier.append(TokeniserStateVars.replacementChar) - break - case ">": - t.error(self) - t.doctypePending.forceQuirks = true - try t.emitDoctypePending() - t.transition(.Data) - break - case TokeniserStateVars.eof: - t.eofError(self) - t.doctypePending.forceQuirks = true - try t.emitDoctypePending() - t.transition(.Data) - break - default: - t.doctypePending.systemIdentifier.append(c) - } - break - case .DoctypeSystemIdentifier_singleQuoted: - let c = r.consume() - switch (c) { - case "'": - t.transition(.AfterDoctypeSystemIdentifier) - break - case TokeniserStateVars.nullScalr: - t.error(self) - t.doctypePending.systemIdentifier.append(TokeniserStateVars.replacementChar) - break - case ">": - t.error(self) - t.doctypePending.forceQuirks = true - try t.emitDoctypePending() - t.transition(.Data) - break - case TokeniserStateVars.eof: - t.eofError(self) - t.doctypePending.forceQuirks = true - try t.emitDoctypePending() - t.transition(.Data) - break - default: - t.doctypePending.systemIdentifier.append(c) - } - break - case .AfterDoctypeSystemIdentifier: - let c = r.consume() - switch (c) { - case UnicodeScalar.BackslashT, "\n", "\r", UnicodeScalar.BackslashF, " ": - break - case ">": - try t.emitDoctypePending() - t.transition(.Data) - break - case TokeniserStateVars.eof: - t.eofError(self) - t.doctypePending.forceQuirks = true - try t.emitDoctypePending() - t.transition(.Data) - break - default: - t.error(self) - t.transition(.BogusDoctype) - // NOT force quirks - } - break - case .BogusDoctype: - let c = r.consume() - switch (c) { - case ">": - try t.emitDoctypePending() - t.transition(.Data) - break - case TokeniserStateVars.eof: - try t.emitDoctypePending() - t.transition(.Data) - break - default: - // ignore char - break - } - break - case .CdataSection: - let data = r.consumeTo("]]>") - t.emit(data) - r.matchConsume("]]>") - t.transition(.Data) - break - } - } - - var description: String {return String(describing: type(of: self))} - /** - * Handles RawtextEndTagName, ScriptDataEndTagName, and ScriptDataEscapedEndTagName. Same body impl, just - * different else exit transitions. - */ - private static func handleDataEndTag(_ t: Tokeniser, _ r: CharacterReader, _ elseTransition: TokeniserState)throws { - if (r.matchesLetter()) { - let name = r.consumeLetterSequence() - t.tagPending.appendTagName(name) - t.dataBuffer.append(name) - return - } - - var needsExitTransition = false - if (try t.isAppropriateEndTagToken() && !r.isEmpty()) { - let c = r.consume() - switch (c) { - case UnicodeScalar.BackslashT, "\n", "\r", UnicodeScalar.BackslashF, " ": - t.transition(BeforeAttributeName) - break - case "/": - t.transition(SelfClosingStartTag) - break - case ">": - try t.emitTagPending() - t.transition(Data) - break - default: - t.dataBuffer.append(c) - needsExitTransition = true - } - } else { - needsExitTransition = true - } - - if (needsExitTransition) { - t.emit("": - if (t.dataBuffer.toString() == "script") { - t.transition(primary) - } else { - t.transition(fallback) - } - t.emit(c) - break - default: - r.unconsume() - t.transition(fallback) - } - } - -} diff --git a/Pods/SwiftSoup/Sources/TreeBuilder.swift b/Pods/SwiftSoup/Sources/TreeBuilder.swift deleted file mode 100644 index a8b9ac0..0000000 --- a/Pods/SwiftSoup/Sources/TreeBuilder.swift +++ /dev/null @@ -1,98 +0,0 @@ -// -// TreeBuilder.swift -// SwiftSoup -// -// Created by Nabil Chatbi on 24/10/16. -// Copyright © 2016 Nabil Chatbi.. All rights reserved. -// - -import Foundation - -public class TreeBuilder { - public var reader: CharacterReader - var tokeniser: Tokeniser - public var doc: Document // current doc we are building into - public var stack: Array // the stack of open elements - public var baseUri: String // current base uri, for creating new elements - public var currentToken: Token? // currentToken is used only for error tracking. - public var errors: ParseErrorList // null when not tracking errors - public var settings: ParseSettings - - private let start: Token.StartTag = Token.StartTag() // start tag to process - private let end: Token.EndTag = Token.EndTag() - - public func defaultSettings() -> ParseSettings {preconditionFailure("This method must be overridden")} - - public init() { - doc = Document("") - reader = CharacterReader("") - tokeniser = Tokeniser(reader, nil) - stack = Array() - baseUri = "" - errors = ParseErrorList(0, 0) - settings = ParseSettings(false, false) - } - - public func initialiseParse(_ input: String, _ baseUri: String, _ errors: ParseErrorList, _ settings: ParseSettings) { - doc = Document(baseUri) - self.settings = settings - reader = CharacterReader(input) - self.errors = errors - tokeniser = Tokeniser(reader, errors) - stack = Array() - self.baseUri = baseUri - } - - func parse(_ input: String, _ baseUri: String, _ errors: ParseErrorList, _ settings: ParseSettings)throws->Document { - initialiseParse(input, baseUri, errors, settings) - try runParser() - return doc - } - - public func runParser()throws { - while (true) { - let token: Token = try tokeniser.read() - try process(token) - token.reset() - - if (token.type == Token.TokenType.EOF) { - break - } - } - } - - @discardableResult - public func process(_ token: Token)throws->Bool {preconditionFailure("This method must be overridden")} - - @discardableResult - public func processStartTag(_ name: String)throws->Bool { - if (currentToken === start) { // don't recycle an in-use token - return try process(Token.StartTag().name(name)) - } - return try process(start.reset().name(name)) - } - - @discardableResult - public func processStartTag(_ name: String, _ attrs: Attributes)throws->Bool { - if (currentToken === start) { // don't recycle an in-use token - return try process(Token.StartTag().nameAttr(name, attrs)) - } - start.reset() - start.nameAttr(name, attrs) - return try process(start) - } - - @discardableResult - public func processEndTag(_ name: String)throws->Bool { - if (currentToken === end) { // don't recycle an in-use token - return try process(Token.EndTag().name(name)) - } - - return try process(end.reset().name(name)) - } - - public func currentElement() -> Element? { - let size: Int = stack.count - return size > 0 ? stack[size-1] : nil - } -} diff --git a/Pods/SwiftSoup/Sources/UnicodeScalar.swift b/Pods/SwiftSoup/Sources/UnicodeScalar.swift deleted file mode 100644 index 0a52709..0000000 --- a/Pods/SwiftSoup/Sources/UnicodeScalar.swift +++ /dev/null @@ -1,67 +0,0 @@ -// -// UnicodeScalar.swift -// SwiftSoup -// -// Created by Nabil Chatbi on 14/11/16. -// Copyright © 2016 Nabil Chatbi. All rights reserved. -// - -import Foundation - -private let uppercaseSet = CharacterSet.uppercaseLetters -private let lowercaseSet = CharacterSet.lowercaseLetters -private let alphaSet = CharacterSet.letters -private let alphaNumericSet = CharacterSet.alphanumerics -private let symbolSet = CharacterSet.symbols -private let digitSet = CharacterSet.decimalDigits - -extension UnicodeScalar { - public static let Ampersand: UnicodeScalar = "&" - public static let LessThan: UnicodeScalar = "<" - public static let GreaterThan: UnicodeScalar = ">" - - public static let Space: UnicodeScalar = " " - public static let BackslashF: UnicodeScalar = UnicodeScalar(12) - public static let BackslashT: UnicodeScalar = "\t" - public static let BackslashN: UnicodeScalar = "\n" - public static let BackslashR: UnicodeScalar = "\r" - public static let Slash: UnicodeScalar = "/" - - public static let FormFeed: UnicodeScalar = "\u{000B}"// Form Feed - public static let VerticalTab: UnicodeScalar = "\u{000C}"// vertical tab - - func isMemberOfCharacterSet(_ set: CharacterSet) -> Bool { - return set.contains(self) - } - - /// True for any space character, and the control characters \t, \n, \r, \f, \v. - var isWhitespace: Bool { - - switch self { - - case UnicodeScalar.Space, UnicodeScalar.BackslashT, UnicodeScalar.BackslashN, UnicodeScalar.BackslashR, UnicodeScalar.BackslashF: return true - - case UnicodeScalar.FormFeed, UnicodeScalar.VerticalTab: return true // Form Feed, vertical tab - - default: return false - - } - - } - - /// `true` if `self` normalized contains a single code unit that is in the categories of Uppercase and Titlecase Letters. - var isUppercase: Bool { - return isMemberOfCharacterSet(uppercaseSet) - } - - /// `true` if `self` normalized contains a single code unit that is in the category of Lowercase Letters. - var isLowercase: Bool { - return isMemberOfCharacterSet(lowercaseSet) - - } - - var uppercase: UnicodeScalar { - let str = String(self).uppercased() - return str.unicodeScalar(0) - } -} diff --git a/Pods/SwiftSoup/Sources/Validate.swift b/Pods/SwiftSoup/Sources/Validate.swift deleted file mode 100644 index 2e6e864..0000000 --- a/Pods/SwiftSoup/Sources/Validate.swift +++ /dev/null @@ -1,133 +0,0 @@ -// -// Validate.swift -// SwifSoup -// -// Created by Nabil Chatbi on 02/10/16. -// Copyright © 2016 Nabil Chatbi.. All rights reserved. -// - -import Foundation - -struct Validate { - - /** - * Validates that the object is not null - * @param obj object to test - */ - public static func notNull(obj: Any?) throws { - if (obj == nil) { - throw Exception.Error(type: ExceptionType.IllegalArgumentException, Message: "Object must not be null") - } - } - - /** - * Validates that the object is not null - * @param obj object to test - * @param msg message to output if validation fails - */ - public static func notNull(obj: AnyObject?, msg: String) throws { - if (obj == nil) { - throw Exception.Error(type: ExceptionType.IllegalArgumentException, Message: msg) - } - } - - /** - * Validates that the value is true - * @param val object to test - */ - public static func isTrue(val: Bool) throws { - if (!val) { - throw Exception.Error(type: ExceptionType.IllegalArgumentException, Message: "Must be true") - } - } - - /** - * Validates that the value is true - * @param val object to test - * @param msg message to output if validation fails - */ - public static func isTrue(val: Bool, msg: String) throws { - if (!val) { - throw Exception.Error(type: ExceptionType.IllegalArgumentException, Message: msg) - } - } - - /** - * Validates that the value is false - * @param val object to test - */ - public static func isFalse(val: Bool) throws { - if (val) { - throw Exception.Error(type: ExceptionType.IllegalArgumentException, Message: "Must be false") - } - } - - /** - * Validates that the value is false - * @param val object to test - * @param msg message to output if validation fails - */ - public static func isFalse(val: Bool, msg: String) throws { - if (val) { - throw Exception.Error(type: ExceptionType.IllegalArgumentException, Message: msg) - } - } - - /** - * Validates that the array contains no null elements - * @param objects the array to test - */ - public static func noNullElements(objects: [AnyObject?]) throws { - try noNullElements(objects: objects, msg: "Array must not contain any null objects") - } - - /** - * Validates that the array contains no null elements - * @param objects the array to test - * @param msg message to output if validation fails - */ - public static func noNullElements(objects: [AnyObject?], msg: String) throws { - for obj in objects { - if (obj == nil) { - throw Exception.Error(type: ExceptionType.IllegalArgumentException, Message: msg) - } - } - } - - /** - * Validates that the string is not empty - * @param string the string to test - */ - public static func notEmpty(string: String?) throws { - if (string == nil || string?.count == 0) { - throw Exception.Error(type: ExceptionType.IllegalArgumentException, Message: "String must not be empty") - } - - } - - /** - * Validates that the string is not empty - * @param string the string to test - * @param msg message to output if validation fails - */ - public static func notEmpty(string: String?, msg: String ) throws { - if (string == nil || string?.count == 0) { - throw Exception.Error(type: ExceptionType.IllegalArgumentException, Message: msg) - } - } - - /** - Cause a failure. - @param msg message to output. - */ - public static func fail(msg: String) throws { - throw Exception.Error(type: ExceptionType.IllegalArgumentException, Message: msg) - } - - /** - Helper - */ - public static func exception(msg: String) throws { - throw Exception.Error(type: ExceptionType.IllegalArgumentException, Message: msg) - } -} diff --git a/Pods/SwiftSoup/Sources/Whitelist.swift b/Pods/SwiftSoup/Sources/Whitelist.swift deleted file mode 100644 index c395170..0000000 --- a/Pods/SwiftSoup/Sources/Whitelist.swift +++ /dev/null @@ -1,650 +0,0 @@ -// -// Whitelist.swift -// SwiftSoup -// -// Created by Nabil Chatbi on 14/10/16. -// Copyright © 2016 Nabil Chatbi.. All rights reserved. -// - -/* - Thank you to Ryan Grove (wonko.com) for the Ruby HTML cleaner http://github.com/rgrove/sanitize/, which inspired - this whitelist configuration, and the initial defaults. - */ - -/** - Whitelists define what HTML (elements and attributes) to allow through the cleaner. Everything else is removed. -

    - Start with one of the defaults: -

    -
      -
    • {@link #none} -
    • {@link #simpleText} -
    • {@link #basic} -
    • {@link #basicWithImages} -
    • {@link #relaxed} -
    -

    - If you need to allow more through (please be careful!), tweak a base whitelist with: -

    -
      -
    • {@link #addTags} -
    • {@link #addAttributes} -
    • {@link #addEnforcedAttribute} -
    • {@link #addProtocols} -
    -

    - You can remove any setting from an existing whitelist with: -

    -
      -
    • {@link #removeTags} -
    • {@link #removeAttributes} -
    • {@link #removeEnforcedAttribute} -
    • {@link #removeProtocols} -
    - -

    - The cleaner and these whitelists assume that you want to clean a body fragment of HTML (to add user - supplied HTML into a templated page), and not to clean a full HTML document. If the latter is the case, either wrap the - document HTML around the cleaned body HTML, or create a whitelist that allows html and head - elements as appropriate. -

    -

    - If you are going to extend a whitelist, please be very careful. Make sure you understand what attributes may lead to - XSS attack vectors. URL attributes are particularly vulnerable and require careful validation. See - http://ha.ckers.org/xss.html for some XSS attack examples. -

    - */ - -import Foundation - -public class Whitelist { - private var tagNames: Set // tags allowed, lower case. e.g. [p, br, span] - private var attributes: Dictionary> // tag -> attribute[]. allowed attributes [href] for a tag. - private var enforcedAttributes: Dictionary> // always set these attribute values - private var protocols: Dictionary>> // allowed URL protocols for attributes - private var preserveRelativeLinks: Bool // option to preserve relative links - - /** - This whitelist allows only text nodes: all HTML will be stripped. - - @return whitelist - */ - public static func none() -> Whitelist { - return Whitelist() - } - - /** - This whitelist allows only simple text formatting: b, em, i, strong, u. All other HTML (tags and - attributes) will be removed. - - @return whitelist - */ - public static func simpleText()throws ->Whitelist { - return try Whitelist().addTags("b", "em", "i", "strong", "u") - } - - /** -

    - This whitelist allows a fuller range of text nodes: a, b, blockquote, br, cite, code, dd, dl, dt, em, i, li, - ol, p, pre, q, small, span, strike, strong, sub, sup, u, ul, and appropriate attributes. -

    -

    - Links (a elements) can point to http, https, ftp, mailto, and have an enforced - rel=nofollow attribute. -

    -

    - Does not allow images. -

    - - @return whitelist - */ - public static func basic()throws->Whitelist { - return try Whitelist() - .addTags( - "a", "b", "blockquote", "br", "cite", "code", "dd", "dl", "dt", "em", - "i", "li", "ol", "p", "pre", "q", "small", "span", "strike", "strong", "sub", - "sup", "u", "ul") - - .addAttributes("a", "href") - .addAttributes("blockquote", "cite") - .addAttributes("q", "cite") - - .addProtocols("a", "href", "ftp", "http", "https", "mailto") - .addProtocols("blockquote", "cite", "http", "https") - .addProtocols("cite", "cite", "http", "https") - - .addEnforcedAttribute("a", "rel", "nofollow") - } - - /** - This whitelist allows the same text tags as {@link #basic}, and also allows img tags, with appropriate - attributes, with src pointing to http or https. - - @return whitelist - */ - public static func basicWithImages()throws->Whitelist { - return try basic() - .addTags("img") - .addAttributes("img", "align", "alt", "height", "src", "title", "width") - .addProtocols("img", "src", "http", "https") - - } - - /** - This whitelist allows a full range of text and structural body HTML: a, b, blockquote, br, caption, cite, - code, col, colgroup, dd, div, dl, dt, em, h1, h2, h3, h4, h5, h6, i, img, li, ol, p, pre, q, small, span, strike, strong, sub, - sup, table, tbody, td, tfoot, th, thead, tr, u, ul -

    - Links do not have an enforced rel=nofollow attribute, but you can add that if desired. -

    - - @return whitelist - */ - public static func relaxed()throws->Whitelist { - return try Whitelist() - .addTags( - "a", "b", "blockquote", "br", "caption", "cite", "code", "col", - "colgroup", "dd", "div", "dl", "dt", "em", "h1", "h2", "h3", "h4", "h5", "h6", - "i", "img", "li", "ol", "p", "pre", "q", "small", "span", "strike", "strong", - "sub", "sup", "table", "tbody", "td", "tfoot", "th", "thead", "tr", "u", - "ul") - - .addAttributes("a", "href", "title") - .addAttributes("blockquote", "cite") - .addAttributes("col", "span", "width") - .addAttributes("colgroup", "span", "width") - .addAttributes("img", "align", "alt", "height", "src", "title", "width") - .addAttributes("ol", "start", "type") - .addAttributes("q", "cite") - .addAttributes("table", "summary", "width") - .addAttributes("td", "abbr", "axis", "colspan", "rowspan", "width") - .addAttributes( - "th", "abbr", "axis", "colspan", "rowspan", "scope", - "width") - .addAttributes("ul", "type") - - .addProtocols("a", "href", "ftp", "http", "https", "mailto") - .addProtocols("blockquote", "cite", "http", "https") - .addProtocols("cite", "cite", "http", "https") - .addProtocols("img", "src", "http", "https") - .addProtocols("q", "cite", "http", "https") - } - - /** - Create a new, empty whitelist. Generally it will be better to start with a default prepared whitelist instead. - - @see #basic() - @see #basicWithImages() - @see #simpleText() - @see #relaxed() - */ - init() { - tagNames = Set() - attributes = Dictionary>() - enforcedAttributes = Dictionary>() - protocols = Dictionary>>() - preserveRelativeLinks = false - } - - /** - Add a list of allowed elements to a whitelist. (If a tag is not allowed, it will be removed from the HTML.) - - @param tags tag names to allow - @return this (for chaining) - */ - @discardableResult - open func addTags(_ tags: String...)throws ->Whitelist { - for tagName in tags { - try Validate.notEmpty(string: tagName) - tagNames.insert(TagName.valueOf(tagName)) - } - return self - } - - /** - Remove a list of allowed elements from a whitelist. (If a tag is not allowed, it will be removed from the HTML.) - - @param tags tag names to disallow - @return this (for chaining) - */ - @discardableResult - open func removeTags(_ tags: String...)throws ->Whitelist { - try Validate.notNull(obj: tags) - - for tag in tags { - try Validate.notEmpty(string: tag) - let tagName: TagName = TagName.valueOf(tag) - - if(tagNames.contains(tagName)) { // Only look in sub-maps if tag was allowed - tagNames.remove(tagName) - attributes.removeValue(forKey: tagName) - enforcedAttributes.removeValue(forKey: tagName) - protocols.removeValue(forKey: tagName) - } - } - return self - } - - /** - Add a list of allowed attributes to a tag. (If an attribute is not allowed on an element, it will be removed.) -

    - E.g.: addAttributes("a", "href", "class") allows href and class attributes - on a tags. -

    -

    - To make an attribute valid for all tags, use the pseudo tag :all, e.g. - addAttributes(":all", "class"). -

    - - @param tag The tag the attributes are for. The tag will be added to the allowed tag list if necessary. - @param keys List of valid attributes for the tag - @return this (for chaining) - */ - @discardableResult - open func addAttributes(_ tag: String, _ keys: String...)throws->Whitelist { - try Validate.notEmpty(string: tag) - try Validate.isTrue(val: keys.count > 0, msg: "No attributes supplied.") - - let tagName = TagName.valueOf(tag) - if (!tagNames.contains(tagName)) { - tagNames.insert(tagName) - } - var attributeSet = Set() - for key in keys { - try Validate.notEmpty(string: key) - attributeSet.insert(AttributeKey.valueOf(key)) - } - - if var currentSet = attributes[tagName] { - for at in attributeSet { - currentSet.insert(at) - } - attributes[tagName] = currentSet - } else { - attributes[tagName] = attributeSet - } - - return self - } - - /** - Remove a list of allowed attributes from a tag. (If an attribute is not allowed on an element, it will be removed.) -

    - E.g.: removeAttributes("a", "href", "class") disallows href and class - attributes on a tags. -

    -

    - To make an attribute invalid for all tags, use the pseudo tag :all, e.g. - removeAttributes(":all", "class"). -

    - - @param tag The tag the attributes are for. - @param keys List of invalid attributes for the tag - @return this (for chaining) - */ - @discardableResult - open func removeAttributes(_ tag: String, _ keys: String...)throws->Whitelist { - try Validate.notEmpty(string: tag) - try Validate.isTrue(val: keys.count > 0, msg: "No attributes supplied.") - - let tagName: TagName = TagName.valueOf(tag) - var attributeSet = Set() - for key in keys { - try Validate.notEmpty(string: key) - attributeSet.insert(AttributeKey.valueOf(key)) - } - - if(tagNames.contains(tagName)) { // Only look in sub-maps if tag was allowed - if var currentSet = attributes[tagName] { - for l in attributeSet { - currentSet.remove(l) - } - attributes[tagName] = currentSet - if(currentSet.isEmpty) { // Remove tag from attribute map if no attributes are allowed for tag - attributes.removeValue(forKey: tagName) - } - } - - } - - if(tag == ":all") { // Attribute needs to be removed from all individually set tags - for name in attributes.keys { - var currentSet: Set = attributes[name]! - for l in attributeSet { - currentSet.remove(l) - } - attributes[name] = currentSet - if(currentSet.isEmpty) { // Remove tag from attribute map if no attributes are allowed for tag - attributes.removeValue(forKey: name) - } - } - } - return self - } - - /** - Add an enforced attribute to a tag. An enforced attribute will always be added to the element. If the element - already has the attribute set, it will be overridden. -

    - E.g.: addEnforcedAttribute("a", "rel", "nofollow") will make all a tags output as - <a href="..." rel="nofollow"> -

    - - @param tag The tag the enforced attribute is for. The tag will be added to the allowed tag list if necessary. - @param key The attribute key - @param value The enforced attribute value - @return this (for chaining) - */ - @discardableResult - open func addEnforcedAttribute(_ tag: String, _ key: String, _ value: String)throws->Whitelist { - try Validate.notEmpty(string: tag) - try Validate.notEmpty(string: key) - try Validate.notEmpty(string: value) - - let tagName: TagName = TagName.valueOf(tag) - if (!tagNames.contains(tagName)) { - tagNames.insert(tagName) - } - let attrKey: AttributeKey = AttributeKey.valueOf(key) - let attrVal: AttributeValue = AttributeValue.valueOf(value) - - if (enforcedAttributes[tagName] != nil) { - enforcedAttributes[tagName]?[attrKey] = attrVal - } else { - var attrMap: Dictionary = Dictionary() - attrMap[attrKey] = attrVal - enforcedAttributes[tagName] = attrMap - } - return self - } - - /** - Remove a previously configured enforced attribute from a tag. - - @param tag The tag the enforced attribute is for. - @param key The attribute key - @return this (for chaining) - */ - @discardableResult - open func removeEnforcedAttribute(_ tag: String, _ key: String)throws->Whitelist { - try Validate.notEmpty(string: tag) - try Validate.notEmpty(string: key) - - let tagName: TagName = TagName.valueOf(tag) - if(tagNames.contains(tagName) && (enforcedAttributes[tagName] != nil)) { - let attrKey: AttributeKey = AttributeKey.valueOf(key) - var attrMap: Dictionary = enforcedAttributes[tagName]! - attrMap.removeValue(forKey: attrKey) - enforcedAttributes[tagName] = attrMap - - if(attrMap.isEmpty) { // Remove tag from enforced attribute map if no enforced attributes are present - enforcedAttributes.removeValue(forKey: tagName) - } - } - return self - } - - /** - * Configure this Whitelist to preserve relative links in an element's URL attribute, or convert them to absolute - * links. By default, this is false: URLs will be made absolute (e.g. start with an allowed protocol, like - * e.g. {@code http://}. - *

    - * Note that when handling relative links, the input document must have an appropriate {@code base URI} set when - * parsing, so that the link's protocol can be confirmed. Regardless of the setting of the {@code preserve relative - * links} option, the link must be resolvable against the base URI to an allowed protocol; otherwise the attribute - * will be removed. - *

    - * - * @param preserve {@code true} to allow relative links, {@code false} (default) to deny - * @return this Whitelist, for chaining. - * @see #addProtocols - */ - @discardableResult - open func preserveRelativeLinks(_ preserve: Bool) -> Whitelist { - preserveRelativeLinks = preserve - return self - } - - /** - Add allowed URL protocols for an element's URL attribute. This restricts the possible values of the attribute to - URLs with the defined protocol. -

    - E.g.: addProtocols("a", "href", "ftp", "http", "https") -

    -

    - To allow a link to an in-page URL anchor (i.e. <a href="#anchor">, add a #:
    - E.g.: addProtocols("a", "href", "#") -

    - - @param tag Tag the URL protocol is for - @param key Attribute key - @param protocols List of valid protocols - @return this, for chaining - */ - @discardableResult - open func addProtocols(_ tag: String, _ key: String, _ protocols: String...)throws->Whitelist { - try Validate.notEmpty(string: tag) - try Validate.notEmpty(string: key) - - let tagName: TagName = TagName.valueOf(tag) - let attrKey: AttributeKey = AttributeKey.valueOf(key) - var attrMap: Dictionary> - var protSet: Set - - if (self.protocols[tagName] != nil) { - attrMap = self.protocols[tagName]! - } else { - attrMap = Dictionary>() - self.protocols[tagName] = attrMap - } - - if (attrMap[attrKey] != nil) { - protSet = attrMap[attrKey]! - } else { - protSet = Set() - attrMap[attrKey] = protSet - self.protocols[tagName] = attrMap - } - for ptl in protocols { - try Validate.notEmpty(string: ptl) - let prot: Protocol = Protocol.valueOf(ptl) - protSet.insert(prot) - } - attrMap[attrKey] = protSet - self.protocols[tagName] = attrMap - - return self - } - - /** - Remove allowed URL protocols for an element's URL attribute. -

    - E.g.: removeProtocols("a", "href", "ftp") -

    - - @param tag Tag the URL protocol is for - @param key Attribute key - @param protocols List of invalid protocols - @return this, for chaining - */ - @discardableResult - open func removeProtocols(_ tag: String, _ key: String, _ protocols: String...)throws->Whitelist { - try Validate.notEmpty(string: tag) - try Validate.notEmpty(string: key) - - let tagName: TagName = TagName.valueOf(tag) - let attrKey: AttributeKey = AttributeKey.valueOf(key) - - if(self.protocols[tagName] != nil) { - var attrMap: Dictionary> = self.protocols[tagName]! - if(attrMap[attrKey] != nil) { - var protSet: Set = attrMap[attrKey]! - for ptl in protocols { - try Validate.notEmpty(string: ptl) - let prot: Protocol = Protocol.valueOf(ptl) - protSet.remove(prot) - } - attrMap[attrKey] = protSet - - if(protSet.isEmpty) { // Remove protocol set if empty - attrMap.removeValue(forKey: attrKey) - if(attrMap.isEmpty) { // Remove entry for tag if empty - self.protocols.removeValue(forKey: tagName) - } - - } - } - self.protocols[tagName] = attrMap - } - return self - } - - /** - * Test if the supplied tag is allowed by this whitelist - * @param tag test tag - * @return true if allowed - */ - public func isSafeTag(_ tag: String) -> Bool { - return tagNames.contains(TagName.valueOf(tag)) - } - - /** - * Test if the supplied attribute is allowed by this whitelist for this tag - * @param tagName tag to consider allowing the attribute in - * @param el element under test, to confirm protocol - * @param attr attribute under test - * @return true if allowed - */ - public func isSafeAttribute(_ tagName: String, _ el: Element, _ attr: Attribute)throws -> Bool { - let tag: TagName = TagName.valueOf(tagName) - let key: AttributeKey = AttributeKey.valueOf(attr.getKey()) - - if (attributes[tag] != nil) { - if (attributes[tag]?.contains(key))! { - if (protocols[tag] != nil) { - let attrProts: Dictionary> = protocols[tag]! - // ok if not defined protocol; otherwise test - return try (attrProts[key] == nil) || testValidProtocol(el, attr, attrProts[key]!) - } else { // attribute found, no protocols defined, so OK - return true - } - } - } - // no attributes defined for tag, try :all tag - return try !(tagName == ":all") && isSafeAttribute(":all", el, attr) - } - - private func testValidProtocol(_ el: Element, _ attr: Attribute, _ protocols: Set)throws->Bool { - // try to resolve relative urls to abs, and optionally update the attribute so output html has abs. - // rels without a baseuri get removed - var value: String = try el.absUrl(attr.getKey()) - if (value.count == 0) { - value = attr.getValue() - }// if it could not be made abs, run as-is to allow custom unknown protocols - if (!preserveRelativeLinks) { - attr.setValue(value: value) - } - - for ptl in protocols { - var prot: String = ptl.toString() - - if (prot=="#") { // allows anchor links - if (isValidAnchor(value)) { - return true - } else { - continue - } - } - - prot += ":" - - if (value.lowercased().hasPrefix(prot)) { - return true - } - - } - - return false - } - - private func isValidAnchor(_ value: String) -> Bool { - return value.startsWith("#") && !(Pattern(".*\\s.*").matcher(in: value).count > 0) - } - - public func getEnforcedAttributes(_ tagName: String)throws->Attributes { - let attrs: Attributes = Attributes() - let tag: TagName = TagName.valueOf(tagName) - if let keyVals: Dictionary = enforcedAttributes[tag] { - for entry in keyVals { - try attrs.put(entry.key.toString(), entry.value.toString()) - } - } - return attrs - } - -} - -// named types for config. All just hold strings, but here for my sanity. - -open class TagName: TypedValue { - override init(_ value: String) { - super.init(value) - } - - static func valueOf(_ value: String) -> TagName { - return TagName(value) - } -} - -open class AttributeKey: TypedValue { - override init(_ value: String) { - super.init(value) - } - - static func valueOf(_ value: String) -> AttributeKey { - return AttributeKey(value) - } -} - -open class AttributeValue: TypedValue { - override init(_ value: String) { - super.init(value) - } - - static func valueOf(_ value: String) -> AttributeValue { - return AttributeValue(value) - } -} - -open class Protocol: TypedValue { - override init(_ value: String) { - super.init(value) - } - - static func valueOf(_ value: String) -> Protocol { - return Protocol(value) - } -} - -open class TypedValue { - fileprivate let value: String - - init(_ value: String) { - self.value = value - } - - public func toString() -> String { - return value - } -} - -extension TypedValue: Hashable { - public func hash(into hasher: inout Hasher) { - hasher.combine(value) - } -} - -public func == (lhs: TypedValue, rhs: TypedValue) -> Bool { - if(lhs === rhs) {return true} - return lhs.value == rhs.value -} diff --git a/Pods/SwiftSoup/Sources/XmlDeclaration.swift b/Pods/SwiftSoup/Sources/XmlDeclaration.swift deleted file mode 100644 index 5f1032b..0000000 --- a/Pods/SwiftSoup/Sources/XmlDeclaration.swift +++ /dev/null @@ -1,77 +0,0 @@ -// -// XmlDeclaration.swift -// SwifSoup -// -// Created by Nabil Chatbi on 29/09/16. -// Copyright © 2016 Nabil Chatbi.. All rights reserved. -// - -import Foundation - -/** - An XML Declaration. - */ -public class XmlDeclaration: Node { - private let _name: String - private let isProcessingInstruction: Bool // String { - return "#declaration" - } - - /** - * Get the name of this declaration. - * @return name of this declaration. - */ - public func name() -> String { - return _name - } - - /** - Get the unencoded XML declaration. - @return XML declaration - */ - public func getWholeDeclaration()throws->String { - return try attributes!.html().trim() // attr html starts with a " " - } - - override func outerHtmlHead(_ accum: StringBuilder, _ depth: Int, _ out: OutputSettings) { - accum - .append("<") - .append(isProcessingInstruction ? "!" : "?") - .append(_name) - do { - try attributes?.html(accum: accum, out: out) - } catch {} - accum - .append(isProcessingInstruction ? "!" : "?") - .append(">") - } - - override func outerHtmlTail(_ accum: StringBuilder, _ depth: Int, _ out: OutputSettings) {} - - public override func copy(with zone: NSZone? = nil) -> Any { - let clone = XmlDeclaration(_name, baseUri!, isProcessingInstruction) - return copy(clone: clone) - } - - public override func copy(parent: Node?) -> Node { - let clone = XmlDeclaration(_name, baseUri!, isProcessingInstruction) - return copy(clone: clone, parent: parent) - } - public override func copy(clone: Node, parent: Node?) -> Node { - return super.copy(clone: clone, parent: parent) - } -} diff --git a/Pods/SwiftSoup/Sources/XmlTreeBuilder.swift b/Pods/SwiftSoup/Sources/XmlTreeBuilder.swift deleted file mode 100644 index 785a68b..0000000 --- a/Pods/SwiftSoup/Sources/XmlTreeBuilder.swift +++ /dev/null @@ -1,146 +0,0 @@ -// -// XmlTreeBuilder.swift -// SwiftSoup -// -// Created by Nabil Chatbi on 14/10/16. -// Copyright © 2016 Nabil Chatbi.. All rights reserved. -// - -import Foundation - -/** - * Use the {@code XmlTreeBuilder} when you want to parse XML without any of the HTML DOM rules being applied to the - * document. - *

    Usage example: {@code Document xmlDoc = Jsoup.parse(html, baseUrl, Parser.xmlParser())}

    - * - */ -public class XmlTreeBuilder: TreeBuilder { - - public override init() { - super.init() - } - - public override func defaultSettings() -> ParseSettings { - return ParseSettings.preserveCase - } - - public func parse(_ input: String, _ baseUri: String)throws->Document { - return try parse(input, baseUri, ParseErrorList.noTracking(), ParseSettings.preserveCase) - } - - override public func initialiseParse(_ input: String, _ baseUri: String, _ errors: ParseErrorList, _ settings: ParseSettings) { - super.initialiseParse(input, baseUri, errors, settings) - stack.append(doc) // place the document onto the stack. differs from HtmlTreeBuilder (not on stack) - doc.outputSettings().syntax(syntax: OutputSettings.Syntax.xml) - } - - override public func process(_ token: Token)throws->Bool { - // start tag, end tag, doctype, comment, character, eof - switch (token.type) { - case .StartTag: - try insert(token.asStartTag()) - break - case .EndTag: - try popStackToClose(token.asEndTag()) - break - case .Comment: - try insert(token.asComment()) - break - case .Char: - try insert(token.asCharacter()) - break - case .Doctype: - try insert(token.asDoctype()) - break - case .EOF: // could put some normalisation here if desired - break -// default: -// try Validate.fail(msg: "Unexpected token type: " + token.tokenType()) - } - return true - } - - private func insertNode(_ node: Node)throws { - try currentElement()?.appendChild(node) - } - - @discardableResult - func insert(_ startTag: Token.StartTag)throws->Element { - let tag: Tag = try Tag.valueOf(startTag.name(), settings) - // todo: wonder if for xml parsing, should treat all tags as unknown? because it's not html. - let el: Element = try Element(tag, baseUri, settings.normalizeAttributes(startTag._attributes)) - try insertNode(el) - if (startTag.isSelfClosing()) { - tokeniser.acknowledgeSelfClosingFlag() - if (!tag.isKnownTag()) // unknown tag, remember this is self closing for output. see above. - { - tag.setSelfClosing() - } - } else { - stack.append(el) - } - return el - } - - func insert(_ commentToken: Token.Comment)throws { - let comment: Comment = Comment(commentToken.getData(), baseUri) - var insert: Node = comment - if (commentToken.bogus) { // xml declarations are emitted as bogus comments (which is right for html, but not xml) - // so we do a bit of a hack and parse the data as an element to pull the attributes out - let data: String = comment.getData() - if (data.count > 1 && (data.startsWith("!") || data.startsWith("?"))) { - let doc: Document = try SwiftSoup.parse("<" + data.substring(1, data.count - 2) + ">", baseUri, Parser.xmlParser()) - let el: Element = doc.child(0) - insert = XmlDeclaration(settings.normalizeTag(el.tagName()), comment.getBaseUri(), data.startsWith("!")) - insert.getAttributes()?.addAll(incoming: el.getAttributes()) - } - } - try insertNode(insert) - } - - func insert(_ characterToken: Token.Char)throws { - let node: Node = TextNode(characterToken.getData()!, baseUri) - try insertNode(node) - } - - func insert(_ d: Token.Doctype)throws { - let doctypeNode = DocumentType(settings.normalizeTag(d.getName()), d.getPubSysKey(), d.getPublicIdentifier(), d.getSystemIdentifier(), baseUri) - try insertNode(doctypeNode) - } - - /** - * If the stack contains an element with this tag's name, pop up the stack to remove the first occurrence. If not - * found, skips. - * - * @param endTag - */ - private func popStackToClose(_ endTag: Token.EndTag)throws { - let elName: String = try endTag.name() - var firstFound: Element? = nil - - for pos in (0..Array { - initialiseParse(inputFragment, baseUri, errors, settings) - try runParser() - return doc.getChildNodes() - } -} diff --git a/Pods/Target Support Files/Just/Just-Info.plist b/Pods/Target Support Files/Just/Just-Info.plist new file mode 100644 index 0000000..2cf03a7 --- /dev/null +++ b/Pods/Target Support Files/Just/Just-Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + ${PRODUCT_BUNDLE_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + FMWK + CFBundleShortVersionString + 0.8.0 + CFBundleSignature + ???? + CFBundleVersion + ${CURRENT_PROJECT_VERSION} + NSPrincipalClass + + + diff --git a/Pods/Target Support Files/Just/Just-dummy.m b/Pods/Target Support Files/Just/Just-dummy.m new file mode 100644 index 0000000..7dd0b8f --- /dev/null +++ b/Pods/Target Support Files/Just/Just-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_Just : NSObject +@end +@implementation PodsDummy_Just +@end diff --git a/Pods/Target Support Files/Just/Just-prefix.pch b/Pods/Target Support Files/Just/Just-prefix.pch new file mode 100644 index 0000000..082f8af --- /dev/null +++ b/Pods/Target Support Files/Just/Just-prefix.pch @@ -0,0 +1,12 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + diff --git a/Pods/Target Support Files/Just/Just-umbrella.h b/Pods/Target Support Files/Just/Just-umbrella.h new file mode 100644 index 0000000..67e9619 --- /dev/null +++ b/Pods/Target Support Files/Just/Just-umbrella.h @@ -0,0 +1,16 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + + +FOUNDATION_EXPORT double JustVersionNumber; +FOUNDATION_EXPORT const unsigned char JustVersionString[]; + diff --git a/Pods/Target Support Files/Just/Just.modulemap b/Pods/Target Support Files/Just/Just.modulemap new file mode 100644 index 0000000..26848f4 --- /dev/null +++ b/Pods/Target Support Files/Just/Just.modulemap @@ -0,0 +1,6 @@ +framework module Just { + umbrella header "Just-umbrella.h" + + export * + module * { export * } +} diff --git a/Pods/Target Support Files/Just/Just.xcconfig b/Pods/Target Support Files/Just/Just.xcconfig new file mode 100644 index 0000000..3f5c8a6 --- /dev/null +++ b/Pods/Target Support Files/Just/Just.xcconfig @@ -0,0 +1,11 @@ +CODE_SIGN_IDENTITY = +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/Just +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/Just +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/Pods/Target Support Files/Pods-RSwitch/Pods-RSwitch-acknowledgements.markdown b/Pods/Target Support Files/Pods-RSwitch/Pods-RSwitch-acknowledgements.markdown index 43976cf..9acf9f1 100644 --- a/Pods/Target Support Files/Pods-RSwitch/Pods-RSwitch-acknowledgements.markdown +++ b/Pods/Target Support Files/Pods-RSwitch/Pods-RSwitch-acknowledgements.markdown @@ -1,28 +1,16 @@ # Acknowledgements This application makes use of the following third party libraries: -## SwiftSoup +## Just -MIT License +The MIT License (MIT) -Copyright (c) 2016 Nabil Chatbi +Copyright (c) 2015 Just contributors -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Generated by CocoaPods - https://cocoapods.org diff --git a/Pods/Target Support Files/Pods-RSwitch/Pods-RSwitch-acknowledgements.plist b/Pods/Target Support Files/Pods-RSwitch/Pods-RSwitch-acknowledgements.plist index 05e5607..4b4170c 100644 --- a/Pods/Target Support Files/Pods-RSwitch/Pods-RSwitch-acknowledgements.plist +++ b/Pods/Target Support Files/Pods-RSwitch/Pods-RSwitch-acknowledgements.plist @@ -14,32 +14,20 @@ FooterText - MIT License + The MIT License (MIT) -Copyright (c) 2016 Nabil Chatbi +Copyright (c) 2015 Just contributors -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. License MIT Title - SwiftSoup + Just Type PSGroupSpecifier diff --git a/Pods/Target Support Files/Pods-RSwitch/Pods-RSwitch-frameworks-Debug-input-files.xcfilelist b/Pods/Target Support Files/Pods-RSwitch/Pods-RSwitch-frameworks-Debug-input-files.xcfilelist index 33882de..429cd2a 100644 --- a/Pods/Target Support Files/Pods-RSwitch/Pods-RSwitch-frameworks-Debug-input-files.xcfilelist +++ b/Pods/Target Support Files/Pods-RSwitch/Pods-RSwitch-frameworks-Debug-input-files.xcfilelist @@ -1,2 +1,2 @@ ${PODS_ROOT}/Target Support Files/Pods-RSwitch/Pods-RSwitch-frameworks.sh -${BUILT_PRODUCTS_DIR}/SwiftSoup/SwiftSoup.framework \ No newline at end of file +${BUILT_PRODUCTS_DIR}/Just/Just.framework \ No newline at end of file diff --git a/Pods/Target Support Files/Pods-RSwitch/Pods-RSwitch-frameworks-Debug-output-files.xcfilelist b/Pods/Target Support Files/Pods-RSwitch/Pods-RSwitch-frameworks-Debug-output-files.xcfilelist index e7d2d3d..c4083ac 100644 --- a/Pods/Target Support Files/Pods-RSwitch/Pods-RSwitch-frameworks-Debug-output-files.xcfilelist +++ b/Pods/Target Support Files/Pods-RSwitch/Pods-RSwitch-frameworks-Debug-output-files.xcfilelist @@ -1 +1 @@ -${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SwiftSoup.framework \ No newline at end of file +${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Just.framework \ No newline at end of file diff --git a/Pods/Target Support Files/Pods-RSwitch/Pods-RSwitch-frameworks-Release-input-files.xcfilelist b/Pods/Target Support Files/Pods-RSwitch/Pods-RSwitch-frameworks-Release-input-files.xcfilelist index 33882de..429cd2a 100644 --- a/Pods/Target Support Files/Pods-RSwitch/Pods-RSwitch-frameworks-Release-input-files.xcfilelist +++ b/Pods/Target Support Files/Pods-RSwitch/Pods-RSwitch-frameworks-Release-input-files.xcfilelist @@ -1,2 +1,2 @@ ${PODS_ROOT}/Target Support Files/Pods-RSwitch/Pods-RSwitch-frameworks.sh -${BUILT_PRODUCTS_DIR}/SwiftSoup/SwiftSoup.framework \ No newline at end of file +${BUILT_PRODUCTS_DIR}/Just/Just.framework \ No newline at end of file diff --git a/Pods/Target Support Files/Pods-RSwitch/Pods-RSwitch-frameworks-Release-output-files.xcfilelist b/Pods/Target Support Files/Pods-RSwitch/Pods-RSwitch-frameworks-Release-output-files.xcfilelist index e7d2d3d..c4083ac 100644 --- a/Pods/Target Support Files/Pods-RSwitch/Pods-RSwitch-frameworks-Release-output-files.xcfilelist +++ b/Pods/Target Support Files/Pods-RSwitch/Pods-RSwitch-frameworks-Release-output-files.xcfilelist @@ -1 +1 @@ -${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SwiftSoup.framework \ No newline at end of file +${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Just.framework \ No newline at end of file diff --git a/Pods/Target Support Files/Pods-RSwitch/Pods-RSwitch-frameworks.sh b/Pods/Target Support Files/Pods-RSwitch/Pods-RSwitch-frameworks.sh index a318c71..cff2231 100755 --- a/Pods/Target Support Files/Pods-RSwitch/Pods-RSwitch-frameworks.sh +++ b/Pods/Target Support Files/Pods-RSwitch/Pods-RSwitch-frameworks.sh @@ -161,10 +161,10 @@ strip_invalid_archs() { if [[ "$CONFIGURATION" == "Debug" ]]; then - install_framework "${BUILT_PRODUCTS_DIR}/SwiftSoup/SwiftSoup.framework" + install_framework "${BUILT_PRODUCTS_DIR}/Just/Just.framework" fi if [[ "$CONFIGURATION" == "Release" ]]; then - install_framework "${BUILT_PRODUCTS_DIR}/SwiftSoup/SwiftSoup.framework" + install_framework "${BUILT_PRODUCTS_DIR}/Just/Just.framework" fi if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then wait diff --git a/Pods/Target Support Files/Pods-RSwitch/Pods-RSwitch.debug.xcconfig b/Pods/Target Support Files/Pods-RSwitch/Pods-RSwitch.debug.xcconfig index d3bb862..8e14bda 100644 --- a/Pods/Target Support Files/Pods-RSwitch/Pods-RSwitch.debug.xcconfig +++ b/Pods/Target Support Files/Pods-RSwitch/Pods-RSwitch.debug.xcconfig @@ -1,11 +1,12 @@ ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES -FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/SwiftSoup" +FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Just" GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 -HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/SwiftSoup/SwiftSoup.framework/Headers" +HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Just/Just.framework/Headers" LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/../Frameworks' '@loader_path/Frameworks' -OTHER_LDFLAGS = $(inherited) -framework "SwiftSoup" +OTHER_LDFLAGS = $(inherited) -framework "Just" OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS PODS_BUILD_DIR = ${BUILD_DIR} PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) PODS_PODFILE_DIR_PATH = ${SRCROOT}/. PODS_ROOT = ${SRCROOT}/Pods +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/Pods/Target Support Files/Pods-RSwitch/Pods-RSwitch.release.xcconfig b/Pods/Target Support Files/Pods-RSwitch/Pods-RSwitch.release.xcconfig index d3bb862..8e14bda 100644 --- a/Pods/Target Support Files/Pods-RSwitch/Pods-RSwitch.release.xcconfig +++ b/Pods/Target Support Files/Pods-RSwitch/Pods-RSwitch.release.xcconfig @@ -1,11 +1,12 @@ ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES -FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/SwiftSoup" +FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Just" GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 -HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/SwiftSoup/SwiftSoup.framework/Headers" +HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Just/Just.framework/Headers" LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/../Frameworks' '@loader_path/Frameworks' -OTHER_LDFLAGS = $(inherited) -framework "SwiftSoup" +OTHER_LDFLAGS = $(inherited) -framework "Just" OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS PODS_BUILD_DIR = ${BUILD_DIR} PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) PODS_PODFILE_DIR_PATH = ${SRCROOT}/. PODS_ROOT = ${SRCROOT}/Pods +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/Pods/Target Support Files/SwiftSoup/SwiftSoup-Info.plist b/Pods/Target Support Files/SwiftSoup/SwiftSoup-Info.plist deleted file mode 100644 index c054f9c..0000000 --- a/Pods/Target Support Files/SwiftSoup/SwiftSoup-Info.plist +++ /dev/null @@ -1,26 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleExecutable - ${EXECUTABLE_NAME} - CFBundleIdentifier - ${PRODUCT_BUNDLE_IDENTIFIER} - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - ${PRODUCT_NAME} - CFBundlePackageType - FMWK - CFBundleShortVersionString - 2.2.0 - CFBundleSignature - ???? - CFBundleVersion - ${CURRENT_PROJECT_VERSION} - NSPrincipalClass - - - diff --git a/Pods/Target Support Files/SwiftSoup/SwiftSoup-dummy.m b/Pods/Target Support Files/SwiftSoup/SwiftSoup-dummy.m deleted file mode 100644 index 8b1126f..0000000 --- a/Pods/Target Support Files/SwiftSoup/SwiftSoup-dummy.m +++ /dev/null @@ -1,5 +0,0 @@ -#import -@interface PodsDummy_SwiftSoup : NSObject -@end -@implementation PodsDummy_SwiftSoup -@end diff --git a/Pods/Target Support Files/SwiftSoup/SwiftSoup-prefix.pch b/Pods/Target Support Files/SwiftSoup/SwiftSoup-prefix.pch deleted file mode 100644 index 082f8af..0000000 --- a/Pods/Target Support Files/SwiftSoup/SwiftSoup-prefix.pch +++ /dev/null @@ -1,12 +0,0 @@ -#ifdef __OBJC__ -#import -#else -#ifndef FOUNDATION_EXPORT -#if defined(__cplusplus) -#define FOUNDATION_EXPORT extern "C" -#else -#define FOUNDATION_EXPORT extern -#endif -#endif -#endif - diff --git a/Pods/Target Support Files/SwiftSoup/SwiftSoup-umbrella.h b/Pods/Target Support Files/SwiftSoup/SwiftSoup-umbrella.h deleted file mode 100644 index 3b4daa6..0000000 --- a/Pods/Target Support Files/SwiftSoup/SwiftSoup-umbrella.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifdef __OBJC__ -#import -#else -#ifndef FOUNDATION_EXPORT -#if defined(__cplusplus) -#define FOUNDATION_EXPORT extern "C" -#else -#define FOUNDATION_EXPORT extern -#endif -#endif -#endif - - -FOUNDATION_EXPORT double SwiftSoupVersionNumber; -FOUNDATION_EXPORT const unsigned char SwiftSoupVersionString[]; - diff --git a/Pods/Target Support Files/SwiftSoup/SwiftSoup.modulemap b/Pods/Target Support Files/SwiftSoup/SwiftSoup.modulemap deleted file mode 100644 index bed11d0..0000000 --- a/Pods/Target Support Files/SwiftSoup/SwiftSoup.modulemap +++ /dev/null @@ -1,6 +0,0 @@ -framework module SwiftSoup { - umbrella header "SwiftSoup-umbrella.h" - - export * - module * { export * } -} diff --git a/Pods/Target Support Files/SwiftSoup/SwiftSoup.xcconfig b/Pods/Target Support Files/SwiftSoup/SwiftSoup.xcconfig deleted file mode 100644 index a60e8f2..0000000 --- a/Pods/Target Support Files/SwiftSoup/SwiftSoup.xcconfig +++ /dev/null @@ -1,10 +0,0 @@ -CODE_SIGN_IDENTITY = -CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/SwiftSoup -GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 -OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS -PODS_BUILD_DIR = ${BUILD_DIR} -PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) -PODS_ROOT = ${SRCROOT} -PODS_TARGET_SRCROOT = ${PODS_ROOT}/SwiftSoup -PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} -SKIP_INSTALL = YES diff --git a/RSwitch.xcodeproj/project.pbxproj b/RSwitch.xcodeproj/project.pbxproj index 70930e2..aec6cde 100644 --- a/RSwitch.xcodeproj/project.pbxproj +++ b/RSwitch.xcodeproj/project.pbxproj @@ -17,6 +17,7 @@ 01073F1F2311E67D007162C9 /* HandleUpdate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01073F1E2311E67D007162C9 /* HandleUpdate.swift */; }; 01073F212311E6BD007162C9 /* HandleRSwitch.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01073F202311E6BD007162C9 /* HandleRSwitch.swift */; }; 010A1C1423215B0900E32A9A /* SessionWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 010A1C1323215B0900E32A9A /* SessionWindowController.swift */; }; + 0117C9E0232270F0004BC889 /* RStudioUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0117C9DF232270F0004BC889 /* RStudioUtils.swift */; }; 011951B4231F00A000B62C3A /* Preferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = 011951B3231F00A000B62C3A /* Preferences.swift */; }; 0178970D230ED25100F8F5BC /* AboutViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0178970C230ED25100F8F5BC /* AboutViewController.swift */; }; 018A8C3B2312C7BC0006E87D /* libprocInfo.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 018A8C3A2312C7BC0006E87D /* libprocInfo.a */; }; @@ -50,6 +51,7 @@ 01073F1E2311E67D007162C9 /* HandleUpdate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HandleUpdate.swift; sourceTree = ""; }; 01073F202311E6BD007162C9 /* HandleRSwitch.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HandleRSwitch.swift; sourceTree = ""; }; 010A1C1323215B0900E32A9A /* SessionWindowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionWindowController.swift; sourceTree = ""; }; + 0117C9DF232270F0004BC889 /* RStudioUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RStudioUtils.swift; sourceTree = ""; }; 011951B3231F00A000B62C3A /* Preferences.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Preferences.swift; sourceTree = ""; }; 016750FB2319A7A4009E2FD6 /* RSwitch.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = RSwitch.entitlements; sourceTree = ""; }; 0178970C230ED25100F8F5BC /* AboutViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutViewController.swift; sourceTree = ""; }; @@ -177,6 +179,7 @@ children = ( 01073F182311E3B8007162C9 /* Bundle.swift */, 01073F122311E1CF007162C9 /* Globals.swift */, + 0117C9DF232270F0004BC889 /* RStudioUtils.swift */, 01975549231BD919003FAD7B /* RVersions.swift */, 0198B9A923197D3A003F7578 /* Running.swift */, 011951B3231F00A000B62C3A /* Preferences.swift */, @@ -362,6 +365,7 @@ 010A1C1423215B0900E32A9A /* SessionWindowController.swift in Sources */, 01D3E43C23211B4C00E3BC02 /* RStudioServerAction.swift in Sources */, 018A8C3F2312CB480006E87D /* procHelper.m in Sources */, + 0117C9E0232270F0004BC889 /* RStudioUtils.swift in Sources */, 01D3E43A232119DD00E3BC02 /* WebViewController.swift in Sources */, 01073F1F2311E67D007162C9 /* HandleUpdate.swift in Sources */, 01073F1B2311E613007162C9 /* DownloadTarball.swift in Sources */, diff --git a/RSwitch/Swift/AppDelegate.swift b/RSwitch/Swift/AppDelegate.swift index 7ff042e..c07d397 100644 --- a/RSwitch/Swift/AppDelegate.swift +++ b/RSwitch/Swift/AppDelegate.swift @@ -7,6 +7,7 @@ // import Cocoa +import Just class DeleteSessionViewController : NSViewController { @@ -25,7 +26,9 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSToolbarDelegate { NSApp.activate(ignoringOtherApps: true) } - @objc func performTimer(_ sender: Timer) { print("timer fired") } + @objc func performTimer(_ sender: Timer) { + print("timer fired") + } var mainStoryboard: NSStoryboard! var abtController: NSWindowController! @@ -66,7 +69,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSToolbarDelegate { } func applicationDidFinishLaunching(_ aNotification: Notification) { - + // dial by IconMark from the Noun Project statusItem.button?.image = #imageLiteral(resourceName: "RSwitch") statusItem.menu = statusMenu @@ -78,8 +81,6 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSToolbarDelegate { newSessController = (mainStoryboard.instantiateController(withIdentifier: "newSessPanel") as! NSWindowController) sess = RStudioServerSessionManager() -// sess.newSession(url: "https://rstudio.hrbrmstr.de", title: "One") -// sess.newSession(url: "https://rud.is/b", title: "Two") timer = Timer.scheduledTimer( timeInterval: 3600, diff --git a/RSwitch/Swift/Downloaders/DownloadRStudio.swift b/RSwitch/Swift/Downloaders/DownloadRStudio.swift index ea54a6c..653d3b0 100644 --- a/RSwitch/Swift/Downloaders/DownloadRStudio.swift +++ b/RSwitch/Swift/Downloaders/DownloadRStudio.swift @@ -8,7 +8,6 @@ import Foundation import Cocoa -import SwiftSoup extension AppDelegate { @@ -17,74 +16,62 @@ extension AppDelegate { self.rstudio_enabled = false - let url = URL(string: app_urls.rstudio_dailies) + let dlurl = RStudioUtils.latestVersionURL()! - do { + let dldir = FileManager.default.urls(for: .downloadsDirectory, in: .userDomainMask).first! + var dlfile = dldir + + dlfile.appendPathComponent(dlurl.lastPathComponent) + + if (FileManager.default.fileExists(atPath: dlfile.relativePath)) { - let html = try String.init(contentsOf: url!) - let document = try SwiftSoup.parse(html) + self.notifyUser(title: "Action required", subtitle: "RStudio Download", text: "A local copy of the latest RStudio daily already exists. Please remove or rename it if you wish to re-download it.") - let link = try document.select("td > a").first! - let href = try link.attr("href") - let dlurl = URL(string: href)! - let dldir = FileManager.default.urls(for: .downloadsDirectory, in: .userDomainMask).first! - var dlfile = dldir + NSWorkspace.shared.openFile(dldir.path, withApplication: "Finder") + NSWorkspace.shared.activateFileViewerSelecting([dlfile]) + + self.rstudio_enabled = true - dlfile.appendPathComponent(dlurl.lastPathComponent) + } else { - if (FileManager.default.fileExists(atPath: dlfile.relativePath)) { + let task = URLSession.shared.downloadTask(with: dlurl) { + tempURL, response, error in - self.notifyUser(title: "Action required", subtitle: "RStudio Download", text: "A local copy of the latest RStudio daily already exists. Please remove or rename it if you wish to re-download it.") - - NSWorkspace.shared.openFile(dldir.path, withApplication: "Finder") - NSWorkspace.shared.activateFileViewerSelecting([dlfile]) - - self.rstudio_enabled = true - - } else { - - let task = URLSession.shared.downloadTask(with: dlurl) { - tempURL, response, error in + if (error != nil) { + self.notifyUser(title: "Action failed", subtitle: "RStudio Download", text: "Error: " + error!.localizedDescription) + } else if (response != nil) { - if (error != nil) { - self.notifyUser(title: "Action failed", subtitle: "RStudio Download", text: "Error: " + error!.localizedDescription) - } else if (response != nil) { + let status = (response as? HTTPURLResponse)!.statusCode + if (status < 300) { - let status = (response as? HTTPURLResponse)!.statusCode - if (status < 300) { - - guard let fileURL = tempURL else { - DispatchQueue.main.async { [weak self] in self?.rstudio_enabled = true } - return - } - - do { - try FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false) - try FileManager.default.moveItem(at: fileURL, to: dlfile) - self.notifyUser(title: "Success", subtitle: "RStudio Download", text: "Download of latest RStudio daily (" + dlurl.lastPathComponent + ") successful.") - NSWorkspace.shared.openFile(dldir.path, withApplication: "Finder") - NSWorkspace.shared.activateFileViewerSelecting([dlfile]) - } catch { - self.notifyUser(title: "Action failed", subtitle: "RStudio Download", text: "Error: \(error)") - } - - } else { - self.notifyUser(title: "Action failed", subtitle: "RStudio Download", text: "Error downloading latest RStudio daily. Status code: " + String(status)) - + guard let fileURL = tempURL else { + DispatchQueue.main.async { [weak self] in self?.rstudio_enabled = true } + return } + + do { + try FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false) + try FileManager.default.moveItem(at: fileURL, to: dlfile) + self.notifyUser(title: "Success", subtitle: "RStudio Download", text: "Download of latest RStudio daily (" + dlurl.lastPathComponent + ") successful.") + NSWorkspace.shared.openFile(dldir.path, withApplication: "Finder") + NSWorkspace.shared.activateFileViewerSelecting([dlfile]) + } catch { + self.notifyUser(title: "Action failed", subtitle: "RStudio Download", text: "Error: \(error)") + } + + } else { + self.notifyUser(title: "Action failed", subtitle: "RStudio Download", text: "Error downloading latest RStudio daily. Status code: " + String(status)) + } - - DispatchQueue.main.async { [weak self] in self?.rstudio_enabled = true } - } - task.resume() + DispatchQueue.main.async { [weak self] in self?.rstudio_enabled = true } + } - } catch { - self.notifyUser(title: "Action failed", subtitle: "RStudio Download", text: "Error downloading and saving latest RStudio daily.") + task.resume() } - + } } diff --git a/RSwitch/Swift/Utils/Preferences.swift b/RSwitch/Swift/Utils/Preferences.swift index d22f861..662e42e 100644 --- a/RSwitch/Swift/Utils/Preferences.swift +++ b/RSwitch/Swift/Utils/Preferences.swift @@ -51,26 +51,19 @@ struct DockIcon { struct Preferences { static var showDockIcon: Bool { - get { return(defaults.bool(forKey: .showDockIcon)) } - set { defaults.set(newValue, forKey: .showDockIcon) defaults.synchronize() } - } - - + static var firstRunGone: Bool { - get { return(defaults.bool(forKey: .firstRunGone)) } - set { defaults.set(newValue, forKey: .firstRunGone) defaults.synchronize() } - } static func restore() { Preferences.showDockIcon = false } diff --git a/RSwitch/Swift/Utils/RStudioUtils.swift b/RSwitch/Swift/Utils/RStudioUtils.swift new file mode 100644 index 0000000..efe4ad3 --- /dev/null +++ b/RSwitch/Swift/Utils/RStudioUtils.swift @@ -0,0 +1,29 @@ +// +// RStudioUtils.swift +// RSwitch +// +// Created by hrbrmstr on 9/6/19. +// Copyright © 2019 Bob Rudis. All rights reserved. +// + +import Foundation +import Just + +class RStudioUtils { + + private static let dailyCleanerRegex = try!NSRegularExpression( + pattern: "https://s3.amazonaws.com/rstudio-ide-build/desktop/macos/RStudio-|.dmg", + options: NSRegularExpression.Options.caseInsensitive + ) + + public static func latestVersionURL() -> URL? { + let res = Just.head("https://www.rstudio.org/download/latest/daily/desktop/mac/RStudio-latest.dmg", timeout: 10) + return(res.url) + } + + public static func latestVersionNumber(fromString : String? = nil) -> String { + let urlString = (fromString == nil) ? latestVersionURL()!.absoluteString : fromString! + return(dailyCleanerRegex.stringByReplacingMatches(in: urlString, options: [], range: NSMakeRange(0, urlString.count), withTemplate: "")) + } + +}