From d9ea76045a5b6a0b426c66bfab9851c94847c9ff Mon Sep 17 00:00:00 2001 From: Michael Babiy Date: Wed, 16 Dec 2020 14:33:53 -0800 Subject: [PATCH] Version 2.0 * Add Combine support. * Introduce `RequestableItem`. * Introduce `HeaderItem` and `QueryItem` types. Conform and implement `ExpressibleByDictionaryLiteral` for cleaner `Requestable` conformance. * Move `Atom`s nested types to be their own (resolves nested issues with SPM, etc). * Update Example to use SwiftUI. * Update UNIT tests. * Update documentation. --- Documentation/Classes.html | 162 +- Documentation/Classes/Atom.html | 565 +----- Documentation/Classes/Service.html | 455 +++++ .../Classes/ServiceConfiguration.html | 359 ++++ .../ServiceConfiguration/Configuration.html | 272 +++ Documentation/Enums.html | 158 +- Documentation/Enums/AtomError.html | 125 +- Documentation/Enums/AuthenticationMethod.html | 274 +++ Documentation/Enums/HTTPMethod.html | 322 ++++ Documentation/Enums/RequestableError.html | 99 +- Documentation/Extensions.html | 152 +- Documentation/Extensions/Array.html | 225 +++ Documentation/Extensions/URLRequest.html | 99 +- Documentation/Extensions/URLResponse.html | 110 +- Documentation/Extensions/URLSessionTask.html | 99 +- .../Extensions/URLSessionTaskMetrics.html | 99 +- Documentation/Protocols.html | 168 +- .../Protocols/BasicCredentialConvertible.html | 111 +- .../ClientCredentialConvertible.html | 109 +- Documentation/Protocols/Requestable.html | 139 +- Documentation/Protocols/RequestableItem.html | 298 +++ .../Protocols/TokenCredentialWritable.html | 113 +- Documentation/Structs.html | 322 +++- Documentation/Structs/AtomResponse.html | 511 +++++ .../Structs/AuthorizationEndpoint.html | 250 +++ Documentation/Structs/BaseURL.html | 278 +++ Documentation/Structs/BaseURL/Scheme.html | 241 +++ Documentation/Structs/BasicCredential.html | 247 +++ Documentation/Structs/ClientCredential.html | 286 +++ .../Structs/ClientCredential/GrantType.html | 214 +++ Documentation/Structs/HeaderItem.html | 299 +++ Documentation/Structs/QueryItem.html | 299 +++ Documentation/Structs/Response.html | 457 +++++ Documentation/Structs/TokenCredential.html | 404 ++++ Documentation/Structs/URLPath.html | 238 +++ Documentation/badge.svg | 4 +- Documentation/css/jazzy.css | 89 +- .../Contents/Resources/Documents/Classes.html | 162 +- .../Resources/Documents/Classes/Atom.html | 565 +----- .../Resources/Documents/Classes/Service.html | 455 +++++ .../Classes/ServiceConfiguration.html | 359 ++++ .../ServiceConfiguration/Configuration.html | 272 +++ .../Contents/Resources/Documents/Enums.html | 158 +- .../Resources/Documents/Enums/AtomError.html | 125 +- .../Documents/Enums/AuthenticationMethod.html | 274 +++ .../Resources/Documents/Enums/HTTPMethod.html | 322 ++++ .../Documents/Enums/RequestableError.html | 99 +- .../Resources/Documents/Extensions.html | 152 +- .../Resources/Documents/Extensions/Array.html | 225 +++ .../Documents/Extensions/URLRequest.html | 99 +- .../Documents/Extensions/URLResponse.html | 110 +- .../Documents/Extensions/URLSessionTask.html | 99 +- .../Extensions/URLSessionTaskMetrics.html | 99 +- .../Resources/Documents/Protocols.html | 168 +- .../Protocols/BasicCredentialConvertible.html | 111 +- .../ClientCredentialConvertible.html | 109 +- .../Documents/Protocols/Requestable.html | 139 +- .../Documents/Protocols/RequestableItem.html | 298 +++ .../Protocols/TokenCredentialWritable.html | 113 +- .../Contents/Resources/Documents/Structs.html | 322 +++- .../Documents/Structs/AtomResponse.html | 511 +++++ .../Structs/AuthorizationEndpoint.html | 250 +++ .../Resources/Documents/Structs/BaseURL.html | 278 +++ .../Documents/Structs/BaseURL/Scheme.html | 241 +++ .../Documents/Structs/BasicCredential.html | 247 +++ .../Documents/Structs/ClientCredential.html | 286 +++ .../Structs/ClientCredential/GrantType.html | 214 +++ .../Documents/Structs/HeaderItem.html | 299 +++ .../Documents/Structs/QueryItem.html | 299 +++ .../Resources/Documents/Structs/Response.html | 457 +++++ .../Documents/Structs/TokenCredential.html | 404 ++++ .../Resources/Documents/Structs/URLPath.html | 238 +++ .../Resources/Documents/css/jazzy.css | 89 +- .../Resources/Documents/img/spinner.gif | Bin 0 -> 1849 bytes .../Contents/Resources/Documents/index.html | 293 +-- .../Contents/Resources/Documents/js/jazzy.js | 13 +- .../Resources/Documents/js/jazzy.search.js | 70 + .../Resources/Documents/js/jquery.min.js | 4 +- .../Resources/Documents/js/lunr.min.js | 6 + .../Documents/js/typeahead.jquery.js | 1694 +++++++++++++++++ .../Contents/Resources/Documents/search.json | 2 +- .../Contents/Resources/docSet.dsidx | Bin 36864 -> 36864 bytes Documentation/docsets/Atom.tgz | Bin 73200 -> 103609 bytes Documentation/img/spinner.gif | Bin 0 -> 1849 bytes Documentation/index.html | 293 +-- Documentation/js/jazzy.js | 13 +- Documentation/js/jazzy.search.js | 70 + Documentation/js/jquery.min.js | 4 +- Documentation/js/lunr.min.js | 6 + Documentation/js/typeahead.jquery.js | 1694 +++++++++++++++++ Documentation/search.json | 2 +- Documentation/undocumented.json | 13 +- Example/Example.xcodeproj/project.pbxproj | 394 ++-- .../contents.xcworkspacedata | 2 +- .../xcshareddata/xcschemes/Example.xcscheme | 91 - Example/Example/AppDelegate.swift | 25 - .../Controllers/RESTViewController.swift | 58 - .../AppIcon.appiconset/Contents.json | 98 - .../Views/Assets.xcassets/Contents.json | 6 - .../Contents.json | 21 - .../alaska-airlines-logo@2x.png | Bin 60881 -> 0 bytes .../rest.imageset/Contents.json | 23 - .../Assets.xcassets/rest.imageset/rest.png | Bin 218 -> 0 bytes .../Assets.xcassets/rest.imageset/rest@2x.png | Bin 352 -> 0 bytes .../Assets.xcassets/rest.imageset/rest@3x.png | Bin 534 -> 0 bytes .../Views/Base.lproj/LaunchScreen.storyboard | 45 - .../Example/Views/Base.lproj/Main.storyboard | 75 - .../Shared/App/ExampleApp.swift | 15 +- .../AccentColor.colorset/Contents.json | 11 + .../AppIcon.appiconset/Contents.json | 148 ++ .../Assets/Assets.xcassets/Contents.json | 6 + .../Endpoints/Joke+Endpoint.swift | 12 +- .../Shared/Extensions/Color+Additions.swift | 21 + .../Global/Constants.swift | 8 +- Example/{Example => Shared}/Models/Joke.swift | 22 +- Example/Shared/Views/ContentView.swift | 63 + Example/Shared/Views/ContentViewModel.swift | 33 + Example/{Example => iOS}/Info.plist | 18 +- Example/macOS/Info.plist | 26 + .../macOS.entitlements} | 6 +- Framework/Atom.xcodeproj/project.pbxproj | 276 +-- .../xcshareddata/xcschemes/Atom.xcscheme | 24 +- Framework/Atom/Atom.h | 2 +- Framework/Atom/Atom/Atom.swift | 28 +- Framework/Atom/Atom/Errors/AtomError.swift | 6 +- .../Atom/Atom/Errors/RequestableError.swift | 2 +- .../Convertibles/StringConvertible.swift | 29 - .../Atom Error/AtomError+Additions.swift | 2 +- .../AtomError+StringConvertible.swift | 2 +- .../Foundation/Array+Additions.swift | 18 +- .../Foundation/Data+Additions.swift | 2 +- .../Foundation/Date+Additions.swift | 2 +- .../NSRegularExpression+Additions.swift | 2 +- .../Foundation/Optional+Additions.swift | 4 +- .../Foundation/Result+Additions.swift | 2 +- .../Foundation/String+Additions.swift | 2 +- .../Foundation/URLComponents+Additions.swift | 6 +- .../Foundation/URLRequest+Additions.swift | 2 +- .../Foundation/URLResponse+Additions.swift | 6 +- .../Requestable+Implementation.swift | 12 +- Framework/Atom/Global/Constants.swift | 2 +- ...om+Interceptor.swift => Interceptor.swift} | 26 +- ...ift => AuthenticationManager+Status.swift} | 10 +- ...ager.swift => AuthenticationManager.swift} | 69 +- .../Models/Atom+AuthenticationMethod.swift | 37 - .../Models/Atom+AuthorizationEndpoint.swift | 51 - Framework/Atom/Models/Atom+BaseURL.swift | 61 - .../Atom/Models/Atom+BasicCredential.swift | 40 - .../Atom/Models/Atom+ClientCredential.swift | 45 - Framework/Atom/Models/Atom+HeaderItem.swift | 38 - Framework/Atom/Models/Atom+Retryable.swift | 55 - .../Atom/Models/Atom+TokenCredential.swift | 48 - ...int.swift => AtomResponse+Additions.swift} | 20 +- ...Atom+Response.swift => AtomResponse.swift} | 48 +- ...t => AuthenticationMethod+Additions.swift} | 6 +- .../Atom/Models/AuthenticationMethod.swift | 35 + .../Atom/Models/AuthorizationEndpoint.swift | 49 + ...eURL+Scheme.swift => BaseURL+Scheme.swift} | 4 +- Framework/Atom/Models/BaseURL.swift | 59 + ....swift => BasicCredential+Additions.swift} | 4 +- Framework/Atom/Models/BasicCredential.swift | 38 + ...swift => ClientCredential+GrantType.swift} | 4 +- Framework/Atom/Models/ClientCredential.swift | 43 + Framework/Atom/Models/Endpoint.swift | 24 + Framework/Atom/Models/HeaderItem.swift | 36 + .../{Atom+Method.swift => Method.swift} | 32 +- Framework/Atom/Models/QueryItem.swift | 36 + ...ditions.swift => Response+Additions.swift} | 6 +- ...itions.swift => Retryable+Additions.swift} | 8 +- Framework/Atom/Models/Retryable.swift | 53 + ....swift => TokenCredential+Additions.swift} | 4 +- ....swift => TokenCredential+Decodable.swift} | 4 +- Framework/Atom/Models/TokenCredential.swift | 46 + .../{Atom+URLPath.swift => URLPath.swift} | 48 +- .../BasicCredentialConvertible.swift | 10 +- .../ClientCredentialConvertible.swift | 8 +- .../Convertibles/StringConvertible.swift | 23 + .../AuthenticationManagerDelegate.swift | 26 + .../{Common => }/Protocols/Types/Model.swift | 4 +- .../Protocols/Types/Requestable.swift | 20 +- .../Types/RequestableItem.swift} | 21 +- .../Types/TokenCredentialWritable.swift | 12 +- .../Service/Atom+ServiceConfiguration.swift | 132 -- Framework/Atom/Service/Service+Combine.swift | 88 + .../{Atom+Service.swift => Service.swift} | 134 +- ...ift => ServiceConfiguration+Timeout.swift} | 4 +- .../Atom/Service/ServiceConfiguration.swift | 130 ++ .../AtomTests/Extensions/ArrayTests.swift | 4 +- .../AtomTests/Extensions/StringTests.swift | 2 +- .../Extensions/URLRequestTests.swift | 22 +- ...nseTests.swift => AtomResponseTests.swift} | 20 +- Framework/AtomTests/Models/BaseCase.swift | 2 +- .../AtomTests/Models/BaseURLSchemeTests.swift | 6 +- Framework/AtomTests/Models/BaseURLTests.swift | 8 +- .../AtomTests/Models/HeaderItemTests.swift | 4 +- Framework/AtomTests/Models/MethodTests.swift | 14 +- .../AtomTests/Models/QueryItemTests.swift | 25 - .../AtomTests/Models/RequestableTests.swift | 8 +- Framework/AtomTests/Models/ResultTests.swift | 2 +- .../Models/ServiceConfigurationTests.swift | 4 +- Framework/AtomTests/Models/URLPathTests.swift | 8 +- Framework/README.md | 64 +- Package.swift | 5 +- README.md | 44 +- 204 files changed, 20824 insertions(+), 4252 deletions(-) create mode 100644 Documentation/Classes/Service.html create mode 100644 Documentation/Classes/ServiceConfiguration.html create mode 100644 Documentation/Classes/ServiceConfiguration/Configuration.html create mode 100644 Documentation/Enums/AuthenticationMethod.html create mode 100644 Documentation/Enums/HTTPMethod.html create mode 100644 Documentation/Extensions/Array.html create mode 100644 Documentation/Protocols/RequestableItem.html create mode 100644 Documentation/Structs/AtomResponse.html create mode 100644 Documentation/Structs/AuthorizationEndpoint.html create mode 100644 Documentation/Structs/BaseURL.html create mode 100644 Documentation/Structs/BaseURL/Scheme.html create mode 100644 Documentation/Structs/BasicCredential.html create mode 100644 Documentation/Structs/ClientCredential.html create mode 100644 Documentation/Structs/ClientCredential/GrantType.html create mode 100644 Documentation/Structs/HeaderItem.html create mode 100644 Documentation/Structs/QueryItem.html create mode 100644 Documentation/Structs/Response.html create mode 100644 Documentation/Structs/TokenCredential.html create mode 100644 Documentation/Structs/URLPath.html create mode 100644 Documentation/docsets/Atom.docset/Contents/Resources/Documents/Classes/Service.html create mode 100644 Documentation/docsets/Atom.docset/Contents/Resources/Documents/Classes/ServiceConfiguration.html create mode 100644 Documentation/docsets/Atom.docset/Contents/Resources/Documents/Classes/ServiceConfiguration/Configuration.html create mode 100644 Documentation/docsets/Atom.docset/Contents/Resources/Documents/Enums/AuthenticationMethod.html create mode 100644 Documentation/docsets/Atom.docset/Contents/Resources/Documents/Enums/HTTPMethod.html create mode 100644 Documentation/docsets/Atom.docset/Contents/Resources/Documents/Extensions/Array.html create mode 100644 Documentation/docsets/Atom.docset/Contents/Resources/Documents/Protocols/RequestableItem.html create mode 100644 Documentation/docsets/Atom.docset/Contents/Resources/Documents/Structs/AtomResponse.html create mode 100644 Documentation/docsets/Atom.docset/Contents/Resources/Documents/Structs/AuthorizationEndpoint.html create mode 100644 Documentation/docsets/Atom.docset/Contents/Resources/Documents/Structs/BaseURL.html create mode 100644 Documentation/docsets/Atom.docset/Contents/Resources/Documents/Structs/BaseURL/Scheme.html create mode 100644 Documentation/docsets/Atom.docset/Contents/Resources/Documents/Structs/BasicCredential.html create mode 100644 Documentation/docsets/Atom.docset/Contents/Resources/Documents/Structs/ClientCredential.html create mode 100644 Documentation/docsets/Atom.docset/Contents/Resources/Documents/Structs/ClientCredential/GrantType.html create mode 100644 Documentation/docsets/Atom.docset/Contents/Resources/Documents/Structs/HeaderItem.html create mode 100644 Documentation/docsets/Atom.docset/Contents/Resources/Documents/Structs/QueryItem.html create mode 100644 Documentation/docsets/Atom.docset/Contents/Resources/Documents/Structs/Response.html create mode 100644 Documentation/docsets/Atom.docset/Contents/Resources/Documents/Structs/TokenCredential.html create mode 100644 Documentation/docsets/Atom.docset/Contents/Resources/Documents/Structs/URLPath.html create mode 100644 Documentation/docsets/Atom.docset/Contents/Resources/Documents/img/spinner.gif create mode 100644 Documentation/docsets/Atom.docset/Contents/Resources/Documents/js/jazzy.search.js create mode 100644 Documentation/docsets/Atom.docset/Contents/Resources/Documents/js/lunr.min.js create mode 100644 Documentation/docsets/Atom.docset/Contents/Resources/Documents/js/typeahead.jquery.js create mode 100644 Documentation/img/spinner.gif create mode 100644 Documentation/js/jazzy.search.js create mode 100644 Documentation/js/lunr.min.js create mode 100644 Documentation/js/typeahead.jquery.js delete mode 100644 Example/Example.xcodeproj/xcshareddata/xcschemes/Example.xcscheme delete mode 100644 Example/Example/AppDelegate.swift delete mode 100644 Example/Example/Controllers/RESTViewController.swift delete mode 100644 Example/Example/Views/Assets.xcassets/AppIcon.appiconset/Contents.json delete mode 100644 Example/Example/Views/Assets.xcassets/Contents.json delete mode 100644 Example/Example/Views/Assets.xcassets/alaska-airlines-logo.imageset/Contents.json delete mode 100644 Example/Example/Views/Assets.xcassets/alaska-airlines-logo.imageset/alaska-airlines-logo@2x.png delete mode 100644 Example/Example/Views/Assets.xcassets/rest.imageset/Contents.json delete mode 100644 Example/Example/Views/Assets.xcassets/rest.imageset/rest.png delete mode 100644 Example/Example/Views/Assets.xcassets/rest.imageset/rest@2x.png delete mode 100644 Example/Example/Views/Assets.xcassets/rest.imageset/rest@3x.png delete mode 100644 Example/Example/Views/Base.lproj/LaunchScreen.storyboard delete mode 100644 Example/Example/Views/Base.lproj/Main.storyboard rename Framework/Atom/Extensions/Foundation/Bool+Additions.swift => Example/Shared/App/ExampleApp.swift (74%) create mode 100644 Example/Shared/Assets/Assets.xcassets/AccentColor.colorset/Contents.json create mode 100644 Example/Shared/Assets/Assets.xcassets/AppIcon.appiconset/Contents.json create mode 100644 Example/Shared/Assets/Assets.xcassets/Contents.json rename Example/{Example/Extensions => Shared}/Endpoints/Joke+Endpoint.swift (72%) create mode 100644 Example/Shared/Extensions/Color+Additions.swift rename Example/{Example => Shared}/Global/Constants.swift (81%) rename Example/{Example => Shared}/Models/Joke.swift (83%) create mode 100644 Example/Shared/Views/ContentView.swift create mode 100644 Example/Shared/Views/ContentViewModel.swift rename Example/{Example => iOS}/Info.plist (79%) create mode 100644 Example/macOS/Info.plist rename Example/{Example/Example.entitlements => macOS/macOS.entitlements} (58%) delete mode 100644 Framework/Atom/Common/Protocols/Convertibles/StringConvertible.swift rename Framework/Atom/Interceptor/{Atom+Interceptor.swift => Interceptor.swift} (67%) rename Framework/Atom/Managers/Authentication Manager/{Atom+AuthenticationManager+Status.swift => AuthenticationManager+Status.swift} (84%) rename Framework/Atom/Managers/Authentication Manager/{Atom+AuthenticationManager.swift => AuthenticationManager.swift} (68%) delete mode 100644 Framework/Atom/Models/Atom+AuthenticationMethod.swift delete mode 100644 Framework/Atom/Models/Atom+AuthorizationEndpoint.swift delete mode 100644 Framework/Atom/Models/Atom+BaseURL.swift delete mode 100644 Framework/Atom/Models/Atom+BasicCredential.swift delete mode 100644 Framework/Atom/Models/Atom+ClientCredential.swift delete mode 100644 Framework/Atom/Models/Atom+HeaderItem.swift delete mode 100644 Framework/Atom/Models/Atom+Retryable.swift delete mode 100644 Framework/Atom/Models/Atom+TokenCredential.swift rename Framework/Atom/Models/{Atom+Endpoint.swift => AtomResponse+Additions.swift} (54%) rename Framework/Atom/Models/{Atom+Response.swift => AtomResponse.swift} (59%) rename Framework/Atom/Models/{Atom+AuthenticationMethod+Additions.swift => AuthenticationMethod+Additions.swift} (95%) create mode 100644 Framework/Atom/Models/AuthenticationMethod.swift create mode 100644 Framework/Atom/Models/AuthorizationEndpoint.swift rename Framework/Atom/Models/{Atom+BaseURL+Scheme.swift => BaseURL+Scheme.swift} (91%) create mode 100644 Framework/Atom/Models/BaseURL.swift rename Framework/Atom/Models/{Atom+BasicCredential+Additions.swift => BasicCredential+Additions.swift} (90%) create mode 100644 Framework/Atom/Models/BasicCredential.swift rename Framework/Atom/Models/{Atom+ClientCredential+GrantType.swift => ClientCredential+GrantType.swift} (90%) create mode 100644 Framework/Atom/Models/ClientCredential.swift create mode 100644 Framework/Atom/Models/Endpoint.swift create mode 100644 Framework/Atom/Models/HeaderItem.swift rename Framework/Atom/Models/{Atom+Method.swift => Method.swift} (66%) create mode 100644 Framework/Atom/Models/QueryItem.swift rename Framework/Atom/Models/{Atom+Response+Additions.swift => Response+Additions.swift} (83%) rename Framework/Atom/Models/{Atom+Retryable+Additions.swift => Retryable+Additions.swift} (78%) create mode 100644 Framework/Atom/Models/Retryable.swift rename Framework/Atom/Models/{Atom+TokenCredential+Additions.swift => TokenCredential+Additions.swift} (89%) rename Framework/Atom/Models/{Atom+TokenCredential+Decodable.swift => TokenCredential+Decodable.swift} (93%) create mode 100644 Framework/Atom/Models/TokenCredential.swift rename Framework/Atom/Models/{Atom+URLPath.swift => URLPath.swift} (57%) rename Framework/Atom/{Common => }/Protocols/Convertibles/BasicCredentialConvertible.swift (79%) rename Framework/Atom/{Common => }/Protocols/Convertibles/ClientCredentialConvertible.swift (75%) create mode 100644 Framework/Atom/Protocols/Convertibles/StringConvertible.swift create mode 100644 Framework/Atom/Protocols/Delegates/AuthenticationManagerDelegate.swift rename Framework/Atom/{Common => }/Protocols/Types/Model.swift (89%) rename Framework/Atom/{Common => }/Protocols/Types/Requestable.swift (80%) rename Framework/Atom/{Models/Atom+QueryItem.swift => Protocols/Types/RequestableItem.swift} (53%) rename Framework/Atom/{Common => }/Protocols/Types/TokenCredentialWritable.swift (80%) delete mode 100644 Framework/Atom/Service/Atom+ServiceConfiguration.swift create mode 100644 Framework/Atom/Service/Service+Combine.swift rename Framework/Atom/Service/{Atom+Service.swift => Service.swift} (68%) rename Framework/Atom/Service/{Atom+ServiceConfiguration+Timeout.swift => ServiceConfiguration+Timeout.swift} (91%) create mode 100644 Framework/Atom/Service/ServiceConfiguration.swift rename Framework/AtomTests/Models/{ResponseTests.swift => AtomResponseTests.swift} (79%) delete mode 100644 Framework/AtomTests/Models/QueryItemTests.swift diff --git a/Documentation/Classes.html b/Documentation/Classes.html index dddde23..6868080 100644 --- a/Documentation/Classes.html +++ b/Documentation/Classes.html @@ -8,13 +8,21 @@ + + +
-

Atom Docs (99% documented)

+

Atom Docs (98% documented)

+

+

+ +
+

@@ -34,40 +42,13 @@ Atom - - - - - - - - - @@ -77,6 +58,12 @@ + + @@ -86,10 +73,10 @@ Extensions +
@@ -158,7 +186,69 @@

Classes

Declaration

Swift

-
public class Atom
+
public final class Atom
+ +
+
+ + + +
  • +
    + + + + Service + +
    +
    +
    +
    +
    +
    +

    Service is a public facing class responsible for managing +URLSession configuration, network calls, and decoding instances of a + data type into internal models.

    + +

    Service is available through the Atom instance only and cannot be +initialized dirrectly. This behavior is intentional to allow for better separation +of responsibilities such as creating a request, network call, and data decoding.

    + + See more +
    +
    +

    Declaration

    +
    +

    Swift

    +
    public class Service
    + +
    +
    +
    +
    +
  • +
  • +
    + + + + ServiceConfiguration + +
    +
    +
    +
    +
    +
    +

    Model object representing Service configuration.

    + + See more +
    +
    +

    Declaration

    +
    +

    Swift

    +
    public final class ServiceConfiguration
    @@ -170,8 +260,8 @@

    Declaration

    diff --git a/Documentation/Classes/Atom.html b/Documentation/Classes/Atom.html index 78f9f81..edb2c17 100644 --- a/Documentation/Classes/Atom.html +++ b/Documentation/Classes/Atom.html @@ -8,13 +8,21 @@ + + +
    -

    Atom Docs (99% documented)

    +

    Atom Docs (98% documented)

    +

    +

    + +
    +

    @@ -34,40 +42,13 @@ Atom
  • - - - - - - - - - @@ -77,6 +58,12 @@ + + @@ -86,10 +73,10 @@ Extensions +
    @@ -133,7 +161,8 @@

    Atom

    -
    public class Atom
    + +
    public final class Atom
    @@ -185,9 +214,9 @@

    Declaration

  • - + - init(serviceConfiguration:) + init(serviceConfiguration:)
    @@ -202,7 +231,7 @@

    Declaration

    Declaration

    Swift

    -
    public init(serviceConfiguration: Atom.ServiceConfiguration = Atom.ServiceConfiguration())
    +
    public init(serviceConfiguration: ServiceConfiguration = ServiceConfiguration())
    @@ -218,7 +247,7 @@

    Parameters

    -

    The service configuration data used for initializing Atom.Service instance.

    +

    The service configuration data used for initializing Service instance.

    @@ -228,10 +257,6 @@

    Parameters

  • - - -
    -
    • @@ -267,9 +292,9 @@

      Declaration

    • - - - load(_:) + + + enqueue(_:)
      @@ -277,14 +302,14 @@

      Declaration

      -

      Prepares Atom.Service for a network call.

      +

      Prepares Service for a network call.

      -

      Calling load() method will not initiate a network call until -one of the available methods on Atom.Service is called first.

      +

      Calling enqueue(_:) method will not initiate a network call until +one of the available methods on Service is called first.

      Note

      -

      Calling load() method multiple times without executing a network call will update -previously set requestable property on Atom.Service with new value. Atom framework +

      Calling enqueue(_:) method multiple times without executing a network call will update +previously set requestable property on Service with new value. Atom framework does not support queue based flow.

      @@ -294,7 +319,7 @@

      Declaration

      Declaration

      Swift

      -
      func load(_ requestable: Requestable) -> Atom.Service
      +
      func enqueue(_ requestable: Requestable) -> Service
      @@ -319,15 +344,11 @@

      Parameters

      Return Value

      -

      Updated Atom.Service instance initialized using Atom.ServiceConfiguration.

      +

      Updated Service instance initialized using ServiceConfiguration.

    - - -
    -
    • @@ -357,439 +378,11 @@

      Declaration

    -
    -
      -
    • -
      - - - - AuthenticationMethod - -
      -
      -
      -
      -
      -
      -

      List of authentication methods a client can choose from for Atom configuration.

      - - See more -
      -
      -

      Declaration

      -
      -

      Swift

      -
      enum AuthenticationMethod
      - -
      -
      -
      -
      -
    • -
    -
    -
    -
      -
    • -
      - - - - AuthorizationEndpoint - -
      -
      -
      -
      -
      -
      -

      Model object representing the location of the authorization server.

      - - See more -
      -
      -

      Declaration

      -
      -

      Swift

      -
      struct AuthorizationEndpoint
      - -
      -
      -
      -
      -
    • -
    -
    -
    -
      -
    • -
      - - - - BaseURL - -
      -
      -
      -
      -
      -
      -

      Model object representing base URL composed from URL scheme and host.

      - - See more -
      -
      -

      Declaration

      -
      -

      Swift

      -
      struct BaseURL
      - -
      -
      -
      -
      -
    • -
    -
    -
    -
      -
    • -
      - - - - BasicCredential - -
      -
      -
      -
      -
      -
      -

      The BasicCredential type declares an object used by Atom in network requests that require basic authentication. Before -basic authentication is applied as Authorization header value, username and password will be combined into a single -string using : and base 64 encoded.

      - - See more -
      -
      -

      Declaration

      -
      -

      Swift

      -
      struct BasicCredential
      - -
      -
      -
      -
      -
    • -
    -
    -
    - -
    -
    -
      -
    • -
      - - - - HeaderItem - -
      -
      -
      -
      -
      -
      -

      A single name-value pair for specifying HTTP header value modeled after URLQueryItem.

      - - See more -
      -
      -

      Declaration

      -
      -

      Swift

      -
      struct HeaderItem
      - -
      -
      -
      -
      -
    • -
    -
    -
    -
      -
    • -
      - - - - Method - -
      -
      -
      -
      -
      -
      -

      List of primary HTTP methods.

      - - See more -
      -
      -

      Declaration

      -
      -

      Swift

      -
      enum Method : Equatable
      - -
      -
      -
      -
      -
    • -
    -
    -
    -
      -
    • -
      - - - - QueryItem - -
      -
      -
      -
      -
      -
      -

      A single name-value pair from the query portion of a URL.

      - -

      Foundation offers URLQueryItem type but not a similar type for creating -HTTP header item. To stay consistent, Atom framework introduced Atom.HeaderItem -and type aliased URLQueryItem to Atom.QueryItem.

      - -
      -
      -

      Declaration

      -
      -

      Swift

      -
      typealias QueryItem = URLQueryItem
      - -
      -
      -
      -
      -
    • -
    -
    -
    -
      -
    • -
      - - - - Response - -
      -
      -
      -
      -
      -
      -

      The metadata associated with the response to a URL load request, independent of protocol and URL scheme.

      - - See more -
      -
      -

      Declaration

      -
      -

      Swift

      -
      struct Response
      - -
      -
      -
      -
      -
    • -
    -
    -
    -
      -
    • -
      - - - - TokenCredential - -
      -
      -
      -
      -
      -
      -

      The TokenCredential type declares an object used by Atom in network requests that require bearer authentication.

      - - See more -
      -
      -

      Declaration

      -
      -

      Swift

      -
      struct TokenCredential
      - -
      -
      -
      -
      -
    • -
    -
    -
    -
      -
    • -
      - - - - URLPath - -
      -
      -
      -
      -
      -
      -

      Model object representing URL path.

      - - See more -
      -
      -

      Declaration

      -
      -

      Swift

      -
      struct URLPath
      - -
      -
      -
      -
      -
    • -
    -
    -
    -
      -
    • -
      - - - - Service - -
      -
      -
      -
      -
      -
      -

      Service is a public facing class responsible for managing -URLSession configuration, network calls, and decoding instances of a - data type into internal models.

      - -

      Service is available through the Atom instance only and cannot be -initialized dirrectly. This behavior is intentional to allow for better separation -of responsibilities such as creating a request, network call, and data decoding.

      - - See more -
      -
      -

      Declaration

      -
      -

      Swift

      -
      class Service
      - -
      -
      -
      -
      -
    • -
    -
    -
    -
      -
    • -
      - - - - ServiceConfiguration - -
      -
      -
      -
      -
      -
      -

      Model object representing Service configuration.

      - - See more -
      -
      -

      Declaration

      -
      -

      Swift

      -
      class ServiceConfiguration
      - -
      -
      -
      -
      -
    • -
    -
    diff --git a/Documentation/Classes/Service.html b/Documentation/Classes/Service.html new file mode 100644 index 0000000..628b8b6 --- /dev/null +++ b/Documentation/Classes/Service.html @@ -0,0 +1,455 @@ + + + + Service Class Reference + + + + + + + + + + + + + +
    +
    +

    Atom Docs (98% documented)

    +

    +

    + +
    +

    +
    +
    +
    + +
    +
    + +
    +
    +
    +

    Service

    +
    +
    + +
    public class Service
    + +
    +
    +

    Service is a public facing class responsible for managing +URLSession configuration, network calls, and decoding instances of a + data type into internal models.

    + +

    Service is available through the Atom instance only and cannot be +initialized dirrectly. This behavior is intentional to allow for better separation +of responsibilities such as creating a request, network call, and data decoding.

    + +
    +
    +
    +
      +
    • +
      + + + + resume(expecting:) + +
      +
      +
      +
      +
      +
      +

      Creates and resumes URLRequest initialized from Requestable.

      + +

      Use this method to make network requests where you expect data returned by the +service and require that data to be decoded into internal representations - models.

      + +

      Network request and decoding will be performed on a background thread after +which the client will be notified on a queue Atom was configured to use.

      + +

      A typical usage pattern for this method could look like this:

      +
      atom
      +    .enqueue(endpoint)
      +    .resume(expecting: User.self)
      +    .sink { completion in
      +        // Handle `AtomError`.
      +    } receiveValue: { user in
      +        // Handle decoded `User` instance.
      +    }
      +    .store(in: &cancelables)
      +
      + +

      In the above example, data will be decoded into a User instance.

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      func resume<T>(expecting type: T.Type) -> AnyPublisher<T, AtomError> where T : Model
      + +
      +
      +
      +

      Parameters

      + + + + + + + +
      + + type + + +
      +

      The type to decode.

      +
      +
      +
      +
      +

      Return Value

      +

      AnyPublisher where Output is the decoded Model and Failure is AtomError.

      +
      +
      +
      +
    • +
    • +
      + + + + resume() + +
      +
      +
      +
      +
      +
      +

      Creates and resumes URLRequest initialized from Requestable.

      + +

      Use this method to make network requests where you don’t expect any data returned +and are only interested in knowing if the network call succeeded or failed.

      + +

      Atom framework uses a convenience computed variable on AtomResponse - isSuccessful +to determine success or a failure of a response based on a status code returned by the service.

      + +

      A typical usage pattern for this method after getting a result could look like this:

      +
      atom
      +    .enqueue(Endpoint.random)
      +    .resume()
      +    .sink {
      +        // Handle `AtomError`.
      +    } receiveValue: {
      +        // Handle `AtomResponse`.
      +    }
      +    .store(in: &cancelables)
      +
      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      func resume() -> AnyPublisher<AtomResponse, AtomError>
      + +
      +
      +
      +

      Return Value

      +

      AnyPublisher where Output is the AtomResponse and Failure is AtomError.

      +
      +
      +
      +
    • +
    • + +
      +
      +
      +
      +
      +

      Creates and resumes URLRequest initialized from Requestable.

      + +

      Use this method to make network requests where you expect data returned by the +service and require that data to be decoded into internal representations - models.

      + +

      Network request and decoding will be performed on a background thread after +which the client will be notified of a result on a queue Atom was configured to use.

      + +

      A typical usage pattern for this method could look like this:

      +
      atom.enqueue(endpoint).resume(expecting: User.self) { result in
      +    switch result {
      +        case .failure(let error):
      +        // Handle `AtomError`.
      +
      +        case .success(let user):
      +        // Handle decoded `User` instance.
      +    }
      +}
      +
      + +

      In the above example, data will be decoded into a User instance.

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      func resume<T>(expecting type: T.Type, completion: @escaping (Result<T, AtomError>) -> Void) where T : Model
      + +
      +
      +
      +

      Parameters

      + + + + + + + + + + + +
      + + type + + +
      +

      The type to decode.

      +
      +
      + + completion + + +
      +

      The completion containing Result where the associated value is either an AtomError or decoded model instance.

      +
      +
      +
      +
      +
      +
    • +
    • +
      + + + + resume(_:) + +
      +
      +
      +
      +
      +
      +

      Creates and resumes URLRequest initialized from Requestable.

      + +

      Use this method to make network requests where you don’t expect any data returned +and are only interested in knowing if the network call succeeded or failed.

      + +

      Atom framework uses a convenience computed variable on AtomResponse - isSuccessful +to determine success or a failure of a response based on a status code returned by the service.

      + +

      A typical usage pattern for this method after getting a result could look like this:

      +
      atom.enqueue(endpoint).resume { result in
      +    switch result {
      +        case .failure(let error):
      +        // Handle `AtomError`.
      +
      +        case .success(let response):
      +        // Handle `AtomResponse`.
      +        }
      +    }
      +}
      +
      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      func resume(_ completion: @escaping (Result<AtomResponse, AtomError>) -> Void)
      + +
      +
      +
      +

      Parameters

      + + + + + + + +
      + + completion + + +
      +

      The completion containing Result where the associated value is either an AtomError or AtomResponse.

      +
      +
      +
      +
      +
      +
    • +
    +
    +
    +
    + +
    +
    + + + diff --git a/Documentation/Classes/ServiceConfiguration.html b/Documentation/Classes/ServiceConfiguration.html new file mode 100644 index 0000000..a44dede --- /dev/null +++ b/Documentation/Classes/ServiceConfiguration.html @@ -0,0 +1,359 @@ + + + + ServiceConfiguration Class Reference + + + + + + + + + + + + + +
    +
    +

    Atom Docs (98% documented)

    +

    +

    + +
    +

    +
    +
    +
    + +
    +
    + +
    +
    +
    +

    ServiceConfiguration

    +
    +
    + +
    public final class ServiceConfiguration
    + +
    +
    +

    Model object representing Service configuration.

    + +
    +
    +
    +
      +
    • +
      + + + + Configuration + +
      +
      +
      +
      +
      +
      +

      List of supported session configurations.

      + +

      Configuration enum is a reflection of available options offered +by Foundation as class properties on URLSessionConfiguration. The +main reason for this abstraction is testability - see ServiceConfigurationTests.

      + + See more +
      +
      +

      Declaration

      +
      +

      Swift

      +
      public enum Configuration : Equatable
      + +
      +
      +
      +
      +
    • +
    • +
      + + + + MultipathServiceType + +
      +
      +
      +
      +
      +
      +

      Undocumented

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      public typealias MultipathServiceType = URLSessionConfiguration.MultipathServiceType
      + +
      +
      +
      +
      +
    • +
    • + +
      +
      +
      +
      +
      +

      Creates a ServiceConfiguration instance given the provided parameter(s).

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      public init(authenticationMethod: AuthenticationMethod = .none, configuration: Configuration = .ephemeral, decoder: JSONDecoder = JSONDecoder(), dispatchQueue: DispatchQueue = .main, multipathServiceType: MultipathServiceType = .none)
      + +
      +
      +
      +

      Parameters

      + + + + + + + + + + + + + + + + + + + + + + + +
      + + authenticationMethod + + +
      +

      The authentication method indicating how authorization header will be handled in Atom.

      +
      +
      + + configuration + + +
      +

      The ServiceConfiguration.Configuration - default value is .ephemeral.

      +
      +
      + + decoder + + +
      +

      The JSONDecoder for decoding data into models.

      +
      +
      + + dispatchQueue + + +
      +

      The queue to dispatch Result object on.

      +
      +
      + + multipathServiceType + + +
      +

      The service type that specifies the Multipath TCP connection policy for transmitting data over Wi-Fi and cellular interfaces.

      +
      +
      +
      +
      +
      +
    • +
    • + +
      +
      +
      +
      +
      +

      Creates a ServiceConfiguration instance given the provided parameter(s).

      + +
      +
      +
      +
    • +
    +
    +
    +
    + +
    +
    + + + diff --git a/Documentation/Classes/ServiceConfiguration/Configuration.html b/Documentation/Classes/ServiceConfiguration/Configuration.html new file mode 100644 index 0000000..8cfd21c --- /dev/null +++ b/Documentation/Classes/ServiceConfiguration/Configuration.html @@ -0,0 +1,272 @@ + + + + Configuration Enumeration Reference + + + + + + + + + + + + + +
    +
    +

    Atom Docs (98% documented)

    +

    +

    + +
    +

    +
    +
    +
    + +
    +
    + +
    +
    +
    +

    Configuration

    +
    +
    + +
    public enum Configuration : Equatable
    + +
    +
    +

    List of supported session configurations.

    + +

    Configuration enum is a reflection of available options offered +by Foundation as class properties on URLSessionConfiguration. The +main reason for this abstraction is testability - see ServiceConfigurationTests.

    + +
    +
    +
    +
      +
    • +
      + + + + background(_:) + +
      +
      +
      +
      +
      +
      +

      The background session configuration is suitable for transferring data files while the app runs in the background.

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      case background(String)
      + +
      +
      +
      +
      +
    • +
    • +
      + + + + default + +
      +
      +
      +
      +
      +
      +

      The default session configuration that uses a persistent disk-based cache.

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      case `default`
      + +
      +
      +
      +
      +
    • +
    • +
      + + + + ephemeral + +
      +
      +
      +
      +
      +
      +

      Ephemeral configuration doesn’t store caches, credential stores, or any session-related data on disk (RAM only).

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      case ephemeral
      + +
      +
      +
      +
      +
    • +
    +
    +
    +
    + +
    +
    + + + diff --git a/Documentation/Enums.html b/Documentation/Enums.html index 33b0420..902a4cb 100644 --- a/Documentation/Enums.html +++ b/Documentation/Enums.html @@ -8,13 +8,21 @@ + + +
    -

    Atom Docs (99% documented)

    +

    Atom Docs (98% documented)

    +

    +

    + +
    +

    - - -
    -
    • @@ -197,13 +221,69 @@

      Declaration

    • +
    • +
      + + + + AuthenticationMethod + +
      +
      +
      +
      +
      +
      +

      List of authentication methods a client can choose from for Atom configuration.

      + + See more +
      +
      +

      Declaration

      +
      +

      Swift

      +
      public enum AuthenticationMethod
      + +
      +
      +
      +
      +
    • +
    • +
      + + + + HTTPMethod + +
      +
      +
      +
      +
      +
      +

      List of primary HTTP methods.

      + + See more +
      +
      +

      Declaration

      +
      +

      Swift

      +
      public enum HTTPMethod : Equatable
      + +
      +
      +
      +
      +
    diff --git a/Documentation/Enums/AtomError.html b/Documentation/Enums/AtomError.html index e27539b..adba8c7 100644 --- a/Documentation/Enums/AtomError.html +++ b/Documentation/Enums/AtomError.html @@ -8,13 +8,21 @@ + + +
    -

    Atom Docs (99% documented)

    +

    Atom Docs (98% documented)

    +

    +

    + +
    +

    @@ -34,40 +42,13 @@ Atom - - - - - - - - - @@ -77,6 +58,12 @@ + + @@ -86,10 +73,10 @@ Extensions +
    @@ -133,6 +161,7 @@

    AtomError

    +
    public enum AtomError : Error
    @@ -148,7 +177,7 @@

    AtomError

    - decoder(_:) + decoder(_:)
    @@ -175,7 +204,7 @@

    Declaration

    - data(_:) + data(_:)
    @@ -202,7 +231,7 @@

    Declaration

    - requestable(_:) + requestable(_:)
    @@ -227,9 +256,9 @@

    Declaration

  • @@ -242,14 +271,14 @@

    Declaration

    An optional response data will be set for further processing of the body. In the context of ACE Group, data will contain the error message or the model object.

    -

    For more information, see Atom.Response.

    +

    For more information, see AtomResponse.

    Declaration

    Swift

    -
    case response(Atom.Response)
    +
    case response(AtomResponse)
    @@ -261,7 +290,7 @@

    Declaration

    - session(_:) + session(_:)
  • @@ -340,10 +369,6 @@

    Declaration

    - -
    -
    -
    • @@ -405,16 +430,12 @@

      Declaration

    • -
    -
    -
    -
    + diff --git a/Documentation/Enums/HTTPMethod.html b/Documentation/Enums/HTTPMethod.html new file mode 100644 index 0000000..9838e2a --- /dev/null +++ b/Documentation/Enums/HTTPMethod.html @@ -0,0 +1,322 @@ + + + + HTTPMethod Enumeration Reference + + + + + + + + + + + + + +
    +
    +

    Atom Docs (98% documented)

    +

    +

    + +
    +

    +
    +
    +
    + +
    +
    + +
    +
    +
    +

    HTTPMethod

    +
    +
    + +
    public enum HTTPMethod : Equatable
    + +
    +
    +

    List of primary HTTP methods.

    + +
    +
    +
    +
      +
    • +
      + + + + delete + +
      +
      +
      +
      +
      +
      +

      Use for deleting a resource identified by a URI.

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      case delete
      + +
      +
      +
      +
      +
    • +
    • +
      + + + + get + +
      +
      +
      +
      +
      +
      +

      Use for reading (or retrieving) a representation of a resource.

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      case get
      + +
      +
      +
      +
      +
    • +
    • +
      + + + + patch(_:) + +
      +
      +
      +
      +
      +
      +

      Use for modifying capabilities.

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      case patch(Data)
      + +
      +
      +
      +
      +
    • +
    • +
      + + + + post(_:) + +
      +
      +
      +
      +
      +
      +

      Use for creating new resources.

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      case post(Data)
      + +
      +
      +
      +
      +
    • +
    • +
      + + + + put(_:) + +
      +
      +
      +
      +
      +
      +

      Use for replacing a resource.

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      case put(Data)
      + +
      +
      +
      +
      +
    • +
    +
    +
    +
    + +
    +
    + + + diff --git a/Documentation/Enums/RequestableError.html b/Documentation/Enums/RequestableError.html index ce3942f..59ae808 100644 --- a/Documentation/Enums/RequestableError.html +++ b/Documentation/Enums/RequestableError.html @@ -8,13 +8,21 @@ + + +
    -

    Atom Docs (99% documented)

    +

    Atom Docs (98% documented)

    +

    +

    + +
    +

    @@ -34,40 +42,13 @@ Atom - - - - - - - - - @@ -77,6 +58,12 @@ + + @@ -86,10 +73,10 @@ Extensions +
    @@ -133,6 +161,7 @@

    RequestableError

    +
    public enum RequestableError : Error
    @@ -229,8 +258,8 @@

    Declaration

    diff --git a/Documentation/Extensions.html b/Documentation/Extensions.html index e382349..84b59d0 100644 --- a/Documentation/Extensions.html +++ b/Documentation/Extensions.html @@ -8,13 +8,21 @@ + + +
    -

    Atom Docs (99% documented)

    +

    Atom Docs (98% documented)

    +

    +

    + +
    +

    @@ -34,40 +42,13 @@ Atom - - - - - - - - - @@ -77,6 +58,12 @@ + + @@ -86,10 +73,10 @@ Extensions +
    @@ -140,9 +168,9 @@

    Extensions

  • - - - Bool + + + Array
    @@ -150,31 +178,30 @@

    Extensions

    - - See more +

    Adds the ability to specify an array as the expected decoded type.

    + +

    Each element must conform to Model protocol.

    + + See more

    Declaration

    Swift

    -
    @frozen
    -public extension Bool
    +
    extension Array: Model where Element: Model
    +
    extension Array: ExpressibleByDictionaryLiteral where Element: RequestableItem
  • - -
    -
    -
    • - - - Optional + + + Data
      @@ -182,15 +209,14 @@

      Declaration

      - - See more +

      Conforming Data type to Model protocol allows it to be used where Model is expected.

      +

      Declaration

      Swift

      -
      @frozen
      -public extension Optional
      +
      extension Data: Model
      @@ -203,9 +229,11 @@

      Declaration

      - -

      Debug Description

      -
      +
      + +

      Debug Description

      +

      +
      • @@ -235,10 +263,6 @@

        Declaration

    • -
    -
    -
    -
    • @@ -266,10 +290,6 @@

      Declaration

    • -
    -
    -
    -
    • @@ -297,10 +317,6 @@

      Declaration

    • -
    -
    -
    -
    + diff --git a/Documentation/Extensions/URLRequest.html b/Documentation/Extensions/URLRequest.html index 13fd158..9212b9e 100644 --- a/Documentation/Extensions/URLRequest.html +++ b/Documentation/Extensions/URLRequest.html @@ -8,13 +8,21 @@ + + +
    -

    Atom Docs (99% documented)

    +

    Atom Docs (98% documented)

    +

    +

    + +
    +

    @@ -34,40 +42,13 @@ Atom - - - - - - - - - @@ -77,6 +58,12 @@ + + @@ -86,10 +73,10 @@ Extensions +
    @@ -133,6 +161,7 @@

    URLRequest

    +
    extension URLRequest
    @@ -177,8 +206,8 @@

    Declaration

    diff --git a/Documentation/Extensions/URLResponse.html b/Documentation/Extensions/URLResponse.html index 18c924e..807d27b 100644 --- a/Documentation/Extensions/URLResponse.html +++ b/Documentation/Extensions/URLResponse.html @@ -8,13 +8,21 @@ + + +
    -

    Atom Docs (99% documented)

    +

    Atom Docs (98% documented)

    +

    +

    + +
    +

    @@ -34,40 +42,13 @@ Atom - - - - - - - - - @@ -77,6 +58,12 @@ + + @@ -86,10 +73,10 @@ Extensions +
    @@ -133,6 +161,7 @@

    URLResponse

    +
    public extension URLResponse
    @@ -199,6 +228,15 @@

    Declaration

    +
    + + +
    + +

    Debug Description

    +

    +
    +
    • @@ -220,7 +258,7 @@

      Declaration

      Declaration

      Swift

      -
      override public var debugDescription: String { get }
      +
      override var debugDescription: String { get }
      @@ -232,8 +270,8 @@

      Declaration

    diff --git a/Documentation/Extensions/URLSessionTask.html b/Documentation/Extensions/URLSessionTask.html index 16ac960..50bb012 100644 --- a/Documentation/Extensions/URLSessionTask.html +++ b/Documentation/Extensions/URLSessionTask.html @@ -8,13 +8,21 @@ + + +
    -

    Atom Docs (99% documented)

    +

    Atom Docs (98% documented)

    +

    +

    + +
    +

    @@ -34,40 +42,13 @@ Atom - - - - - - - - - @@ -77,6 +58,12 @@ + + @@ -86,10 +73,10 @@ Extensions +
    @@ -133,6 +161,7 @@

    URLSessionTask

    +
    extension URLSessionTask
    @@ -174,8 +203,8 @@

    Declaration

    diff --git a/Documentation/Extensions/URLSessionTaskMetrics.html b/Documentation/Extensions/URLSessionTaskMetrics.html index e7ec583..500955f 100644 --- a/Documentation/Extensions/URLSessionTaskMetrics.html +++ b/Documentation/Extensions/URLSessionTaskMetrics.html @@ -8,13 +8,21 @@ + + +
    -

    Atom Docs (99% documented)

    +

    Atom Docs (98% documented)

    +

    +

    + +
    +

    @@ -34,40 +42,13 @@ Atom - - - - - - - - - @@ -77,6 +58,12 @@ + + @@ -86,10 +73,10 @@ Extensions +
    @@ -133,6 +161,7 @@

    URLSessionTaskMetrics

    +
    extension URLSessionTaskMetrics
    @@ -174,8 +203,8 @@

    Declaration

    diff --git a/Documentation/Protocols.html b/Documentation/Protocols.html index 3100732..6d567d9 100644 --- a/Documentation/Protocols.html +++ b/Documentation/Protocols.html @@ -8,13 +8,21 @@ + + +
    -

    Atom Docs (99% documented)

    +

    Atom Docs (98% documented)

    +

    +

    + +
    +

    @@ -34,40 +42,13 @@ Atom - - - - - - - - - @@ -77,6 +58,12 @@ + + @@ -86,10 +73,10 @@ Extensions +
    @@ -137,6 +165,34 @@

    Protocols

      +
    • +
      + + + + Requestable + +
      +
      +
      +
      +
      +
      +

      The Requestable protocol declares an interface used for initializing network request object.

      + + See more +
      +
      +

      Declaration

      +
      +

      Swift

      +
      public protocol Requestable
      + +
      +
      +
      +
      +
    • @@ -150,13 +206,13 @@

      Protocols

      -

      The BasicCredentialConvertible protocol declares an interface used for converting conforming type to Atom.BasicCredential.

      +

      The BasicCredentialConvertible protocol declares an interface used for converting conforming type to BasicCredential.

      Atom can be configured to automatically apply authorization header to any Requestable instance. Once properly configured, Atom will read credentials from the storage specified by the client and apply them to Requestable instance if requiresAuthentication property is set to true. Values will be set as Authorization: Basic base64-encoded-credential header value.

      -

      For more information see Atom.Configuration documentation.

      +

      For more information see Configuration documentation.

      See more
      @@ -171,10 +227,6 @@

      Declaration

    • -
    -
    -
    -
    • @@ -188,7 +240,7 @@

      Declaration

      -

      The ClientCredentialConvertible protocol declares an interface used for converting conforming type to Atom.ClientCredential.

      +

      The ClientCredentialConvertible protocol declares an interface used for converting conforming type to ClientCredential.

      See more
      @@ -203,10 +255,6 @@

      Declaration

    • -
    -
    -
    -
    • @@ -220,7 +268,7 @@

      Declaration

      -

      The Model protocol declares an interface used as a generic constraint on Atom.Service methods.

      +

      The Model protocol declares an interface used as a generic constraint on Service methods.

      @@ -234,16 +282,12 @@

      Declaration

    • -
    -
    -
    -
    • @@ -251,25 +295,21 @@

      Declaration

      -

      The Requestable protocol declares an interface used for initializing network request object.

      +

      The RequestableItem protocol declares an interface used for specifying HTTP header values & request queries.

      - See more + See more

      Declaration

      Swift

      -
      public protocol Requestable
      +
      public protocol RequestableItem
    • -
    -
    -
    -
    • @@ -283,7 +323,7 @@

      Declaration

      -

      The TokenCredentialWritable protocol declares an interface used for reading from / writing to Atom.TokenCredential.

      +

      The TokenCredentialWritable protocol declares an interface used for reading from / writing to TokenCredential.

      Atom can be configured to automatically apply authorization header to any Requestable instance. Once properly configured, Atom will read credentials from the storage specified by the client and apply them to Requestable instance if requiresAuthentication property @@ -291,14 +331,14 @@

      Declaration

      Proper configuration requires that the client conform and implement TokenCredentialWritable protocol where the conforming type is a class.

      class SSOCredential: TokenCredentialWritable {
      -    var tokenCredential: Atom.TokenCredential {
      +    var tokenCredential: TokenCredential {
               get { keychain.value() }
               set { keychain.save(newValue) }
           }
       }
       
      -

      For more information see Atom.Configuration documentation.

      +

      For more information see Configuration documentation.

      See more
      @@ -318,8 +358,8 @@

      Declaration

    diff --git a/Documentation/Protocols/BasicCredentialConvertible.html b/Documentation/Protocols/BasicCredentialConvertible.html index 4047954..3109d32 100644 --- a/Documentation/Protocols/BasicCredentialConvertible.html +++ b/Documentation/Protocols/BasicCredentialConvertible.html @@ -8,13 +8,21 @@ + + +
    -

    Atom Docs (99% documented)

    +

    Atom Docs (98% documented)

    +

    +

    + +
    +

    @@ -34,40 +42,13 @@ Atom - - - - - - - - - @@ -77,6 +58,12 @@ + + @@ -86,10 +73,10 @@ Extensions +
    @@ -133,17 +161,18 @@

    BasicCredentialConvertible

    +
    public protocol BasicCredentialConvertible
    -

    The BasicCredentialConvertible protocol declares an interface used for converting conforming type to Atom.BasicCredential.

    +

    The BasicCredentialConvertible protocol declares an interface used for converting conforming type to BasicCredential.

    Atom can be configured to automatically apply authorization header to any Requestable instance. Once properly configured, Atom will read credentials from the storage specified by the client and apply them to Requestable instance if requiresAuthentication property is set to true. Values will be set as Authorization: Basic base64-encoded-credential header value.

    -

    For more information see Atom.Configuration documentation.

    +

    For more information see Configuration documentation.

    @@ -152,9 +181,9 @@

    BasicCredentialConvertible

  • @@ -162,14 +191,14 @@

    BasicCredentialConvertible

    -

    Returns conforming type as Atom.BasicCredential.

    +

    Returns conforming type as BasicCredential.

    Declaration

    Swift

    -
    var basicCredential: Atom.BasicCredential { get }
    +
    var basicCredential: BasicCredential { get }
    @@ -181,8 +210,8 @@

    Declaration

  • diff --git a/Documentation/Protocols/ClientCredentialConvertible.html b/Documentation/Protocols/ClientCredentialConvertible.html index 5d2cac7..f12016f 100644 --- a/Documentation/Protocols/ClientCredentialConvertible.html +++ b/Documentation/Protocols/ClientCredentialConvertible.html @@ -8,13 +8,21 @@ + + +
    -

    Atom Docs (99% documented)

    +

    Atom Docs (98% documented)

    +

    +

    + +
    +

    @@ -34,40 +42,13 @@ Atom - - - - - - - - - @@ -77,6 +58,12 @@ + + @@ -86,10 +73,10 @@ Extensions +
    @@ -133,11 +161,12 @@

    ClientCredentialConvertible

    +
    public protocol ClientCredentialConvertible
    -

    The ClientCredentialConvertible protocol declares an interface used for converting conforming type to Atom.ClientCredential.

    +

    The ClientCredentialConvertible protocol declares an interface used for converting conforming type to ClientCredential.

    @@ -146,9 +175,9 @@

    ClientCredentialConvertible

  • @@ -156,14 +185,14 @@

    ClientCredentialConvertible

    -

    Returns conforming type as Atom.ClientCredential.

    +

    Returns conforming type as ClientCredential.

    Declaration

    Swift

    -
    var clientCredential: Atom.ClientCredential { get }
    +
    var clientCredential: ClientCredential { get }
    @@ -175,8 +204,8 @@

    Declaration

  • diff --git a/Documentation/Protocols/Requestable.html b/Documentation/Protocols/Requestable.html index 2707f65..46f9a12 100644 --- a/Documentation/Protocols/Requestable.html +++ b/Documentation/Protocols/Requestable.html @@ -8,13 +8,21 @@ + + +
    -

    Atom Docs (99% documented)

    +

    Atom Docs (98% documented)

    +

    +

    + +
    +

    @@ -34,40 +42,13 @@ Atom - - - - - - - - - @@ -77,6 +58,12 @@ + + @@ -86,10 +73,10 @@ Extensions +
    @@ -133,6 +161,7 @@

    Requestable

    +
    public protocol Requestable
    @@ -146,9 +175,9 @@

    Requestable

  • - + - headerItems + headerItems Default implementation @@ -171,7 +200,7 @@

    Default Implementation

    Declaration

    Swift

    -
    var headerItems: [Atom.HeaderItem]? { get }
    +
    var headerItems: [HeaderItem]? { get }
    @@ -181,9 +210,9 @@

    Declaration

  • - + - method + method Default implementation @@ -206,7 +235,7 @@

    Default Implementation

    Declaration

    Swift

    -
    var method: Atom.Method { get }
    +
    var method: HTTPMethod { get }
    @@ -216,9 +245,9 @@

    Declaration

  • - + - queryItems + queryItems Default implementation @@ -241,7 +270,7 @@

    Default Implementation

    Declaration

    Swift

    -
    var queryItems: [Atom.QueryItem]? { get }
    +
    var queryItems: [QueryItem]? { get }
    @@ -287,9 +316,9 @@

    Declaration

  • @@ -300,8 +329,8 @@

    Declaration

    The base url to initialize URLRequest with.

    The URL host must begin and end with a word.

    -
    func baseURL() throws -> Atom.BaseURL {
    -    try Atom.BaseURL(host: "api.alaskaair.net")
    +
    func baseURL() throws -> BaseURL {
    +    try BaseURL(host: "api.alaskaair.net")
     }
     
    @@ -313,7 +342,7 @@

    Declaration

    Declaration

    Swift

    -
    func baseURL() throws -> Atom.BaseURL
    +
    func baseURL() throws -> BaseURL
    @@ -323,9 +352,9 @@

    Declaration

  • - + - path() + path() Default implementation @@ -339,8 +368,8 @@

    Declaration

    The URL path to append to a base URL.

    The path should begin with a forward slash / and end with a word.

    -
    func path() throws -> Atom.URLPath {
    -    try Atom.URLPath("/path/to/resource")
    +
    func path() throws -> URLPath {
    +    try URLPath("/path/to/resource")
     }
     
    @@ -350,14 +379,14 @@

    Declaration

    Default Implementation

    -

    The default valus is Atom.URLPath.default.

    +

    The default valus is URLPath.default.

    Declaration

    Swift

    -
    func path() throws -> Atom.URLPath
    +
    func path() throws -> URLPath
    @@ -369,8 +398,8 @@

    Declaration

  • diff --git a/Documentation/Protocols/RequestableItem.html b/Documentation/Protocols/RequestableItem.html new file mode 100644 index 0000000..f1cc2ec --- /dev/null +++ b/Documentation/Protocols/RequestableItem.html @@ -0,0 +1,298 @@ + + + + RequestableItem Protocol Reference + + + + + + + + + + + + + +
    +
    +

    Atom Docs (98% documented)

    +

    +

    + +
    +

    +
    +
    +
    + +
    +
    + +
    +
    +
    +

    RequestableItem

    +
    +
    + +
    public protocol RequestableItem
    + +
    +
    +

    The RequestableItem protocol declares an interface used for specifying HTTP header values & request queries.

    + +
    +
    +
    +
      +
    • +
      + + + + name + +
      +
      +
      +
      +
      +
      +

      The name of the requestable item.

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      var name: String { get }
      + +
      +
      +
      +
      +
    • +
    • +
      + + + + value + +
      +
      +
      +
      +
      +
      +

      The value of the requestable item.

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      var value: String { get }
      + +
      +
      +
      +
      +
    • +
    • +
      + + + + init(name:value:) + +
      +
      +
      +
      +
      +
      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      init(name: String, value: String)
      + +
      +
      +
      +

      Parameters

      + + + + + + + + + + + +
      + + name + + +
      +

      The name of the requestable item.

      +
      +
      + + value + + +
      +

      The value of the requestable item.

      +
      +
      +
      +
      +
      +
    • +
    +
    +
    +
    + +
    +
    + + + diff --git a/Documentation/Protocols/TokenCredentialWritable.html b/Documentation/Protocols/TokenCredentialWritable.html index cee1122..2356ae0 100644 --- a/Documentation/Protocols/TokenCredentialWritable.html +++ b/Documentation/Protocols/TokenCredentialWritable.html @@ -8,13 +8,21 @@ + + +
    -

    Atom Docs (99% documented)

    +

    Atom Docs (98% documented)

    +

    +

    + +
    +

    @@ -34,40 +42,13 @@ Atom - - - - - - - - - @@ -77,6 +58,12 @@ + + @@ -86,10 +73,10 @@ Extensions +
    @@ -133,11 +161,12 @@

    TokenCredentialWritable

    +
    public protocol TokenCredentialWritable : AnyObject
    -

    The TokenCredentialWritable protocol declares an interface used for reading from / writing to Atom.TokenCredential.

    +

    The TokenCredentialWritable protocol declares an interface used for reading from / writing to TokenCredential.

    Atom can be configured to automatically apply authorization header to any Requestable instance. Once properly configured, Atom will read credentials from the storage specified by the client and apply them to Requestable instance if requiresAuthentication property @@ -145,14 +174,14 @@

    TokenCredentialWritable

    Proper configuration requires that the client conform and implement TokenCredentialWritable protocol where the conforming type is a class.

    class SSOCredential: TokenCredentialWritable {
    -    var tokenCredential: Atom.TokenCredential {
    +    var tokenCredential: TokenCredential {
             get { keychain.value() }
             set { keychain.save(newValue) }
         }
     }
     
    -

    For more information see Atom.Configuration documentation.

    +

    For more information see Configuration documentation.

    @@ -161,9 +190,9 @@

    TokenCredentialWritable

  • @@ -171,14 +200,14 @@

    TokenCredentialWritable

    -

    Returns conforming type as Atom.TokenCredential.

    +

    Returns conforming type as TokenCredential.

    Declaration

    Swift

    -
    var tokenCredential: Atom.TokenCredential { get set }
    +
    var tokenCredential: TokenCredential { get set }
    @@ -190,8 +219,8 @@

    Declaration

  • diff --git a/Documentation/Structs.html b/Documentation/Structs.html index 7629d34..fa32e84 100644 --- a/Documentation/Structs.html +++ b/Documentation/Structs.html @@ -8,13 +8,21 @@ + + +
    -

    Atom Docs (99% documented)

    +

    Atom Docs (98% documented)

    +

    +

    + +
    +

    @@ -27,12 +35,35 @@
    + diff --git a/Documentation/Structs/AuthorizationEndpoint.html b/Documentation/Structs/AuthorizationEndpoint.html new file mode 100644 index 0000000..4e388ea --- /dev/null +++ b/Documentation/Structs/AuthorizationEndpoint.html @@ -0,0 +1,250 @@ + + + + AuthorizationEndpoint Structure Reference + + + + + + + + + + + + + +
    +
    +

    Atom Docs (98% documented)

    +

    +

    + +
    +

    +
    +
    +
    + +
    +
    + +
    +
    +
    +

    AuthorizationEndpoint

    +
    +
    + +
    public struct AuthorizationEndpoint
    + +
    +
    +

    Model object representing the location of the authorization server.

    + +
    +
    +
    +
      +
    • +
      + + + + init(host:path:) + +
      +
      +
      +
      +
      +
      +

      Creates a AuthorizationEndpoint instance given the provided parameter(s).

      + +

      Before an instance of the AuthorizationEndpoint can be created, host and path will be +validated using regex patters defined in NSRegularExpression+Additions. If validation +fails for any reason, an exception will be raised by Atom - this is intentional to ensure +a valid authorization endpoint is provided during Atom configuration.

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      public init(host: String, path: String)
      + +
      +
      +
      +

      Parameters

      + + + + + + + + + + + +
      + + host + + +
      +

      The URL host as defined in RFC 1738.

      +
      +
      + + path + + +
      +

      The URL path as defined in RFC 1738.

      +
      +
      +
      +
      +
      +
    • +
    +
    +
    +
    + +
    +
    + +
    + diff --git a/Documentation/Structs/BaseURL.html b/Documentation/Structs/BaseURL.html new file mode 100644 index 0000000..4c2522a --- /dev/null +++ b/Documentation/Structs/BaseURL.html @@ -0,0 +1,278 @@ + + + + BaseURL Structure Reference + + + + + + + + + + + + + +
    +
    +

    Atom Docs (98% documented)

    +

    +

    + +
    +

    +
    +
    +
    + +
    +
    + +
    +
    +
    +

    BaseURL

    +
    +
    + +
    public struct BaseURL
    + +
    +
    +

    Model object representing base URL composed from URL scheme and host.

    + +
    +
    +
    +
      +
    • +
      + + + + init(scheme:host:) + +
      +
      +
      +
      +
      +
      +

      Creates a BaseURL instance given the provided parameter(s).

      +
      +

      Throws

      +

      RequestableError.invalidBaseURL when URL host validation fails.

      + +
      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      public init(scheme: BaseURL.Scheme = .https, host: String) throws
      + +
      +
      +
      +

      Parameters

      + + + + + + + + + + + +
      + + scheme + + +
      +

      The URL scheme as defined in RFC 2718.

      +
      +
      + + host + + +
      +

      The URL host as defined in RFC 1738.

      +
      +
      +
      +
      +
      +
    • +
    • +
      + + + + Scheme + +
      +
      +
      +
      +
      +
      +

      List of supported scheme types.

      + + See more +
      +
      +

      Declaration

      +
      +

      Swift

      +
      enum Scheme
      + +
      +
      +
      +
      +
    • +
    +
    +
    +
    + +
    +
    + + + diff --git a/Documentation/Structs/BaseURL/Scheme.html b/Documentation/Structs/BaseURL/Scheme.html new file mode 100644 index 0000000..fc689e1 --- /dev/null +++ b/Documentation/Structs/BaseURL/Scheme.html @@ -0,0 +1,241 @@ + + + + Scheme Enumeration Reference + + + + + + + + + + + + + +
    +
    +

    Atom Docs (98% documented)

    +

    +

    + +
    +

    +
    +
    +
    + +
    +
    + +
    +
    +
    +

    Scheme

    +
    +
    + +
    enum Scheme
    + +
    +
    +

    List of supported scheme types.

    + +
    +
    +
    +
      +
    • +
      + + + + http + +
      +
      +
      +
      +
      +
      +

      The hyper text transfer protocol.

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      case http
      + +
      +
      +
      +
      +
    • +
    • +
      + + + + https + +
      +
      +
      +
      +
      +
      +

      The hyper text transfer protocol secure.

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      case https
      + +
      +
      +
      +
      +
    • +
    +
    +
    +
    + +
    +
    + + + diff --git a/Documentation/Structs/BasicCredential.html b/Documentation/Structs/BasicCredential.html new file mode 100644 index 0000000..5d3dc7c --- /dev/null +++ b/Documentation/Structs/BasicCredential.html @@ -0,0 +1,247 @@ + + + + BasicCredential Structure Reference + + + + + + + + + + + + + +
    +
    +

    Atom Docs (98% documented)

    +

    +

    + +
    +

    +
    +
    +
    + +
    +
    + +
    +
    +
    +

    BasicCredential

    +
    +
    + +
    public struct BasicCredential
    + +
    +
    +

    The BasicCredential type declares an object used by Atom in network requests that require basic authentication. Before +basic authentication is applied as Authorization header value, username and password will be combined into a single +string using : and base 64 encoded.

    + +
    +
    +
    +
      +
    • + +
      +
      +
      +
      +
      +

      Creates a BasicCredential instance given the provided parameter(s).

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      public init(password: String, username: String)
      + +
      +
      +
      +

      Parameters

      + + + + + + + + + + + +
      + + password + + +
      +

      The password to encode and use when applying basic authentication to a request.

      +
      +
      + + username + + +
      +

      The username to encode and use when applying basic authentication to a request.

      +
      +
      +
      +
      +
      +
    • +
    +
    +
    +
    + +
    +
    + + + diff --git a/Documentation/Structs/ClientCredential.html b/Documentation/Structs/ClientCredential.html new file mode 100644 index 0000000..e13c42b --- /dev/null +++ b/Documentation/Structs/ClientCredential.html @@ -0,0 +1,286 @@ + + + + ClientCredential Structure Reference + + + + + + + + + + + + + +
    +
    +

    Atom Docs (98% documented)

    +

    +

    + +
    +

    +
    +
    +
    + +
    +
    + +
    +
    +
    +

    ClientCredential

    +
    +
    + +
    public struct ClientCredential
    + +
    +
    +

    The ClientCredential type declares an object used by Atom for automated refreshing of the access token. +See https://tools.ietf.org/html/RFC6749

    + +
    +
    +
    +
      +
    • + +
      +
      +
      +
      +
      +

      Creates a ClientCredential instance given the provided parameter(s).

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      public init(grantType: GrantType = .refreshToken, id: String, secret: String)
      + +
      +
      +
      +

      Parameters

      + + + + + + + + + + + + + + + +
      + + grantType + + +
      +

      The authorization grant type as described in Sections 4.1.3, 4.3.2, 4.4.2, RFC 6749.

      +
      +
      + + id + + +
      +

      The client identifier issued to the client during the registration process described by Section 2.2, RFC 6749.

      +
      +
      + + secret + + +
      +

      The client secret. The client MAY omit the parameter if the client secret is an empty string. See RFC 6749.

      +
      +
      +
      +
      +
      +
    • +
    • +
      + + + + GrantType + +
      +
      +
      +
      +
      +
      +

      List of supported grant types by Atom.

      + + See more +
      +
      +

      Declaration

      +
      +

      Swift

      +
      enum GrantType : String
      + +
      +
      +
      +
      +
    • +
    +
    +
    +
    + +
    +
    + + + diff --git a/Documentation/Structs/ClientCredential/GrantType.html b/Documentation/Structs/ClientCredential/GrantType.html new file mode 100644 index 0000000..270983b --- /dev/null +++ b/Documentation/Structs/ClientCredential/GrantType.html @@ -0,0 +1,214 @@ + + + + GrantType Enumeration Reference + + + + + + + + + + + + + +
    +
    +

    Atom Docs (98% documented)

    +

    +

    + +
    +

    +
    +
    +
    + +
    +
    + +
    +
    +
    +

    GrantType

    +
    +
    + +
    enum GrantType : String
    + +
    +
    +

    List of supported grant types by Atom.

    + +
    +
    +
    +
      +
    • +
      + + + + refreshToken + +
      +
      +
      +
      +
      +
      +

      The refresh_token grant type as defined in Sections 6.0, RFC 6749.

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      case refreshToken = "refresh_token"
      + +
      +
      +
      +
      +
    • +
    +
    +
    +
    + +
    +
    + + + diff --git a/Documentation/Structs/HeaderItem.html b/Documentation/Structs/HeaderItem.html new file mode 100644 index 0000000..6c39697 --- /dev/null +++ b/Documentation/Structs/HeaderItem.html @@ -0,0 +1,299 @@ + + + + HeaderItem Structure Reference + + + + + + + + + + + + + +
    +
    +

    Atom Docs (98% documented)

    +

    +

    + +
    +

    +
    +
    +
    + +
    +
    + +
    +
    +
    +

    HeaderItem

    +
    +
    + +
    public struct HeaderItem : RequestableItem
    + +
    +
    +

    A single name-value pair from the header portion of a request.

    + +
    +
    +
    +
      +
    • +
      + + + + name + +
      +
      +
      +
      +
      +
      +

      The name of the header item.

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      public let name: String
      + +
      +
      +
      +
      +
    • +
    • +
      + + + + value + +
      +
      +
      +
      +
      +
      +

      The value of the header item.

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      public let value: String
      + +
      +
      +
      +
      +
    • +
    • +
      + + + + init(name:value:) + +
      +
      +
      +
      +
      +
      +

      Creates a HeaderItem instance given the provided parameter(s).

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      public init(name: String, value: String)
      + +
      +
      +
      +

      Parameters

      + + + + + + + + + + + +
      + + name + + +
      +

      The name of the header item.

      +
      +
      + + value + + +
      +

      The value of the header item.

      +
      +
      +
      +
      +
      +
    • +
    +
    +
    +
    + +
    +
    + + + diff --git a/Documentation/Structs/QueryItem.html b/Documentation/Structs/QueryItem.html new file mode 100644 index 0000000..d581f82 --- /dev/null +++ b/Documentation/Structs/QueryItem.html @@ -0,0 +1,299 @@ + + + + QueryItem Structure Reference + + + + + + + + + + + + + +
    +
    +

    Atom Docs (98% documented)

    +

    +

    + +
    +

    +
    +
    +
    + +
    +
    + +
    +
    +
    +

    QueryItem

    +
    +
    + +
    public struct QueryItem : RequestableItem
    + +
    +
    +

    A single name-value pair from the query portion of a URL.

    + +
    +
    +
    +
      +
    • +
      + + + + name + +
      +
      +
      +
      +
      +
      +

      The name of the query item.

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      public let name: String
      + +
      +
      +
      +
      +
    • +
    • +
      + + + + value + +
      +
      +
      +
      +
      +
      +

      The value of the query item.

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      public let value: String
      + +
      +
      +
      +
      +
    • +
    • +
      + + + + init(name:value:) + +
      +
      +
      +
      +
      +
      +

      Creates a QueryItem instance given the provided parameter(s).

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      public init(name: String, value: String)
      + +
      +
      +
      +

      Parameters

      + + + + + + + + + + + +
      + + name + + +
      +

      The name of the query item.

      +
      +
      + + value + + +
      +

      The value of the query item.

      +
      +
      +
      +
      +
      +
    • +
    +
    +
    +
    + +
    +
    + + + diff --git a/Documentation/Structs/Response.html b/Documentation/Structs/Response.html new file mode 100644 index 0000000..27bd41b --- /dev/null +++ b/Documentation/Structs/Response.html @@ -0,0 +1,457 @@ + + + + Response Structure Reference + + + + + + + + + + + + + +
    +
    +

    Atom Docs (98% documented)

    +

    +

    + +
    +

    +
    +
    +
    + +
    +
    + +
    +
    +
    +

    Response

    +
    +
    + +
    public struct Response
    + +
    +
    +

    The metadata associated with the response to a URL load request, independent of protocol and URL scheme.

    + +
    +
    +
    +
      +
    • +
      + + + + HeaderFields + +
      +
      +
      +
      +
      +
      +

      Undocumented

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      public typealias HeaderFields = NSDictionary
      + +
      +
      +
      +
      +
    • +
    • +
      + + + + allHeaderFields + +
      +
      +
      +
      +
      +
      +

      All HTTP header fields of the response.

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      public let allHeaderFields: HeaderFields?
      + +
      +
      +
      +
      +
    • +
    • +
      + + + + expectedContentLength + +
      +
      +
      +
      +
      +
      +

      The expected length of the response’s content.

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      public let expectedContentLength: Int64?
      + +
      +
      +
      +
      +
    • +
    • +
      + + + + data + +
      +
      +
      +
      +
      +
      +

      The data returned by the server.

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      public let data: Data?
      + +
      +
      +
      +
      +
    • +
    • +
      + + + + mimeType + +
      +
      +
      +
      +
      +
      +

      The MIME type of the response.

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      public let mimeType: String?
      + +
      +
      +
      +
      +
    • +
    • +
      + + + + statusCode + +
      +
      +
      +
      +
      +
      +

      The response’s HTTP status code.

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      public let statusCode: Int?
      + +
      +
      +
      +
      +
    • +
    • +
      + + + + suggestedFilename + +
      +
      +
      +
      +
      +
      +

      A suggested filename for the response data.

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      public let suggestedFilename: String?
      + +
      +
      +
      +
      +
    • +
    • +
      + + + + textEncodingName + +
      +
      +
      +
      +
      +
      +

      The name of the text encoding provided by the response’s originating source.

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      public let textEncodingName: String?
      + +
      +
      +
      +
      +
    • +
    • +
      + + + + url + +
      +
      +
      +
      +
      +
      +

      The URL for the response.

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      public let url: URL?
      + +
      +
      +
      +
      +
    • +
    • +
      + + + + success + +
      +
      +
      +
      +
      +
      +

      Returns default, success response where status code is 200.

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      static let success: Response
      + +
      +
      +
      +
      +
    • +
    +
    +
    +
    + +
    +
    + + + diff --git a/Documentation/Structs/TokenCredential.html b/Documentation/Structs/TokenCredential.html new file mode 100644 index 0000000..a4250f1 --- /dev/null +++ b/Documentation/Structs/TokenCredential.html @@ -0,0 +1,404 @@ + + + + TokenCredential Structure Reference + + + + + + + + + + + + + +
    +
    +

    Atom Docs (98% documented)

    +

    +

    + +
    +

    +
    +
    +
    + +
    +
    + +
    +
    +
    +

    TokenCredential

    +
    +
    + +
    public struct TokenCredential
    +
    extension TokenCredential: Decodable
    + +
    +
    +

    The TokenCredential type declares an object used by Atom in network requests that require bearer authentication.

    + +
    +
    +
    +
      +
    • +
      + + + + accessToken + +
      +
      +
      +
      +
      +
      +

      The access token as defined in OAuth 2.0 spec.

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      public let accessToken: String
      + +
      +
      +
      +
      +
    • +
    • +
      + + + + expiresIn + +
      +
      +
      +
      +
      +
      +

      The number of seconds access token is valid for.

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      public let expiresIn: Int
      + +
      +
      +
      +
      +
    • +
    • +
      + + + + expiresAt + +
      +
      +
      +
      +
      +
      +

      The expiration date of the access token.

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      public let expiresAt: Date
      + +
      +
      +
      +
      +
    • +
    • +
      + + + + refreshToken + +
      +
      +
      +
      +
      +
      +

      The refresh token as defined in OAuth 2.0 spec.

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      public let refreshToken: String
      + +
      +
      +
      +
      +
    • +
    • + +
      +
      +
      +
      +
      +

      Creates a TokenCredential instance given the provided parameter(s).

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      public init(accessToken: String, expiresIn: Int, expiresAt: Date, refreshToken: String)
      + +
      +
      +
      +

      Parameters

      + + + + + + + + + + + + + + + + + + + +
      + + accessToken + + +
      +

      The access token as defined in OAuth 2.0 spec.

      +
      +
      + + expiresIn + + +
      +

      The number of seconds access token is valid for.

      +
      +
      + + expiresAt + + +
      +

      The expiration date of the access token.

      +
      +
      + + refreshToken + + +
      +

      The refresh token as defined in OAuth 2.0 spec.

      +
      +
      +
      +
      +
      +
    • +
    • +
      + + + + init(from:) + +
      +
      +
      +
      +
      +
      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      public init(from decoder: Decoder) throws
      + +
      +
      +
      +
      +
    • +
    +
    +
    +
    + +
    +
    + + + diff --git a/Documentation/Structs/URLPath.html b/Documentation/Structs/URLPath.html new file mode 100644 index 0000000..3ba3036 --- /dev/null +++ b/Documentation/Structs/URLPath.html @@ -0,0 +1,238 @@ + + + + URLPath Structure Reference + + + + + + + + + + + + + +
    +
    +

    Atom Docs (98% documented)

    +

    +

    + +
    +

    +
    +
    +
    + +
    +
    + +
    +
    +
    +

    URLPath

    +
    +
    + +
    public struct URLPath
    + +
    +
    +

    Model object representing URL path.

    + +
    +
    +
    +
      +
    • +
      + + + + init(_:) + +
      +
      +
      +
      +
      +
      +

      Creates a URLPath instance given the provided parameter(s).

      +
      +

      Throws

      +

      RequestableError.invalidURLPath when URL path validation fails.

      + +
      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      public init(_ path: String) throws
      + +
      +
      +
      +

      Parameters

      + + + + + + + +
      + + path + + +
      +

      The URL path as defined in RFC 3986.

      +
      +
      +
      +
      +
      +
    • +
    +
    +
    +
    + +
    +
    + + + diff --git a/Documentation/badge.svg b/Documentation/badge.svg index bfac052..f47d948 100644 --- a/Documentation/badge.svg +++ b/Documentation/badge.svg @@ -19,10 +19,10 @@ documentation - 99% + 98% - 99% + 98% diff --git a/Documentation/css/jazzy.css b/Documentation/css/jazzy.css index 103ee29..5cdffe9 100644 --- a/Documentation/css/jazzy.css +++ b/Documentation/css/jazzy.css @@ -56,9 +56,14 @@ p code, li code { padding: 2px 4px; border-radius: 4px; } +pre > code { + padding: 0; } + a { color: #0088cc; text-decoration: none; } + a code { + color: inherit; } ul { padding-left: 15px; } @@ -80,11 +85,11 @@ blockquote { header { font-size: 0.85em; - line-height: 26px; + line-height: 32px; background-color: #414141; position: fixed; width: 100%; - z-index: 1; } + z-index: 3; } header img { padding-right: 6px; vertical-align: -4px; @@ -100,12 +105,12 @@ header { #breadcrumbs { background-color: #f2f2f2; - height: 27px; + height: 21px; padding-top: 17px; position: fixed; width: 100%; - z-index: 1; - margin-top: 26px; } + z-index: 2; + margin-top: 32px; } #breadcrumbs #carat { height: 10px; margin: 0 5px; } @@ -169,6 +174,13 @@ header { display: block; padding-top: 70px; margin: -70px 0 0; } + .main-content .section-name p { + margin-bottom: inherit; + line-height: inherit; } + .main-content .section-name code { + background-color: inherit; + padding: inherit; + color: inherit; } .section { padding: 0 25px; } @@ -192,6 +204,7 @@ header { margin-left: 18px; } .task-group-section { + margin-top: 10px; padding-left: 6px; border-top: 1px solid #e2e2e2; } @@ -204,6 +217,23 @@ header { padding-top: 70px; margin: -70px 0 0; } +.section-name-container { + position: relative; + display: inline-block; } + .section-name-container .section-name-link { + position: absolute; + top: 0; + left: 0; + bottom: 0; + right: 0; + margin-bottom: 0; } + .section-name-container .section-name { + position: relative; + pointer-events: none; + z-index: 1; } + .section-name-container .section-name a { + pointer-events: auto; } + .item { padding-top: 8px; width: 100%; @@ -217,12 +247,14 @@ header { background-color: transparent; padding: 0; } .item .token, .item .direct-link { + display: inline-block; + text-indent: -20px; padding-left: 3px; - margin-left: 15px; + margin-left: 35px; font-size: 11.9px; transition: all 300ms; } .item .token-open { - margin-left: 0px; } + margin-left: 20px; } .item .discouraged { text-decoration: line-through; } .item .declaration-note { @@ -346,3 +378,46 @@ html.dash .content-wrapper { html.dash #footer { position: static; } + +form[role=search] { + float: right; } + form[role=search] input { + font: Helvetica, freesans, Arial, sans-serif; + margin-top: 6px; + font-size: 13px; + line-height: 20px; + padding: 0px 10px; + border: none; + border-radius: 1em; } + .loading form[role=search] input { + background: white url(../img/spinner.gif) center right 4px no-repeat; } + form[role=search] .tt-menu { + margin: 0; + min-width: 300px; + background: #fff; + color: #333; + border: 1px solid #e2e2e2; + z-index: 4; } + form[role=search] .tt-highlight { + font-weight: bold; } + form[role=search] .tt-suggestion { + font: Helvetica, freesans, Arial, sans-serif; + font-size: 14px; + padding: 0 8px; } + form[role=search] .tt-suggestion span { + display: table-cell; + white-space: nowrap; } + form[role=search] .tt-suggestion .doc-parent-name { + width: 100%; + text-align: right; + font-weight: normal; + font-size: 0.9em; + padding-left: 16px; } + form[role=search] .tt-suggestion:hover, + form[role=search] .tt-suggestion.tt-cursor { + cursor: pointer; + background-color: #4183c4; + color: #fff; } + form[role=search] .tt-suggestion:hover .doc-parent-name, + form[role=search] .tt-suggestion.tt-cursor .doc-parent-name { + color: #fff; } diff --git a/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Classes.html b/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Classes.html index dddde23..6868080 100644 --- a/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Classes.html +++ b/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Classes.html @@ -8,13 +8,21 @@ + + +
    -

    Atom Docs (99% documented)

    +

    Atom Docs (98% documented)

    +

    +

    + +
    +

    @@ -34,40 +42,13 @@ Atom - - - - - - - - - @@ -77,6 +58,12 @@ + + @@ -86,10 +73,10 @@ Extensions +
    @@ -158,7 +186,69 @@

    Classes

    Declaration

    Swift

    -
    public class Atom
    +
    public final class Atom
    + +
    +
    + + + +
  • +
    + + + + Service + +
    +
    +
    +
    +
    +
    +

    Service is a public facing class responsible for managing +URLSession configuration, network calls, and decoding instances of a + data type into internal models.

    + +

    Service is available through the Atom instance only and cannot be +initialized dirrectly. This behavior is intentional to allow for better separation +of responsibilities such as creating a request, network call, and data decoding.

    + + See more +
    +
    +

    Declaration

    +
    +

    Swift

    +
    public class Service
    + +
    +
    +
    +
    +
  • +
  • +
    + + + + ServiceConfiguration + +
    +
    +
    +
    +
    +
    +

    Model object representing Service configuration.

    + + See more +
    +
    +

    Declaration

    +
    +

    Swift

    +
    public final class ServiceConfiguration
    @@ -170,8 +260,8 @@

    Declaration

    diff --git a/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Classes/Atom.html b/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Classes/Atom.html index 78f9f81..edb2c17 100644 --- a/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Classes/Atom.html +++ b/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Classes/Atom.html @@ -8,13 +8,21 @@ + + +
    -

    Atom Docs (99% documented)

    +

    Atom Docs (98% documented)

    +

    +

    + +
    +

    @@ -34,40 +42,13 @@ Atom
  • - - - - - - - - - @@ -77,6 +58,12 @@ + + @@ -86,10 +73,10 @@ Extensions +
    @@ -133,7 +161,8 @@

    Atom

    -
    public class Atom
    + +
    public final class Atom
    @@ -185,9 +214,9 @@

    Declaration

  • @@ -202,7 +231,7 @@

    Declaration

    Declaration

    Swift

    -
    public init(serviceConfiguration: Atom.ServiceConfiguration = Atom.ServiceConfiguration())
    +
    public init(serviceConfiguration: ServiceConfiguration = ServiceConfiguration())
    @@ -218,7 +247,7 @@

    Parameters

    -

    The service configuration data used for initializing Atom.Service instance.

    +

    The service configuration data used for initializing Service instance.

    @@ -228,10 +257,6 @@

    Parameters

  • - - -
    -
    • @@ -267,9 +292,9 @@

      Declaration

    • - - - load(_:) + + + enqueue(_:)
      @@ -277,14 +302,14 @@

      Declaration

      -

      Prepares Atom.Service for a network call.

      +

      Prepares Service for a network call.

      -

      Calling load() method will not initiate a network call until -one of the available methods on Atom.Service is called first.

      +

      Calling enqueue(_:) method will not initiate a network call until +one of the available methods on Service is called first.

      Note

      -

      Calling load() method multiple times without executing a network call will update -previously set requestable property on Atom.Service with new value. Atom framework +

      Calling enqueue(_:) method multiple times without executing a network call will update +previously set requestable property on Service with new value. Atom framework does not support queue based flow.

      @@ -294,7 +319,7 @@

      Declaration

      Declaration

      Swift

      -
      func load(_ requestable: Requestable) -> Atom.Service
      +
      func enqueue(_ requestable: Requestable) -> Service
      @@ -319,15 +344,11 @@

      Parameters

      Return Value

      -

      Updated Atom.Service instance initialized using Atom.ServiceConfiguration.

      +

      Updated Service instance initialized using ServiceConfiguration.

    - - -
    -
    • @@ -357,439 +378,11 @@

      Declaration

    -
    -
      -
    • -
      - - - - AuthenticationMethod - -
      -
      -
      -
      -
      -
      -

      List of authentication methods a client can choose from for Atom configuration.

      - - See more -
      -
      -

      Declaration

      -
      -

      Swift

      -
      enum AuthenticationMethod
      - -
      -
      -
      -
      -
    • -
    -
    -
    -
      -
    • -
      - - - - AuthorizationEndpoint - -
      -
      -
      -
      -
      -
      -

      Model object representing the location of the authorization server.

      - - See more -
      -
      -

      Declaration

      -
      -

      Swift

      -
      struct AuthorizationEndpoint
      - -
      -
      -
      -
      -
    • -
    -
    -
    -
      -
    • -
      - - - - BaseURL - -
      -
      -
      -
      -
      -
      -

      Model object representing base URL composed from URL scheme and host.

      - - See more -
      -
      -

      Declaration

      -
      -

      Swift

      -
      struct BaseURL
      - -
      -
      -
      -
      -
    • -
    -
    -
    -
      -
    • -
      - - - - BasicCredential - -
      -
      -
      -
      -
      -
      -

      The BasicCredential type declares an object used by Atom in network requests that require basic authentication. Before -basic authentication is applied as Authorization header value, username and password will be combined into a single -string using : and base 64 encoded.

      - - See more -
      -
      -

      Declaration

      -
      -

      Swift

      -
      struct BasicCredential
      - -
      -
      -
      -
      -
    • -
    -
    -
    - -
    -
    -
      -
    • -
      - - - - HeaderItem - -
      -
      -
      -
      -
      -
      -

      A single name-value pair for specifying HTTP header value modeled after URLQueryItem.

      - - See more -
      -
      -

      Declaration

      -
      -

      Swift

      -
      struct HeaderItem
      - -
      -
      -
      -
      -
    • -
    -
    -
    -
      -
    • -
      - - - - Method - -
      -
      -
      -
      -
      -
      -

      List of primary HTTP methods.

      - - See more -
      -
      -

      Declaration

      -
      -

      Swift

      -
      enum Method : Equatable
      - -
      -
      -
      -
      -
    • -
    -
    -
    -
      -
    • -
      - - - - QueryItem - -
      -
      -
      -
      -
      -
      -

      A single name-value pair from the query portion of a URL.

      - -

      Foundation offers URLQueryItem type but not a similar type for creating -HTTP header item. To stay consistent, Atom framework introduced Atom.HeaderItem -and type aliased URLQueryItem to Atom.QueryItem.

      - -
      -
      -

      Declaration

      -
      -

      Swift

      -
      typealias QueryItem = URLQueryItem
      - -
      -
      -
      -
      -
    • -
    -
    -
    -
      -
    • -
      - - - - Response - -
      -
      -
      -
      -
      -
      -

      The metadata associated with the response to a URL load request, independent of protocol and URL scheme.

      - - See more -
      -
      -

      Declaration

      -
      -

      Swift

      -
      struct Response
      - -
      -
      -
      -
      -
    • -
    -
    -
    -
      -
    • -
      - - - - TokenCredential - -
      -
      -
      -
      -
      -
      -

      The TokenCredential type declares an object used by Atom in network requests that require bearer authentication.

      - - See more -
      -
      -

      Declaration

      -
      -

      Swift

      -
      struct TokenCredential
      - -
      -
      -
      -
      -
    • -
    -
    -
    -
      -
    • -
      - - - - URLPath - -
      -
      -
      -
      -
      -
      -

      Model object representing URL path.

      - - See more -
      -
      -

      Declaration

      -
      -

      Swift

      -
      struct URLPath
      - -
      -
      -
      -
      -
    • -
    -
    -
    -
      -
    • -
      - - - - Service - -
      -
      -
      -
      -
      -
      -

      Service is a public facing class responsible for managing -URLSession configuration, network calls, and decoding instances of a - data type into internal models.

      - -

      Service is available through the Atom instance only and cannot be -initialized dirrectly. This behavior is intentional to allow for better separation -of responsibilities such as creating a request, network call, and data decoding.

      - - See more -
      -
      -

      Declaration

      -
      -

      Swift

      -
      class Service
      - -
      -
      -
      -
      -
    • -
    -
    -
    -
      -
    • -
      - - - - ServiceConfiguration - -
      -
      -
      -
      -
      -
      -

      Model object representing Service configuration.

      - - See more -
      -
      -

      Declaration

      -
      -

      Swift

      -
      class ServiceConfiguration
      - -
      -
      -
      -
      -
    • -
    -
    diff --git a/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Classes/Service.html b/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Classes/Service.html new file mode 100644 index 0000000..628b8b6 --- /dev/null +++ b/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Classes/Service.html @@ -0,0 +1,455 @@ + + + + Service Class Reference + + + + + + + + + + + + + +
    +
    +

    Atom Docs (98% documented)

    +

    +

    + +
    +

    +
    +
    +
    + +
    +
    + +
    +
    +
    +

    Service

    +
    +
    + +
    public class Service
    + +
    +
    +

    Service is a public facing class responsible for managing +URLSession configuration, network calls, and decoding instances of a + data type into internal models.

    + +

    Service is available through the Atom instance only and cannot be +initialized dirrectly. This behavior is intentional to allow for better separation +of responsibilities such as creating a request, network call, and data decoding.

    + +
    +
    +
    +
      +
    • +
      + + + + resume(expecting:) + +
      +
      +
      +
      +
      +
      +

      Creates and resumes URLRequest initialized from Requestable.

      + +

      Use this method to make network requests where you expect data returned by the +service and require that data to be decoded into internal representations - models.

      + +

      Network request and decoding will be performed on a background thread after +which the client will be notified on a queue Atom was configured to use.

      + +

      A typical usage pattern for this method could look like this:

      +
      atom
      +    .enqueue(endpoint)
      +    .resume(expecting: User.self)
      +    .sink { completion in
      +        // Handle `AtomError`.
      +    } receiveValue: { user in
      +        // Handle decoded `User` instance.
      +    }
      +    .store(in: &cancelables)
      +
      + +

      In the above example, data will be decoded into a User instance.

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      func resume<T>(expecting type: T.Type) -> AnyPublisher<T, AtomError> where T : Model
      + +
      +
      +
      +

      Parameters

      + + + + + + + +
      + + type + + +
      +

      The type to decode.

      +
      +
      +
      +
      +

      Return Value

      +

      AnyPublisher where Output is the decoded Model and Failure is AtomError.

      +
      +
      +
      +
    • +
    • +
      + + + + resume() + +
      +
      +
      +
      +
      +
      +

      Creates and resumes URLRequest initialized from Requestable.

      + +

      Use this method to make network requests where you don’t expect any data returned +and are only interested in knowing if the network call succeeded or failed.

      + +

      Atom framework uses a convenience computed variable on AtomResponse - isSuccessful +to determine success or a failure of a response based on a status code returned by the service.

      + +

      A typical usage pattern for this method after getting a result could look like this:

      +
      atom
      +    .enqueue(Endpoint.random)
      +    .resume()
      +    .sink {
      +        // Handle `AtomError`.
      +    } receiveValue: {
      +        // Handle `AtomResponse`.
      +    }
      +    .store(in: &cancelables)
      +
      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      func resume() -> AnyPublisher<AtomResponse, AtomError>
      + +
      +
      +
      +

      Return Value

      +

      AnyPublisher where Output is the AtomResponse and Failure is AtomError.

      +
      +
      +
      +
    • +
    • + +
      +
      +
      +
      +
      +

      Creates and resumes URLRequest initialized from Requestable.

      + +

      Use this method to make network requests where you expect data returned by the +service and require that data to be decoded into internal representations - models.

      + +

      Network request and decoding will be performed on a background thread after +which the client will be notified of a result on a queue Atom was configured to use.

      + +

      A typical usage pattern for this method could look like this:

      +
      atom.enqueue(endpoint).resume(expecting: User.self) { result in
      +    switch result {
      +        case .failure(let error):
      +        // Handle `AtomError`.
      +
      +        case .success(let user):
      +        // Handle decoded `User` instance.
      +    }
      +}
      +
      + +

      In the above example, data will be decoded into a User instance.

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      func resume<T>(expecting type: T.Type, completion: @escaping (Result<T, AtomError>) -> Void) where T : Model
      + +
      +
      +
      +

      Parameters

      + + + + + + + + + + + +
      + + type + + +
      +

      The type to decode.

      +
      +
      + + completion + + +
      +

      The completion containing Result where the associated value is either an AtomError or decoded model instance.

      +
      +
      +
      +
      +
      +
    • +
    • +
      + + + + resume(_:) + +
      +
      +
      +
      +
      +
      +

      Creates and resumes URLRequest initialized from Requestable.

      + +

      Use this method to make network requests where you don’t expect any data returned +and are only interested in knowing if the network call succeeded or failed.

      + +

      Atom framework uses a convenience computed variable on AtomResponse - isSuccessful +to determine success or a failure of a response based on a status code returned by the service.

      + +

      A typical usage pattern for this method after getting a result could look like this:

      +
      atom.enqueue(endpoint).resume { result in
      +    switch result {
      +        case .failure(let error):
      +        // Handle `AtomError`.
      +
      +        case .success(let response):
      +        // Handle `AtomResponse`.
      +        }
      +    }
      +}
      +
      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      func resume(_ completion: @escaping (Result<AtomResponse, AtomError>) -> Void)
      + +
      +
      +
      +

      Parameters

      + + + + + + + +
      + + completion + + +
      +

      The completion containing Result where the associated value is either an AtomError or AtomResponse.

      +
      +
      +
      +
      +
      +
    • +
    +
    +
    +
    + +
    +
    + + + diff --git a/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Classes/ServiceConfiguration.html b/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Classes/ServiceConfiguration.html new file mode 100644 index 0000000..a44dede --- /dev/null +++ b/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Classes/ServiceConfiguration.html @@ -0,0 +1,359 @@ + + + + ServiceConfiguration Class Reference + + + + + + + + + + + + + +
    +
    +

    Atom Docs (98% documented)

    +

    +

    + +
    +

    +
    +
    +
    + +
    +
    + +
    +
    +
    +

    ServiceConfiguration

    +
    +
    + +
    public final class ServiceConfiguration
    + +
    +
    +

    Model object representing Service configuration.

    + +
    +
    +
    +
      +
    • +
      + + + + Configuration + +
      +
      +
      +
      +
      +
      +

      List of supported session configurations.

      + +

      Configuration enum is a reflection of available options offered +by Foundation as class properties on URLSessionConfiguration. The +main reason for this abstraction is testability - see ServiceConfigurationTests.

      + + See more +
      +
      +

      Declaration

      +
      +

      Swift

      +
      public enum Configuration : Equatable
      + +
      +
      +
      +
      +
    • +
    • +
      + + + + MultipathServiceType + +
      +
      +
      +
      +
      +
      +

      Undocumented

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      public typealias MultipathServiceType = URLSessionConfiguration.MultipathServiceType
      + +
      +
      +
      +
      +
    • +
    • + +
      +
      +
      +
      +
      +

      Creates a ServiceConfiguration instance given the provided parameter(s).

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      public init(authenticationMethod: AuthenticationMethod = .none, configuration: Configuration = .ephemeral, decoder: JSONDecoder = JSONDecoder(), dispatchQueue: DispatchQueue = .main, multipathServiceType: MultipathServiceType = .none)
      + +
      +
      +
      +

      Parameters

      + + + + + + + + + + + + + + + + + + + + + + + +
      + + authenticationMethod + + +
      +

      The authentication method indicating how authorization header will be handled in Atom.

      +
      +
      + + configuration + + +
      +

      The ServiceConfiguration.Configuration - default value is .ephemeral.

      +
      +
      + + decoder + + +
      +

      The JSONDecoder for decoding data into models.

      +
      +
      + + dispatchQueue + + +
      +

      The queue to dispatch Result object on.

      +
      +
      + + multipathServiceType + + +
      +

      The service type that specifies the Multipath TCP connection policy for transmitting data over Wi-Fi and cellular interfaces.

      +
      +
      +
      +
      +
      +
    • +
    • + +
      +
      +
      +
      +
      +

      Creates a ServiceConfiguration instance given the provided parameter(s).

      + +
      +
      +
      +
    • +
    +
    +
    +
    + +
    +
    + + + diff --git a/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Classes/ServiceConfiguration/Configuration.html b/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Classes/ServiceConfiguration/Configuration.html new file mode 100644 index 0000000..8cfd21c --- /dev/null +++ b/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Classes/ServiceConfiguration/Configuration.html @@ -0,0 +1,272 @@ + + + + Configuration Enumeration Reference + + + + + + + + + + + + + +
    +
    +

    Atom Docs (98% documented)

    +

    +

    + +
    +

    +
    +
    +
    + +
    +
    + +
    +
    +
    +

    Configuration

    +
    +
    + +
    public enum Configuration : Equatable
    + +
    +
    +

    List of supported session configurations.

    + +

    Configuration enum is a reflection of available options offered +by Foundation as class properties on URLSessionConfiguration. The +main reason for this abstraction is testability - see ServiceConfigurationTests.

    + +
    +
    +
    +
      +
    • +
      + + + + background(_:) + +
      +
      +
      +
      +
      +
      +

      The background session configuration is suitable for transferring data files while the app runs in the background.

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      case background(String)
      + +
      +
      +
      +
      +
    • +
    • +
      + + + + default + +
      +
      +
      +
      +
      +
      +

      The default session configuration that uses a persistent disk-based cache.

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      case `default`
      + +
      +
      +
      +
      +
    • +
    • +
      + + + + ephemeral + +
      +
      +
      +
      +
      +
      +

      Ephemeral configuration doesn’t store caches, credential stores, or any session-related data on disk (RAM only).

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      case ephemeral
      + +
      +
      +
      +
      +
    • +
    +
    +
    +
    + +
    +
    + + + diff --git a/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Enums.html b/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Enums.html index 33b0420..902a4cb 100644 --- a/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Enums.html +++ b/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Enums.html @@ -8,13 +8,21 @@ + + +
    -

    Atom Docs (99% documented)

    +

    Atom Docs (98% documented)

    +

    +

    + +
    +

    - - -
    -
    • @@ -197,13 +221,69 @@

      Declaration

    • +
    • +
      + + + + AuthenticationMethod + +
      +
      +
      +
      +
      +
      +

      List of authentication methods a client can choose from for Atom configuration.

      + + See more +
      +
      +

      Declaration

      +
      +

      Swift

      +
      public enum AuthenticationMethod
      + +
      +
      +
      +
      +
    • +
    • +
      + + + + HTTPMethod + +
      +
      +
      +
      +
      +
      +

      List of primary HTTP methods.

      + + See more +
      +
      +

      Declaration

      +
      +

      Swift

      +
      public enum HTTPMethod : Equatable
      + +
      +
      +
      +
      +
    diff --git a/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Enums/AtomError.html b/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Enums/AtomError.html index e27539b..adba8c7 100644 --- a/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Enums/AtomError.html +++ b/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Enums/AtomError.html @@ -8,13 +8,21 @@ + + +
    -

    Atom Docs (99% documented)

    +

    Atom Docs (98% documented)

    +

    +

    + +
    +

    @@ -34,40 +42,13 @@ Atom - - - - - - - - - @@ -77,6 +58,12 @@ + + @@ -86,10 +73,10 @@ Extensions +
    @@ -133,6 +161,7 @@

    AtomError

    +
    public enum AtomError : Error
    @@ -148,7 +177,7 @@

    AtomError

    - decoder(_:) + decoder(_:)
    @@ -175,7 +204,7 @@

    Declaration

    - data(_:) + data(_:)
    @@ -202,7 +231,7 @@

    Declaration

    - requestable(_:) + requestable(_:)
    @@ -227,9 +256,9 @@

    Declaration

  • @@ -242,14 +271,14 @@

    Declaration

    An optional response data will be set for further processing of the body. In the context of ACE Group, data will contain the error message or the model object.

    -

    For more information, see Atom.Response.

    +

    For more information, see AtomResponse.

    Declaration

    Swift

    -
    case response(Atom.Response)
    +
    case response(AtomResponse)
    @@ -261,7 +290,7 @@

    Declaration

    - session(_:) + session(_:)
  • @@ -340,10 +369,6 @@

    Declaration

    - -
    -
    -
    • @@ -405,16 +430,12 @@

      Declaration

    • -
    -
    -
    -
    + diff --git a/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Enums/HTTPMethod.html b/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Enums/HTTPMethod.html new file mode 100644 index 0000000..9838e2a --- /dev/null +++ b/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Enums/HTTPMethod.html @@ -0,0 +1,322 @@ + + + + HTTPMethod Enumeration Reference + + + + + + + + + + + + + +
    +
    +

    Atom Docs (98% documented)

    +

    +

    + +
    +

    +
    +
    +
    + +
    +
    + +
    +
    +
    +

    HTTPMethod

    +
    +
    + +
    public enum HTTPMethod : Equatable
    + +
    +
    +

    List of primary HTTP methods.

    + +
    +
    +
    +
      +
    • +
      + + + + delete + +
      +
      +
      +
      +
      +
      +

      Use for deleting a resource identified by a URI.

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      case delete
      + +
      +
      +
      +
      +
    • +
    • +
      + + + + get + +
      +
      +
      +
      +
      +
      +

      Use for reading (or retrieving) a representation of a resource.

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      case get
      + +
      +
      +
      +
      +
    • +
    • +
      + + + + patch(_:) + +
      +
      +
      +
      +
      +
      +

      Use for modifying capabilities.

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      case patch(Data)
      + +
      +
      +
      +
      +
    • +
    • +
      + + + + post(_:) + +
      +
      +
      +
      +
      +
      +

      Use for creating new resources.

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      case post(Data)
      + +
      +
      +
      +
      +
    • +
    • +
      + + + + put(_:) + +
      +
      +
      +
      +
      +
      +

      Use for replacing a resource.

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      case put(Data)
      + +
      +
      +
      +
      +
    • +
    +
    +
    +
    + +
    +
    + + + diff --git a/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Enums/RequestableError.html b/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Enums/RequestableError.html index ce3942f..59ae808 100644 --- a/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Enums/RequestableError.html +++ b/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Enums/RequestableError.html @@ -8,13 +8,21 @@ + + +
    -

    Atom Docs (99% documented)

    +

    Atom Docs (98% documented)

    +

    +

    + +
    +

    @@ -34,40 +42,13 @@ Atom - - - - - - - - - @@ -77,6 +58,12 @@ + + @@ -86,10 +73,10 @@ Extensions +
    @@ -133,6 +161,7 @@

    RequestableError

    +
    public enum RequestableError : Error
    @@ -229,8 +258,8 @@

    Declaration

    diff --git a/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Extensions.html b/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Extensions.html index e382349..84b59d0 100644 --- a/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Extensions.html +++ b/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Extensions.html @@ -8,13 +8,21 @@ + + +
    -

    Atom Docs (99% documented)

    +

    Atom Docs (98% documented)

    +

    +

    + +
    +

    @@ -34,40 +42,13 @@ Atom - - - - - - - - - @@ -77,6 +58,12 @@ + + @@ -86,10 +73,10 @@ Extensions +
    @@ -140,9 +168,9 @@

    Extensions

  • - - - Bool + + + Array
    @@ -150,31 +178,30 @@

    Extensions

    - - See more +

    Adds the ability to specify an array as the expected decoded type.

    + +

    Each element must conform to Model protocol.

    + + See more

    Declaration

    Swift

    -
    @frozen
    -public extension Bool
    +
    extension Array: Model where Element: Model
    +
    extension Array: ExpressibleByDictionaryLiteral where Element: RequestableItem
  • - -
    -
    -
    • - - - Optional + + + Data
      @@ -182,15 +209,14 @@

      Declaration

      - - See more +

      Conforming Data type to Model protocol allows it to be used where Model is expected.

      +

      Declaration

      Swift

      -
      @frozen
      -public extension Optional
      +
      extension Data: Model
      @@ -203,9 +229,11 @@

      Declaration

      - -

      Debug Description

      -
      +
      + +

      Debug Description

      +

      +
      • @@ -235,10 +263,6 @@

        Declaration

    • -
    -
    -
    -
    • @@ -266,10 +290,6 @@

      Declaration

    • -
    -
    -
    -
    • @@ -297,10 +317,6 @@

      Declaration

    • -
    -
    -
    -
    + diff --git a/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Extensions/URLRequest.html b/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Extensions/URLRequest.html index 13fd158..9212b9e 100644 --- a/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Extensions/URLRequest.html +++ b/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Extensions/URLRequest.html @@ -8,13 +8,21 @@ + + +
    -

    Atom Docs (99% documented)

    +

    Atom Docs (98% documented)

    +

    +

    + +
    +

    @@ -34,40 +42,13 @@ Atom - - - - - - - - - @@ -77,6 +58,12 @@ + + @@ -86,10 +73,10 @@ Extensions +
    @@ -133,6 +161,7 @@

    URLRequest

    +
    extension URLRequest
    @@ -177,8 +206,8 @@

    Declaration

    diff --git a/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Extensions/URLResponse.html b/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Extensions/URLResponse.html index 18c924e..807d27b 100644 --- a/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Extensions/URLResponse.html +++ b/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Extensions/URLResponse.html @@ -8,13 +8,21 @@ + + +
    -

    Atom Docs (99% documented)

    +

    Atom Docs (98% documented)

    +

    +

    + +
    +

    @@ -34,40 +42,13 @@ Atom - - - - - - - - - @@ -77,6 +58,12 @@ + + @@ -86,10 +73,10 @@ Extensions +
    @@ -133,6 +161,7 @@

    URLResponse

    +
    public extension URLResponse
    @@ -199,6 +228,15 @@

    Declaration

    +
    + + +
    + +

    Debug Description

    +

    +
    +
    • @@ -220,7 +258,7 @@

      Declaration

      Declaration

      Swift

      -
      override public var debugDescription: String { get }
      +
      override var debugDescription: String { get }
      @@ -232,8 +270,8 @@

      Declaration

    diff --git a/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Extensions/URLSessionTask.html b/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Extensions/URLSessionTask.html index 16ac960..50bb012 100644 --- a/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Extensions/URLSessionTask.html +++ b/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Extensions/URLSessionTask.html @@ -8,13 +8,21 @@ + + +
    -

    Atom Docs (99% documented)

    +

    Atom Docs (98% documented)

    +

    +

    + +
    +

    @@ -34,40 +42,13 @@ Atom - - - - - - - - - @@ -77,6 +58,12 @@ + + @@ -86,10 +73,10 @@ Extensions +
    @@ -133,6 +161,7 @@

    URLSessionTask

    +
    extension URLSessionTask
    @@ -174,8 +203,8 @@

    Declaration

    diff --git a/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Extensions/URLSessionTaskMetrics.html b/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Extensions/URLSessionTaskMetrics.html index e7ec583..500955f 100644 --- a/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Extensions/URLSessionTaskMetrics.html +++ b/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Extensions/URLSessionTaskMetrics.html @@ -8,13 +8,21 @@ + + +
    -

    Atom Docs (99% documented)

    +

    Atom Docs (98% documented)

    +

    +

    + +
    +

    @@ -34,40 +42,13 @@ Atom - - - - - - - - - @@ -77,6 +58,12 @@ + + @@ -86,10 +73,10 @@ Extensions +
    @@ -133,6 +161,7 @@

    URLSessionTaskMetrics

    +
    extension URLSessionTaskMetrics
    @@ -174,8 +203,8 @@

    Declaration

    diff --git a/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Protocols.html b/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Protocols.html index 3100732..6d567d9 100644 --- a/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Protocols.html +++ b/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Protocols.html @@ -8,13 +8,21 @@ + + +
    -

    Atom Docs (99% documented)

    +

    Atom Docs (98% documented)

    +

    +

    + +
    +

    @@ -34,40 +42,13 @@ Atom - - - - - - - - - @@ -77,6 +58,12 @@ + + @@ -86,10 +73,10 @@ Extensions +
    @@ -137,6 +165,34 @@

    Protocols

      +
    • +
      + + + + Requestable + +
      +
      +
      +
      +
      +
      +

      The Requestable protocol declares an interface used for initializing network request object.

      + + See more +
      +
      +

      Declaration

      +
      +

      Swift

      +
      public protocol Requestable
      + +
      +
      +
      +
      +
    • @@ -150,13 +206,13 @@

      Protocols

      -

      The BasicCredentialConvertible protocol declares an interface used for converting conforming type to Atom.BasicCredential.

      +

      The BasicCredentialConvertible protocol declares an interface used for converting conforming type to BasicCredential.

      Atom can be configured to automatically apply authorization header to any Requestable instance. Once properly configured, Atom will read credentials from the storage specified by the client and apply them to Requestable instance if requiresAuthentication property is set to true. Values will be set as Authorization: Basic base64-encoded-credential header value.

      -

      For more information see Atom.Configuration documentation.

      +

      For more information see Configuration documentation.

      See more
      @@ -171,10 +227,6 @@

      Declaration

    • -
    -
    -
    -
    • @@ -188,7 +240,7 @@

      Declaration

      -

      The ClientCredentialConvertible protocol declares an interface used for converting conforming type to Atom.ClientCredential.

      +

      The ClientCredentialConvertible protocol declares an interface used for converting conforming type to ClientCredential.

      See more
      @@ -203,10 +255,6 @@

      Declaration

    • -
    -
    -
    -
    • @@ -220,7 +268,7 @@

      Declaration

      -

      The Model protocol declares an interface used as a generic constraint on Atom.Service methods.

      +

      The Model protocol declares an interface used as a generic constraint on Service methods.

      @@ -234,16 +282,12 @@

      Declaration

    • -
    -
    -
    -
    • @@ -251,25 +295,21 @@

      Declaration

      -

      The Requestable protocol declares an interface used for initializing network request object.

      +

      The RequestableItem protocol declares an interface used for specifying HTTP header values & request queries.

      - See more + See more

      Declaration

      Swift

      -
      public protocol Requestable
      +
      public protocol RequestableItem
    • -
    -
    -
    -
    • @@ -283,7 +323,7 @@

      Declaration

      -

      The TokenCredentialWritable protocol declares an interface used for reading from / writing to Atom.TokenCredential.

      +

      The TokenCredentialWritable protocol declares an interface used for reading from / writing to TokenCredential.

      Atom can be configured to automatically apply authorization header to any Requestable instance. Once properly configured, Atom will read credentials from the storage specified by the client and apply them to Requestable instance if requiresAuthentication property @@ -291,14 +331,14 @@

      Declaration

      Proper configuration requires that the client conform and implement TokenCredentialWritable protocol where the conforming type is a class.

      class SSOCredential: TokenCredentialWritable {
      -    var tokenCredential: Atom.TokenCredential {
      +    var tokenCredential: TokenCredential {
               get { keychain.value() }
               set { keychain.save(newValue) }
           }
       }
       
      -

      For more information see Atom.Configuration documentation.

      +

      For more information see Configuration documentation.

      See more
      @@ -318,8 +358,8 @@

      Declaration

    diff --git a/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Protocols/BasicCredentialConvertible.html b/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Protocols/BasicCredentialConvertible.html index 4047954..3109d32 100644 --- a/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Protocols/BasicCredentialConvertible.html +++ b/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Protocols/BasicCredentialConvertible.html @@ -8,13 +8,21 @@ + + +
    -

    Atom Docs (99% documented)

    +

    Atom Docs (98% documented)

    +

    +

    + +
    +

    @@ -34,40 +42,13 @@ Atom - - - - - - - - - @@ -77,6 +58,12 @@ + + @@ -86,10 +73,10 @@ Extensions +
    @@ -133,17 +161,18 @@

    BasicCredentialConvertible

    +
    public protocol BasicCredentialConvertible
    -

    The BasicCredentialConvertible protocol declares an interface used for converting conforming type to Atom.BasicCredential.

    +

    The BasicCredentialConvertible protocol declares an interface used for converting conforming type to BasicCredential.

    Atom can be configured to automatically apply authorization header to any Requestable instance. Once properly configured, Atom will read credentials from the storage specified by the client and apply them to Requestable instance if requiresAuthentication property is set to true. Values will be set as Authorization: Basic base64-encoded-credential header value.

    -

    For more information see Atom.Configuration documentation.

    +

    For more information see Configuration documentation.

    @@ -152,9 +181,9 @@

    BasicCredentialConvertible

  • @@ -162,14 +191,14 @@

    BasicCredentialConvertible

    -

    Returns conforming type as Atom.BasicCredential.

    +

    Returns conforming type as BasicCredential.

    Declaration

    Swift

    -
    var basicCredential: Atom.BasicCredential { get }
    +
    var basicCredential: BasicCredential { get }
    @@ -181,8 +210,8 @@

    Declaration

  • diff --git a/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Protocols/ClientCredentialConvertible.html b/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Protocols/ClientCredentialConvertible.html index 5d2cac7..f12016f 100644 --- a/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Protocols/ClientCredentialConvertible.html +++ b/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Protocols/ClientCredentialConvertible.html @@ -8,13 +8,21 @@ + + +
    -

    Atom Docs (99% documented)

    +

    Atom Docs (98% documented)

    +

    +

    + +
    +

    @@ -34,40 +42,13 @@ Atom - - - - - - - - - @@ -77,6 +58,12 @@ + + @@ -86,10 +73,10 @@ Extensions +
    @@ -133,11 +161,12 @@

    ClientCredentialConvertible

    +
    public protocol ClientCredentialConvertible
    -

    The ClientCredentialConvertible protocol declares an interface used for converting conforming type to Atom.ClientCredential.

    +

    The ClientCredentialConvertible protocol declares an interface used for converting conforming type to ClientCredential.

    @@ -146,9 +175,9 @@

    ClientCredentialConvertible

  • @@ -156,14 +185,14 @@

    ClientCredentialConvertible

    -

    Returns conforming type as Atom.ClientCredential.

    +

    Returns conforming type as ClientCredential.

    Declaration

    Swift

    -
    var clientCredential: Atom.ClientCredential { get }
    +
    var clientCredential: ClientCredential { get }
    @@ -175,8 +204,8 @@

    Declaration

  • diff --git a/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Protocols/Requestable.html b/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Protocols/Requestable.html index 2707f65..46f9a12 100644 --- a/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Protocols/Requestable.html +++ b/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Protocols/Requestable.html @@ -8,13 +8,21 @@ + + +
    -

    Atom Docs (99% documented)

    +

    Atom Docs (98% documented)

    +

    +

    + +
    +

    @@ -34,40 +42,13 @@ Atom - - - - - - - - - @@ -77,6 +58,12 @@ + + @@ -86,10 +73,10 @@ Extensions +
    @@ -133,6 +161,7 @@

    Requestable

    +
    public protocol Requestable
    @@ -146,9 +175,9 @@

    Requestable

  • - + - headerItems + headerItems Default implementation @@ -171,7 +200,7 @@

    Default Implementation

    Declaration

    Swift

    -
    var headerItems: [Atom.HeaderItem]? { get }
    +
    var headerItems: [HeaderItem]? { get }
    @@ -181,9 +210,9 @@

    Declaration

  • - + - method + method Default implementation @@ -206,7 +235,7 @@

    Default Implementation

    Declaration

    Swift

    -
    var method: Atom.Method { get }
    +
    var method: HTTPMethod { get }
    @@ -216,9 +245,9 @@

    Declaration

  • - + - queryItems + queryItems Default implementation @@ -241,7 +270,7 @@

    Default Implementation

    Declaration

    Swift

    -
    var queryItems: [Atom.QueryItem]? { get }
    +
    var queryItems: [QueryItem]? { get }
    @@ -287,9 +316,9 @@

    Declaration

  • @@ -300,8 +329,8 @@

    Declaration

    The base url to initialize URLRequest with.

    The URL host must begin and end with a word.

    -
    func baseURL() throws -> Atom.BaseURL {
    -    try Atom.BaseURL(host: "api.alaskaair.net")
    +
    func baseURL() throws -> BaseURL {
    +    try BaseURL(host: "api.alaskaair.net")
     }
     
    @@ -313,7 +342,7 @@

    Declaration

    Declaration

    Swift

    -
    func baseURL() throws -> Atom.BaseURL
    +
    func baseURL() throws -> BaseURL
    @@ -323,9 +352,9 @@

    Declaration

  • - + - path() + path() Default implementation @@ -339,8 +368,8 @@

    Declaration

    The URL path to append to a base URL.

    The path should begin with a forward slash / and end with a word.

    -
    func path() throws -> Atom.URLPath {
    -    try Atom.URLPath("/path/to/resource")
    +
    func path() throws -> URLPath {
    +    try URLPath("/path/to/resource")
     }
     
    @@ -350,14 +379,14 @@

    Declaration

    Default Implementation

    -

    The default valus is Atom.URLPath.default.

    +

    The default valus is URLPath.default.

    Declaration

    Swift

    -
    func path() throws -> Atom.URLPath
    +
    func path() throws -> URLPath
    @@ -369,8 +398,8 @@

    Declaration

  • diff --git a/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Protocols/RequestableItem.html b/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Protocols/RequestableItem.html new file mode 100644 index 0000000..f1cc2ec --- /dev/null +++ b/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Protocols/RequestableItem.html @@ -0,0 +1,298 @@ + + + + RequestableItem Protocol Reference + + + + + + + + + + + + + +
    +
    +

    Atom Docs (98% documented)

    +

    +

    + +
    +

    +
    +
    +
    + +
    +
    + +
    +
    +
    +

    RequestableItem

    +
    +
    + +
    public protocol RequestableItem
    + +
    +
    +

    The RequestableItem protocol declares an interface used for specifying HTTP header values & request queries.

    + +
    +
    +
    +
      +
    • +
      + + + + name + +
      +
      +
      +
      +
      +
      +

      The name of the requestable item.

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      var name: String { get }
      + +
      +
      +
      +
      +
    • +
    • +
      + + + + value + +
      +
      +
      +
      +
      +
      +

      The value of the requestable item.

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      var value: String { get }
      + +
      +
      +
      +
      +
    • +
    • +
      + + + + init(name:value:) + +
      +
      +
      +
      +
      +
      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      init(name: String, value: String)
      + +
      +
      +
      +

      Parameters

      + + + + + + + + + + + +
      + + name + + +
      +

      The name of the requestable item.

      +
      +
      + + value + + +
      +

      The value of the requestable item.

      +
      +
      +
      +
      +
      +
    • +
    +
    +
    +
    + +
    +
    + + + diff --git a/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Protocols/TokenCredentialWritable.html b/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Protocols/TokenCredentialWritable.html index cee1122..2356ae0 100644 --- a/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Protocols/TokenCredentialWritable.html +++ b/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Protocols/TokenCredentialWritable.html @@ -8,13 +8,21 @@ + + +
    -

    Atom Docs (99% documented)

    +

    Atom Docs (98% documented)

    +

    +

    + +
    +

    @@ -34,40 +42,13 @@ Atom - - - - - - - - - @@ -77,6 +58,12 @@ + + @@ -86,10 +73,10 @@ Extensions +
    @@ -133,11 +161,12 @@

    TokenCredentialWritable

    +
    public protocol TokenCredentialWritable : AnyObject
    -

    The TokenCredentialWritable protocol declares an interface used for reading from / writing to Atom.TokenCredential.

    +

    The TokenCredentialWritable protocol declares an interface used for reading from / writing to TokenCredential.

    Atom can be configured to automatically apply authorization header to any Requestable instance. Once properly configured, Atom will read credentials from the storage specified by the client and apply them to Requestable instance if requiresAuthentication property @@ -145,14 +174,14 @@

    TokenCredentialWritable

    Proper configuration requires that the client conform and implement TokenCredentialWritable protocol where the conforming type is a class.

    class SSOCredential: TokenCredentialWritable {
    -    var tokenCredential: Atom.TokenCredential {
    +    var tokenCredential: TokenCredential {
             get { keychain.value() }
             set { keychain.save(newValue) }
         }
     }
     
    -

    For more information see Atom.Configuration documentation.

    +

    For more information see Configuration documentation.

    @@ -161,9 +190,9 @@

    TokenCredentialWritable

  • @@ -171,14 +200,14 @@

    TokenCredentialWritable

    -

    Returns conforming type as Atom.TokenCredential.

    +

    Returns conforming type as TokenCredential.

    Declaration

    Swift

    -
    var tokenCredential: Atom.TokenCredential { get set }
    +
    var tokenCredential: TokenCredential { get set }
    @@ -190,8 +219,8 @@

    Declaration

  • diff --git a/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Structs.html b/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Structs.html index 7629d34..fa32e84 100644 --- a/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Structs.html +++ b/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Structs.html @@ -8,13 +8,21 @@ + + +
    -

    Atom Docs (99% documented)

    +

    Atom Docs (98% documented)

    +

    +

    + +
    +

    @@ -27,12 +35,35 @@
    + diff --git a/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Structs/AuthorizationEndpoint.html b/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Structs/AuthorizationEndpoint.html new file mode 100644 index 0000000..4e388ea --- /dev/null +++ b/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Structs/AuthorizationEndpoint.html @@ -0,0 +1,250 @@ + + + + AuthorizationEndpoint Structure Reference + + + + + + + + + + + + + +
    +
    +

    Atom Docs (98% documented)

    +

    +

    + +
    +

    +
    +
    +
    + +
    +
    + +
    +
    +
    +

    AuthorizationEndpoint

    +
    +
    + +
    public struct AuthorizationEndpoint
    + +
    +
    +

    Model object representing the location of the authorization server.

    + +
    +
    +
    +
      +
    • +
      + + + + init(host:path:) + +
      +
      +
      +
      +
      +
      +

      Creates a AuthorizationEndpoint instance given the provided parameter(s).

      + +

      Before an instance of the AuthorizationEndpoint can be created, host and path will be +validated using regex patters defined in NSRegularExpression+Additions. If validation +fails for any reason, an exception will be raised by Atom - this is intentional to ensure +a valid authorization endpoint is provided during Atom configuration.

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      public init(host: String, path: String)
      + +
      +
      +
      +

      Parameters

      + + + + + + + + + + + +
      + + host + + +
      +

      The URL host as defined in RFC 1738.

      +
      +
      + + path + + +
      +

      The URL path as defined in RFC 1738.

      +
      +
      +
      +
      +
      +
    • +
    +
    +
    +
    + +
    +
    + +
    + diff --git a/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Structs/BaseURL.html b/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Structs/BaseURL.html new file mode 100644 index 0000000..4c2522a --- /dev/null +++ b/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Structs/BaseURL.html @@ -0,0 +1,278 @@ + + + + BaseURL Structure Reference + + + + + + + + + + + + + +
    +
    +

    Atom Docs (98% documented)

    +

    +

    + +
    +

    +
    +
    +
    + +
    +
    + +
    +
    +
    +

    BaseURL

    +
    +
    + +
    public struct BaseURL
    + +
    +
    +

    Model object representing base URL composed from URL scheme and host.

    + +
    +
    +
    +
      +
    • +
      + + + + init(scheme:host:) + +
      +
      +
      +
      +
      +
      +

      Creates a BaseURL instance given the provided parameter(s).

      +
      +

      Throws

      +

      RequestableError.invalidBaseURL when URL host validation fails.

      + +
      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      public init(scheme: BaseURL.Scheme = .https, host: String) throws
      + +
      +
      +
      +

      Parameters

      + + + + + + + + + + + +
      + + scheme + + +
      +

      The URL scheme as defined in RFC 2718.

      +
      +
      + + host + + +
      +

      The URL host as defined in RFC 1738.

      +
      +
      +
      +
      +
      +
    • +
    • +
      + + + + Scheme + +
      +
      +
      +
      +
      +
      +

      List of supported scheme types.

      + + See more +
      +
      +

      Declaration

      +
      +

      Swift

      +
      enum Scheme
      + +
      +
      +
      +
      +
    • +
    +
    +
    +
    + +
    +
    + + + diff --git a/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Structs/BaseURL/Scheme.html b/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Structs/BaseURL/Scheme.html new file mode 100644 index 0000000..fc689e1 --- /dev/null +++ b/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Structs/BaseURL/Scheme.html @@ -0,0 +1,241 @@ + + + + Scheme Enumeration Reference + + + + + + + + + + + + + +
    +
    +

    Atom Docs (98% documented)

    +

    +

    + +
    +

    +
    +
    +
    + +
    +
    + +
    +
    +
    +

    Scheme

    +
    +
    + +
    enum Scheme
    + +
    +
    +

    List of supported scheme types.

    + +
    +
    +
    +
      +
    • +
      + + + + http + +
      +
      +
      +
      +
      +
      +

      The hyper text transfer protocol.

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      case http
      + +
      +
      +
      +
      +
    • +
    • +
      + + + + https + +
      +
      +
      +
      +
      +
      +

      The hyper text transfer protocol secure.

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      case https
      + +
      +
      +
      +
      +
    • +
    +
    +
    +
    + +
    +
    + + + diff --git a/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Structs/BasicCredential.html b/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Structs/BasicCredential.html new file mode 100644 index 0000000..5d3dc7c --- /dev/null +++ b/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Structs/BasicCredential.html @@ -0,0 +1,247 @@ + + + + BasicCredential Structure Reference + + + + + + + + + + + + + +
    +
    +

    Atom Docs (98% documented)

    +

    +

    + +
    +

    +
    +
    +
    + +
    +
    + +
    +
    +
    +

    BasicCredential

    +
    +
    + +
    public struct BasicCredential
    + +
    +
    +

    The BasicCredential type declares an object used by Atom in network requests that require basic authentication. Before +basic authentication is applied as Authorization header value, username and password will be combined into a single +string using : and base 64 encoded.

    + +
    +
    +
    +
      +
    • + +
      +
      +
      +
      +
      +

      Creates a BasicCredential instance given the provided parameter(s).

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      public init(password: String, username: String)
      + +
      +
      +
      +

      Parameters

      + + + + + + + + + + + +
      + + password + + +
      +

      The password to encode and use when applying basic authentication to a request.

      +
      +
      + + username + + +
      +

      The username to encode and use when applying basic authentication to a request.

      +
      +
      +
      +
      +
      +
    • +
    +
    +
    +
    + +
    +
    + + + diff --git a/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Structs/ClientCredential.html b/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Structs/ClientCredential.html new file mode 100644 index 0000000..e13c42b --- /dev/null +++ b/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Structs/ClientCredential.html @@ -0,0 +1,286 @@ + + + + ClientCredential Structure Reference + + + + + + + + + + + + + +
    +
    +

    Atom Docs (98% documented)

    +

    +

    + +
    +

    +
    +
    +
    + +
    +
    + +
    +
    +
    +

    ClientCredential

    +
    +
    + +
    public struct ClientCredential
    + +
    +
    +

    The ClientCredential type declares an object used by Atom for automated refreshing of the access token. +See https://tools.ietf.org/html/RFC6749

    + +
    +
    +
    +
      +
    • + +
      +
      +
      +
      +
      +

      Creates a ClientCredential instance given the provided parameter(s).

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      public init(grantType: GrantType = .refreshToken, id: String, secret: String)
      + +
      +
      +
      +

      Parameters

      + + + + + + + + + + + + + + + +
      + + grantType + + +
      +

      The authorization grant type as described in Sections 4.1.3, 4.3.2, 4.4.2, RFC 6749.

      +
      +
      + + id + + +
      +

      The client identifier issued to the client during the registration process described by Section 2.2, RFC 6749.

      +
      +
      + + secret + + +
      +

      The client secret. The client MAY omit the parameter if the client secret is an empty string. See RFC 6749.

      +
      +
      +
      +
      +
      +
    • +
    • +
      + + + + GrantType + +
      +
      +
      +
      +
      +
      +

      List of supported grant types by Atom.

      + + See more +
      +
      +

      Declaration

      +
      +

      Swift

      +
      enum GrantType : String
      + +
      +
      +
      +
      +
    • +
    +
    +
    +
    + +
    +
    + + + diff --git a/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Structs/ClientCredential/GrantType.html b/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Structs/ClientCredential/GrantType.html new file mode 100644 index 0000000..270983b --- /dev/null +++ b/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Structs/ClientCredential/GrantType.html @@ -0,0 +1,214 @@ + + + + GrantType Enumeration Reference + + + + + + + + + + + + + +
    +
    +

    Atom Docs (98% documented)

    +

    +

    + +
    +

    +
    +
    +
    + +
    +
    + +
    +
    +
    +

    GrantType

    +
    +
    + +
    enum GrantType : String
    + +
    +
    +

    List of supported grant types by Atom.

    + +
    +
    +
    +
      +
    • +
      + + + + refreshToken + +
      +
      +
      +
      +
      +
      +

      The refresh_token grant type as defined in Sections 6.0, RFC 6749.

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      case refreshToken = "refresh_token"
      + +
      +
      +
      +
      +
    • +
    +
    +
    +
    + +
    +
    + + + diff --git a/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Structs/HeaderItem.html b/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Structs/HeaderItem.html new file mode 100644 index 0000000..6c39697 --- /dev/null +++ b/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Structs/HeaderItem.html @@ -0,0 +1,299 @@ + + + + HeaderItem Structure Reference + + + + + + + + + + + + + +
    +
    +

    Atom Docs (98% documented)

    +

    +

    + +
    +

    +
    +
    +
    + +
    +
    + +
    +
    +
    +

    HeaderItem

    +
    +
    + +
    public struct HeaderItem : RequestableItem
    + +
    +
    +

    A single name-value pair from the header portion of a request.

    + +
    +
    +
    +
      +
    • +
      + + + + name + +
      +
      +
      +
      +
      +
      +

      The name of the header item.

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      public let name: String
      + +
      +
      +
      +
      +
    • +
    • +
      + + + + value + +
      +
      +
      +
      +
      +
      +

      The value of the header item.

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      public let value: String
      + +
      +
      +
      +
      +
    • +
    • +
      + + + + init(name:value:) + +
      +
      +
      +
      +
      +
      +

      Creates a HeaderItem instance given the provided parameter(s).

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      public init(name: String, value: String)
      + +
      +
      +
      +

      Parameters

      + + + + + + + + + + + +
      + + name + + +
      +

      The name of the header item.

      +
      +
      + + value + + +
      +

      The value of the header item.

      +
      +
      +
      +
      +
      +
    • +
    +
    +
    +
    + +
    +
    + + + diff --git a/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Structs/QueryItem.html b/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Structs/QueryItem.html new file mode 100644 index 0000000..d581f82 --- /dev/null +++ b/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Structs/QueryItem.html @@ -0,0 +1,299 @@ + + + + QueryItem Structure Reference + + + + + + + + + + + + + +
    +
    +

    Atom Docs (98% documented)

    +

    +

    + +
    +

    +
    +
    +
    + +
    +
    + +
    +
    +
    +

    QueryItem

    +
    +
    + +
    public struct QueryItem : RequestableItem
    + +
    +
    +

    A single name-value pair from the query portion of a URL.

    + +
    +
    +
    +
      +
    • +
      + + + + name + +
      +
      +
      +
      +
      +
      +

      The name of the query item.

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      public let name: String
      + +
      +
      +
      +
      +
    • +
    • +
      + + + + value + +
      +
      +
      +
      +
      +
      +

      The value of the query item.

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      public let value: String
      + +
      +
      +
      +
      +
    • +
    • +
      + + + + init(name:value:) + +
      +
      +
      +
      +
      +
      +

      Creates a QueryItem instance given the provided parameter(s).

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      public init(name: String, value: String)
      + +
      +
      +
      +

      Parameters

      + + + + + + + + + + + +
      + + name + + +
      +

      The name of the query item.

      +
      +
      + + value + + +
      +

      The value of the query item.

      +
      +
      +
      +
      +
      +
    • +
    +
    +
    +
    + +
    +
    + + + diff --git a/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Structs/Response.html b/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Structs/Response.html new file mode 100644 index 0000000..27bd41b --- /dev/null +++ b/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Structs/Response.html @@ -0,0 +1,457 @@ + + + + Response Structure Reference + + + + + + + + + + + + + +
    +
    +

    Atom Docs (98% documented)

    +

    +

    + +
    +

    +
    +
    +
    + +
    +
    + +
    +
    +
    +

    Response

    +
    +
    + +
    public struct Response
    + +
    +
    +

    The metadata associated with the response to a URL load request, independent of protocol and URL scheme.

    + +
    +
    +
    +
      +
    • +
      + + + + HeaderFields + +
      +
      +
      +
      +
      +
      +

      Undocumented

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      public typealias HeaderFields = NSDictionary
      + +
      +
      +
      +
      +
    • +
    • +
      + + + + allHeaderFields + +
      +
      +
      +
      +
      +
      +

      All HTTP header fields of the response.

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      public let allHeaderFields: HeaderFields?
      + +
      +
      +
      +
      +
    • +
    • +
      + + + + expectedContentLength + +
      +
      +
      +
      +
      +
      +

      The expected length of the response’s content.

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      public let expectedContentLength: Int64?
      + +
      +
      +
      +
      +
    • +
    • +
      + + + + data + +
      +
      +
      +
      +
      +
      +

      The data returned by the server.

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      public let data: Data?
      + +
      +
      +
      +
      +
    • +
    • +
      + + + + mimeType + +
      +
      +
      +
      +
      +
      +

      The MIME type of the response.

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      public let mimeType: String?
      + +
      +
      +
      +
      +
    • +
    • +
      + + + + statusCode + +
      +
      +
      +
      +
      +
      +

      The response’s HTTP status code.

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      public let statusCode: Int?
      + +
      +
      +
      +
      +
    • +
    • +
      + + + + suggestedFilename + +
      +
      +
      +
      +
      +
      +

      A suggested filename for the response data.

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      public let suggestedFilename: String?
      + +
      +
      +
      +
      +
    • +
    • +
      + + + + textEncodingName + +
      +
      +
      +
      +
      +
      +

      The name of the text encoding provided by the response’s originating source.

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      public let textEncodingName: String?
      + +
      +
      +
      +
      +
    • +
    • +
      + + + + url + +
      +
      +
      +
      +
      +
      +

      The URL for the response.

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      public let url: URL?
      + +
      +
      +
      +
      +
    • +
    • +
      + + + + success + +
      +
      +
      +
      +
      +
      +

      Returns default, success response where status code is 200.

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      static let success: Response
      + +
      +
      +
      +
      +
    • +
    +
    +
    +
    + +
    +
    + + + diff --git a/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Structs/TokenCredential.html b/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Structs/TokenCredential.html new file mode 100644 index 0000000..a4250f1 --- /dev/null +++ b/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Structs/TokenCredential.html @@ -0,0 +1,404 @@ + + + + TokenCredential Structure Reference + + + + + + + + + + + + + +
    +
    +

    Atom Docs (98% documented)

    +

    +

    + +
    +

    +
    +
    +
    + +
    +
    + +
    +
    +
    +

    TokenCredential

    +
    +
    + +
    public struct TokenCredential
    +
    extension TokenCredential: Decodable
    + +
    +
    +

    The TokenCredential type declares an object used by Atom in network requests that require bearer authentication.

    + +
    +
    +
    +
      +
    • +
      + + + + accessToken + +
      +
      +
      +
      +
      +
      +

      The access token as defined in OAuth 2.0 spec.

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      public let accessToken: String
      + +
      +
      +
      +
      +
    • +
    • +
      + + + + expiresIn + +
      +
      +
      +
      +
      +
      +

      The number of seconds access token is valid for.

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      public let expiresIn: Int
      + +
      +
      +
      +
      +
    • +
    • +
      + + + + expiresAt + +
      +
      +
      +
      +
      +
      +

      The expiration date of the access token.

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      public let expiresAt: Date
      + +
      +
      +
      +
      +
    • +
    • +
      + + + + refreshToken + +
      +
      +
      +
      +
      +
      +

      The refresh token as defined in OAuth 2.0 spec.

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      public let refreshToken: String
      + +
      +
      +
      +
      +
    • +
    • + +
      +
      +
      +
      +
      +

      Creates a TokenCredential instance given the provided parameter(s).

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      public init(accessToken: String, expiresIn: Int, expiresAt: Date, refreshToken: String)
      + +
      +
      +
      +

      Parameters

      + + + + + + + + + + + + + + + + + + + +
      + + accessToken + + +
      +

      The access token as defined in OAuth 2.0 spec.

      +
      +
      + + expiresIn + + +
      +

      The number of seconds access token is valid for.

      +
      +
      + + expiresAt + + +
      +

      The expiration date of the access token.

      +
      +
      + + refreshToken + + +
      +

      The refresh token as defined in OAuth 2.0 spec.

      +
      +
      +
      +
      +
      +
    • +
    • +
      + + + + init(from:) + +
      +
      +
      +
      +
      +
      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      public init(from decoder: Decoder) throws
      + +
      +
      +
      +
      +
    • +
    +
    +
    +
    + +
    +
    + + + diff --git a/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Structs/URLPath.html b/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Structs/URLPath.html new file mode 100644 index 0000000..3ba3036 --- /dev/null +++ b/Documentation/docsets/Atom.docset/Contents/Resources/Documents/Structs/URLPath.html @@ -0,0 +1,238 @@ + + + + URLPath Structure Reference + + + + + + + + + + + + + +
    +
    +

    Atom Docs (98% documented)

    +

    +

    + +
    +

    +
    +
    +
    + +
    +
    + +
    +
    +
    +

    URLPath

    +
    +
    + +
    public struct URLPath
    + +
    +
    +

    Model object representing URL path.

    + +
    +
    +
    +
      +
    • +
      + + + + init(_:) + +
      +
      +
      +
      +
      +
      +

      Creates a URLPath instance given the provided parameter(s).

      +
      +

      Throws

      +

      RequestableError.invalidURLPath when URL path validation fails.

      + +
      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      public init(_ path: String) throws
      + +
      +
      +
      +

      Parameters

      + + + + + + + +
      + + path + + +
      +

      The URL path as defined in RFC 3986.

      +
      +
      +
      +
      +
      +
    • +
    +
    +
    +
    + +
    +
    + + + diff --git a/Documentation/docsets/Atom.docset/Contents/Resources/Documents/css/jazzy.css b/Documentation/docsets/Atom.docset/Contents/Resources/Documents/css/jazzy.css index 103ee29..5cdffe9 100644 --- a/Documentation/docsets/Atom.docset/Contents/Resources/Documents/css/jazzy.css +++ b/Documentation/docsets/Atom.docset/Contents/Resources/Documents/css/jazzy.css @@ -56,9 +56,14 @@ p code, li code { padding: 2px 4px; border-radius: 4px; } +pre > code { + padding: 0; } + a { color: #0088cc; text-decoration: none; } + a code { + color: inherit; } ul { padding-left: 15px; } @@ -80,11 +85,11 @@ blockquote { header { font-size: 0.85em; - line-height: 26px; + line-height: 32px; background-color: #414141; position: fixed; width: 100%; - z-index: 1; } + z-index: 3; } header img { padding-right: 6px; vertical-align: -4px; @@ -100,12 +105,12 @@ header { #breadcrumbs { background-color: #f2f2f2; - height: 27px; + height: 21px; padding-top: 17px; position: fixed; width: 100%; - z-index: 1; - margin-top: 26px; } + z-index: 2; + margin-top: 32px; } #breadcrumbs #carat { height: 10px; margin: 0 5px; } @@ -169,6 +174,13 @@ header { display: block; padding-top: 70px; margin: -70px 0 0; } + .main-content .section-name p { + margin-bottom: inherit; + line-height: inherit; } + .main-content .section-name code { + background-color: inherit; + padding: inherit; + color: inherit; } .section { padding: 0 25px; } @@ -192,6 +204,7 @@ header { margin-left: 18px; } .task-group-section { + margin-top: 10px; padding-left: 6px; border-top: 1px solid #e2e2e2; } @@ -204,6 +217,23 @@ header { padding-top: 70px; margin: -70px 0 0; } +.section-name-container { + position: relative; + display: inline-block; } + .section-name-container .section-name-link { + position: absolute; + top: 0; + left: 0; + bottom: 0; + right: 0; + margin-bottom: 0; } + .section-name-container .section-name { + position: relative; + pointer-events: none; + z-index: 1; } + .section-name-container .section-name a { + pointer-events: auto; } + .item { padding-top: 8px; width: 100%; @@ -217,12 +247,14 @@ header { background-color: transparent; padding: 0; } .item .token, .item .direct-link { + display: inline-block; + text-indent: -20px; padding-left: 3px; - margin-left: 15px; + margin-left: 35px; font-size: 11.9px; transition: all 300ms; } .item .token-open { - margin-left: 0px; } + margin-left: 20px; } .item .discouraged { text-decoration: line-through; } .item .declaration-note { @@ -346,3 +378,46 @@ html.dash .content-wrapper { html.dash #footer { position: static; } + +form[role=search] { + float: right; } + form[role=search] input { + font: Helvetica, freesans, Arial, sans-serif; + margin-top: 6px; + font-size: 13px; + line-height: 20px; + padding: 0px 10px; + border: none; + border-radius: 1em; } + .loading form[role=search] input { + background: white url(../img/spinner.gif) center right 4px no-repeat; } + form[role=search] .tt-menu { + margin: 0; + min-width: 300px; + background: #fff; + color: #333; + border: 1px solid #e2e2e2; + z-index: 4; } + form[role=search] .tt-highlight { + font-weight: bold; } + form[role=search] .tt-suggestion { + font: Helvetica, freesans, Arial, sans-serif; + font-size: 14px; + padding: 0 8px; } + form[role=search] .tt-suggestion span { + display: table-cell; + white-space: nowrap; } + form[role=search] .tt-suggestion .doc-parent-name { + width: 100%; + text-align: right; + font-weight: normal; + font-size: 0.9em; + padding-left: 16px; } + form[role=search] .tt-suggestion:hover, + form[role=search] .tt-suggestion.tt-cursor { + cursor: pointer; + background-color: #4183c4; + color: #fff; } + form[role=search] .tt-suggestion:hover .doc-parent-name, + form[role=search] .tt-suggestion.tt-cursor .doc-parent-name { + color: #fff; } diff --git a/Documentation/docsets/Atom.docset/Contents/Resources/Documents/img/spinner.gif b/Documentation/docsets/Atom.docset/Contents/Resources/Documents/img/spinner.gif new file mode 100644 index 0000000000000000000000000000000000000000..e3038d0a42c55b1a07caecb7c7a6cbac982ec09d GIT binary patch literal 1849 zcmb8wZBSF$83*voz31lM+?V7Kkqwb`LI|3K#DupH#kDs91c6du6?SMB!bsTr6|ge_{#vAVj^!DyNA-l zJ&$jDFNv;BTZXX@Qk-7+S5ErF>mkOcZ@lQv>F1VyCEMe2Ud@f<|L%#&QJi${E`2lR zqKFaW2Y$aTRxUY&ae$IHsN;Z;rdZ%CjYLTv!tMi234j-ON=CnvK-1QU|MG$YErn{gHZ@0Q6&?xSyply?S$EVNXH;gp?S5kV2-)$ga^gw`(f4Mm_Y(`RbgRkQTHF2@zL}dCiLk$RoZIc{xZL z_J*d5)Kb;#oKCFyfL*NGSs?y;e(QKvPJe1#G)h5*6E(?L9$nt?UaQJfP^$GDL0PU; z?r}C|);JQ4HES3w5VMlY7x6xfJAzDKlHE~>x;D`Fa=WygYot{pfFehH69o9pK|72W zwC6?t^AnATIJa=kewn=ep?Nk(aZ*pZo}51`S=^)jPRb`~l^VE}08>P3OJtQlXx1K8 z8Q}_u=F*fS;=k=?(fIv#+%811NTx8^}rHwvH%LbYmpFl9p1A{Idh@2x$ zuVp7)VD9}Uc(*(C**!QOdS(6B)$5^Tq5p3q*7un&_Z-NKEiEYg$D{Uq&sa>wj|za5 zJ6M~p)z+E6*X${8j6Ci+sqZ}zxeCAo0gZmZuhl+)Q%1U$Br_`NXcA-3yBdYMha+{o z{?q0Q(kaR2n`M29{!pwpgX6+CPQEgIO%x*0#!TC=c-ZPSkLO>OcmQUao5%-3w)U`F zRz?uGCEKQDh!TQPDmyd;iDX$TkMIe)%61q51Y2b-ie4r00!csilXgKL$txqj|6D(# z@(#!nQ}3R1JGeB3B5Tuqdvyg@*!-bq`9`pmasNGvy9^*+cd1Y*g>HK#rl7i79QQAG zl4SL_wW@WY1d+F?j0gFInGhsRrqvV3SKl{oqW+;9!fu|u@J)h4WM!0Cu02l@p60b#5M9c{dKh=_eRw~yl zWT0gw8RePzf%i8X&twiB|LF0bI@CYE{x1PI;Ylr4RJzU#Zc0j!c07g&q7=_eSd(sH z9VKChd?}^52IKcMqolAWiQH;HSp1Ploa$t zQhg|2sK;%Eb!By`)j9G1w?>`Wt6IK3gB}~uoue(MlRiIoZ#d{pgJZ8b{^{HO8)@%= zX)og3`*D5v1g;*Lz8@Sm(Q|&}PUytlb@Q_dzKFOzKK!Z_&?GO4+JO-)iPH=fs{(`& zZ9{oNn~LUZaeN!>i9p*0N^sHye8nw4xSi!REaP@@^Jy66|)Y9_AFoLlrlkg(42 zVq2J??I(+1*BcSKsTyO7LCho{8tVQm1b>*GQ*H~Mn71Lhy`alw%;D@CU^0)5Ng{cHz@LS7QZ o8uGHYt7)tmZjae5ge5$b`e_;HIklOseoIbqeod19BU-8d00{dbSpWb4 literal 0 HcmV?d00001 diff --git a/Documentation/docsets/Atom.docset/Contents/Resources/Documents/index.html b/Documentation/docsets/Atom.docset/Contents/Resources/Documents/index.html index 2a7bcd8..4e30c42 100644 --- a/Documentation/docsets/Atom.docset/Contents/Resources/Documents/index.html +++ b/Documentation/docsets/Atom.docset/Contents/Resources/Documents/index.html @@ -8,12 +8,20 @@ + + +
    -

    Atom Docs (99% documented)

    +

    Atom Docs (98% documented)

    +

    +

    + +
    +

    @@ -33,40 +41,13 @@ Atom - - - - - - - - - @@ -76,6 +57,12 @@ + + @@ -85,10 +72,10 @@ Extensions +
    @@ -134,125 +162,140 @@

    Overview

    The lightweight & delightful networking library.

    -

    Atom is a wrapper library built around a subset of features offered by URLSession with added ability to decode data into models, handle access token refresh and authorization headers on behalf of the client, and more. It takes advantage of Swift features such as default implementation for protocols, generics and Decodable to make it extremely easy to integrate and use in an existing project. Atom offers support for any endpoint, a much stricter URL host and path validation, comprehensive documentation and an example application to eliminate any guesswork.

    +

    Atom is a wrapper library built around a subset of features offered by URLSession with added ability to decode data into models, handle access token refresh and authorization headers on behalf of the client, and more. It takes advantage of Swift features such as default implementation for protocols, generics and Decodable to make it extremely easy to integrate and use in an existing project. Atom offers support for any endpoint, a much stricter URL host and path validation, comprehensive documentation and an example application to eliminate any guesswork.

    Features

    • [x] Simple to setup, easy to use & efficient
    • [x] Supports any endpoint
    • +
    • [x] Supports Combine publishers
    • +
    • [x] Supports Multipath TCP configuration
    • [x] Handles object decoding from data returned by the service
    • [x] Handles token refresh
    • [x] Handles and applies authorization headers on behalf of the client
    • [x] Handles URL host validation
    • [x] Handles URL path validation
    • -
    • [x] Complete Documentation
    • +
    • [x] Complete Documentation

    Requirements

      -
    • iOS 11.0+
    • -
    • Xcode 11.0+
    • +
    • iOS 12.0+
    • +
    • Xcode 12.0+
    • Swift 5.0+

    Installation

    -

    Carthage

    - -

    Carthage is a decentralized dependency manager that builds your dependencies and provides you with binary frameworks. To integrate Atom into your Xcode project using Carthage, specify it in your Cartfile:

    -
    git "https://github.com/AlaskaAirlines/atom" ~> 1.0.0
    -
    - -

    For more information on getting started with Carthage, visit the repo.

    Swift Package Manager

    The Swift Package Manager is a tool for automating the distribution of Swift code and is integrated into the swift compiler.

    Once you have your Swift package set up, adding Atom as a dependency is as easy as adding it to the dependencies value of your Package.swift.

    + +

    If you are using Xcode, adding Atom as a dependency is even easier. First, select your application, then your application project. Once you see Swift Packages tab at the top of the Project Editor, click on it. Click + button and add the following URL:

    + +

    https://github.com/alaskaairlines/atom/

    + +

    At this point you can setup your project to either use a branch or tagged version of the package.

    Usage

    Getting started is easy. First, create an instance of Atom.

    -
    let atom = Atom()
    +
    let atom = Atom()
     

    In the above example, default configuration will be used. Default configuration will setup URLSessionto use ephemeral configuration as well as ensure that the data returned by the service is available on the main thread.

    -

    Any network request needs to conform and implement Requestable protocol. The Requestable protocol provides default implementation for all of its properties - except for the func baseURL() throws -> Atom.BaseURL. See documentation for more information.

    -
    extension Seatmap {
    -    enum Endpoint: Requestable {
    -        case refresh
    +

    Any endpoint needs to conform and implement Requestable protocol. The Requestable protocol provides default implementation for all of its properties - except for the func baseURL() throws -> BaseURL. See documentation for more information.

    +
    extension Seatmap {
    +    enum Endpoint: Requestable {
    +        case refresh
     
    -        func baseURL() throws -> Atom.BaseURL {
    -            try Atom.BaseURL(host: "api.alaskaair.net")
    -        }
    -    }
    -}
    +        func baseURL() throws -> Atom.BaseURL {
    +            try Atom.BaseURL(host: "api.alaskaair.net")
    +        }
    +    }
    +}
     

    Atom offers a handful of methods with support for fully decoded model objects, raw data, or status indicating success / failure of a request.

    -
    typealias Endpoint = Seatmap.Endpoint
    -
    -service.load(Endpoint.refresh).execute(expecting: Seatmap.self) { [weak self] result in
    -    switch result {
    -        case .failure(let error):
    -        // Handle error.
    -
    -        case .success(let seatmap):
    -        // Handle seatmap model.
    -    }
    -}
    +
    // Completion based.
    +
    +typealias Endpoint = Seatmap.Endpoint
    +
    +atom.enqueue(Endpoint.refresh).resume(expecting: Seatmap.self) { result in
    +    switch result {
    +        case .failure(let error):
    +        // Handle error.
    +
    +        case .success(let seatmap):
    +        // Handle seatmap model.
    +    }
    +}
    +
    +// Publisher based.
    +
    +atom
    +    .enqueue(Endpoint.refresh)
    +    .resume(expecting: Seatmap.self)
    +    .sink { completion in
    +        // Handle `AtomError`.
    +    } receiveValue: { seatmap in
    +        // Handle decoded `Seatmap` instance.
    +    }
    +    .store(in: &cancelables)
     
    -

    The above example demonstrates how to use execute() method to get a fully decoded Seatmap model object.

    +

    The above example demonstrates how to use resume(expecting:) function to get a fully decoded Seatmap model object.

    -

    For more information, please see documentation.

    +

    For more information, please see documentation.

    Authentication

    Atom can be configured to apply authorization headers on behalf of the client.

    -

    Atom supports Basic and Bearer authentication methods. When configured properly, Atom will perform automatic token refresh on behalf of the client if it determines that the access token being used has expired. Any in-flight calls will be enqueued and executed once a new token is obtained.

    +

    Atom supports Basic and Bearer authentication methods. When configured properly, Atom will perform automatic token refresh on behalf of the client if it determines that the access token being used has expired. Any in-flight calls will be enqueued and resumed once a new token is obtained.

    If the token refresh call fails, all enqueued network calls will be executed at once with completions set to AtomError failure.

    Basic

    You can configure Atom to apply Basic authorization header like this:

    -
    let atom: Atom = {
    -    let credential = Atom.BasicCredential(password: "password", username: "username")
    -    let basic = Atom.AuthenticationMethod.basic(credential)
    -    let configuration = Atom.ServiceConfiguration(authenticationMethod: basic)
    +
    let atom: Atom = {
    +    let credential = Atom.BasicCredential(password: "password", username: "username")
    +    let basic = Atom.AuthenticationMethod.basic(credential)
    +    let configuration = Atom.ServiceConfiguration(authenticationMethod: basic)
     
    -    return Atom(serviceConfiguration: configuration)
    -}()
    +    return Atom(serviceConfiguration: configuration)
    +}()
     
     

    An existing implementation can be extended by conforming and implementing BasicCredentialConvertible protocol. A hypothetical configuration can look something like this:

    -
    final class CredentialManager {
    -    private(set) var username = String()
    -    private(set) var password = String()
    +
    final class CredentialManager {
    +    private(set) var username = String()
    +    private(set) var password = String()
     
    -    static let shared = CredentialManager()
    -    private init() { }
    +    static let shared = CredentialManager()
    +    private init() { }
     
    -    func update(username aUsername: String) {
    -        username = aUsername
    -    }
    +    func update(username aUsername: String) {
    +        username = aUsername
    +    }
     
    -    func update(password aPassword: String) {
    -        password = aPassword
    -    }
    -}
    +    func update(password aPassword: String) {
    +        password = aPassword
    +    }
    +}
     
    -extension CredentialManager: BasicCredentialConvertible {
    -    var basicCredential: Atom.BasicCredential {
    -        .init(password: password, username: username)
    -    }
    -}
    +extension CredentialManager: BasicCredentialConvertible {
    +    var basicCredential: Atom.BasicCredential {
    +        .init(password: password, username: username)
    +    }
    +}
     
    -let atom: Atom = {
    -    let basic = Atom.AuthenticationMethod.basic(CredentialManager.shared.basicCredential)
    -    let configuration = Atom.ServiceConfiguration(authenticationMethod: basic)
    +let atom: Atom = {
    +    let basic = Atom.AuthenticationMethod.basic(CredentialManager.shared.basicCredential)
    +    let configuration = Atom.ServiceConfiguration(authenticationMethod: basic)
     
    -    return Atom(serviceConfiguration: configuration)
    -}()
    +    return Atom(serviceConfiguration: configuration)
    +}()
     
     
    @@ -260,26 +303,26 @@

    Basic

    Bearer

    You can configure Atom to apply Bearer authorization header. Here is an example:

    -
    class TokenManager: TokenCredentialWritable {
    -    var tokenCredential: Atom.TokenCredential {
    -        // Read values from the keychain.
    -        get { keychain.tokenCredential() }
    -
    -        // Save new value to the keychain.  
    -        set { keychain.save(tokenCredential: newValue)  }
    -    }
    -}
    -
    -let atom: Atom = {
    -    let endpoint = Atom.AuthorizationEndpoint(host: "api.alaskaair.net", path: "/oauth2")
    -    let clientCredential = Atom.ClientCredential(id: "client-id", secret: "client-secret")
    -    let tokenManager = TokenManager()
    -
    -    let bearer = Atom.AuthenticationMethod.bearer(endpoint, clientCredential, tokenManager)
    -    let configuration = Atom.ServiceConfiguration(authenticationMethod: bearer)
    -
    -    return Atom(serviceConfiguration: configuration)
    -}()
    +
    class TokenManager: TokenCredentialWritable {
    +    var tokenCredential: Atom.TokenCredential {
    +        // Read values from the keychain.
    +        get { keychain.tokenCredential() }
    +
    +        // Save new value to the keychain.  
    +        set { keychain.save(tokenCredential: newValue)  }
    +    }
    +}
    +
    +let atom: Atom = {
    +    let endpoint = Atom.AuthorizationEndpoint(host: "api.alaskaair.net", path: "/oauth2")
    +    let clientCredential = Atom.ClientCredential(id: "client-id", secret: "client-secret")
    +    let tokenManager = TokenManager()
    +
    +    let bearer = Atom.AuthenticationMethod.bearer(endpoint, clientCredential, tokenManager)
    +    let configuration = Atom.ServiceConfiguration(authenticationMethod: bearer)
    +
    +    return Atom(serviceConfiguration: configuration)
    +}()
     

    The setup is hopefully easy to understand. Atom requires a few pieces of information from the client:

    @@ -293,16 +336,16 @@

    Bearer

    Once configured, Atom will apply authorization header to a request as Authorization: Bearer ... header key-value.

    Please note, Atom will only decode token credential from a JSON objecting returned in this form:

    -
    {
    -    "access_token": "2YotnFZFEjr1zCsicMWpAA",
    -    "expires_in": 3600,
    -    "refresh_token": "tGzv3JOkF0XG5Qx2TlKWIA"
    -}
    -
    +
    {
    +    "access_token": "2YotnFZFEjr1zCsicMWpAA",
    +    "expires_in": 3600,
    +    "refresh_token": "tGzv3JOkF0XG5Qx2TlKWIA"
    +}
    +

    The above response is in accordance with RFC 6749, section 1.5.

    -

    For more information and Atom usage example, please see documentation and the provided Example application.

    +

    For more information and Atom usage example, please see documentation and the provided Example application.

    Communication

      @@ -319,8 +362,8 @@

      Authors

    diff --git a/Documentation/docsets/Atom.docset/Contents/Resources/Documents/js/jazzy.js b/Documentation/docsets/Atom.docset/Contents/Resources/Documents/js/jazzy.js index c31dc05..1e55d6e 100755 --- a/Documentation/docsets/Atom.docset/Contents/Resources/Documents/js/jazzy.js +++ b/Documentation/docsets/Atom.docset/Contents/Resources/Documents/js/jazzy.js @@ -23,7 +23,7 @@ function openCurrentItemIfClosed() { if (window.jazzy.docset) { return; } - var $link = $(`.token[href="${location.hash}"]`); + var $link = $(`a[name="${location.hash.substring(1)}"]`).nextAll('.token'); $content = itemLinkToContent($link); if ($content.is(':hidden')) { toggleItem($link, $content); @@ -57,3 +57,14 @@ $("a:not('.token')").on('click', function() { openCurrentItemIfClosed(); } }); + +// KaTeX rendering +if ("katex" in window) { + $($('.math').each( (_, element) => { + katex.render(element.textContent, element, { + displayMode: $(element).hasClass('m-block'), + throwOnError: false, + trust: true + }); + })) +} diff --git a/Documentation/docsets/Atom.docset/Contents/Resources/Documents/js/jazzy.search.js b/Documentation/docsets/Atom.docset/Contents/Resources/Documents/js/jazzy.search.js new file mode 100644 index 0000000..e3d1ab9 --- /dev/null +++ b/Documentation/docsets/Atom.docset/Contents/Resources/Documents/js/jazzy.search.js @@ -0,0 +1,70 @@ +$(function(){ + var $typeahead = $('[data-typeahead]'); + var $form = $typeahead.parents('form'); + var searchURL = $form.attr('action'); + + function displayTemplate(result) { + return result.name; + } + + function suggestionTemplate(result) { + var t = '
    '; + t += '' + result.name + ''; + if (result.parent_name) { + t += '' + result.parent_name + ''; + } + t += '
    '; + return t; + } + + $typeahead.one('focus', function() { + $form.addClass('loading'); + + $.getJSON(searchURL).then(function(searchData) { + const searchIndex = lunr(function() { + this.ref('url'); + this.field('name'); + this.field('abstract'); + for (const [url, doc] of Object.entries(searchData)) { + this.add({url: url, name: doc.name, abstract: doc.abstract}); + } + }); + + $typeahead.typeahead( + { + highlight: true, + minLength: 3, + autoselect: true + }, + { + limit: 10, + display: displayTemplate, + templates: { suggestion: suggestionTemplate }, + source: function(query, sync) { + const lcSearch = query.toLowerCase(); + const results = searchIndex.query(function(q) { + q.term(lcSearch, { boost: 100 }); + q.term(lcSearch, { + boost: 10, + wildcard: lunr.Query.wildcard.TRAILING + }); + }).map(function(result) { + var doc = searchData[result.ref]; + doc.url = result.ref; + return doc; + }); + sync(results); + } + } + ); + $form.removeClass('loading'); + $typeahead.trigger('focus'); + }); + }); + + var baseURL = searchURL.slice(0, -"search.json".length); + + $typeahead.on('typeahead:select', function(e, result) { + window.location = baseURL + result.url; + }); +}); diff --git a/Documentation/docsets/Atom.docset/Contents/Resources/Documents/js/jquery.min.js b/Documentation/docsets/Atom.docset/Contents/Resources/Documents/js/jquery.min.js index a1c07fd..b061403 100755 --- a/Documentation/docsets/Atom.docset/Contents/Resources/Documents/js/jquery.min.js +++ b/Documentation/docsets/Atom.docset/Contents/Resources/Documents/js/jquery.min.js @@ -1,2 +1,2 @@ -/*! jQuery v3.4.1 | (c) JS Foundation and other contributors | jquery.org/license */ -!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(C,e){"use strict";var t=[],E=C.document,r=Object.getPrototypeOf,s=t.slice,g=t.concat,u=t.push,i=t.indexOf,n={},o=n.toString,v=n.hasOwnProperty,a=v.toString,l=a.call(Object),y={},m=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType},x=function(e){return null!=e&&e===e.window},c={type:!0,src:!0,nonce:!0,noModule:!0};function b(e,t,n){var r,i,o=(n=n||E).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function w(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e}var f="3.4.1",k=function(e,t){return new k.fn.init(e,t)},p=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g;function d(e){var t=!!e&&"length"in e&&e.length,n=w(e);return!m(e)&&!x(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+M+")"+M+"*"),U=new RegExp(M+"|>"),X=new RegExp($),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+$),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+R+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\d$/i,K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\([\\da-f]{1,6}"+M+"?|("+M+")|.)","ig"),ne=function(e,t,n){var r="0x"+t-65536;return r!=r||n?t:r<0?String.fromCharCode(r+65536):String.fromCharCode(r>>10|55296,1023&r|56320)},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{H.apply(t=O.call(m.childNodes),m.childNodes),t[m.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&((e?e.ownerDocument||e:m)!==C&&T(e),e=e||C,E)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!A[t+" "]&&(!v||!v.test(t))&&(1!==p||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&U.test(t)){(s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=k),o=(l=h(t)).length;while(o--)l[o]="#"+s+" "+xe(l[o]);c=l.join(","),f=ee.test(t)&&ye(e.parentNode)||e}try{return H.apply(n,f.querySelectorAll(c)),n}catch(e){A(t,!0)}finally{s===k&&e.removeAttribute("id")}}}return g(t.replace(B,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[k]=!0,e}function ce(e){var t=C.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e.namespaceURI,n=(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:m;return r!==C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,E=!i(C),m!==C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),d.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment("")),!e.getElementsByTagName("*").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=k,!C.getElementsByName||!C.getElementsByName(k).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){a.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+k+"-]").length||v.push("~="),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+k+"+*").length||v.push(".#.+[+~]")}),ce(function(e){e.innerHTML="";var t=C.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",$)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=K.test(a.compareDocumentPosition),y=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},D=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)===(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e===C||e.ownerDocument===m&&y(m,e)?-1:t===C||t.ownerDocument===m&&y(m,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e===C?-1:t===C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]===m?-1:s[r]===m?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if((e.ownerDocument||e)!==C&&T(e),d.matchesSelector&&E&&!A[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){A(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=p[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&p(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function j(e,n,r){return m(n)?k.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?k.grep(e,function(e){return e===n!==r}):"string"!=typeof n?k.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(k.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||q,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:L.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof k?t[0]:t,k.merge(this,k.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),D.test(r[1])&&k.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(k):k.makeArray(e,this)}).prototype=k.fn,q=k(E);var H=/^(?:parents|prev(?:Until|All))/,O={children:!0,contents:!0,next:!0,prev:!0};function P(e,t){while((e=e[t])&&1!==e.nodeType);return e}k.fn.extend({has:function(e){var t=k(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,he=/^$|^module$|\/(?:java|ecma)script/i,ge={option:[1,""],thead:[1,"","
    "],col:[2,"","
    "],tr:[2,"","
    "],td:[3,"","
    "],_default:[0,"",""]};function ve(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&A(e,t)?k.merge([e],n):n}function ye(e,t){for(var n=0,r=e.length;nx",y.noCloneChecked=!!me.cloneNode(!0).lastChild.defaultValue;var Te=/^key/,Ce=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,Ee=/^([^.]*)(?:\.(.+)|)/;function ke(){return!0}function Se(){return!1}function Ne(e,t){return e===function(){try{return E.activeElement}catch(e){}}()==("focus"===t)}function Ae(e,t,n,r,i,o){var a,s;if("object"==typeof t){for(s in"string"!=typeof n&&(r=r||n,n=void 0),t)Ae(e,s,n,r,t[s],o);return e}if(null==r&&null==i?(i=n,r=n=void 0):null==i&&("string"==typeof n?(i=r,r=void 0):(i=r,r=n,n=void 0)),!1===i)i=Se;else if(!i)return e;return 1===o&&(a=i,(i=function(e){return k().off(e),a.apply(this,arguments)}).guid=a.guid||(a.guid=k.guid++)),e.each(function(){k.event.add(this,t,i,r,n)})}function De(e,i,o){o?(Q.set(e,i,!1),k.event.add(e,i,{namespace:!1,handler:function(e){var t,n,r=Q.get(this,i);if(1&e.isTrigger&&this[i]){if(r.length)(k.event.special[i]||{}).delegateType&&e.stopPropagation();else if(r=s.call(arguments),Q.set(this,i,r),t=o(this,i),this[i](),r!==(n=Q.get(this,i))||t?Q.set(this,i,!1):n={},r!==n)return e.stopImmediatePropagation(),e.preventDefault(),n.value}else r.length&&(Q.set(this,i,{value:k.event.trigger(k.extend(r[0],k.Event.prototype),r.slice(1),this)}),e.stopImmediatePropagation())}})):void 0===Q.get(e,i)&&k.event.add(e,i,ke)}k.event={global:{},add:function(t,e,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=Q.get(t);if(v){n.handler&&(n=(o=n).handler,i=o.selector),i&&k.find.matchesSelector(ie,i),n.guid||(n.guid=k.guid++),(u=v.events)||(u=v.events={}),(a=v.handle)||(a=v.handle=function(e){return"undefined"!=typeof k&&k.event.triggered!==e.type?k.event.dispatch.apply(t,arguments):void 0}),l=(e=(e||"").match(R)||[""]).length;while(l--)d=g=(s=Ee.exec(e[l])||[])[1],h=(s[2]||"").split(".").sort(),d&&(f=k.event.special[d]||{},d=(i?f.delegateType:f.bindType)||d,f=k.event.special[d]||{},c=k.extend({type:d,origType:g,data:r,handler:n,guid:n.guid,selector:i,needsContext:i&&k.expr.match.needsContext.test(i),namespace:h.join(".")},o),(p=u[d])||((p=u[d]=[]).delegateCount=0,f.setup&&!1!==f.setup.call(t,r,h,a)||t.addEventListener&&t.addEventListener(d,a)),f.add&&(f.add.call(t,c),c.handler.guid||(c.handler.guid=n.guid)),i?p.splice(p.delegateCount++,0,c):p.push(c),k.event.global[d]=!0)}},remove:function(e,t,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=Q.hasData(e)&&Q.get(e);if(v&&(u=v.events)){l=(t=(t||"").match(R)||[""]).length;while(l--)if(d=g=(s=Ee.exec(t[l])||[])[1],h=(s[2]||"").split(".").sort(),d){f=k.event.special[d]||{},p=u[d=(r?f.delegateType:f.bindType)||d]||[],s=s[2]&&new RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),a=o=p.length;while(o--)c=p[o],!i&&g!==c.origType||n&&n.guid!==c.guid||s&&!s.test(c.namespace)||r&&r!==c.selector&&("**"!==r||!c.selector)||(p.splice(o,1),c.selector&&p.delegateCount--,f.remove&&f.remove.call(e,c));a&&!p.length&&(f.teardown&&!1!==f.teardown.call(e,h,v.handle)||k.removeEvent(e,d,v.handle),delete u[d])}else for(d in u)k.event.remove(e,d+t[l],n,r,!0);k.isEmptyObject(u)&&Q.remove(e,"handle events")}},dispatch:function(e){var t,n,r,i,o,a,s=k.event.fix(e),u=new Array(arguments.length),l=(Q.get(this,"events")||{})[s.type]||[],c=k.event.special[s.type]||{};for(u[0]=s,t=1;t\x20\t\r\n\f]*)[^>]*)\/>/gi,qe=/\s*$/g;function Oe(e,t){return A(e,"table")&&A(11!==t.nodeType?t:t.firstChild,"tr")&&k(e).children("tbody")[0]||e}function Pe(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function Re(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Me(e,t){var n,r,i,o,a,s,u,l;if(1===t.nodeType){if(Q.hasData(e)&&(o=Q.access(e),a=Q.set(t,o),l=o.events))for(i in delete a.handle,a.events={},l)for(n=0,r=l[i].length;n")},clone:function(e,t,n){var r,i,o,a,s,u,l,c=e.cloneNode(!0),f=oe(e);if(!(y.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||k.isXMLDoc(e)))for(a=ve(c),r=0,i=(o=ve(e)).length;r").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),E.head.appendChild(r[0])},abort:function(){i&&i()}}});var Vt,Gt=[],Yt=/(=)\?(?=&|$)|\?\?/;k.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Gt.pop()||k.expando+"_"+kt++;return this[e]=!0,e}}),k.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Yt.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Yt.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Yt,"$1"+r):!1!==e.jsonp&&(e.url+=(St.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||k.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=C[r],C[r]=function(){o=arguments},n.always(function(){void 0===i?k(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,Gt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),"script"}),y.createHTMLDocument=((Vt=E.implementation.createHTMLDocument("").body).innerHTML="
    ",2===Vt.childNodes.length),k.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(y.createHTMLDocument?((r=(t=E.implementation.createHTMLDocument("")).createElement("base")).href=E.location.href,t.head.appendChild(r)):t=E),o=!n&&[],(i=D.exec(e))?[t.createElement(i[1])]:(i=we([e],t,o),o&&o.length&&k(o).remove(),k.merge([],i.childNodes)));var r,i,o},k.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(k.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},k.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){k.fn[t]=function(e){return this.on(t,e)}}),k.expr.pseudos.animated=function(t){return k.grep(k.timers,function(e){return t===e.elem}).length},k.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=k.css(e,"position"),c=k(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=k.css(e,"top"),u=k.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,k.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},k.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){k.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===k.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===k.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=k(e).offset()).top+=k.css(e,"borderTopWidth",!0),i.left+=k.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-k.css(r,"marginTop",!0),left:t.left-i.left-k.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===k.css(e,"position"))e=e.offsetParent;return e||ie})}}),k.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;k.fn[t]=function(e){return _(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),k.each(["top","left"],function(e,n){k.cssHooks[n]=ze(y.pixelPosition,function(e,t){if(t)return t=_e(e,n),$e.test(t)?k(e).position()[n]+"px":t})}),k.each({Height:"height",Width:"width"},function(a,s){k.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){k.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return _(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?k.css(e,t,i):k.style(e,t,n,i)},s,n?e:void 0,n)}})}),k.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){k.fn[n]=function(e,t){return 0+~]|"+M+")"+M+"*"),U=new RegExp(M+"|>"),X=new RegExp(F),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+F),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+R+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\d$/i,K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\[\\da-fA-F]{1,6}"+M+"?|\\\\([^\\r\\n\\f])","g"),ne=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{H.apply(t=O.call(p.childNodes),p.childNodes),t[p.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&(T(e),e=e||C,E)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!N[t+" "]&&(!v||!v.test(t))&&(1!==p||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&(U.test(t)||z.test(t))){(f=ee.test(t)&&ye(e.parentNode)||e)===e&&d.scope||((s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=S)),o=(l=h(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+xe(l[o]);c=l.join(",")}try{return H.apply(n,f.querySelectorAll(c)),n}catch(e){N(t,!0)}finally{s===S&&e.removeAttribute("id")}}}return g(t.replace($,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[S]=!0,e}function ce(e){var t=C.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e.namespaceURI,n=(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:p;return r!=C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,E=!i(C),p!=C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),d.scope=ce(function(e){return a.appendChild(e).appendChild(C.createElement("div")),"undefined"!=typeof e.querySelectorAll&&!e.querySelectorAll(":scope fieldset div").length}),d.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment("")),!e.getElementsByTagName("*").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=S,!C.getElementsByName||!C.getElementsByName(S).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){var t;a.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+S+"-]").length||v.push("~="),(t=C.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||v.push("\\["+M+"*name"+M+"*="+M+"*(?:''|\"\")"),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+S+"+*").length||v.push(".#.+[+~]"),e.querySelectorAll("\\\f"),v.push("[\\r\\n\\f]")}),ce(function(e){e.innerHTML="";var t=C.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",F)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=K.test(a.compareDocumentPosition),y=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},D=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e==C||e.ownerDocument==p&&y(p,e)?-1:t==C||t.ownerDocument==p&&y(p,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e==C?-1:t==C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]==p?-1:s[r]==p?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if(T(e),d.matchesSelector&&E&&!N[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){N(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=m[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&m(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function D(e,n,r){return m(n)?S.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?S.grep(e,function(e){return e===n!==r}):"string"!=typeof n?S.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(S.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||j,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:q.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof S?t[0]:t,S.merge(this,S.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),N.test(r[1])&&S.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(S):S.makeArray(e,this)}).prototype=S.fn,j=S(E);var L=/^(?:parents|prev(?:Until|All))/,H={children:!0,contents:!0,next:!0,prev:!0};function O(e,t){while((e=e[t])&&1!==e.nodeType);return e}S.fn.extend({has:function(e){var t=S(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,he=/^$|^module$|\/(?:java|ecma)script/i;ce=E.createDocumentFragment().appendChild(E.createElement("div")),(fe=E.createElement("input")).setAttribute("type","radio"),fe.setAttribute("checked","checked"),fe.setAttribute("name","t"),ce.appendChild(fe),y.checkClone=ce.cloneNode(!0).cloneNode(!0).lastChild.checked,ce.innerHTML="",y.noCloneChecked=!!ce.cloneNode(!0).lastChild.defaultValue,ce.innerHTML="",y.option=!!ce.lastChild;var ge={thead:[1,"","
    "],col:[2,"","
    "],tr:[2,"","
    "],td:[3,"","
    "],_default:[0,"",""]};function ve(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&A(e,t)?S.merge([e],n):n}function ye(e,t){for(var n=0,r=e.length;n",""]);var me=/<|&#?\w+;/;function xe(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d\s*$/g;function qe(e,t){return A(e,"table")&&A(11!==t.nodeType?t:t.firstChild,"tr")&&S(e).children("tbody")[0]||e}function Le(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function He(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Oe(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(Y.hasData(e)&&(s=Y.get(e).events))for(i in Y.remove(t,"handle events"),s)for(n=0,r=s[i].length;n").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),E.head.appendChild(r[0])},abort:function(){i&&i()}}});var Ut,Xt=[],Vt=/(=)\?(?=&|$)|\?\?/;S.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Xt.pop()||S.expando+"_"+Ct.guid++;return this[e]=!0,e}}),S.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Vt.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Vt.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Vt,"$1"+r):!1!==e.jsonp&&(e.url+=(Et.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||S.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=C[r],C[r]=function(){o=arguments},n.always(function(){void 0===i?S(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,Xt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),"script"}),y.createHTMLDocument=((Ut=E.implementation.createHTMLDocument("").body).innerHTML="
    ",2===Ut.childNodes.length),S.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(y.createHTMLDocument?((r=(t=E.implementation.createHTMLDocument("")).createElement("base")).href=E.location.href,t.head.appendChild(r)):t=E),o=!n&&[],(i=N.exec(e))?[t.createElement(i[1])]:(i=xe([e],t,o),o&&o.length&&S(o).remove(),S.merge([],i.childNodes)));var r,i,o},S.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(S.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},S.expr.pseudos.animated=function(t){return S.grep(S.timers,function(e){return t===e.elem}).length},S.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=S.css(e,"position"),c=S(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=S.css(e,"top"),u=S.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,S.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):("number"==typeof f.top&&(f.top+="px"),"number"==typeof f.left&&(f.left+="px"),c.css(f))}},S.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){S.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===S.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===S.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=S(e).offset()).top+=S.css(e,"borderTopWidth",!0),i.left+=S.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-S.css(r,"marginTop",!0),left:t.left-i.left-S.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===S.css(e,"position"))e=e.offsetParent;return e||re})}}),S.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;S.fn[t]=function(e){return $(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),S.each(["top","left"],function(e,n){S.cssHooks[n]=$e(y.pixelPosition,function(e,t){if(t)return t=Be(e,n),Me.test(t)?S(e).position()[n]+"px":t})}),S.each({Height:"height",Width:"width"},function(a,s){S.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){S.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return $(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?S.css(e,t,i):S.style(e,t,n,i)},s,n?e:void 0,n)}})}),S.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){S.fn[t]=function(e){return this.on(t,e)}}),S.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),S.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){S.fn[n]=function(e,t){return 00){var c=e.utils.clone(r)||{};c.position=[a,l],c.index=s.length,s.push(new e.Token(i.slice(a,o),c))}a=o+1}}return s},e.tokenizer.separator=/[\s\-]+/,e.Pipeline=function(){this._stack=[]},e.Pipeline.registeredFunctions=Object.create(null),e.Pipeline.registerFunction=function(t,r){r in this.registeredFunctions&&e.utils.warn("Overwriting existing registered function: "+r),t.label=r,e.Pipeline.registeredFunctions[t.label]=t},e.Pipeline.warnIfFunctionNotRegistered=function(t){var r=t.label&&t.label in this.registeredFunctions;r||e.utils.warn("Function is not registered with pipeline. This may cause problems when serialising the index.\n",t)},e.Pipeline.load=function(t){var r=new e.Pipeline;return t.forEach(function(t){var i=e.Pipeline.registeredFunctions[t];if(!i)throw new Error("Cannot load unregistered function: "+t);r.add(i)}),r},e.Pipeline.prototype.add=function(){var t=Array.prototype.slice.call(arguments);t.forEach(function(t){e.Pipeline.warnIfFunctionNotRegistered(t),this._stack.push(t)},this)},e.Pipeline.prototype.after=function(t,r){e.Pipeline.warnIfFunctionNotRegistered(r);var i=this._stack.indexOf(t);if(i==-1)throw new Error("Cannot find existingFn");i+=1,this._stack.splice(i,0,r)},e.Pipeline.prototype.before=function(t,r){e.Pipeline.warnIfFunctionNotRegistered(r);var i=this._stack.indexOf(t);if(i==-1)throw new Error("Cannot find existingFn");this._stack.splice(i,0,r)},e.Pipeline.prototype.remove=function(e){var t=this._stack.indexOf(e);t!=-1&&this._stack.splice(t,1)},e.Pipeline.prototype.run=function(e){for(var t=this._stack.length,r=0;r1&&(se&&(r=n),s!=e);)i=r-t,n=t+Math.floor(i/2),s=this.elements[2*n];return s==e?2*n:s>e?2*n:sa?l+=2:o==a&&(t+=r[u+1]*i[l+1],u+=2,l+=2);return t},e.Vector.prototype.similarity=function(e){return this.dot(e)/this.magnitude()||0},e.Vector.prototype.toArray=function(){for(var e=new Array(this.elements.length/2),t=1,r=0;t0){var o,a=s.str.charAt(0);a in s.node.edges?o=s.node.edges[a]:(o=new e.TokenSet,s.node.edges[a]=o),1==s.str.length&&(o["final"]=!0),n.push({node:o,editsRemaining:s.editsRemaining,str:s.str.slice(1)})}if(0!=s.editsRemaining){if("*"in s.node.edges)var u=s.node.edges["*"];else{var u=new e.TokenSet;s.node.edges["*"]=u}if(0==s.str.length&&(u["final"]=!0),n.push({node:u,editsRemaining:s.editsRemaining-1,str:s.str}),s.str.length>1&&n.push({node:s.node,editsRemaining:s.editsRemaining-1,str:s.str.slice(1)}),1==s.str.length&&(s.node["final"]=!0),s.str.length>=1){if("*"in s.node.edges)var l=s.node.edges["*"];else{var l=new e.TokenSet;s.node.edges["*"]=l}1==s.str.length&&(l["final"]=!0),n.push({node:l,editsRemaining:s.editsRemaining-1,str:s.str.slice(1)})}if(s.str.length>1){var c,h=s.str.charAt(0),d=s.str.charAt(1);d in s.node.edges?c=s.node.edges[d]:(c=new e.TokenSet,s.node.edges[d]=c),1==s.str.length&&(c["final"]=!0),n.push({node:c,editsRemaining:s.editsRemaining-1,str:h+s.str.slice(2)})}}}return i},e.TokenSet.fromString=function(t){for(var r=new e.TokenSet,i=r,n=0,s=t.length;n=e;t--){var r=this.uncheckedNodes[t],i=r.child.toString();i in this.minimizedNodes?r.parent.edges[r["char"]]=this.minimizedNodes[i]:(r.child._str=i,this.minimizedNodes[i]=r.child),this.uncheckedNodes.pop()}},e.Index=function(e){this.invertedIndex=e.invertedIndex,this.fieldVectors=e.fieldVectors,this.tokenSet=e.tokenSet,this.fields=e.fields,this.pipeline=e.pipeline},e.Index.prototype.search=function(t){return this.query(function(r){var i=new e.QueryParser(t,r);i.parse()})},e.Index.prototype.query=function(t){for(var r=new e.Query(this.fields),i=Object.create(null),n=Object.create(null),s=Object.create(null),o=Object.create(null),a=Object.create(null),u=0;u1?this._b=1:this._b=e},e.Builder.prototype.k1=function(e){this._k1=e},e.Builder.prototype.add=function(t,r){var i=t[this._ref],n=Object.keys(this._fields);this._documents[i]=r||{},this.documentCount+=1;for(var s=0;s=this.length)return e.QueryLexer.EOS;var t=this.str.charAt(this.pos);return this.pos+=1,t},e.QueryLexer.prototype.width=function(){return this.pos-this.start},e.QueryLexer.prototype.ignore=function(){this.start==this.pos&&(this.pos+=1),this.start=this.pos},e.QueryLexer.prototype.backup=function(){this.pos-=1},e.QueryLexer.prototype.acceptDigitRun=function(){var t,r;do t=this.next(),r=t.charCodeAt(0);while(r>47&&r<58);t!=e.QueryLexer.EOS&&this.backup()},e.QueryLexer.prototype.more=function(){return this.pos1&&(t.backup(),t.emit(e.QueryLexer.TERM)),t.ignore(),t.more())return e.QueryLexer.lexText},e.QueryLexer.lexEditDistance=function(t){return t.ignore(),t.acceptDigitRun(),t.emit(e.QueryLexer.EDIT_DISTANCE),e.QueryLexer.lexText},e.QueryLexer.lexBoost=function(t){return t.ignore(),t.acceptDigitRun(),t.emit(e.QueryLexer.BOOST),e.QueryLexer.lexText},e.QueryLexer.lexEOS=function(t){t.width()>0&&t.emit(e.QueryLexer.TERM)},e.QueryLexer.termSeparator=e.tokenizer.separator,e.QueryLexer.lexText=function(t){for(;;){var r=t.next();if(r==e.QueryLexer.EOS)return e.QueryLexer.lexEOS;if(92!=r.charCodeAt(0)){if(":"==r)return e.QueryLexer.lexField;if("~"==r)return t.backup(),t.width()>0&&t.emit(e.QueryLexer.TERM),e.QueryLexer.lexEditDistance;if("^"==r)return t.backup(),t.width()>0&&t.emit(e.QueryLexer.TERM),e.QueryLexer.lexBoost;if("+"==r&&1===t.width())return t.emit(e.QueryLexer.PRESENCE),e.QueryLexer.lexText;if("-"==r&&1===t.width())return t.emit(e.QueryLexer.PRESENCE),e.QueryLexer.lexText;if(r.match(e.QueryLexer.termSeparator))return e.QueryLexer.lexTerm}else t.escapeCharacter()}},e.QueryParser=function(t,r){this.lexer=new e.QueryLexer(t),this.query=r,this.currentClause={},this.lexemeIdx=0},e.QueryParser.prototype.parse=function(){this.lexer.run(),this.lexemes=this.lexer.lexemes;for(var t=e.QueryParser.parseClause;t;)t=t(this);return this.query},e.QueryParser.prototype.peekLexeme=function(){return this.lexemes[this.lexemeIdx]},e.QueryParser.prototype.consumeLexeme=function(){var e=this.peekLexeme();return this.lexemeIdx+=1,e},e.QueryParser.prototype.nextClause=function(){var e=this.currentClause;this.query.clause(e),this.currentClause={}},e.QueryParser.parseClause=function(t){var r=t.peekLexeme();if(void 0!=r)switch(r.type){case e.QueryLexer.PRESENCE:return e.QueryParser.parsePresence;case e.QueryLexer.FIELD:return e.QueryParser.parseField;case e.QueryLexer.TERM:return e.QueryParser.parseTerm;default:var i="expected either a field or a term, found "+r.type;throw r.str.length>=1&&(i+=" with value '"+r.str+"'"),new e.QueryParseError(i,r.start,r.end)}},e.QueryParser.parsePresence=function(t){var r=t.consumeLexeme();if(void 0!=r){switch(r.str){case"-":t.currentClause.presence=e.Query.presence.PROHIBITED;break;case"+":t.currentClause.presence=e.Query.presence.REQUIRED;break;default:var i="unrecognised presence operator'"+r.str+"'";throw new e.QueryParseError(i,r.start,r.end)}var n=t.peekLexeme();if(void 0==n){var i="expecting term or field, found nothing";throw new e.QueryParseError(i,r.start,r.end)}switch(n.type){case e.QueryLexer.FIELD:return e.QueryParser.parseField;case e.QueryLexer.TERM:return e.QueryParser.parseTerm;default:var i="expecting term or field, found '"+n.type+"'";throw new e.QueryParseError(i,n.start,n.end)}}},e.QueryParser.parseField=function(t){var r=t.consumeLexeme();if(void 0!=r){if(t.query.allFields.indexOf(r.str)==-1){var i=t.query.allFields.map(function(e){return"'"+e+"'"}).join(", "),n="unrecognised field '"+r.str+"', possible fields: "+i;throw new e.QueryParseError(n,r.start,r.end)}t.currentClause.fields=[r.str];var s=t.peekLexeme();if(void 0==s){var n="expecting term, found nothing";throw new e.QueryParseError(n,r.start,r.end)}switch(s.type){case e.QueryLexer.TERM:return e.QueryParser.parseTerm;default:var n="expecting term, found '"+s.type+"'";throw new e.QueryParseError(n,s.start,s.end)}}},e.QueryParser.parseTerm=function(t){var r=t.consumeLexeme();if(void 0!=r){t.currentClause.term=r.str.toLowerCase(),r.str.indexOf("*")!=-1&&(t.currentClause.usePipeline=!1);var i=t.peekLexeme();if(void 0==i)return void t.nextClause();switch(i.type){case e.QueryLexer.TERM:return t.nextClause(),e.QueryParser.parseTerm;case e.QueryLexer.FIELD:return t.nextClause(),e.QueryParser.parseField;case e.QueryLexer.EDIT_DISTANCE:return e.QueryParser.parseEditDistance;case e.QueryLexer.BOOST:return e.QueryParser.parseBoost;case e.QueryLexer.PRESENCE:return t.nextClause(),e.QueryParser.parsePresence;default:var n="Unexpected lexeme type '"+i.type+"'";throw new e.QueryParseError(n,i.start,i.end)}}},e.QueryParser.parseEditDistance=function(t){var r=t.consumeLexeme();if(void 0!=r){var i=parseInt(r.str,10);if(isNaN(i)){var n="edit distance must be numeric";throw new e.QueryParseError(n,r.start,r.end)}t.currentClause.editDistance=i;var s=t.peekLexeme();if(void 0==s)return void t.nextClause();switch(s.type){case e.QueryLexer.TERM:return t.nextClause(),e.QueryParser.parseTerm;case e.QueryLexer.FIELD:return t.nextClause(),e.QueryParser.parseField;case e.QueryLexer.EDIT_DISTANCE:return e.QueryParser.parseEditDistance;case e.QueryLexer.BOOST:return e.QueryParser.parseBoost;case e.QueryLexer.PRESENCE:return t.nextClause(),e.QueryParser.parsePresence;default:var n="Unexpected lexeme type '"+s.type+"'";throw new e.QueryParseError(n,s.start,s.end)}}},e.QueryParser.parseBoost=function(t){var r=t.consumeLexeme();if(void 0!=r){var i=parseInt(r.str,10);if(isNaN(i)){var n="boost must be numeric";throw new e.QueryParseError(n,r.start,r.end)}t.currentClause.boost=i;var s=t.peekLexeme();if(void 0==s)return void t.nextClause();switch(s.type){case e.QueryLexer.TERM:return t.nextClause(),e.QueryParser.parseTerm;case e.QueryLexer.FIELD:return t.nextClause(),e.QueryParser.parseField;case e.QueryLexer.EDIT_DISTANCE:return e.QueryParser.parseEditDistance;case e.QueryLexer.BOOST:return e.QueryParser.parseBoost;case e.QueryLexer.PRESENCE:return t.nextClause(),e.QueryParser.parsePresence;default:var n="Unexpected lexeme type '"+s.type+"'";throw new e.QueryParseError(n,s.start,s.end)}}},function(e,t){"function"==typeof define&&define.amd?define(t):"object"==typeof exports?module.exports=t():e.lunr=t()}(this,function(){return e})}(); diff --git a/Documentation/docsets/Atom.docset/Contents/Resources/Documents/js/typeahead.jquery.js b/Documentation/docsets/Atom.docset/Contents/Resources/Documents/js/typeahead.jquery.js new file mode 100644 index 0000000..3a2d2ab --- /dev/null +++ b/Documentation/docsets/Atom.docset/Contents/Resources/Documents/js/typeahead.jquery.js @@ -0,0 +1,1694 @@ +/*! + * typeahead.js 1.3.1 + * https://github.com/corejavascript/typeahead.js + * Copyright 2013-2020 Twitter, Inc. and other contributors; Licensed MIT + */ + + +(function(root, factory) { + if (typeof define === "function" && define.amd) { + define([ "jquery" ], function(a0) { + return factory(a0); + }); + } else if (typeof module === "object" && module.exports) { + module.exports = factory(require("jquery")); + } else { + factory(root["jQuery"]); + } +})(this, function($) { + var _ = function() { + "use strict"; + return { + isMsie: function() { + return /(msie|trident)/i.test(navigator.userAgent) ? navigator.userAgent.match(/(msie |rv:)(\d+(.\d+)?)/i)[2] : false; + }, + isBlankString: function(str) { + return !str || /^\s*$/.test(str); + }, + escapeRegExChars: function(str) { + return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"); + }, + isString: function(obj) { + return typeof obj === "string"; + }, + isNumber: function(obj) { + return typeof obj === "number"; + }, + isArray: $.isArray, + isFunction: $.isFunction, + isObject: $.isPlainObject, + isUndefined: function(obj) { + return typeof obj === "undefined"; + }, + isElement: function(obj) { + return !!(obj && obj.nodeType === 1); + }, + isJQuery: function(obj) { + return obj instanceof $; + }, + toStr: function toStr(s) { + return _.isUndefined(s) || s === null ? "" : s + ""; + }, + bind: $.proxy, + each: function(collection, cb) { + $.each(collection, reverseArgs); + function reverseArgs(index, value) { + return cb(value, index); + } + }, + map: $.map, + filter: $.grep, + every: function(obj, test) { + var result = true; + if (!obj) { + return result; + } + $.each(obj, function(key, val) { + if (!(result = test.call(null, val, key, obj))) { + return false; + } + }); + return !!result; + }, + some: function(obj, test) { + var result = false; + if (!obj) { + return result; + } + $.each(obj, function(key, val) { + if (result = test.call(null, val, key, obj)) { + return false; + } + }); + return !!result; + }, + mixin: $.extend, + identity: function(x) { + return x; + }, + clone: function(obj) { + return $.extend(true, {}, obj); + }, + getIdGenerator: function() { + var counter = 0; + return function() { + return counter++; + }; + }, + templatify: function templatify(obj) { + return $.isFunction(obj) ? obj : template; + function template() { + return String(obj); + } + }, + defer: function(fn) { + setTimeout(fn, 0); + }, + debounce: function(func, wait, immediate) { + var timeout, result; + return function() { + var context = this, args = arguments, later, callNow; + later = function() { + timeout = null; + if (!immediate) { + result = func.apply(context, args); + } + }; + callNow = immediate && !timeout; + clearTimeout(timeout); + timeout = setTimeout(later, wait); + if (callNow) { + result = func.apply(context, args); + } + return result; + }; + }, + throttle: function(func, wait) { + var context, args, timeout, result, previous, later; + previous = 0; + later = function() { + previous = new Date(); + timeout = null; + result = func.apply(context, args); + }; + return function() { + var now = new Date(), remaining = wait - (now - previous); + context = this; + args = arguments; + if (remaining <= 0) { + clearTimeout(timeout); + timeout = null; + previous = now; + result = func.apply(context, args); + } else if (!timeout) { + timeout = setTimeout(later, remaining); + } + return result; + }; + }, + stringify: function(val) { + return _.isString(val) ? val : JSON.stringify(val); + }, + guid: function() { + function _p8(s) { + var p = (Math.random().toString(16) + "000000000").substr(2, 8); + return s ? "-" + p.substr(0, 4) + "-" + p.substr(4, 4) : p; + } + return "tt-" + _p8() + _p8(true) + _p8(true) + _p8(); + }, + noop: function() {} + }; + }(); + var WWW = function() { + "use strict"; + var defaultClassNames = { + wrapper: "twitter-typeahead", + input: "tt-input", + hint: "tt-hint", + menu: "tt-menu", + dataset: "tt-dataset", + suggestion: "tt-suggestion", + selectable: "tt-selectable", + empty: "tt-empty", + open: "tt-open", + cursor: "tt-cursor", + highlight: "tt-highlight" + }; + return build; + function build(o) { + var www, classes; + classes = _.mixin({}, defaultClassNames, o); + www = { + css: buildCss(), + classes: classes, + html: buildHtml(classes), + selectors: buildSelectors(classes) + }; + return { + css: www.css, + html: www.html, + classes: www.classes, + selectors: www.selectors, + mixin: function(o) { + _.mixin(o, www); + } + }; + } + function buildHtml(c) { + return { + wrapper: '', + menu: '
    ' + }; + } + function buildSelectors(classes) { + var selectors = {}; + _.each(classes, function(v, k) { + selectors[k] = "." + v; + }); + return selectors; + } + function buildCss() { + var css = { + wrapper: { + position: "relative", + display: "inline-block" + }, + hint: { + position: "absolute", + top: "0", + left: "0", + borderColor: "transparent", + boxShadow: "none", + opacity: "1" + }, + input: { + position: "relative", + verticalAlign: "top", + backgroundColor: "transparent" + }, + inputWithNoHint: { + position: "relative", + verticalAlign: "top" + }, + menu: { + position: "absolute", + top: "100%", + left: "0", + zIndex: "100", + display: "none" + }, + ltr: { + left: "0", + right: "auto" + }, + rtl: { + left: "auto", + right: " 0" + } + }; + if (_.isMsie()) { + _.mixin(css.input, { + backgroundImage: "url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)" + }); + } + return css; + } + }(); + var EventBus = function() { + "use strict"; + var namespace, deprecationMap; + namespace = "typeahead:"; + deprecationMap = { + render: "rendered", + cursorchange: "cursorchanged", + select: "selected", + autocomplete: "autocompleted" + }; + function EventBus(o) { + if (!o || !o.el) { + $.error("EventBus initialized without el"); + } + this.$el = $(o.el); + } + _.mixin(EventBus.prototype, { + _trigger: function(type, args) { + var $e = $.Event(namespace + type); + this.$el.trigger.call(this.$el, $e, args || []); + return $e; + }, + before: function(type) { + var args, $e; + args = [].slice.call(arguments, 1); + $e = this._trigger("before" + type, args); + return $e.isDefaultPrevented(); + }, + trigger: function(type) { + var deprecatedType; + this._trigger(type, [].slice.call(arguments, 1)); + if (deprecatedType = deprecationMap[type]) { + this._trigger(deprecatedType, [].slice.call(arguments, 1)); + } + } + }); + return EventBus; + }(); + var EventEmitter = function() { + "use strict"; + var splitter = /\s+/, nextTick = getNextTick(); + return { + onSync: onSync, + onAsync: onAsync, + off: off, + trigger: trigger + }; + function on(method, types, cb, context) { + var type; + if (!cb) { + return this; + } + types = types.split(splitter); + cb = context ? bindContext(cb, context) : cb; + this._callbacks = this._callbacks || {}; + while (type = types.shift()) { + this._callbacks[type] = this._callbacks[type] || { + sync: [], + async: [] + }; + this._callbacks[type][method].push(cb); + } + return this; + } + function onAsync(types, cb, context) { + return on.call(this, "async", types, cb, context); + } + function onSync(types, cb, context) { + return on.call(this, "sync", types, cb, context); + } + function off(types) { + var type; + if (!this._callbacks) { + return this; + } + types = types.split(splitter); + while (type = types.shift()) { + delete this._callbacks[type]; + } + return this; + } + function trigger(types) { + var type, callbacks, args, syncFlush, asyncFlush; + if (!this._callbacks) { + return this; + } + types = types.split(splitter); + args = [].slice.call(arguments, 1); + while ((type = types.shift()) && (callbacks = this._callbacks[type])) { + syncFlush = getFlush(callbacks.sync, this, [ type ].concat(args)); + asyncFlush = getFlush(callbacks.async, this, [ type ].concat(args)); + syncFlush() && nextTick(asyncFlush); + } + return this; + } + function getFlush(callbacks, context, args) { + return flush; + function flush() { + var cancelled; + for (var i = 0, len = callbacks.length; !cancelled && i < len; i += 1) { + cancelled = callbacks[i].apply(context, args) === false; + } + return !cancelled; + } + } + function getNextTick() { + var nextTickFn; + if (window.setImmediate) { + nextTickFn = function nextTickSetImmediate(fn) { + setImmediate(function() { + fn(); + }); + }; + } else { + nextTickFn = function nextTickSetTimeout(fn) { + setTimeout(function() { + fn(); + }, 0); + }; + } + return nextTickFn; + } + function bindContext(fn, context) { + return fn.bind ? fn.bind(context) : function() { + fn.apply(context, [].slice.call(arguments, 0)); + }; + } + }(); + var highlight = function(doc) { + "use strict"; + var defaults = { + node: null, + pattern: null, + tagName: "strong", + className: null, + wordsOnly: false, + caseSensitive: false, + diacriticInsensitive: false + }; + var accented = { + A: "[AaªÀ-Åà-åĀ-ąǍǎȀ-ȃȦȧᴬᵃḀḁẚẠ-ảₐ℀℁℻⒜Ⓐⓐ㍱-㍴㎀-㎄㎈㎉㎩-㎯㏂㏊㏟㏿Aa]", + B: "[BbᴮᵇḂ-ḇℬ⒝Ⓑⓑ㍴㎅-㎇㏃㏈㏔㏝Bb]", + C: "[CcÇçĆ-čᶜ℀ℂ℃℅℆ℭⅭⅽ⒞Ⓒⓒ㍶㎈㎉㎝㎠㎤㏄-㏇Cc]", + D: "[DdĎďDŽ-džDZ-dzᴰᵈḊ-ḓⅅⅆⅮⅾ⒟Ⓓⓓ㋏㍲㍷-㍹㎗㎭-㎯㏅㏈Dd]", + E: "[EeÈ-Ëè-ëĒ-ěȄ-ȇȨȩᴱᵉḘ-ḛẸ-ẽₑ℡ℯℰⅇ⒠Ⓔⓔ㉐㋍㋎Ee]", + F: "[FfᶠḞḟ℉ℱ℻⒡Ⓕⓕ㎊-㎌㎙ff-fflFf]", + G: "[GgĜ-ģǦǧǴǵᴳᵍḠḡℊ⒢Ⓖⓖ㋌㋍㎇㎍-㎏㎓㎬㏆㏉㏒㏿Gg]", + H: "[HhĤĥȞȟʰᴴḢ-ḫẖℋ-ℎ⒣Ⓗⓗ㋌㍱㎐-㎔㏊㏋㏗Hh]", + I: "[IiÌ-Ïì-ïĨ-İIJijǏǐȈ-ȋᴵᵢḬḭỈ-ịⁱℐℑℹⅈⅠ-ⅣⅥ-ⅨⅪⅫⅰ-ⅳⅵ-ⅸⅺⅻ⒤Ⓘⓘ㍺㏌㏕fiffiIi]", + J: "[JjIJ-ĵLJ-njǰʲᴶⅉ⒥ⒿⓙⱼJj]", + K: "[KkĶķǨǩᴷᵏḰ-ḵK⒦Ⓚⓚ㎄㎅㎉㎏㎑㎘㎞㎢㎦㎪㎸㎾㏀㏆㏍-㏏Kk]", + L: "[LlĹ-ŀLJ-ljˡᴸḶḷḺ-ḽℒℓ℡Ⅼⅼ⒧Ⓛⓛ㋏㎈㎉㏐-㏓㏕㏖㏿flfflLl]", + M: "[MmᴹᵐḾ-ṃ℠™ℳⅯⅿ⒨Ⓜⓜ㍷-㍹㎃㎆㎎㎒㎖㎙-㎨㎫㎳㎷㎹㎽㎿㏁㏂㏎㏐㏔-㏖㏘㏙㏞㏟Mm]", + N: "[NnÑñŃ-ʼnNJ-njǸǹᴺṄ-ṋⁿℕ№⒩Ⓝⓝ㎁㎋㎚㎱㎵㎻㏌㏑Nn]", + O: "[OoºÒ-Öò-öŌ-őƠơǑǒǪǫȌ-ȏȮȯᴼᵒỌ-ỏₒ℅№ℴ⒪Ⓞⓞ㍵㏇㏒㏖Oo]", + P: "[PpᴾᵖṔ-ṗℙ⒫Ⓟⓟ㉐㍱㍶㎀㎊㎩-㎬㎰㎴㎺㏋㏗-㏚Pp]", + Q: "[Qqℚ⒬Ⓠⓠ㏃Qq]", + R: "[RrŔ-řȐ-ȓʳᴿᵣṘ-ṛṞṟ₨ℛ-ℝ⒭Ⓡⓡ㋍㍴㎭-㎯㏚㏛Rr]", + S: "[SsŚ-šſȘșˢṠ-ṣ₨℁℠⒮Ⓢⓢ㎧㎨㎮-㎳㏛㏜stSs]", + T: "[TtŢ-ťȚțᵀᵗṪ-ṱẗ℡™⒯Ⓣⓣ㉐㋏㎔㏏ſtstTt]", + U: "[UuÙ-Üù-üŨ-ųƯưǓǔȔ-ȗᵁᵘᵤṲ-ṷỤ-ủ℆⒰Ⓤⓤ㍳㍺Uu]", + V: "[VvᵛᵥṼ-ṿⅣ-Ⅷⅳ-ⅷ⒱Ⓥⓥⱽ㋎㍵㎴-㎹㏜㏞Vv]", + W: "[WwŴŵʷᵂẀ-ẉẘ⒲Ⓦⓦ㎺-㎿㏝Ww]", + X: "[XxˣẊ-ẍₓ℻Ⅸ-Ⅻⅸ-ⅻ⒳Ⓧⓧ㏓Xx]", + Y: "[YyÝýÿŶ-ŸȲȳʸẎẏẙỲ-ỹ⒴Ⓨⓨ㏉Yy]", + Z: "[ZzŹ-žDZ-dzᶻẐ-ẕℤℨ⒵Ⓩⓩ㎐-㎔Zz]" + }; + return function hightlight(o) { + var regex; + o = _.mixin({}, defaults, o); + if (!o.node || !o.pattern) { + return; + } + o.pattern = _.isArray(o.pattern) ? o.pattern : [ o.pattern ]; + regex = getRegex(o.pattern, o.caseSensitive, o.wordsOnly, o.diacriticInsensitive); + traverse(o.node, hightlightTextNode); + function hightlightTextNode(textNode) { + var match, patternNode, wrapperNode; + if (match = regex.exec(textNode.data)) { + wrapperNode = doc.createElement(o.tagName); + o.className && (wrapperNode.className = o.className); + patternNode = textNode.splitText(match.index); + patternNode.splitText(match[0].length); + wrapperNode.appendChild(patternNode.cloneNode(true)); + textNode.parentNode.replaceChild(wrapperNode, patternNode); + } + return !!match; + } + function traverse(el, hightlightTextNode) { + var childNode, TEXT_NODE_TYPE = 3; + for (var i = 0; i < el.childNodes.length; i++) { + childNode = el.childNodes[i]; + if (childNode.nodeType === TEXT_NODE_TYPE) { + i += hightlightTextNode(childNode) ? 1 : 0; + } else { + traverse(childNode, hightlightTextNode); + } + } + } + }; + function accent_replacer(chr) { + return accented[chr.toUpperCase()] || chr; + } + function getRegex(patterns, caseSensitive, wordsOnly, diacriticInsensitive) { + var escapedPatterns = [], regexStr; + for (var i = 0, len = patterns.length; i < len; i++) { + var escapedWord = _.escapeRegExChars(patterns[i]); + if (diacriticInsensitive) { + escapedWord = escapedWord.replace(/\S/g, accent_replacer); + } + escapedPatterns.push(escapedWord); + } + regexStr = wordsOnly ? "\\b(" + escapedPatterns.join("|") + ")\\b" : "(" + escapedPatterns.join("|") + ")"; + return caseSensitive ? new RegExp(regexStr) : new RegExp(regexStr, "i"); + } + }(window.document); + var Input = function() { + "use strict"; + var specialKeyCodeMap; + specialKeyCodeMap = { + 9: "tab", + 27: "esc", + 37: "left", + 39: "right", + 13: "enter", + 38: "up", + 40: "down" + }; + function Input(o, www) { + var id; + o = o || {}; + if (!o.input) { + $.error("input is missing"); + } + www.mixin(this); + this.$hint = $(o.hint); + this.$input = $(o.input); + this.$menu = $(o.menu); + id = this.$input.attr("id") || _.guid(); + this.$menu.attr("id", id + "_listbox"); + this.$hint.attr({ + "aria-hidden": true + }); + this.$input.attr({ + "aria-owns": id + "_listbox", + role: "combobox", + "aria-autocomplete": "list", + "aria-expanded": false + }); + this.query = this.$input.val(); + this.queryWhenFocused = this.hasFocus() ? this.query : null; + this.$overflowHelper = buildOverflowHelper(this.$input); + this._checkLanguageDirection(); + if (this.$hint.length === 0) { + this.setHint = this.getHint = this.clearHint = this.clearHintIfInvalid = _.noop; + } + this.onSync("cursorchange", this._updateDescendent); + } + Input.normalizeQuery = function(str) { + return _.toStr(str).replace(/^\s*/g, "").replace(/\s{2,}/g, " "); + }; + _.mixin(Input.prototype, EventEmitter, { + _onBlur: function onBlur() { + this.resetInputValue(); + this.trigger("blurred"); + }, + _onFocus: function onFocus() { + this.queryWhenFocused = this.query; + this.trigger("focused"); + }, + _onKeydown: function onKeydown($e) { + var keyName = specialKeyCodeMap[$e.which || $e.keyCode]; + this._managePreventDefault(keyName, $e); + if (keyName && this._shouldTrigger(keyName, $e)) { + this.trigger(keyName + "Keyed", $e); + } + }, + _onInput: function onInput() { + this._setQuery(this.getInputValue()); + this.clearHintIfInvalid(); + this._checkLanguageDirection(); + }, + _managePreventDefault: function managePreventDefault(keyName, $e) { + var preventDefault; + switch (keyName) { + case "up": + case "down": + preventDefault = !withModifier($e); + break; + + default: + preventDefault = false; + } + preventDefault && $e.preventDefault(); + }, + _shouldTrigger: function shouldTrigger(keyName, $e) { + var trigger; + switch (keyName) { + case "tab": + trigger = !withModifier($e); + break; + + default: + trigger = true; + } + return trigger; + }, + _checkLanguageDirection: function checkLanguageDirection() { + var dir = (this.$input.css("direction") || "ltr").toLowerCase(); + if (this.dir !== dir) { + this.dir = dir; + this.$hint.attr("dir", dir); + this.trigger("langDirChanged", dir); + } + }, + _setQuery: function setQuery(val, silent) { + var areEquivalent, hasDifferentWhitespace; + areEquivalent = areQueriesEquivalent(val, this.query); + hasDifferentWhitespace = areEquivalent ? this.query.length !== val.length : false; + this.query = val; + if (!silent && !areEquivalent) { + this.trigger("queryChanged", this.query); + } else if (!silent && hasDifferentWhitespace) { + this.trigger("whitespaceChanged", this.query); + } + }, + _updateDescendent: function updateDescendent(event, id) { + this.$input.attr("aria-activedescendant", id); + }, + bind: function() { + var that = this, onBlur, onFocus, onKeydown, onInput; + onBlur = _.bind(this._onBlur, this); + onFocus = _.bind(this._onFocus, this); + onKeydown = _.bind(this._onKeydown, this); + onInput = _.bind(this._onInput, this); + this.$input.on("blur.tt", onBlur).on("focus.tt", onFocus).on("keydown.tt", onKeydown); + if (!_.isMsie() || _.isMsie() > 9) { + this.$input.on("input.tt", onInput); + } else { + this.$input.on("keydown.tt keypress.tt cut.tt paste.tt", function($e) { + if (specialKeyCodeMap[$e.which || $e.keyCode]) { + return; + } + _.defer(_.bind(that._onInput, that, $e)); + }); + } + return this; + }, + focus: function focus() { + this.$input.focus(); + }, + blur: function blur() { + this.$input.blur(); + }, + getLangDir: function getLangDir() { + return this.dir; + }, + getQuery: function getQuery() { + return this.query || ""; + }, + setQuery: function setQuery(val, silent) { + this.setInputValue(val); + this._setQuery(val, silent); + }, + hasQueryChangedSinceLastFocus: function hasQueryChangedSinceLastFocus() { + return this.query !== this.queryWhenFocused; + }, + getInputValue: function getInputValue() { + return this.$input.val(); + }, + setInputValue: function setInputValue(value) { + this.$input.val(value); + this.clearHintIfInvalid(); + this._checkLanguageDirection(); + }, + resetInputValue: function resetInputValue() { + this.setInputValue(this.query); + }, + getHint: function getHint() { + return this.$hint.val(); + }, + setHint: function setHint(value) { + this.$hint.val(value); + }, + clearHint: function clearHint() { + this.setHint(""); + }, + clearHintIfInvalid: function clearHintIfInvalid() { + var val, hint, valIsPrefixOfHint, isValid; + val = this.getInputValue(); + hint = this.getHint(); + valIsPrefixOfHint = val !== hint && hint.indexOf(val) === 0; + isValid = val !== "" && valIsPrefixOfHint && !this.hasOverflow(); + !isValid && this.clearHint(); + }, + hasFocus: function hasFocus() { + return this.$input.is(":focus"); + }, + hasOverflow: function hasOverflow() { + var constraint = this.$input.width() - 2; + this.$overflowHelper.text(this.getInputValue()); + return this.$overflowHelper.width() >= constraint; + }, + isCursorAtEnd: function() { + var valueLength, selectionStart, range; + valueLength = this.$input.val().length; + selectionStart = this.$input[0].selectionStart; + if (_.isNumber(selectionStart)) { + return selectionStart === valueLength; + } else if (document.selection) { + range = document.selection.createRange(); + range.moveStart("character", -valueLength); + return valueLength === range.text.length; + } + return true; + }, + destroy: function destroy() { + this.$hint.off(".tt"); + this.$input.off(".tt"); + this.$overflowHelper.remove(); + this.$hint = this.$input = this.$overflowHelper = $("
    "); + }, + setAriaExpanded: function setAriaExpanded(value) { + this.$input.attr("aria-expanded", value); + } + }); + return Input; + function buildOverflowHelper($input) { + return $('').css({ + position: "absolute", + visibility: "hidden", + whiteSpace: "pre", + fontFamily: $input.css("font-family"), + fontSize: $input.css("font-size"), + fontStyle: $input.css("font-style"), + fontVariant: $input.css("font-variant"), + fontWeight: $input.css("font-weight"), + wordSpacing: $input.css("word-spacing"), + letterSpacing: $input.css("letter-spacing"), + textIndent: $input.css("text-indent"), + textRendering: $input.css("text-rendering"), + textTransform: $input.css("text-transform") + }).insertAfter($input); + } + function areQueriesEquivalent(a, b) { + return Input.normalizeQuery(a) === Input.normalizeQuery(b); + } + function withModifier($e) { + return $e.altKey || $e.ctrlKey || $e.metaKey || $e.shiftKey; + } + }(); + var Dataset = function() { + "use strict"; + var keys, nameGenerator; + keys = { + dataset: "tt-selectable-dataset", + val: "tt-selectable-display", + obj: "tt-selectable-object" + }; + nameGenerator = _.getIdGenerator(); + function Dataset(o, www) { + o = o || {}; + o.templates = o.templates || {}; + o.templates.notFound = o.templates.notFound || o.templates.empty; + if (!o.source) { + $.error("missing source"); + } + if (!o.node) { + $.error("missing node"); + } + if (o.name && !isValidName(o.name)) { + $.error("invalid dataset name: " + o.name); + } + www.mixin(this); + this.highlight = !!o.highlight; + this.name = _.toStr(o.name || nameGenerator()); + this.limit = o.limit || 5; + this.displayFn = getDisplayFn(o.display || o.displayKey); + this.templates = getTemplates(o.templates, this.displayFn); + this.source = o.source.__ttAdapter ? o.source.__ttAdapter() : o.source; + this.async = _.isUndefined(o.async) ? this.source.length > 2 : !!o.async; + this._resetLastSuggestion(); + this.$el = $(o.node).attr("role", "presentation").addClass(this.classes.dataset).addClass(this.classes.dataset + "-" + this.name); + } + Dataset.extractData = function extractData(el) { + var $el = $(el); + if ($el.data(keys.obj)) { + return { + dataset: $el.data(keys.dataset) || "", + val: $el.data(keys.val) || "", + obj: $el.data(keys.obj) || null + }; + } + return null; + }; + _.mixin(Dataset.prototype, EventEmitter, { + _overwrite: function overwrite(query, suggestions) { + suggestions = suggestions || []; + if (suggestions.length) { + this._renderSuggestions(query, suggestions); + } else if (this.async && this.templates.pending) { + this._renderPending(query); + } else if (!this.async && this.templates.notFound) { + this._renderNotFound(query); + } else { + this._empty(); + } + this.trigger("rendered", suggestions, false, this.name); + }, + _append: function append(query, suggestions) { + suggestions = suggestions || []; + if (suggestions.length && this.$lastSuggestion.length) { + this._appendSuggestions(query, suggestions); + } else if (suggestions.length) { + this._renderSuggestions(query, suggestions); + } else if (!this.$lastSuggestion.length && this.templates.notFound) { + this._renderNotFound(query); + } + this.trigger("rendered", suggestions, true, this.name); + }, + _renderSuggestions: function renderSuggestions(query, suggestions) { + var $fragment; + $fragment = this._getSuggestionsFragment(query, suggestions); + this.$lastSuggestion = $fragment.children().last(); + this.$el.html($fragment).prepend(this._getHeader(query, suggestions)).append(this._getFooter(query, suggestions)); + }, + _appendSuggestions: function appendSuggestions(query, suggestions) { + var $fragment, $lastSuggestion; + $fragment = this._getSuggestionsFragment(query, suggestions); + $lastSuggestion = $fragment.children().last(); + this.$lastSuggestion.after($fragment); + this.$lastSuggestion = $lastSuggestion; + }, + _renderPending: function renderPending(query) { + var template = this.templates.pending; + this._resetLastSuggestion(); + template && this.$el.html(template({ + query: query, + dataset: this.name + })); + }, + _renderNotFound: function renderNotFound(query) { + var template = this.templates.notFound; + this._resetLastSuggestion(); + template && this.$el.html(template({ + query: query, + dataset: this.name + })); + }, + _empty: function empty() { + this.$el.empty(); + this._resetLastSuggestion(); + }, + _getSuggestionsFragment: function getSuggestionsFragment(query, suggestions) { + var that = this, fragment; + fragment = document.createDocumentFragment(); + _.each(suggestions, function getSuggestionNode(suggestion) { + var $el, context; + context = that._injectQuery(query, suggestion); + $el = $(that.templates.suggestion(context)).data(keys.dataset, that.name).data(keys.obj, suggestion).data(keys.val, that.displayFn(suggestion)).addClass(that.classes.suggestion + " " + that.classes.selectable); + fragment.appendChild($el[0]); + }); + this.highlight && highlight({ + className: this.classes.highlight, + node: fragment, + pattern: query + }); + return $(fragment); + }, + _getFooter: function getFooter(query, suggestions) { + return this.templates.footer ? this.templates.footer({ + query: query, + suggestions: suggestions, + dataset: this.name + }) : null; + }, + _getHeader: function getHeader(query, suggestions) { + return this.templates.header ? this.templates.header({ + query: query, + suggestions: suggestions, + dataset: this.name + }) : null; + }, + _resetLastSuggestion: function resetLastSuggestion() { + this.$lastSuggestion = $(); + }, + _injectQuery: function injectQuery(query, obj) { + return _.isObject(obj) ? _.mixin({ + _query: query + }, obj) : obj; + }, + update: function update(query) { + var that = this, canceled = false, syncCalled = false, rendered = 0; + this.cancel(); + this.cancel = function cancel() { + canceled = true; + that.cancel = $.noop; + that.async && that.trigger("asyncCanceled", query, that.name); + }; + this.source(query, sync, async); + !syncCalled && sync([]); + function sync(suggestions) { + if (syncCalled) { + return; + } + syncCalled = true; + suggestions = (suggestions || []).slice(0, that.limit); + rendered = suggestions.length; + that._overwrite(query, suggestions); + if (rendered < that.limit && that.async) { + that.trigger("asyncRequested", query, that.name); + } + } + function async(suggestions) { + suggestions = suggestions || []; + if (!canceled && rendered < that.limit) { + that.cancel = $.noop; + var idx = Math.abs(rendered - that.limit); + rendered += idx; + that._append(query, suggestions.slice(0, idx)); + that.async && that.trigger("asyncReceived", query, that.name); + } + } + }, + cancel: $.noop, + clear: function clear() { + this._empty(); + this.cancel(); + this.trigger("cleared"); + }, + isEmpty: function isEmpty() { + return this.$el.is(":empty"); + }, + destroy: function destroy() { + this.$el = $("
    "); + } + }); + return Dataset; + function getDisplayFn(display) { + display = display || _.stringify; + return _.isFunction(display) ? display : displayFn; + function displayFn(obj) { + return obj[display]; + } + } + function getTemplates(templates, displayFn) { + return { + notFound: templates.notFound && _.templatify(templates.notFound), + pending: templates.pending && _.templatify(templates.pending), + header: templates.header && _.templatify(templates.header), + footer: templates.footer && _.templatify(templates.footer), + suggestion: templates.suggestion ? userSuggestionTemplate : suggestionTemplate + }; + function userSuggestionTemplate(context) { + var template = templates.suggestion; + return $(template(context)).attr("id", _.guid()); + } + function suggestionTemplate(context) { + return $('
    ').attr("id", _.guid()).text(displayFn(context)); + } + } + function isValidName(str) { + return /^[_a-zA-Z0-9-]+$/.test(str); + } + }(); + var Menu = function() { + "use strict"; + function Menu(o, www) { + var that = this; + o = o || {}; + if (!o.node) { + $.error("node is required"); + } + www.mixin(this); + this.$node = $(o.node); + this.query = null; + this.datasets = _.map(o.datasets, initializeDataset); + function initializeDataset(oDataset) { + var node = that.$node.find(oDataset.node).first(); + oDataset.node = node.length ? node : $("
    ").appendTo(that.$node); + return new Dataset(oDataset, www); + } + } + _.mixin(Menu.prototype, EventEmitter, { + _onSelectableClick: function onSelectableClick($e) { + this.trigger("selectableClicked", $($e.currentTarget)); + }, + _onRendered: function onRendered(type, dataset, suggestions, async) { + this.$node.toggleClass(this.classes.empty, this._allDatasetsEmpty()); + this.trigger("datasetRendered", dataset, suggestions, async); + }, + _onCleared: function onCleared() { + this.$node.toggleClass(this.classes.empty, this._allDatasetsEmpty()); + this.trigger("datasetCleared"); + }, + _propagate: function propagate() { + this.trigger.apply(this, arguments); + }, + _allDatasetsEmpty: function allDatasetsEmpty() { + return _.every(this.datasets, _.bind(function isDatasetEmpty(dataset) { + var isEmpty = dataset.isEmpty(); + this.$node.attr("aria-expanded", !isEmpty); + return isEmpty; + }, this)); + }, + _getSelectables: function getSelectables() { + return this.$node.find(this.selectors.selectable); + }, + _removeCursor: function _removeCursor() { + var $selectable = this.getActiveSelectable(); + $selectable && $selectable.removeClass(this.classes.cursor); + }, + _ensureVisible: function ensureVisible($el) { + var elTop, elBottom, nodeScrollTop, nodeHeight; + elTop = $el.position().top; + elBottom = elTop + $el.outerHeight(true); + nodeScrollTop = this.$node.scrollTop(); + nodeHeight = this.$node.height() + parseInt(this.$node.css("paddingTop"), 10) + parseInt(this.$node.css("paddingBottom"), 10); + if (elTop < 0) { + this.$node.scrollTop(nodeScrollTop + elTop); + } else if (nodeHeight < elBottom) { + this.$node.scrollTop(nodeScrollTop + (elBottom - nodeHeight)); + } + }, + bind: function() { + var that = this, onSelectableClick; + onSelectableClick = _.bind(this._onSelectableClick, this); + this.$node.on("click.tt", this.selectors.selectable, onSelectableClick); + this.$node.on("mouseover", this.selectors.selectable, function() { + that.setCursor($(this)); + }); + this.$node.on("mouseleave", function() { + that._removeCursor(); + }); + _.each(this.datasets, function(dataset) { + dataset.onSync("asyncRequested", that._propagate, that).onSync("asyncCanceled", that._propagate, that).onSync("asyncReceived", that._propagate, that).onSync("rendered", that._onRendered, that).onSync("cleared", that._onCleared, that); + }); + return this; + }, + isOpen: function isOpen() { + return this.$node.hasClass(this.classes.open); + }, + open: function open() { + this.$node.scrollTop(0); + this.$node.addClass(this.classes.open); + }, + close: function close() { + this.$node.attr("aria-expanded", false); + this.$node.removeClass(this.classes.open); + this._removeCursor(); + }, + setLanguageDirection: function setLanguageDirection(dir) { + this.$node.attr("dir", dir); + }, + selectableRelativeToCursor: function selectableRelativeToCursor(delta) { + var $selectables, $oldCursor, oldIndex, newIndex; + $oldCursor = this.getActiveSelectable(); + $selectables = this._getSelectables(); + oldIndex = $oldCursor ? $selectables.index($oldCursor) : -1; + newIndex = oldIndex + delta; + newIndex = (newIndex + 1) % ($selectables.length + 1) - 1; + newIndex = newIndex < -1 ? $selectables.length - 1 : newIndex; + return newIndex === -1 ? null : $selectables.eq(newIndex); + }, + setCursor: function setCursor($selectable) { + this._removeCursor(); + if ($selectable = $selectable && $selectable.first()) { + $selectable.addClass(this.classes.cursor); + this._ensureVisible($selectable); + } + }, + getSelectableData: function getSelectableData($el) { + return $el && $el.length ? Dataset.extractData($el) : null; + }, + getActiveSelectable: function getActiveSelectable() { + var $selectable = this._getSelectables().filter(this.selectors.cursor).first(); + return $selectable.length ? $selectable : null; + }, + getTopSelectable: function getTopSelectable() { + var $selectable = this._getSelectables().first(); + return $selectable.length ? $selectable : null; + }, + update: function update(query) { + var isValidUpdate = query !== this.query; + if (isValidUpdate) { + this.query = query; + _.each(this.datasets, updateDataset); + } + return isValidUpdate; + function updateDataset(dataset) { + dataset.update(query); + } + }, + empty: function empty() { + _.each(this.datasets, clearDataset); + this.query = null; + this.$node.addClass(this.classes.empty); + function clearDataset(dataset) { + dataset.clear(); + } + }, + destroy: function destroy() { + this.$node.off(".tt"); + this.$node = $("
    "); + _.each(this.datasets, destroyDataset); + function destroyDataset(dataset) { + dataset.destroy(); + } + } + }); + return Menu; + }(); + var Status = function() { + "use strict"; + function Status(options) { + this.$el = $("", { + role: "status", + "aria-live": "polite" + }).css({ + position: "absolute", + padding: "0", + border: "0", + height: "1px", + width: "1px", + "margin-bottom": "-1px", + "margin-right": "-1px", + overflow: "hidden", + clip: "rect(0 0 0 0)", + "white-space": "nowrap" + }); + options.$input.after(this.$el); + _.each(options.menu.datasets, _.bind(function(dataset) { + if (dataset.onSync) { + dataset.onSync("rendered", _.bind(this.update, this)); + dataset.onSync("cleared", _.bind(this.cleared, this)); + } + }, this)); + } + _.mixin(Status.prototype, { + update: function update(event, suggestions) { + var length = suggestions.length; + var words; + if (length === 1) { + words = { + result: "result", + is: "is" + }; + } else { + words = { + result: "results", + is: "are" + }; + } + this.$el.text(length + " " + words.result + " " + words.is + " available, use up and down arrow keys to navigate."); + }, + cleared: function() { + this.$el.text(""); + } + }); + return Status; + }(); + var DefaultMenu = function() { + "use strict"; + var s = Menu.prototype; + function DefaultMenu() { + Menu.apply(this, [].slice.call(arguments, 0)); + } + _.mixin(DefaultMenu.prototype, Menu.prototype, { + open: function open() { + !this._allDatasetsEmpty() && this._show(); + return s.open.apply(this, [].slice.call(arguments, 0)); + }, + close: function close() { + this._hide(); + return s.close.apply(this, [].slice.call(arguments, 0)); + }, + _onRendered: function onRendered() { + if (this._allDatasetsEmpty()) { + this._hide(); + } else { + this.isOpen() && this._show(); + } + return s._onRendered.apply(this, [].slice.call(arguments, 0)); + }, + _onCleared: function onCleared() { + if (this._allDatasetsEmpty()) { + this._hide(); + } else { + this.isOpen() && this._show(); + } + return s._onCleared.apply(this, [].slice.call(arguments, 0)); + }, + setLanguageDirection: function setLanguageDirection(dir) { + this.$node.css(dir === "ltr" ? this.css.ltr : this.css.rtl); + return s.setLanguageDirection.apply(this, [].slice.call(arguments, 0)); + }, + _hide: function hide() { + this.$node.hide(); + }, + _show: function show() { + this.$node.css("display", "block"); + } + }); + return DefaultMenu; + }(); + var Typeahead = function() { + "use strict"; + function Typeahead(o, www) { + var onFocused, onBlurred, onEnterKeyed, onTabKeyed, onEscKeyed, onUpKeyed, onDownKeyed, onLeftKeyed, onRightKeyed, onQueryChanged, onWhitespaceChanged; + o = o || {}; + if (!o.input) { + $.error("missing input"); + } + if (!o.menu) { + $.error("missing menu"); + } + if (!o.eventBus) { + $.error("missing event bus"); + } + www.mixin(this); + this.eventBus = o.eventBus; + this.minLength = _.isNumber(o.minLength) ? o.minLength : 1; + this.input = o.input; + this.menu = o.menu; + this.enabled = true; + this.autoselect = !!o.autoselect; + this.active = false; + this.input.hasFocus() && this.activate(); + this.dir = this.input.getLangDir(); + this._hacks(); + this.menu.bind().onSync("selectableClicked", this._onSelectableClicked, this).onSync("asyncRequested", this._onAsyncRequested, this).onSync("asyncCanceled", this._onAsyncCanceled, this).onSync("asyncReceived", this._onAsyncReceived, this).onSync("datasetRendered", this._onDatasetRendered, this).onSync("datasetCleared", this._onDatasetCleared, this); + onFocused = c(this, "activate", "open", "_onFocused"); + onBlurred = c(this, "deactivate", "_onBlurred"); + onEnterKeyed = c(this, "isActive", "isOpen", "_onEnterKeyed"); + onTabKeyed = c(this, "isActive", "isOpen", "_onTabKeyed"); + onEscKeyed = c(this, "isActive", "_onEscKeyed"); + onUpKeyed = c(this, "isActive", "open", "_onUpKeyed"); + onDownKeyed = c(this, "isActive", "open", "_onDownKeyed"); + onLeftKeyed = c(this, "isActive", "isOpen", "_onLeftKeyed"); + onRightKeyed = c(this, "isActive", "isOpen", "_onRightKeyed"); + onQueryChanged = c(this, "_openIfActive", "_onQueryChanged"); + onWhitespaceChanged = c(this, "_openIfActive", "_onWhitespaceChanged"); + this.input.bind().onSync("focused", onFocused, this).onSync("blurred", onBlurred, this).onSync("enterKeyed", onEnterKeyed, this).onSync("tabKeyed", onTabKeyed, this).onSync("escKeyed", onEscKeyed, this).onSync("upKeyed", onUpKeyed, this).onSync("downKeyed", onDownKeyed, this).onSync("leftKeyed", onLeftKeyed, this).onSync("rightKeyed", onRightKeyed, this).onSync("queryChanged", onQueryChanged, this).onSync("whitespaceChanged", onWhitespaceChanged, this).onSync("langDirChanged", this._onLangDirChanged, this); + } + _.mixin(Typeahead.prototype, { + _hacks: function hacks() { + var $input, $menu; + $input = this.input.$input || $("
    "); + $menu = this.menu.$node || $("
    "); + $input.on("blur.tt", function($e) { + var active, isActive, hasActive; + active = document.activeElement; + isActive = $menu.is(active); + hasActive = $menu.has(active).length > 0; + if (_.isMsie() && (isActive || hasActive)) { + $e.preventDefault(); + $e.stopImmediatePropagation(); + _.defer(function() { + $input.focus(); + }); + } + }); + $menu.on("mousedown.tt", function($e) { + $e.preventDefault(); + }); + }, + _onSelectableClicked: function onSelectableClicked(type, $el) { + this.select($el); + }, + _onDatasetCleared: function onDatasetCleared() { + this._updateHint(); + }, + _onDatasetRendered: function onDatasetRendered(type, suggestions, async, dataset) { + this._updateHint(); + if (this.autoselect) { + var cursorClass = this.selectors.cursor.substr(1); + this.menu.$node.find(this.selectors.suggestion).first().addClass(cursorClass); + } + this.eventBus.trigger("render", suggestions, async, dataset); + }, + _onAsyncRequested: function onAsyncRequested(type, dataset, query) { + this.eventBus.trigger("asyncrequest", query, dataset); + }, + _onAsyncCanceled: function onAsyncCanceled(type, dataset, query) { + this.eventBus.trigger("asynccancel", query, dataset); + }, + _onAsyncReceived: function onAsyncReceived(type, dataset, query) { + this.eventBus.trigger("asyncreceive", query, dataset); + }, + _onFocused: function onFocused() { + this._minLengthMet() && this.menu.update(this.input.getQuery()); + }, + _onBlurred: function onBlurred() { + if (this.input.hasQueryChangedSinceLastFocus()) { + this.eventBus.trigger("change", this.input.getQuery()); + } + }, + _onEnterKeyed: function onEnterKeyed(type, $e) { + var $selectable; + if ($selectable = this.menu.getActiveSelectable()) { + if (this.select($selectable)) { + $e.preventDefault(); + $e.stopPropagation(); + } + } else if (this.autoselect) { + if (this.select(this.menu.getTopSelectable())) { + $e.preventDefault(); + $e.stopPropagation(); + } + } + }, + _onTabKeyed: function onTabKeyed(type, $e) { + var $selectable; + if ($selectable = this.menu.getActiveSelectable()) { + this.select($selectable) && $e.preventDefault(); + } else if (this.autoselect) { + if ($selectable = this.menu.getTopSelectable()) { + this.autocomplete($selectable) && $e.preventDefault(); + } + } + }, + _onEscKeyed: function onEscKeyed() { + this.close(); + }, + _onUpKeyed: function onUpKeyed() { + this.moveCursor(-1); + }, + _onDownKeyed: function onDownKeyed() { + this.moveCursor(+1); + }, + _onLeftKeyed: function onLeftKeyed() { + if (this.dir === "rtl" && this.input.isCursorAtEnd()) { + this.autocomplete(this.menu.getActiveSelectable() || this.menu.getTopSelectable()); + } + }, + _onRightKeyed: function onRightKeyed() { + if (this.dir === "ltr" && this.input.isCursorAtEnd()) { + this.autocomplete(this.menu.getActiveSelectable() || this.menu.getTopSelectable()); + } + }, + _onQueryChanged: function onQueryChanged(e, query) { + this._minLengthMet(query) ? this.menu.update(query) : this.menu.empty(); + }, + _onWhitespaceChanged: function onWhitespaceChanged() { + this._updateHint(); + }, + _onLangDirChanged: function onLangDirChanged(e, dir) { + if (this.dir !== dir) { + this.dir = dir; + this.menu.setLanguageDirection(dir); + } + }, + _openIfActive: function openIfActive() { + this.isActive() && this.open(); + }, + _minLengthMet: function minLengthMet(query) { + query = _.isString(query) ? query : this.input.getQuery() || ""; + return query.length >= this.minLength; + }, + _updateHint: function updateHint() { + var $selectable, data, val, query, escapedQuery, frontMatchRegEx, match; + $selectable = this.menu.getTopSelectable(); + data = this.menu.getSelectableData($selectable); + val = this.input.getInputValue(); + if (data && !_.isBlankString(val) && !this.input.hasOverflow()) { + query = Input.normalizeQuery(val); + escapedQuery = _.escapeRegExChars(query); + frontMatchRegEx = new RegExp("^(?:" + escapedQuery + ")(.+$)", "i"); + match = frontMatchRegEx.exec(data.val); + match && this.input.setHint(val + match[1]); + } else { + this.input.clearHint(); + } + }, + isEnabled: function isEnabled() { + return this.enabled; + }, + enable: function enable() { + this.enabled = true; + }, + disable: function disable() { + this.enabled = false; + }, + isActive: function isActive() { + return this.active; + }, + activate: function activate() { + if (this.isActive()) { + return true; + } else if (!this.isEnabled() || this.eventBus.before("active")) { + return false; + } else { + this.active = true; + this.eventBus.trigger("active"); + return true; + } + }, + deactivate: function deactivate() { + if (!this.isActive()) { + return true; + } else if (this.eventBus.before("idle")) { + return false; + } else { + this.active = false; + this.close(); + this.eventBus.trigger("idle"); + return true; + } + }, + isOpen: function isOpen() { + return this.menu.isOpen(); + }, + open: function open() { + if (!this.isOpen() && !this.eventBus.before("open")) { + this.input.setAriaExpanded(true); + this.menu.open(); + this._updateHint(); + this.eventBus.trigger("open"); + } + return this.isOpen(); + }, + close: function close() { + if (this.isOpen() && !this.eventBus.before("close")) { + this.input.setAriaExpanded(false); + this.menu.close(); + this.input.clearHint(); + this.input.resetInputValue(); + this.eventBus.trigger("close"); + } + return !this.isOpen(); + }, + setVal: function setVal(val) { + this.input.setQuery(_.toStr(val)); + }, + getVal: function getVal() { + return this.input.getQuery(); + }, + select: function select($selectable) { + var data = this.menu.getSelectableData($selectable); + if (data && !this.eventBus.before("select", data.obj, data.dataset)) { + this.input.setQuery(data.val, true); + this.eventBus.trigger("select", data.obj, data.dataset); + this.close(); + return true; + } + return false; + }, + autocomplete: function autocomplete($selectable) { + var query, data, isValid; + query = this.input.getQuery(); + data = this.menu.getSelectableData($selectable); + isValid = data && query !== data.val; + if (isValid && !this.eventBus.before("autocomplete", data.obj, data.dataset)) { + this.input.setQuery(data.val); + this.eventBus.trigger("autocomplete", data.obj, data.dataset); + return true; + } + return false; + }, + moveCursor: function moveCursor(delta) { + var query, $candidate, data, suggestion, datasetName, cancelMove, id; + query = this.input.getQuery(); + $candidate = this.menu.selectableRelativeToCursor(delta); + data = this.menu.getSelectableData($candidate); + suggestion = data ? data.obj : null; + datasetName = data ? data.dataset : null; + id = $candidate ? $candidate.attr("id") : null; + this.input.trigger("cursorchange", id); + cancelMove = this._minLengthMet() && this.menu.update(query); + if (!cancelMove && !this.eventBus.before("cursorchange", suggestion, datasetName)) { + this.menu.setCursor($candidate); + if (data) { + if (typeof data.val === "string") { + this.input.setInputValue(data.val); + } + } else { + this.input.resetInputValue(); + this._updateHint(); + } + this.eventBus.trigger("cursorchange", suggestion, datasetName); + return true; + } + return false; + }, + destroy: function destroy() { + this.input.destroy(); + this.menu.destroy(); + } + }); + return Typeahead; + function c(ctx) { + var methods = [].slice.call(arguments, 1); + return function() { + var args = [].slice.call(arguments); + _.each(methods, function(method) { + return ctx[method].apply(ctx, args); + }); + }; + } + }(); + (function() { + "use strict"; + var old, keys, methods; + old = $.fn.typeahead; + keys = { + www: "tt-www", + attrs: "tt-attrs", + typeahead: "tt-typeahead" + }; + methods = { + initialize: function initialize(o, datasets) { + var www; + datasets = _.isArray(datasets) ? datasets : [].slice.call(arguments, 1); + o = o || {}; + www = WWW(o.classNames); + return this.each(attach); + function attach() { + var $input, $wrapper, $hint, $menu, defaultHint, defaultMenu, eventBus, input, menu, status, typeahead, MenuConstructor; + _.each(datasets, function(d) { + d.highlight = !!o.highlight; + }); + $input = $(this); + $wrapper = $(www.html.wrapper); + $hint = $elOrNull(o.hint); + $menu = $elOrNull(o.menu); + defaultHint = o.hint !== false && !$hint; + defaultMenu = o.menu !== false && !$menu; + defaultHint && ($hint = buildHintFromInput($input, www)); + defaultMenu && ($menu = $(www.html.menu).css(www.css.menu)); + $hint && $hint.val(""); + $input = prepInput($input, www); + if (defaultHint || defaultMenu) { + $wrapper.css(www.css.wrapper); + $input.css(defaultHint ? www.css.input : www.css.inputWithNoHint); + $input.wrap($wrapper).parent().prepend(defaultHint ? $hint : null).append(defaultMenu ? $menu : null); + } + MenuConstructor = defaultMenu ? DefaultMenu : Menu; + eventBus = new EventBus({ + el: $input + }); + input = new Input({ + hint: $hint, + input: $input, + menu: $menu + }, www); + menu = new MenuConstructor({ + node: $menu, + datasets: datasets + }, www); + status = new Status({ + $input: $input, + menu: menu + }); + typeahead = new Typeahead({ + input: input, + menu: menu, + eventBus: eventBus, + minLength: o.minLength, + autoselect: o.autoselect + }, www); + $input.data(keys.www, www); + $input.data(keys.typeahead, typeahead); + } + }, + isEnabled: function isEnabled() { + var enabled; + ttEach(this.first(), function(t) { + enabled = t.isEnabled(); + }); + return enabled; + }, + enable: function enable() { + ttEach(this, function(t) { + t.enable(); + }); + return this; + }, + disable: function disable() { + ttEach(this, function(t) { + t.disable(); + }); + return this; + }, + isActive: function isActive() { + var active; + ttEach(this.first(), function(t) { + active = t.isActive(); + }); + return active; + }, + activate: function activate() { + ttEach(this, function(t) { + t.activate(); + }); + return this; + }, + deactivate: function deactivate() { + ttEach(this, function(t) { + t.deactivate(); + }); + return this; + }, + isOpen: function isOpen() { + var open; + ttEach(this.first(), function(t) { + open = t.isOpen(); + }); + return open; + }, + open: function open() { + ttEach(this, function(t) { + t.open(); + }); + return this; + }, + close: function close() { + ttEach(this, function(t) { + t.close(); + }); + return this; + }, + select: function select(el) { + var success = false, $el = $(el); + ttEach(this.first(), function(t) { + success = t.select($el); + }); + return success; + }, + autocomplete: function autocomplete(el) { + var success = false, $el = $(el); + ttEach(this.first(), function(t) { + success = t.autocomplete($el); + }); + return success; + }, + moveCursor: function moveCursoe(delta) { + var success = false; + ttEach(this.first(), function(t) { + success = t.moveCursor(delta); + }); + return success; + }, + val: function val(newVal) { + var query; + if (!arguments.length) { + ttEach(this.first(), function(t) { + query = t.getVal(); + }); + return query; + } else { + ttEach(this, function(t) { + t.setVal(_.toStr(newVal)); + }); + return this; + } + }, + destroy: function destroy() { + ttEach(this, function(typeahead, $input) { + revert($input); + typeahead.destroy(); + }); + return this; + } + }; + $.fn.typeahead = function(method) { + if (methods[method]) { + return methods[method].apply(this, [].slice.call(arguments, 1)); + } else { + return methods.initialize.apply(this, arguments); + } + }; + $.fn.typeahead.noConflict = function noConflict() { + $.fn.typeahead = old; + return this; + }; + function ttEach($els, fn) { + $els.each(function() { + var $input = $(this), typeahead; + (typeahead = $input.data(keys.typeahead)) && fn(typeahead, $input); + }); + } + function buildHintFromInput($input, www) { + return $input.clone().addClass(www.classes.hint).removeData().css(www.css.hint).css(getBackgroundStyles($input)).prop({ + readonly: true, + required: false + }).removeAttr("id name placeholder").removeClass("required").attr({ + spellcheck: "false", + tabindex: -1 + }); + } + function prepInput($input, www) { + $input.data(keys.attrs, { + dir: $input.attr("dir"), + autocomplete: $input.attr("autocomplete"), + spellcheck: $input.attr("spellcheck"), + style: $input.attr("style") + }); + $input.addClass(www.classes.input).attr({ + spellcheck: false + }); + try { + !$input.attr("dir") && $input.attr("dir", "auto"); + } catch (e) {} + return $input; + } + function getBackgroundStyles($el) { + return { + backgroundAttachment: $el.css("background-attachment"), + backgroundClip: $el.css("background-clip"), + backgroundColor: $el.css("background-color"), + backgroundImage: $el.css("background-image"), + backgroundOrigin: $el.css("background-origin"), + backgroundPosition: $el.css("background-position"), + backgroundRepeat: $el.css("background-repeat"), + backgroundSize: $el.css("background-size") + }; + } + function revert($input) { + var www, $wrapper; + www = $input.data(keys.www); + $wrapper = $input.parent().filter(www.selectors.wrapper); + _.each($input.data(keys.attrs), function(val, key) { + _.isUndefined(val) ? $input.removeAttr(key) : $input.attr(key, val); + }); + $input.removeData(keys.typeahead).removeData(keys.www).removeData(keys.attr).removeClass(www.classes.input); + if ($wrapper.length) { + $input.detach().insertAfter($wrapper); + $wrapper.remove(); + } + } + function $elOrNull(obj) { + var isValid, $el; + isValid = _.isJQuery(obj) || _.isElement(obj); + $el = isValid ? $(obj).first() : []; + return $el.length ? $el : null; + } + })(); +}); \ No newline at end of file diff --git a/Documentation/docsets/Atom.docset/Contents/Resources/Documents/search.json b/Documentation/docsets/Atom.docset/Contents/Resources/Documents/search.json index 5f869d8..9ad06df 100644 --- a/Documentation/docsets/Atom.docset/Contents/Resources/Documents/search.json +++ b/Documentation/docsets/Atom.docset/Contents/Resources/Documents/search.json @@ -1 +1 @@ -{"Protocols/TokenCredentialWritable.html#/s:4Atom23TokenCredentialWritableP05tokenC0A2AC0bC0Vvp":{"name":"tokenCredential","abstract":"

    Returns conforming type as Atom.TokenCredential.

    ","parent_name":"TokenCredentialWritable"},"Protocols/Requestable.html#/s:4Atom11RequestableP11headerItemsSayA2AC10HeaderItemVGSgvp":{"name":"headerItems","abstract":"

    The array of header items to apply to a URLRequest.

    ","parent_name":"Requestable"},"Protocols/Requestable.html#/s:4Atom11RequestableP6methodA2AC6MethodOvp":{"name":"method","abstract":"

    The HTTP method to apply to a URLRequest.

    ","parent_name":"Requestable"},"Protocols/Requestable.html#/s:4Atom11RequestableP10queryItemsSay10Foundation12URLQueryItemVGSgvp":{"name":"queryItems","abstract":"

    The array of query items to apply to a URL.

    ","parent_name":"Requestable"},"Protocols/Requestable.html#/s:4Atom11RequestableP22requiresAuthenticationSbvp":{"name":"requiresAuthentication","abstract":"

    The Bool indicating whether or not authorization header should be applied","parent_name":"Requestable"},"Protocols/Requestable.html#/s:4Atom11RequestableP7baseURLA2AC04BaseD0VyKF":{"name":"baseURL()","abstract":"

    The base url to initialize URLRequest with.

    ","parent_name":"Requestable"},"Protocols/Requestable.html#/s:4Atom11RequestableP4pathA2AC7URLPathVyKF":{"name":"path()","abstract":"

    The URL path to append to a base URL.

    ","parent_name":"Requestable"},"Protocols/ClientCredentialConvertible.html#/s:4Atom27ClientCredentialConvertibleP06clientC0A2AC0bC0Vvp":{"name":"clientCredential","abstract":"

    Returns conforming type as Atom.ClientCredential.

    ","parent_name":"ClientCredentialConvertible"},"Protocols/BasicCredentialConvertible.html#/s:4Atom26BasicCredentialConvertibleP05basicC0A2AC0bC0Vvp":{"name":"basicCredential","abstract":"

    Returns conforming type as Atom.BasicCredential.

    ","parent_name":"BasicCredentialConvertible"},"Protocols/BasicCredentialConvertible.html":{"name":"BasicCredentialConvertible","abstract":"

    The BasicCredentialConvertible protocol declares an interface used for converting conforming type to Atom.BasicCredential.

    "},"Protocols/ClientCredentialConvertible.html":{"name":"ClientCredentialConvertible","abstract":"

    The ClientCredentialConvertible protocol declares an interface used for converting conforming type to Atom.ClientCredential.

    "},"Protocols.html#/s:4Atom5ModelP":{"name":"Model","abstract":"

    The Model protocol declares an interface used as a generic constraint on Atom.Service methods.

    "},"Protocols/Requestable.html":{"name":"Requestable","abstract":"

    The Requestable protocol declares an interface used for initializing network request object.

    "},"Protocols/TokenCredentialWritable.html":{"name":"TokenCredentialWritable","abstract":"

    The TokenCredentialWritable protocol declares an interface used for reading from / writing to Atom.TokenCredential.

    "},"Extensions/URLSessionTaskMetrics.html#/c:@CM@Atom@@objc(cs)NSURLSessionTaskMetrics(py)debugDescription":{"name":"debugDescription","abstract":"

    Returns a textual representation of this instance, suitable for debugging.

    ","parent_name":"URLSessionTaskMetrics"},"Extensions/URLSessionTask.html#/c:@CM@Atom@@objc(cs)NSURLSessionTask(py)debugDescription":{"name":"debugDescription","abstract":"

    Returns a textual representation of this instance, suitable for debugging.

    ","parent_name":"URLSessionTask"},"Extensions/URLResponse.html#/s:So13NSURLResponseC4AtomE9isFailureSbvp":{"name":"isFailure","abstract":"

    Returns true if the status code of the HTTPURLResponse is not in 200...299 range.

    ","parent_name":"URLResponse"},"Extensions/URLResponse.html#/s:So13NSURLResponseC4AtomE12isSuccessfulSbvp":{"name":"isSuccessful","abstract":"

    Returns true if the status code of the HTTPURLResponse is in 200...299 range.

    ","parent_name":"URLResponse"},"Extensions/URLResponse.html#/c:@CM@Atom@@objc(cs)NSURLResponse(py)debugDescription":{"name":"debugDescription","abstract":"

    Returns a textual representation of this instance, suitable for debugging.

    ","parent_name":"URLResponse"},"Extensions/URLRequest.html#/s:10Foundation10URLRequestV4AtomE16debugDescriptionSSvp":{"name":"debugDescription","abstract":"

    Returns a textual representation of this instance, suitable for debugging.

    ","parent_name":"URLRequest"},"Extensions/Optional.html#/s:Sq4AtomE6unwrap_4file4linexSSycSg_s12StaticStringVSutF":{"name":"unwrap(_:file:line:)","abstract":"

    Unwraps an optional value. Terminates the process if the value is nil.

    ","parent_name":"Optional"},"Extensions/Bool.html#/s:Sb4AtomE2onSbvpZ":{"name":"on","abstract":"

    Convenience property for returning true.

    ","parent_name":"Bool"},"Extensions/Bool.html#/s:Sb4AtomE3offSbvpZ":{"name":"off","abstract":"

    Convenience property for returning false.

    ","parent_name":"Bool"},"Extensions/Bool.html":{"name":"Bool"},"Extensions/Optional.html":{"name":"Optional"},"Extensions/URLRequest.html":{"name":"URLRequest"},"Extensions/URLResponse.html":{"name":"URLResponse"},"Extensions/URLSessionTask.html":{"name":"URLSessionTask"},"Extensions/URLSessionTaskMetrics.html":{"name":"URLSessionTaskMetrics"},"Enums/RequestableError.html#/s:4Atom16RequestableErrorO14invalidBaseURLyA2CmF":{"name":"invalidBaseURL","abstract":"

    Base URL failed validation. Most probable cause is invalid URL host.

    ","parent_name":"RequestableError"},"Enums/RequestableError.html#/s:4Atom16RequestableErrorO10invalidURLyA2CmF":{"name":"invalidURL","abstract":"

    URLComponents initialization with provided URL string failed.

    ","parent_name":"RequestableError"},"Enums/RequestableError.html#/s:4Atom16RequestableErrorO14invalidURLPathyA2CmF":{"name":"invalidURLPath","abstract":"

    URL path failed validation.

    ","parent_name":"RequestableError"},"Enums/AtomError.html#/s:4Atom0A5ErrorO7decoderyACs0B0_pcACmF":{"name":"decoder(_:)","abstract":"

    Decoder failed to decode data.

    ","parent_name":"AtomError"},"Enums/AtomError.html#/s:4Atom0A5ErrorO4datayACs0B0_pcACmF":{"name":"data(_:)","abstract":"

    Failed to initialize Data instance from URL.

    ","parent_name":"AtomError"},"Enums/AtomError.html#/s:4Atom0A5ErrorO11requestableyAcA011RequestableB0OcACmF":{"name":"requestable(_:)","abstract":"

    Failed to initialize URLRequest with Requestable instance.

    ","parent_name":"AtomError"},"Enums/AtomError.html#/s:4Atom0A5ErrorO8responseyAc2AC8ResponseVcACmF":{"name":"response(_:)","abstract":"

    Service returned invalid response where the status code is not in 200...299 range.

    ","parent_name":"AtomError"},"Enums/AtomError.html#/s:4Atom0A5ErrorO7sessionyACs0B0_pcACmF":{"name":"session(_:)","abstract":"

    URLSession failed with error.

    ","parent_name":"AtomError"},"Enums/AtomError.html#/s:4Atom0A5ErrorO10unexpectedyA2CmF":{"name":"unexpected","abstract":"

    Unexpected, logic error.

    ","parent_name":"AtomError"},"Enums/AtomError.html#/s:4Atom0A5ErrorO7unknownyA2CmF":{"name":"unknown","abstract":"

    Unknown error occurred.

    ","parent_name":"AtomError"},"Enums/AtomError.html#/s:4Atom0A5ErrorO22isAuthorizationFailureSbvp":{"name":"isAuthorizationFailure","abstract":"

    Returns Bool indicating whether the error is due to an invalid or expired access token.

    ","parent_name":"AtomError"},"Enums/AtomError.html#/s:4Atom0A5ErrorO27isAccessTokenRefreshFailureSbvp":{"name":"isAccessTokenRefreshFailure","abstract":"

    Returns Bool indicating whether the error is due to a failed attempt to refresh an access token.

    ","parent_name":"AtomError"},"Enums/AtomError.html#/s:4Atom0A5ErrorO15decodeIfPresent2asxSgxm_tKSeRzlF":{"name":"decodeIfPresent(as:)","abstract":"

    Convenience method for decoding error object or message returned by the service.

    ","parent_name":"AtomError"},"Enums/AtomError.html":{"name":"AtomError","abstract":"

    List of all possible error cases thrown by Atom framework.

    "},"Enums/RequestableError.html":{"name":"RequestableError","abstract":"

    List of all possible error cases thrown when conversion from Requestable to URLRequest fails.

    "},"Classes/Atom/ServiceConfiguration/Configuration.html#/s:4AtomAAC20ServiceConfigurationC0C0O10backgroundyAFSScAFmF":{"name":"background(_:)","abstract":"

    The background session configuration is suitable for transferring data files while the app runs in the background.

    ","parent_name":"Configuration"},"Classes/Atom/ServiceConfiguration/Configuration.html#/s:4AtomAAC20ServiceConfigurationC0C0O7defaultyA2FmF":{"name":"default","abstract":"

    The default session configuration that uses a persistent disk-based cache.

    ","parent_name":"Configuration"},"Classes/Atom/ServiceConfiguration/Configuration.html#/s:4AtomAAC20ServiceConfigurationC0C0O9ephemeralyA2FmF":{"name":"ephemeral","abstract":"

    Ephemeral configuration doesn’t store caches, credential stores, or any session-related data on disk (RAM only).

    ","parent_name":"Configuration"},"Classes/Atom/ServiceConfiguration/Configuration.html":{"name":"Configuration","abstract":"

    List of supported session configurations.

    ","parent_name":"ServiceConfiguration"},"Classes/Atom/ServiceConfiguration.html#/s:4AtomAAC20ServiceConfigurationC20authenticationMethod13configuration7decoder13dispatchQueueAdB014AuthenticationE0O_AD0C0O10Foundation11JSONDecoderCSo03OS_H6_queueCtcfc":{"name":"init(authenticationMethod:configuration:decoder:dispatchQueue:)","abstract":"

    Creates a ServiceConfiguration instance given the provided parameter(s).

    ","parent_name":"ServiceConfiguration"},"Classes/Atom/Service.html#/s:4AtomAAC7ServiceC7execute9expecting10completionyxm_ys6ResultOyxAA0A5ErrorOGctAA5ModelRzlF":{"name":"execute(expecting:completion:)","abstract":"

    Creates and executes URLRequest initialized from Requestable.

    ","parent_name":"Service"},"Classes/Atom/Service.html#/s:4AtomAAC7ServiceC7executeyyys6ResultOyAB8ResponseVAA0A5ErrorOGcF":{"name":"execute(_:)","abstract":"

    Creates and executes URLRequest initialized from Requestable.

    ","parent_name":"Service"},"Classes/Atom/URLPath.html#/s:4AtomAAC7URLPathVyADSSKcfc":{"name":"init(_:)","abstract":"

    Creates a URLPath instance given the provided parameter(s).

    ","parent_name":"URLPath"},"Classes/Atom/TokenCredential.html#/s:4AtomAAC15TokenCredentialV06accessB0SSvp":{"name":"accessToken","abstract":"

    The access token as defined in OAuth 2.0 spec.

    ","parent_name":"TokenCredential"},"Classes/Atom/TokenCredential.html#/s:4AtomAAC15TokenCredentialV9expiresInSivp":{"name":"expiresIn","abstract":"

    The number of seconds access token is valid for.

    ","parent_name":"TokenCredential"},"Classes/Atom/TokenCredential.html#/s:4AtomAAC15TokenCredentialV9expiresAt10Foundation4DateVvp":{"name":"expiresAt","abstract":"

    The expiration date of the access token.

    ","parent_name":"TokenCredential"},"Classes/Atom/TokenCredential.html#/s:4AtomAAC15TokenCredentialV07refreshB0SSvp":{"name":"refreshToken","abstract":"

    The refresh token as defined in OAuth 2.0 spec.

    ","parent_name":"TokenCredential"},"Classes/Atom/TokenCredential.html#/s:4AtomAAC15TokenCredentialV06accessB09expiresIn0E2At07refreshB0ADSS_Si10Foundation4DateVSStcfc":{"name":"init(accessToken:expiresIn:expiresAt:refreshToken:)","abstract":"

    Creates a TokenCredential instance given the provided parameter(s).

    ","parent_name":"TokenCredential"},"Classes/Atom/TokenCredential.html#/s:Se4fromxs7Decoder_p_tKcfc":{"name":"init(from:)","parent_name":"TokenCredential"},"Classes/Atom/Response.html#/s:4AtomAAC8ResponseV12HeaderFieldsa":{"name":"HeaderFields","abstract":"

    Undocumented

    ","parent_name":"Response"},"Classes/Atom/Response.html#/s:4AtomAAC8ResponseV15allHeaderFieldsSo12NSDictionaryCSgvp":{"name":"allHeaderFields","abstract":"

    All HTTP header fields of the response.

    ","parent_name":"Response"},"Classes/Atom/Response.html#/s:4AtomAAC8ResponseV21expectedContentLengths5Int64VSgvp":{"name":"expectedContentLength","abstract":"

    The expected length of the response’s content.

    ","parent_name":"Response"},"Classes/Atom/Response.html#/s:4AtomAAC8ResponseV4data10Foundation4DataVSgvp":{"name":"data","abstract":"

    The data returned by the server.

    ","parent_name":"Response"},"Classes/Atom/Response.html#/s:4AtomAAC8ResponseV8mimeTypeSSSgvp":{"name":"mimeType","abstract":"

    The MIME type of the response.

    ","parent_name":"Response"},"Classes/Atom/Response.html#/s:4AtomAAC8ResponseV10statusCodeSiSgvp":{"name":"statusCode","abstract":"

    The response’s HTTP status code.

    ","parent_name":"Response"},"Classes/Atom/Response.html#/s:4AtomAAC8ResponseV17suggestedFilenameSSSgvp":{"name":"suggestedFilename","abstract":"

    A suggested filename for the response data.

    ","parent_name":"Response"},"Classes/Atom/Response.html#/s:4AtomAAC8ResponseV16textEncodingNameSSSgvp":{"name":"textEncodingName","abstract":"

    The name of the text encoding provided by the response’s originating source.

    ","parent_name":"Response"},"Classes/Atom/Response.html#/s:4AtomAAC8ResponseV3url10Foundation3URLVSgvp":{"name":"url","abstract":"

    The URL for the response.

    ","parent_name":"Response"},"Classes/Atom/Response.html#/s:4AtomAAC8ResponseV7successADvpZ":{"name":"success","abstract":"

    Returns default, success response where status code is 200.

    ","parent_name":"Response"},"Classes/Atom/Method.html#/s:4AtomAAC6MethodO6deleteyA2DmF":{"name":"delete","abstract":"

    Use for deleting a resource identified by a URI.

    ","parent_name":"Method"},"Classes/Atom/Method.html#/s:4AtomAAC6MethodO3getyA2DmF":{"name":"get","abstract":"

    Use for reading (or retrieving) a representation of a resource.

    ","parent_name":"Method"},"Classes/Atom/Method.html#/s:4AtomAAC6MethodO5patchyAD10Foundation4DataVcADmF":{"name":"patch(_:)","abstract":"

    Use for modifying capabilities.

    ","parent_name":"Method"},"Classes/Atom/Method.html#/s:4AtomAAC6MethodO4postyAD10Foundation4DataVcADmF":{"name":"post(_:)","abstract":"

    Use for creating new resources.

    ","parent_name":"Method"},"Classes/Atom/Method.html#/s:4AtomAAC6MethodO3putyAD10Foundation4DataVcADmF":{"name":"put(_:)","abstract":"

    Use for replacing a resource.

    ","parent_name":"Method"},"Classes/Atom/HeaderItem.html#/s:4AtomAAC10HeaderItemV4name5valueADSS_SStcfc":{"name":"init(name:value:)","abstract":"

    Creates a HeaderItem instance given the provided parameter(s).

    ","parent_name":"HeaderItem"},"Classes/Atom/ClientCredential/GrantType.html#/s:4AtomAAC16ClientCredentialV9GrantTypeO12refreshTokenyA2FmF":{"name":"refreshToken","abstract":"

    The refresh_token grant type as defined in Sections 6.0, RFC 6749.

    ","parent_name":"GrantType"},"Classes/Atom/ClientCredential.html#/s:4AtomAAC16ClientCredentialV9grantType2id6secretA2D05GrantE0O_S2Stcfc":{"name":"init(grantType:id:secret:)","abstract":"

    Creates a ClientCredential instance given the provided parameter(s).

    ","parent_name":"ClientCredential"},"Classes/Atom/ClientCredential/GrantType.html":{"name":"GrantType","abstract":"

    List of supported grant types by Atom.

    ","parent_name":"ClientCredential"},"Classes/Atom/BasicCredential.html#/s:4AtomAAC15BasicCredentialV8password8usernameADSS_SStcfc":{"name":"init(password:username:)","abstract":"

    Creates a BasicCredential instance given the provided parameter(s).

    ","parent_name":"BasicCredential"},"Classes/Atom/BaseURL/Scheme.html#/s:4AtomAAC7BaseURLV6SchemeO4httpyA2FmF":{"name":"http","abstract":"

    The hyper text transfer protocol.

    ","parent_name":"Scheme"},"Classes/Atom/BaseURL/Scheme.html#/s:4AtomAAC7BaseURLV6SchemeO5httpsyA2FmF":{"name":"https","abstract":"

    The hyper text transfer protocol secure.

    ","parent_name":"Scheme"},"Classes/Atom/BaseURL.html#/s:4AtomAAC7BaseURLV6scheme4hostA2D6SchemeO_SStKcfc":{"name":"init(scheme:host:)","abstract":"

    Creates a BaseURL instance given the provided parameter(s).

    ","parent_name":"BaseURL"},"Classes/Atom/BaseURL/Scheme.html":{"name":"Scheme","abstract":"

    List of supported scheme types.

    ","parent_name":"BaseURL"},"Classes/Atom/AuthorizationEndpoint.html#/s:4AtomAAC21AuthorizationEndpointV4host4pathADSS_SStcfc":{"name":"init(host:path:)","abstract":"

    Creates a AuthorizationEndpoint instance given the provided parameter(s).

    ","parent_name":"AuthorizationEndpoint"},"Classes/Atom/AuthenticationMethod.html#/s:4AtomAAC20AuthenticationMethodO5basicyAdB15BasicCredentialVcADmF":{"name":"basic(_:)","abstract":"

    Atom will apply basic authorization header to a request on behalf of the client.

    ","parent_name":"AuthenticationMethod"},"Classes/Atom/AuthenticationMethod.html#/s:4AtomAAC20AuthenticationMethodO6beareryAdB21AuthorizationEndpointV_AB16ClientCredentialVAA05TokenH8Writable_ptcADmF":{"name":"bearer(_:_:_:)","abstract":"

    Atom will manage access token expiration and apply authorization header to a request on behalf of the client.

    ","parent_name":"AuthenticationMethod"},"Classes/Atom/AuthenticationMethod.html#/s:4AtomAAC20AuthenticationMethodO4noneyA2DmF":{"name":"none","abstract":"

    Application will manage its own authorization headers.

    ","parent_name":"AuthenticationMethod"},"Classes/Atom.html#/s:4AtomAAC3logSbvp":{"name":"log","abstract":"

    A Bool indicating whether or not all service requests should be logged to the console.

    ","parent_name":"Atom"},"Classes/Atom.html#/s:4AtomAAC20serviceConfigurationA2B07ServiceC0C_tcfc":{"name":"init(serviceConfiguration:)","abstract":"

    Creates a Atom instance given the provided parameter(s).

    ","parent_name":"Atom"},"Classes/Atom.html#/s:4AtomAAC21cancelAllSessionTasksyyF":{"name":"cancelAllSessionTasks()","abstract":"

    Cancels all currently running and suspended tasks.

    ","parent_name":"Atom"},"Classes/Atom.html#/s:4AtomAAC4loadyAB7ServiceCAA11Requestable_pF":{"name":"load(_:)","abstract":"

    Prepares Atom.Service for a network call.

    ","parent_name":"Atom"},"Classes/Atom.html#/s:4AtomAAC27didFailToRefreshAccessTokenSo18NSNotificationNameavpZ":{"name":"didFailToRefreshAccessToken","abstract":"

    Posted when Atom fails to refresh access token.

    ","parent_name":"Atom"},"Classes/Atom/AuthenticationMethod.html":{"name":"AuthenticationMethod","abstract":"

    List of authentication methods a client can choose from for Atom configuration.

    ","parent_name":"Atom"},"Classes/Atom/AuthorizationEndpoint.html":{"name":"AuthorizationEndpoint","abstract":"

    Model object representing the location of the authorization server.

    ","parent_name":"Atom"},"Classes/Atom/BaseURL.html":{"name":"BaseURL","abstract":"

    Model object representing base URL composed from URL scheme and host.

    ","parent_name":"Atom"},"Classes/Atom/BasicCredential.html":{"name":"BasicCredential","abstract":"

    The BasicCredential type declares an object used by Atom in network requests that require basic authentication. Before","parent_name":"Atom"},"Classes/Atom/ClientCredential.html":{"name":"ClientCredential","abstract":"

    The ClientCredential type declares an object used by Atom for automated refreshing of the access token.","parent_name":"Atom"},"Classes/Atom/HeaderItem.html":{"name":"HeaderItem","abstract":"

    A single name-value pair for specifying HTTP header value modeled after URLQueryItem.

    ","parent_name":"Atom"},"Classes/Atom/Method.html":{"name":"Method","abstract":"

    List of primary HTTP methods.

    ","parent_name":"Atom"},"Classes/Atom.html#/s:4AtomAAC9QueryItema":{"name":"QueryItem","abstract":"

    A single name-value pair from the query portion of a URL.

    ","parent_name":"Atom"},"Classes/Atom/Response.html":{"name":"Response","abstract":"

    The metadata associated with the response to a URL load request, independent of protocol and URL scheme.

    ","parent_name":"Atom"},"Classes/Atom/TokenCredential.html":{"name":"TokenCredential","abstract":"

    The TokenCredential type declares an object used by Atom in network requests that require bearer authentication.

    ","parent_name":"Atom"},"Classes/Atom/URLPath.html":{"name":"URLPath","abstract":"

    Model object representing URL path.

    ","parent_name":"Atom"},"Classes/Atom/Service.html":{"name":"Service","abstract":"

    Service is a public facing class responsible for managing","parent_name":"Atom"},"Classes/Atom/ServiceConfiguration.html":{"name":"ServiceConfiguration","abstract":"

    Model object representing Service configuration.

    ","parent_name":"Atom"},"Classes/Atom.html":{"name":"Atom","abstract":"

    The lightweight & delightful networking library.

    "},"Classes.html":{"name":"Classes","abstract":"

    The following classes are available globally.

    "},"Enums.html":{"name":"Enumerations","abstract":"

    The following enumerations are available globally.

    "},"Extensions.html":{"name":"Extensions","abstract":"

    The following extensions are available globally.

    "},"Protocols.html":{"name":"Protocols","abstract":"

    The following protocols are available globally.

    "}} \ No newline at end of file +{"Structs/URLPath.html#/s:4Atom7URLPathVyACSSKcfc":{"name":"init(_:)","abstract":"

    Creates a URLPath instance given the provided parameter(s).

    ","parent_name":"URLPath"},"Structs/TokenCredential.html#/s:4Atom15TokenCredentialV06accessB0SSvp":{"name":"accessToken","abstract":"

    The access token as defined in OAuth 2.0 spec.

    ","parent_name":"TokenCredential"},"Structs/TokenCredential.html#/s:4Atom15TokenCredentialV9expiresInSivp":{"name":"expiresIn","abstract":"

    The number of seconds access token is valid for.

    ","parent_name":"TokenCredential"},"Structs/TokenCredential.html#/s:4Atom15TokenCredentialV9expiresAt10Foundation4DateVvp":{"name":"expiresAt","abstract":"

    The expiration date of the access token.

    ","parent_name":"TokenCredential"},"Structs/TokenCredential.html#/s:4Atom15TokenCredentialV07refreshB0SSvp":{"name":"refreshToken","abstract":"

    The refresh token as defined in OAuth 2.0 spec.

    ","parent_name":"TokenCredential"},"Structs/TokenCredential.html#/s:4Atom15TokenCredentialV06accessB09expiresIn0E2At07refreshB0ACSS_Si10Foundation4DateVSStcfc":{"name":"init(accessToken:expiresIn:expiresAt:refreshToken:)","abstract":"

    Creates a TokenCredential instance given the provided parameter(s).

    ","parent_name":"TokenCredential"},"Structs/TokenCredential.html#/s:Se4fromxs7Decoder_p_tKcfc":{"name":"init(from:)","parent_name":"TokenCredential"},"Structs/QueryItem.html#/s:4Atom9QueryItemV4nameSSvp":{"name":"name","abstract":"

    The name of the query item.

    ","parent_name":"QueryItem"},"Structs/QueryItem.html#/s:4Atom9QueryItemV5valueSSvp":{"name":"value","abstract":"

    The value of the query item.

    ","parent_name":"QueryItem"},"Structs/QueryItem.html#/s:4Atom9QueryItemV4name5valueACSS_SStcfc":{"name":"init(name:value:)","abstract":"

    Creates a QueryItem instance given the provided parameter(s).

    ","parent_name":"QueryItem"},"Structs/HeaderItem.html#/s:4Atom10HeaderItemV4nameSSvp":{"name":"name","abstract":"

    The name of the header item.

    ","parent_name":"HeaderItem"},"Structs/HeaderItem.html#/s:4Atom10HeaderItemV5valueSSvp":{"name":"value","abstract":"

    The value of the header item.

    ","parent_name":"HeaderItem"},"Structs/HeaderItem.html#/s:4Atom10HeaderItemV4name5valueACSS_SStcfc":{"name":"init(name:value:)","abstract":"

    Creates a HeaderItem instance given the provided parameter(s).

    ","parent_name":"HeaderItem"},"Structs/ClientCredential/GrantType.html#/s:4Atom16ClientCredentialV9GrantTypeO12refreshTokenyA2EmF":{"name":"refreshToken","abstract":"

    The refresh_token grant type as defined in Sections 6.0, RFC 6749.

    ","parent_name":"GrantType"},"Structs/ClientCredential.html#/s:4Atom16ClientCredentialV9grantType2id6secretA2C05GrantE0O_S2Stcfc":{"name":"init(grantType:id:secret:)","abstract":"

    Creates a ClientCredential instance given the provided parameter(s).

    ","parent_name":"ClientCredential"},"Structs/ClientCredential/GrantType.html":{"name":"GrantType","abstract":"

    List of supported grant types by Atom.

    ","parent_name":"ClientCredential"},"Structs/BasicCredential.html#/s:4Atom15BasicCredentialV8password8usernameACSS_SStcfc":{"name":"init(password:username:)","abstract":"

    Creates a BasicCredential instance given the provided parameter(s).

    ","parent_name":"BasicCredential"},"Structs/BaseURL/Scheme.html#/s:4Atom7BaseURLV6SchemeO4httpyA2EmF":{"name":"http","abstract":"

    The hyper text transfer protocol.

    ","parent_name":"Scheme"},"Structs/BaseURL/Scheme.html#/s:4Atom7BaseURLV6SchemeO5httpsyA2EmF":{"name":"https","abstract":"

    The hyper text transfer protocol secure.

    ","parent_name":"Scheme"},"Structs/BaseURL.html#/s:4Atom7BaseURLV6scheme4hostA2C6SchemeO_SStKcfc":{"name":"init(scheme:host:)","abstract":"

    Creates a BaseURL instance given the provided parameter(s).

    ","parent_name":"BaseURL"},"Structs/BaseURL/Scheme.html":{"name":"Scheme","abstract":"

    List of supported scheme types.

    ","parent_name":"BaseURL"},"Structs/AuthorizationEndpoint.html#/s:4Atom21AuthorizationEndpointV4host4pathACSS_SStcfc":{"name":"init(host:path:)","abstract":"

    Creates a AuthorizationEndpoint instance given the provided parameter(s).

    ","parent_name":"AuthorizationEndpoint"},"Structs/AtomResponse.html#/s:4Atom0A8ResponseV12HeaderFieldsa":{"name":"HeaderFields","abstract":"

    Undocumented

    ","parent_name":"AtomResponse"},"Structs/AtomResponse.html#/s:4Atom0A8ResponseV15allHeaderFieldsSo12NSDictionaryCSgvp":{"name":"allHeaderFields","abstract":"

    All HTTP header fields of the response.

    ","parent_name":"AtomResponse"},"Structs/AtomResponse.html#/s:4Atom0A8ResponseV21expectedContentLengths5Int64VSgvp":{"name":"expectedContentLength","abstract":"

    The expected length of the response’s content.

    ","parent_name":"AtomResponse"},"Structs/AtomResponse.html#/s:4Atom0A8ResponseV4data10Foundation4DataVSgvp":{"name":"data","abstract":"

    The data returned by the server.

    ","parent_name":"AtomResponse"},"Structs/AtomResponse.html#/s:4Atom0A8ResponseV8mimeTypeSSSgvp":{"name":"mimeType","abstract":"

    The MIME type of the response.

    ","parent_name":"AtomResponse"},"Structs/AtomResponse.html#/s:4Atom0A8ResponseV10statusCodeSiSgvp":{"name":"statusCode","abstract":"

    The response’s HTTP status code.

    ","parent_name":"AtomResponse"},"Structs/AtomResponse.html#/s:4Atom0A8ResponseV17suggestedFilenameSSSgvp":{"name":"suggestedFilename","abstract":"

    A suggested filename for the response data.

    ","parent_name":"AtomResponse"},"Structs/AtomResponse.html#/s:4Atom0A8ResponseV16textEncodingNameSSSgvp":{"name":"textEncodingName","abstract":"

    The name of the text encoding provided by the response’s originating source.

    ","parent_name":"AtomResponse"},"Structs/AtomResponse.html#/s:4Atom0A8ResponseV3url10Foundation3URLVSgvp":{"name":"url","abstract":"

    The URL for the response.

    ","parent_name":"AtomResponse"},"Structs/AtomResponse.html#/s:4Atom0A8ResponseV9isFailureSbvp":{"name":"isFailure","abstract":"

    Returns true if the status code of the AtomResponse is not in 200...299 range.

    ","parent_name":"AtomResponse"},"Structs/AtomResponse.html#/s:4Atom0A8ResponseV12isSuccessfulSbvp":{"name":"isSuccessful","abstract":"

    Returns true if the status code of the AtomResponse is in 200...299 range.

    ","parent_name":"AtomResponse"},"Structs/AtomResponse.html#/s:4Atom0A8ResponseV7successACvpZ":{"name":"success","abstract":"

    Returns default, success response where status code is 200.

    ","parent_name":"AtomResponse"},"Structs/AtomResponse.html":{"name":"AtomResponse","abstract":"

    The metadata associated with the response to a URL load request, independent of protocol and URL scheme.

    "},"Structs/AuthorizationEndpoint.html":{"name":"AuthorizationEndpoint","abstract":"

    Model object representing the location of the authorization server.

    "},"Structs/BaseURL.html":{"name":"BaseURL","abstract":"

    Model object representing base URL composed from URL scheme and host.

    "},"Structs/BasicCredential.html":{"name":"BasicCredential","abstract":"

    The BasicCredential type declares an object used by Atom in network requests that require basic authentication. Before"},"Structs/ClientCredential.html":{"name":"ClientCredential","abstract":"

    The ClientCredential type declares an object used by Atom for automated refreshing of the access token."},"Structs/HeaderItem.html":{"name":"HeaderItem","abstract":"

    A single name-value pair from the header portion of a request.

    "},"Structs/QueryItem.html":{"name":"QueryItem","abstract":"

    A single name-value pair from the query portion of a URL.

    "},"Structs/TokenCredential.html":{"name":"TokenCredential","abstract":"

    The TokenCredential type declares an object used by Atom in network requests that require bearer authentication.

    "},"Structs/URLPath.html":{"name":"URLPath","abstract":"

    Model object representing URL path.

    "},"Protocols/TokenCredentialWritable.html#/s:4Atom23TokenCredentialWritableP05tokenC0AA0bC0Vvp":{"name":"tokenCredential","abstract":"

    Returns conforming type as TokenCredential.

    ","parent_name":"TokenCredentialWritable"},"Protocols/RequestableItem.html#/s:4Atom15RequestableItemP4nameSSvp":{"name":"name","abstract":"

    The name of the requestable item.

    ","parent_name":"RequestableItem"},"Protocols/RequestableItem.html#/s:4Atom15RequestableItemP5valueSSvp":{"name":"value","abstract":"

    The value of the requestable item.

    ","parent_name":"RequestableItem"},"Protocols/RequestableItem.html#/s:4Atom15RequestableItemP4name5valuexSS_SStcfc":{"name":"init(name:value:)","parent_name":"RequestableItem"},"Protocols/ClientCredentialConvertible.html#/s:4Atom27ClientCredentialConvertibleP06clientC0AA0bC0Vvp":{"name":"clientCredential","abstract":"

    Returns conforming type as ClientCredential.

    ","parent_name":"ClientCredentialConvertible"},"Protocols/BasicCredentialConvertible.html#/s:4Atom26BasicCredentialConvertibleP05basicC0AA0bC0Vvp":{"name":"basicCredential","abstract":"

    Returns conforming type as BasicCredential.

    ","parent_name":"BasicCredentialConvertible"},"Protocols/Requestable.html#/s:4Atom11RequestableP11headerItemsSayAA10HeaderItemVGSgvp":{"name":"headerItems","abstract":"

    The array of header items to apply to a URLRequest.

    ","parent_name":"Requestable"},"Protocols/Requestable.html#/s:4Atom11RequestableP6methodAA10HTTPMethodOvp":{"name":"method","abstract":"

    The HTTP method to apply to a URLRequest.

    ","parent_name":"Requestable"},"Protocols/Requestable.html#/s:4Atom11RequestableP10queryItemsSayAA9QueryItemVGSgvp":{"name":"queryItems","abstract":"

    The array of query items to apply to a URL.

    ","parent_name":"Requestable"},"Protocols/Requestable.html#/s:4Atom11RequestableP22requiresAuthenticationSbvp":{"name":"requiresAuthentication","abstract":"

    The Bool indicating whether or not authorization header should be applied","parent_name":"Requestable"},"Protocols/Requestable.html#/s:4Atom11RequestableP7baseURLAA04BaseD0VyKF":{"name":"baseURL()","abstract":"

    The base url to initialize URLRequest with.

    ","parent_name":"Requestable"},"Protocols/Requestable.html#/s:4Atom11RequestableP4pathAA7URLPathVyKF":{"name":"path()","abstract":"

    The URL path to append to a base URL.

    ","parent_name":"Requestable"},"Protocols/Requestable.html":{"name":"Requestable","abstract":"

    The Requestable protocol declares an interface used for initializing network request object.

    "},"Protocols/BasicCredentialConvertible.html":{"name":"BasicCredentialConvertible","abstract":"

    The BasicCredentialConvertible protocol declares an interface used for converting conforming type to BasicCredential.

    "},"Protocols/ClientCredentialConvertible.html":{"name":"ClientCredentialConvertible","abstract":"

    The ClientCredentialConvertible protocol declares an interface used for converting conforming type to ClientCredential.

    "},"Protocols.html#/s:4Atom5ModelP":{"name":"Model","abstract":"

    The Model protocol declares an interface used as a generic constraint on Service methods.

    "},"Protocols/RequestableItem.html":{"name":"RequestableItem","abstract":"

    The RequestableItem protocol declares an interface used for specifying HTTP header values & request queries.

    "},"Protocols/TokenCredentialWritable.html":{"name":"TokenCredentialWritable","abstract":"

    The TokenCredentialWritable protocol declares an interface used for reading from / writing to TokenCredential.

    "},"Extensions/URLSessionTaskMetrics.html#/c:@CM@Atom@@objc(cs)NSURLSessionTaskMetrics(py)debugDescription":{"name":"debugDescription","abstract":"

    Returns a textual representation of this instance, suitable for debugging.

    ","parent_name":"URLSessionTaskMetrics"},"Extensions/URLSessionTask.html#/c:@CM@Atom@@objc(cs)NSURLSessionTask(py)debugDescription":{"name":"debugDescription","abstract":"

    Returns a textual representation of this instance, suitable for debugging.

    ","parent_name":"URLSessionTask"},"Extensions/URLResponse.html#/s:So13NSURLResponseC4AtomE9isFailureSbvp":{"name":"isFailure","abstract":"

    Returns true if the status code of the HTTPURLResponse is not in 200...299 range.

    ","parent_name":"URLResponse"},"Extensions/URLResponse.html#/s:So13NSURLResponseC4AtomE12isSuccessfulSbvp":{"name":"isSuccessful","abstract":"

    Returns true if the status code of the HTTPURLResponse is in 200...299 range.

    ","parent_name":"URLResponse"},"Extensions/URLResponse.html#/c:@CM@Atom@@objc(cs)NSURLResponse(py)debugDescription":{"name":"debugDescription","abstract":"

    Returns a textual representation of this instance, suitable for debugging.

    ","parent_name":"URLResponse"},"Extensions/URLRequest.html#/s:10Foundation10URLRequestV4AtomE16debugDescriptionSSvp":{"name":"debugDescription","abstract":"

    Returns a textual representation of this instance, suitable for debugging.

    ","parent_name":"URLRequest"},"Extensions/Array.html#/s:s30ExpressibleByDictionaryLiteralP010dictionaryD0x3KeyQz_5ValueQztd_tcfc":{"name":"init(dictionaryLiteral:)","parent_name":"Array"},"Extensions/Array.html":{"name":"Array","abstract":"

    Adds the ability to specify an array as the expected decoded type.

    "},"Extensions.html#/s:10Foundation4DataV":{"name":"Data","abstract":"

    Conforming Data type to Model protocol allows it to be used where Model is expected.

    "},"Extensions/URLRequest.html":{"name":"URLRequest"},"Extensions/URLResponse.html":{"name":"URLResponse"},"Extensions/URLSessionTask.html":{"name":"URLSessionTask"},"Extensions/URLSessionTaskMetrics.html":{"name":"URLSessionTaskMetrics"},"Enums/HTTPMethod.html#/s:4Atom10HTTPMethodO6deleteyA2CmF":{"name":"delete","abstract":"

    Use for deleting a resource identified by a URI.

    ","parent_name":"HTTPMethod"},"Enums/HTTPMethod.html#/s:4Atom10HTTPMethodO3getyA2CmF":{"name":"get","abstract":"

    Use for reading (or retrieving) a representation of a resource.

    ","parent_name":"HTTPMethod"},"Enums/HTTPMethod.html#/s:4Atom10HTTPMethodO5patchyAC10Foundation4DataVcACmF":{"name":"patch(_:)","abstract":"

    Use for modifying capabilities.

    ","parent_name":"HTTPMethod"},"Enums/HTTPMethod.html#/s:4Atom10HTTPMethodO4postyAC10Foundation4DataVcACmF":{"name":"post(_:)","abstract":"

    Use for creating new resources.

    ","parent_name":"HTTPMethod"},"Enums/HTTPMethod.html#/s:4Atom10HTTPMethodO3putyAC10Foundation4DataVcACmF":{"name":"put(_:)","abstract":"

    Use for replacing a resource.

    ","parent_name":"HTTPMethod"},"Enums/AuthenticationMethod.html#/s:4Atom20AuthenticationMethodO5basicyAcA15BasicCredentialVcACmF":{"name":"basic(_:)","abstract":"

    Atom will apply basic authorization header to a request on behalf of the client.

    ","parent_name":"AuthenticationMethod"},"Enums/AuthenticationMethod.html#/s:4Atom20AuthenticationMethodO6beareryAcA21AuthorizationEndpointV_AA16ClientCredentialVAA05TokenH8Writable_ptcACmF":{"name":"bearer(_:_:_:)","abstract":"

    Atom will manage access token expiration and apply authorization header to a request on behalf of the client.

    ","parent_name":"AuthenticationMethod"},"Enums/AuthenticationMethod.html#/s:4Atom20AuthenticationMethodO4noneyA2CmF":{"name":"none","abstract":"

    Application will manage its own authorization headers.

    ","parent_name":"AuthenticationMethod"},"Enums/RequestableError.html#/s:4Atom16RequestableErrorO14invalidBaseURLyA2CmF":{"name":"invalidBaseURL","abstract":"

    Base URL failed validation. Most probable cause is invalid URL host.

    ","parent_name":"RequestableError"},"Enums/RequestableError.html#/s:4Atom16RequestableErrorO10invalidURLyA2CmF":{"name":"invalidURL","abstract":"

    URLComponents initialization with provided URL string failed.

    ","parent_name":"RequestableError"},"Enums/RequestableError.html#/s:4Atom16RequestableErrorO14invalidURLPathyA2CmF":{"name":"invalidURLPath","abstract":"

    URL path failed validation.

    ","parent_name":"RequestableError"},"Enums/AtomError.html#/s:4Atom0A5ErrorO7decoderyACs0B0_pcACmF":{"name":"decoder(_:)","abstract":"

    Decoder failed to decode data.

    ","parent_name":"AtomError"},"Enums/AtomError.html#/s:4Atom0A5ErrorO4datayACs0B0_pcACmF":{"name":"data(_:)","abstract":"

    Failed to initialize Data instance from URL.

    ","parent_name":"AtomError"},"Enums/AtomError.html#/s:4Atom0A5ErrorO11requestableyAcA011RequestableB0OcACmF":{"name":"requestable(_:)","abstract":"

    Failed to initialize URLRequest with Requestable instance.

    ","parent_name":"AtomError"},"Enums/AtomError.html#/s:4Atom0A5ErrorO8responseyAcA0A8ResponseVcACmF":{"name":"response(_:)","abstract":"

    Service returned invalid response where the status code is not in 200...299 range.

    ","parent_name":"AtomError"},"Enums/AtomError.html#/s:4Atom0A5ErrorO7sessionyACs0B0_pcACmF":{"name":"session(_:)","abstract":"

    URLSession failed with error.

    ","parent_name":"AtomError"},"Enums/AtomError.html#/s:4Atom0A5ErrorO10unexpectedyA2CmF":{"name":"unexpected","abstract":"

    Unexpected, logic error.

    ","parent_name":"AtomError"},"Enums/AtomError.html#/s:4Atom0A5ErrorO7unknownyA2CmF":{"name":"unknown","abstract":"

    Unknown error occurred.

    ","parent_name":"AtomError"},"Enums/AtomError.html#/s:4Atom0A5ErrorO22isAuthorizationFailureSbvp":{"name":"isAuthorizationFailure","abstract":"

    Returns Bool indicating whether the error is due to an invalid or expired access token.

    ","parent_name":"AtomError"},"Enums/AtomError.html#/s:4Atom0A5ErrorO27isAccessTokenRefreshFailureSbvp":{"name":"isAccessTokenRefreshFailure","abstract":"

    Returns Bool indicating whether the error is due to a failed attempt to refresh an access token.

    ","parent_name":"AtomError"},"Enums/AtomError.html#/s:4Atom0A5ErrorO15decodeIfPresent2asxSgxm_tKSeRzlF":{"name":"decodeIfPresent(as:)","abstract":"

    Convenience method for decoding error object or message returned by the service.

    ","parent_name":"AtomError"},"Enums/AtomError.html":{"name":"AtomError","abstract":"

    List of all possible error cases thrown by Atom framework.

    "},"Enums/RequestableError.html":{"name":"RequestableError","abstract":"

    List of all possible error cases thrown when conversion from Requestable to URLRequest fails.

    "},"Enums/AuthenticationMethod.html":{"name":"AuthenticationMethod","abstract":"

    List of authentication methods a client can choose from for Atom configuration.

    "},"Enums/HTTPMethod.html":{"name":"HTTPMethod","abstract":"

    List of primary HTTP methods.

    "},"Classes/ServiceConfiguration/Configuration.html#/s:4Atom20ServiceConfigurationC0C0O10backgroundyAESScAEmF":{"name":"background(_:)","abstract":"

    The background session configuration is suitable for transferring data files while the app runs in the background.

    ","parent_name":"Configuration"},"Classes/ServiceConfiguration/Configuration.html#/s:4Atom20ServiceConfigurationC0C0O7defaultyA2EmF":{"name":"default","abstract":"

    The default session configuration that uses a persistent disk-based cache.

    ","parent_name":"Configuration"},"Classes/ServiceConfiguration/Configuration.html#/s:4Atom20ServiceConfigurationC0C0O9ephemeralyA2EmF":{"name":"ephemeral","abstract":"

    Ephemeral configuration doesn’t store caches, credential stores, or any session-related data on disk (RAM only).

    ","parent_name":"Configuration"},"Classes/ServiceConfiguration/Configuration.html":{"name":"Configuration","abstract":"

    List of supported session configurations.

    ","parent_name":"ServiceConfiguration"},"Classes/ServiceConfiguration.html#/s:4Atom20ServiceConfigurationC09MultipathB4Typea":{"name":"MultipathServiceType","abstract":"

    Undocumented

    ","parent_name":"ServiceConfiguration"},"Classes/ServiceConfiguration.html#/s:4Atom20ServiceConfigurationC20authenticationMethod13configuration7decoder13dispatchQueue09multipathB4TypeAcA014AuthenticationE0O_AC0C0O10Foundation11JSONDecoderCSo03OS_H6_queueCSo021NSURLSessionMultipathbK0Vtcfc":{"name":"init(authenticationMethod:configuration:decoder:dispatchQueue:multipathServiceType:)","abstract":"

    Creates a ServiceConfiguration instance given the provided parameter(s).

    ","parent_name":"ServiceConfiguration"},"Classes/ServiceConfiguration.html#/init(authenticationMethod:configuration:decoder:dispatchQueue:)":{"name":"init(authenticationMethod:configuration:decoder:dispatchQueue:)","abstract":"

    Creates a ServiceConfiguration instance given the provided parameter(s).

    ","parent_name":"ServiceConfiguration"},"Classes/Service.html#/s:4Atom7ServiceC6resume9expecting7Combine12AnyPublisherVyxAA0A5ErrorOGxm_tAA5ModelRzlF":{"name":"resume(expecting:)","abstract":"

    Creates and resumes URLRequest initialized from Requestable.

    ","parent_name":"Service"},"Classes/Service.html#/s:4Atom7ServiceC6resume7Combine12AnyPublisherVyAA0A8ResponseVAA0A5ErrorOGyF":{"name":"resume()","abstract":"

    Creates and resumes URLRequest initialized from Requestable.

    ","parent_name":"Service"},"Classes/Service.html#/s:4Atom7ServiceC6resume9expecting10completionyxm_ys6ResultOyxAA0A5ErrorOGctAA5ModelRzlF":{"name":"resume(expecting:completion:)","abstract":"

    Creates and resumes URLRequest initialized from Requestable.

    ","parent_name":"Service"},"Classes/Service.html#/s:4Atom7ServiceC6resumeyyys6ResultOyAA0A8ResponseVAA0A5ErrorOGcF":{"name":"resume(_:)","abstract":"

    Creates and resumes URLRequest initialized from Requestable.

    ","parent_name":"Service"},"Classes/Atom.html#/s:4AtomAAC3logSbvp":{"name":"log","abstract":"

    A Bool indicating whether or not all service requests should be logged to the console.

    ","parent_name":"Atom"},"Classes/Atom.html#/s:4AtomAAC20serviceConfigurationAbA07ServiceC0C_tcfc":{"name":"init(serviceConfiguration:)","abstract":"

    Creates a Atom instance given the provided parameter(s).

    ","parent_name":"Atom"},"Classes/Atom.html#/s:4AtomAAC21cancelAllSessionTasksyyF":{"name":"cancelAllSessionTasks()","abstract":"

    Cancels all currently running and suspended tasks.

    ","parent_name":"Atom"},"Classes/Atom.html#/s:4AtomAAC7enqueueyAA7ServiceCAA11Requestable_pF":{"name":"enqueue(_:)","abstract":"

    Prepares Service for a network call.

    ","parent_name":"Atom"},"Classes/Atom.html#/s:4AtomAAC27didFailToRefreshAccessTokenSo18NSNotificationNameavpZ":{"name":"didFailToRefreshAccessToken","abstract":"

    Posted when Atom fails to refresh access token.

    ","parent_name":"Atom"},"Classes/Atom.html":{"name":"Atom","abstract":"

    The lightweight & delightful networking library.

    "},"Classes/Service.html":{"name":"Service","abstract":"

    Service is a public facing class responsible for managing"},"Classes/ServiceConfiguration.html":{"name":"ServiceConfiguration","abstract":"

    Model object representing Service configuration.

    "},"Classes.html":{"name":"Classes","abstract":"

    The following classes are available globally.

    "},"Enums.html":{"name":"Enumerations","abstract":"

    The following enumerations are available globally.

    "},"Extensions.html":{"name":"Extensions","abstract":"

    The following extensions are available globally.

    "},"Protocols.html":{"name":"Protocols","abstract":"

    The following protocols are available globally.

    "},"Structs.html":{"name":"Structures","abstract":"

    The following structures are available globally.

    "}} \ No newline at end of file diff --git a/Documentation/docsets/Atom.docset/Contents/Resources/docSet.dsidx b/Documentation/docsets/Atom.docset/Contents/Resources/docSet.dsidx index 5fa8c2a5584a23d1bc675da4d95ae76287a08868..b6e02df663673cfc21a2650f3e840571b25d365b 100644 GIT binary patch literal 36864 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 GJNv((apR%@ diff --git a/Documentation/docsets/Atom.tgz b/Documentation/docsets/Atom.tgz index bccf1fa72c97c1a8ed46f9700cb6b2a6ac74e219..6996c07407551df2caa3293f1624e344baf576fc 100644 GIT binary patch literal 103609 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�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%0DY-4uRLB;ua5G>T8NzG$;OHG z^=LVUjq_=tj#q&dC4bVh*+|_+Rn8E9V&>1Km`CB|^L^Dk)Eb!DFWwlFYOHQ67Frgf zlvu)H_B_gtra~{oP^Iw8w=doB zgIPquEcEKAF|EppomV@HBbjD`agy`nw#`F^wnrooa%kU;CZag#!!g- zuz8I!SPaK*Uj*bHN$ZPEvU;YV3i#iojUy(LJe65fNe2EmnMhTWi1k{>;jr#&poi4G zIMhQifkc6wWPPI><#X;Q4T!dBUZRm72ioB46 z8I;F(n+=qqV-+(wx)>z}u!>Qk!#53epO)rbPwisTO{3v{aKsF^Cdr7Uf+x43GxFZI z6)obhuew$6n7u%^ivMGK!QA+*elS1y(I^JX=50jWcA38sUz)}jCn#09q9vh`Rol|n z59x4b3!LoLVtv9cs<@7}rVMJ4SHx2_2f%ZKXH3aX_bgc?t-#P!yBaM zRY~cv(&2G|so)bxz%Gf!nIy_O;YPIl48N_UNiTmQ%sXo*qt#>QgW5ViJES;cZ|3E+ z%j`YKN>sGL8EWifxJFj}KiomG)LkXtUO1?abi>|RF|y?CM>#20XBO?yw`w)XS>p7w z=k^4TKeNYaj&T5WI4t)xtF&{#UtxsUYOO}k8@~5BzuiQIM5~O+n)iR(d)M{0ab!_+ z{mxS`n(Rbs)4JGBoXBRf+__9=t?ncfXS(-39#4jnD2pA6)bL_kiM_x54*S=7g>&9& zJ;|vmTnLaLB{`0h^vKa&z`<2PVHIgWb92-%B0ir9UNRo6iikh-zsC(qe7xgIW%r7b)Z%(vKUM<>gp z1*NDw!L)GSzIY_VPYS?!$}-Rm`}if|lmxRPa_dRs8jSe`@M61H4KO2J1!|245{atu zS9ysrp;5diN9}N-=t%Rzz#B)g*JL}~USm;}2C6D`)~RD+nR&m7OYEoarv(DONs9 za3B7CKHo4zcr-xdp8U|f=wvguiIUX}r&8#8*={w4TMmz#Wh!F;LB$qa8_R~X(w!kp zFFrf!$=E923YS}=7=~C}EAmT3PD7v1c6rSj^DT_cb2SE*l^Mz>>h&@N?1}7PW1I<5 zDJM;#6n|4$l17Ts`X|am9#GmGp9KFD`sTANQAqB-`XfU#^Zt`zIhNRzuCjJ07f2Au z8l6YSt%ASm$FQ(?ijX>W-6^m`;B}i-q_@pyUNn|ciW&7;O#a3qk1SodC<@X734?#; zdsu4MM1?As)XHS3C6sJ4QdN50a=m)967dT0F&H&#f=uN6SCOgqM3nSF&EMopismpq zHyvV{dg&yhL)VqZ%8J{3f<%krSptX}xQ6EQ2n8G^#SxIDELi+Q1CLn7V}4u?QYa3x z(Qm6r+5E8(#NO;TS$)_!3Pv`a?6w7Q^Y`$MF0dJg?X=umbR4{R`u*$-gG;38Cj2Oz zc1Ho8u$T0+@LJZuvdG8$K)llEoDcNs^N8`<1!p1=kH?815>O3Ex{eh+|iV zgHBp}exnTihUfXRcsVj!NfR&8Hh9 zd(1Gv{GEv(3MX%jZ$o|xKT+B!Kj3IvLMYl62f+%k2rhQs)$Azy(@J(ucDu-Sxy0sI5Y)z zt@g}~=`LV-pSxZyqcBs|hS!FSd zmPV*Lk6`0|KJiw=6ARnEdd|B#f9@oS1@foWJB&+_k-P{SvaXb0Q5)pXFTbTuH!zsC z((x}%pUc31{3wQ^omBdjD!b_F{_bMEAOEB&=*Dq98^BPzc zX$kClv0l{~AwOn#Z9J84(JQ;#E4A_qctxz-KULuv7NEYEt*+oMusU;jUkd$Iw$Eu* z4==Bcvk(~PE7Q*7g0_`Wx$5-;t9D1#_WI{^#0p``RzVmd&81?dMiQUC-h!py+=a(Qz{mz(IzcW^##}^?% zX_xNWNpPyUD&Wc=H1=Q3ei3p%uv{Z;^GNF+caE+c-B%+F{>jb5w(zQ0&3L7{a2se@ z>uk1~2%{ox?r0*sM>uV-hICoHQK9;Yex;2La|`o@#+}NrV+_qxFBaCIMN7llc-|JOqQ+gPkaM{Jf4!31P!+T3wX}1C{c?9iE~ZC2jGji} z7|=`=(pY(Fi91U4jDo^i%h*2(2C^2;WFXIx$x0W0V>&Z%FWjRl8lshjaG8IaD)!Zj z=@#v7k4;=(AhYspxR`l?VYkpCahZj1x{E?jjbcDHN`A`#*~9r2P2{qmTY1@QOab}$ zqdWX?663Y!hv^*e)8H*ZBV{x*7-M2+ZxjX~FL2AXYz7f`D)-rxS0D(->VUf@SRwj6 z%mR1lO@LjzxY5$CmTKfTG&6UGGCs-73xeUq!^?UbRHY$ibm|W1b|SoxXq7H9+pml4 zSmYGitTV;sANjE`s3})b87^YiwJ@!O<~?M(!(E|=Rxp2IEQY;bEP-i_Rwcod#vA#N zandp!XJQq-o)o6^GK|}0V$v2xF%?7F0o_VbBdsBwXKA9B+-3D}tK|{nAS$cK9ALQ( z16lZhb{J7$_vzjt3Zk07-gM=AQxE1DpVEZ{CJ1;{!Gf|;fSRtcFutlU{c`G_c;?bR zzN#<%I`&We&|EyCclG7p$h#>_5X8+D^)TLgAk!=8AJe<~@`tpOZYrI?o8n-qWh`A+ zGWd3oIaq8j>730r!c7L`;`mkeU|DXtOU18{!V#T^(lKwV@%?7ABvci5^3jD?ruiEE z1pW$AdhCbZi1}SV5lAW129?$&6(rGF$C~+<+N#2OW|-JZuaI7)M66PurpiK3ub84D zh)v4sb&nvQ#~cj+R00feK$m{psou|&kQqufK1F37Q})FNzngfByVcT4zR)P?s*4@> zAIv$Epj=!~5)bA^X@!m;tAGFiolJSeI*&X;jGCi%85;sA`ZaRbo)*#odjH?nf8X-o zK^jflqi6^V;0`P+Qe3HY-g-%t#X~RYJmawelg{t(zx(my9ORH24=3&4lcnqEcDoOD zb}anfeQ=+?yIbrT|F(CxdRA|H_rY#=YjjjnhAlrCc1BbQ6lHcFS-yLQBhLVRCY}y*EdG81(liauM_#TN8$~lf=ym>t@!KbdI zc@JOZIT_dd_3h7?8(*GJ)nY7a{W}kIY}}Y&H^2zl$R!a=Y~%6;Yq``Q zya0gzX)uaF_S9qx+-NCS<{Dm+B zNWv*Sh^yLr6qxd!;j(Vtd19?`FNj>cW{meBnjkg*l_K7tb_* z?jibVa4r!y#0FVd5mA#&lCd{#-pk_Po-(s>TcsC_n)i?-RqtGkX9&EfzK4ccO@_x2 zfVD9&>ai7#t=EI!LGx+@nPVRo77F_MY|W0jjz-N-P`qyu3`C-jkccI0OH|C##FJ?W zd?_fZb&mYilm%22q_1GvG@$rUY^&+2uLPFK5wVR`1pd^Ati7%Zgb&z$apbCbQl6Id ztxwAM>>I|aZXacnk#ZvwKkSkiu0>=07Yq-nlf;RRti z53;K!a~AxkF?>lIbi-*=RB1!w22qp{iMmD`X}N^K1}kBhyj;%wU^H~&QJ=<0oAkc6 zNNm4*d+_q-m#_Z3&|rJnYERu+-acJI=6`e?F&awZAnzY>`2(ZyxY$HwZQy>$pJyuO z;Svb4)-M>alR09#3ALZxX|NS7$STWA_WG(JZu7!l8xDr zn_b)5Y)HKbmbYSou~!nU&3n1aI2(1UkOcvu_raMTj-s=65Di^^ph;jMCjcO{KotM2 zIRCGr{}Hc&7+FR4!@qj{Z?|{9yIauzcDC;Cto6T}`0M=e!!7Fv5+l~8HA&N1ze64U zd(s|8Q%F0o20lns|AS{8MnP;_gDkbC83@;8>IQ)q(~Wy!lv-|L4Jh_Jl-g=l>FHoWjBvf zVh7z8z4ni2#rNVpp%}Jj{>%&fkgfo3dN{zRQ!lnzEXv=ac=UqoDwN>itCk(}h0Pni zsC=KYoub&LytHr7Y+deoZD>jYI5`b!asyyysUIZHr%Um(edfktj=b0UR6O1T?eW?; z5k-M__b&fI#q=l0czMZpQ3P<82hB27a2mndzUw%ScX5HMbo}+C(dc_@pA!QzwQ@9R zLqh}OkDH>{#YGORCA|6eK+rZxlXke0G>kpewaGc!jzuckYyh6^JKa5hU)W#v{EZFP zk)abG`NwwRct_#!9@I)_RpgnKq}58{g_Cf3+uFk|ImAvJ?z`>qqkqZWyN!@82-4GF zIt5)mR1#b11n-9wj<3(zEk{HH%TI`*N1i9{lk`|hlFepOoI)v#0BuFoJiG~s;dgl{ z6lnTQ2csdB zk1>X;7?8!wRJ zPR=JE112Y^vl~V|v?B{qvo^m2fs(p@nDk53hRQ`%6v@$8j|7D%Ub&{8tSM&$k=-E4 zZr?5t>$qH8;#%f^V7?Hf%Mr+q%?-8K4S6 zvP=@{9E}{JDJ2>_(I5K-8a%-k_4C@)hG|{X!fpg@RnL*XZV{UPNSBI2PIV<^d~CYc zYP=`G1#;Vm5g%{pGYU)^Evaj>iKLls#vASXtxl7^ggE-eO(&p6pEP?L^b=Oz&5+^p zF8bhw1#GBEAQ^DpYcyrpj0B9=4j&hsk?;MS$_^IQ*EO4F4E>!CJ)FgIEvQg1bbQWNBsOdqr?yLD)d}-ann5mDHN*#LGiup^ z6K%TKsH{x^7@G=VK)IZ`v71J5>*6AEoREkUJnk|;L#K!-ve@3REjCP@Bi9a&?ID}S zokSwX(<}G2G_}C z+t5r>xy%x|_T(UivGiQ?0plfnXAx;>^xyUsC7dhZPu&n3iilXS3^n&+3UZwmXg-W+ zJJyf)Br%9Tom zx}TDI@8{aRf!26kj~qBJFan>y;qtLJ}|7y)ueW>vXV?U1mp_@6%H5fs1C*Z>0XTUjWTWJIgjFFn5vF&<=ov%_T{=G z5i?Ze_@E^vkO9^xdwf2=?KsihyKF*czZ(twZj~nFsMQkn;_T<{N1_H7Y6ux?M@Q~4 zTajBLrFH2!;bpE^RMDceUPYE+t<-c8NZwObA}HD<-A~gJ6kSHOZ&Y`9qOSF7XE;^I z!_BQK4UczVh4Qk3{9uy>!~IwC`_cG@$9r;5LO;z$9%v`}A{EqD)&f>m!Cz<;FQSb4>HW_6&{Bie+Em_pg)3p5(aA^}#dsG#O#ZDvnqcz(<#PL^=CjtF%92XgW1M@+r`~dl|Z!njQIdYL_Y)Ily{lEpacV4-2 zgtkIbhb`CyiJGvsFtdFck91eANSK_$PXhDN<6wpi z%n*MfW$+i&jM-Sl048=CM}K!cKgy0F8$8hOIXuAV*bwjL$3HZ1jBN1t_!v2jzc(8j z;YOqNq_L4~gfK7)DI1L@e#7IP28^fTTPzc3slGjQl=~Q9xjRvxvz9$lpWT){R-a)( zI&(UIZ?-p{w3@|jv;qbUd!Bp;7kfBReSPNQZ2Ma%McY@IJjd3HWO#!Mf0m4f=MIRHPD zcyQjn;9tnj7s$sK$iRRNJOR^Q5Wijkr(O`3UU2@r5T8+eLEL!38S#R%;00&C3u3zq z;2unXd?3uG&Vc!8j>$j>?c0ix?6;_wke)(Z@HaN*;J z8>SaDz%S?n|3%paqKWk&WIzv5#?~U-LEftuDc}=@nEFO`B0RivIza&6ua_bI%UqfW z^%Tv?c4WJDW(Tx?BCNvOV)~0QIdSCOsa;qU*o}F^aT3yP5)f*CMVDb_aoSKWS#7~+ znZfv&+fh69k`!uv5oP*Hh5P#a5y03$#qaz50xjw2MKJn|c?z~K@FLipN3%bz5UXvhZcQu3;w ze;%YXhx9YhXRrjc$e9$utk5wVgo+C=+#(FZ;?0s6xXuXr^0nQRs9anq5N~JVw*)UD zD>(0{`Y7*Bm5a@NUmQ4!sa792@ug5CjH^N(1otKGqSu-u^PPXY!GAQczzN937(g6q zegp=i0fHQ5&;WfAAus`r$4PBac0OIUOc+C7z!E4uQWvtvw{b@%f0n!OmzO2a2B!+u z=263K*bSF71o(=w6u*aYlqC2A%~1Fq1oSzL5_%sb5q?eSBMMLOJEV^hea`VSCXfUM z3k^K_AbTYJ^035!DjZ;eA%Pf@0SA9XS%A<+o{K1qe0qrJ!$YW^pH2unk4_ji@N5qM zLU5p~;%6KomM0#9JR!gncSN5FeWIS!n6QtSebNhmN}u!_R&(^pYw+>k7(YV#ND(Q@ z>8JF8KY!1NRDtL6Z~F8F6s9H%aQV%iklU+|lec*=@T@qH*;8b7B`aHw;zzHldafz-8Ap)O>dP3w#CcFa@pOoJQ^?4Ezw&{dA3%*kN zVrd?p>%;FU`(jzVn7>W<_nf|nU@7~I=z~7bs9#X2ZJfbW&%Wu?qYnah#_By|Rh&&k zsz02t?|?l=>~l(ASnZiloQ%eD{NgQ~Q|HX1jD5z93kcr+hRTkNgJzTJnPZp-G@V%Dmt*s7$hCr~39K(@iz!!dyt%iB&dFHNA09~y<0 zwAiMthAZScX6|I{rQWW+QeG#!WLDBb+p?OrWsBOj*~?pZ*|N2+>fODo0b>}g0#Tut zp;H(<9eWJ{r&mYLppKluVsZwTWt4&%S_W5a`DJkk^!V1hJt+Jg()((o%u`@K$e^}Gl;gXG=Y^crM!sf~if4?Mr3|@j&vKS5dAbGlIW*4$0+)wtx ze1i#>Fd#-kXxL_Nk1+~vCdItn(J_FC^G3QgqfHq^uB`ybU`>!!v}j5D<awi?PkWXcz3|8no8*U#2`_WziWD!+> zl)>GD3A~!@XL}Ptv615*O~{90y4lfQS0ckt+KZ<0<{ZFa7W(P5M zL`B|*k+xsLt?b(HI!p2RA-wZq>kPgu29^S7NG=5F3?ey|6G~VHE#Hxsx>I_OgAFA* z49GpLxlJDjuGkXRX(QZUB|ZCwOh?rPH+#n*9D#63OMImz`5coJdx}jud&&fnn0il0 zPdXtB1G|B;xB;3bRohR{b;wCBV|4~EqJ)l+08dD%w93`bMcY*XxU^d{$gbWt#+DYQ9zVdDQb-7 zju{$L&90k~G1WDuX0#8kARtC`hE79A%8R26c#2`ox@k{2W+mkUgBN3Xmn`u#Xnd6+ z-{FossNsNyJt;W2?+u-x4S9qK<%!nCxi?ZXU<>?D48?xHalLHykJzhYiP;D+8|@DT zMk9gI*crlfw#TwNV{+w~IYxT~ZbQx;jX865ra5Z~t(Gm~@%YtTit_*kRf3yl&v&#pXD4f1$3wTL7`Ws0_#&pygGt5Mn|W|>Is0$0rc^QO9ATyV4ds> zT=q^BrRCh2ADtZAXHI$89-SZCe{s&*%&XsC1tI%`a|S5chnhC^p=CdJ&NmvJ#>T1r zvy&fCI3#+h6sjZ;sOuAF!VXI`e{R|Gpc|5a%odUo^2A8X&OzTUgMRb&^-nKKNJKS2m-ya-#LdzgJZsrshqcZ zXP@H6<%gqp$9u9p%{Q>FczxV@f}gy^FX*aHftAkfQ~PDB|AriE*~2BGfoGD~29pHj zGQzk876E~PDK52^Q}gn&&mO^ z=k>CSlXk8)?{rO`isf~MBkU1BU8>7q@A#NIqZdx-mYHe+T&;_sM_418Edie!=Rff? z(tUYa+UAq1GO}zH7-;Jn&agfgGj(5|w?&n?=2&%z;nOAPLGXcF3YunErSYT%71OQS zsK}hc5sGFi5yZ0uywNyM@SnvaEWfg3Yw9P&bL`j#4_YCQZ+Ihqa>II>#i*cL92_na z=?MS5#)hn8qj4`kxXhq(KpzDl%%3Xxm1QNfMo9ZdAVxcASIi>21pS?8Z$^U2FVqhJ7ds9kH*K&OpGvB-QeNsdMbD))>VJsjtk2L%p#S4 zm)5Ix9w)%b_}Mq+UCYi0R2dZBgN$(SPG5dPg5zT1A(mkzf@oCd(UGmpMpeB7o$>_+ z>d?Bi;>6)|$=m$eu}uK^Q@_zmW_ zrrPqk=@d^#?3<;CK>bvZ`NT12#I@wPGm|f1$-1`$-jJ;xb;tmc%p}*3xja^2?B*+rO7X)n%t~@3a5CH?!^0JH!lHv}$t9I_OB8eb z3L+DGy--yLBWXWfR%*%xfzcvUE2ndnfel;av!>*MAk1`+%XA0%XriVaXd0Lhi$`5@xUJ0;T`S~%Yy?af7JP3=?r1V-EBXpVNF zAu|IR%|l#d{+f<~AI-uba%DnfQV#|@?alpxrr&h&?7Q_Pkdz19zBt&V*D zq1oHy^X>-!{-K$5D%c4RJhnE@TK4G=&KN&t_6a+AL}A98J#YJm(^dz*>_F(Vf3Z(m zmpGw0!DZQ2o!0SZl@FI{%`W>|l|ytGSB|X;bp=zZ4&2nqrY4ts<)Nj&5eQ?j1x5A# zR9N6LP0YBLhi_o*Jl$@gQ55+PrD3M;csYI3_updd4~2 zE@nbUXkTxu77>W-G!+|TS|}JLKnXuLEuAw&Ls99Ci^^_Zkh}>s4M2HQYTqIqWug9C zi3D^(H6HNNfC_e9EjG+{=Nh(7T(oG`)CRNa6LYdt#2V826k;8NZRdYTB-mt$U5qZm&Pj_nK)E&``$Nfdi%J? zotSC_m`@C8z*mkrSrD4EiGD>xJ3sGucy?*r^7Ez`2pPwH*d->|m2F^urSdRIRZhWdVjy>5&}LIu%67E(J52MZC`Y!iAyIq2YVubBaLjP=VN99`Jg8ULXnNQfa^J+P&C4Uog$-ql$tS$v#C~#myyP~Yh--Qb~)OQW{aoF@bDj z=70ql)ZA$lvdVaANdn5Dh;WHya0_gc_) zrs!3Iq~TO{%q;k@=9r6k1<)eyQ(4szHQ=fUa!}5NKA7A|RZx--aqMtB;2&@F z$}W3H3#Y?yvC~Ry&iqk2sag$Ut8yAv!thT*Ej*MAvWSG2lo!e^Lus|n!Hd4KS=j*; z@T;M;I~;nm^qGI+r*HK!O(eAAy-_46iM_&onUSDRqmjoB&Cm(7X8d?(_wLfv3(|TTx&YfT zy^<~~>cB6ClBUq^mAsv6u=BhRKT|zbGaSd_NN@3RHAuW5A)9(-sQGy%rP`*BuB-qR zAg{U-6bZ!x#99qnkL~585GyOMW$xKhl{t}((PXujC_Zm-D>?I#wPU&?s`Y8;0;?K_ zM_=b~wcz z!E<_YPdvO z4V1yq@~x&gQ}!1t7KMZFUPx#vk215 zFlBPk?sZw5^5m8K3Im@>F#&bqy_i&)g>jy&foFvPJ@$tyiisl2t1)OCe+k*OnB$id zL2Hix;v9dyQo3yA`2ws?o1fRr;%q~8&D(3!IFV77aMsb=vnMR{50D;OLowSJ|z3@y8{$zJ9+GUFcx`s7ZzjgK7`CH}w z*WcZbALpxH{`zlpHR|sD`&IY9cDJ`5Y!&W*-F|TY!TSE!oA~1w3{%%yj`isth0pa&h)BeO}H1k4s z&$NJtd)6cG9c68nK;qrb3R*rO^fQ2d7x5v>uwyuJ$;9eraXgx>{0HCLKzN;w^_p(r zX16VESQF@&O&A8@iD#p^Cxph$Ef^msUW!5->&>yi4E!7-Qt0LQX%HoNR+-Si{xeWn zTx`v-q>HOL9SLEe-JRw?+#}{!a_5t{__~d#@j$=0tKVx~Hje+nT5}Kt&3kO)N2e(O ztD@8%$54{rhra1g{Lu)32qbH|pJ5I}ywj|p17x|wDbS*ezp)97xcBTT;^B?qtXmLs zi%7zm1_s$M@P~i|Lkn^wxU3jv37+1B$|Mn}I?AkFE`BQc_A@$%S^RIAh*L#ub`3f- z>pwkjme2)cVw_s&u5SIFO=o1Li0CEtHLrMrm(Mz!o82^xfsT-LPxc_70|H`BUKWR` zn|h)Vr5DXlm$r2eD1rc32U@hB!}4pa231b@rS(VxA{|8qg70Tc$!YQn*Rj8zBCQh( z1_k1oh=y=Q)`pJ5&Sew=RR@L=Sg)7WeYeE9J*ePv}>B?BL<4qOi_B*1(_Xp8v z&Ox~r)5$s=Jf-B}x$#bN=8sb*8AvWPEYi1~25R^R;cybg4FK&*5X2%*!^A&oMywx@ z;=+7?aWSi(R}sr6KY_uGwR#K=J~MlYz|KVC)K#EWsMA=A(!IL+T%(aqV|z zDil!@!(lU~DE)Z`$TE)NsTD`q5Jty_<~Rf|4q~Fv*{pF$y`Tc zMHskB5r29@5Qpet(~#T<$sI~+&%zTqRPoQmAF^dL(XPCS%QOnsk|Iw6E3JX6F;5nV zmymDsB#yFKqW5~>mvU_4h$wclLLWY5atiS$jWkttZ>DbYAt`{aKmxOtavBlI=WfNY2sp{DnJ_*Ph{ZC#laCV83|jBpL}s46kkk zr=Q-vd!u2JC)`N=Z!y3C=*fe?Q#+=Z{PlSF9HxeZ&SY>#mI+^ljb-f}b^?sE5B~nr z{iRdlPo1RS>%Ktu5aQV#JaGGK<1v2S7$%*+zWtfA3a3P#aKlI>Gx+JLSg@2EMdQ#T zyWTq}mt&$Nel27`pv3+#G2+DEeYFw(2K{x1Q6R9B&tGGF%gQ@Hx`{u08haz07Tf@4 zbPQ;LUThrC>I`4FmvbDS20re&*C1Jw#JAKHY5Hox|b8n|jL1j3wM07U~pXo;Yp@ zm*PxNF+qGKY&w6A-7tNJr*`tbl4&=D)K6q|QzUbqa6=f7FO`CTe7>Rj3qs#K72FUm zFnr%&cs8lC;?p%uKkD244xlC)JNCZBn&6V(55~rdka=OXR&Oa+;y>NOQ7+1A02HT?r@vj?J0p~IfJ#u zyaQ0`ca;o41$j`^i0#2Y8Bv2D)qpxx4K^~6AYQ(IggmmzLr7~|RaHeuq4Hw2Ol4Ke z%8A;VYT@f8T=cwhhiN5v8ZQT&OMZ-^fYT2H&66n=xcO zPIdiHtp9GD{4{uUY7amCsA2qvh(;^o)c!~otn(c&b;~P zl0y;qFE?o`9Tu-BF10OeQ_<_4sT+?^-PrglJmoT#&BN*|khcBG$(zXw!%HajsS1e` zFRgl&RJ;Okm&+*$l6JK`QX`#Bv;Kl|Ce8PTXYH+SV%VEJ7#wtW#inKV>HBmz9$sx; zXS-1yA7o9_R8zlo?X&$VO{&Ig|7;LHZmpGtYg87VQs`BfHaL?q4PGb>{J7+af6BdN zXK{22f^TGDpq8nJVONq?N!!-ySj+dT$oFu}2111tZ<^9k@SDcX$}_<=IdK@_M~%nM z4OLtsTB~(4^G@AdKyQI*--rQ}EZ||X(u-D{#O{0$o!2vQntKdZ=ZWhxV3yIMEVVP6 zmd%@1aHcn1qI9KP*K;jKc)2#!_MMWCnI^>IX{a`gJO)uwACX>p4 zZBE%Bp}TNW)&>SI8bX8d2p1}w2_6}J_w)^l){ynfTGh0!rfTBBwMs?P$S0Lb)OzhM zUKvFHt``DRXWsnaK(1^L4thPsC*=L?^QHk_L-YL?Sf?+GevZR>O@8h2|4oc>P+?L2 z8Jgml!ZZr|Hr{(wHAyJ!R6Q}E`kHzLh*k#TJ-8Kx9$tNm65Bm>{eadh32^v9Bc3Mn=0;WRbRtVQukRw04vOFQCS&;fL7Om8udI^QHj53({&b?tq z+aCqG5aF^JtO2}RcwX6$vIJ&ujBmiIidA1VR@IDewtXhWD9k3taiLI~ZG%;3jO$Ls z^_IMsILT%haK)nbTLYJtEkSf9Scb9pde*((S(o$MN*12R zEHe(?vY0o&;>5FHB+MTFm1f7$br{2P>l(mQodd4TnoQ8@y84f|j@jBB`J)%0&Ap4> zdSg&VCkMkJtPa_Yp;7PQt3%MH{4sYC!01ly>Focx+QQ~nH};V+J2iD)zm@B%EvzZF zUIty~GAK$=LYz&!(4@vf7m#~P%zD9csT(Zn@3oo8x|+h8pu1J2$4OA((Sh1$?WkB$ z8&$`hsW51gZBsgxb*J9sL5y)8#!-|O1O<$#yTfQU-?O&5TU|v) zVu%+ZA{#u^oYQze01kz8iv8l91GLZ$n9OZkXu_qi90@v>!OZE6+E(*t7aii*)ZV9B zHhWu}z1>!URRNPfdm$cQhXFpASD-RU(^=B*bWUJRn+@fX}8_mZa+ZeZFF|1t&nPI`_aNG-eN`yXadW3x=~gSWK!%S$jV&Oxd}q_ z^L~dZZae{G2*m;V+Hr~2e>d~Da{RAKEw;Lj1@XVOc6ST$U$?ux`}f!Jzi#61O7Xu; zJg|-jwvGp;#sf3)$g=Ulmf^2;ys&k=Fi~O|evvI*#}8Zi7^Rr|*YU&F@x!XnU&jwy z#}8Y_56jD~t>cGXor3H5Vb_l3I)2zXe%LyG*ca%@b^Ne}b+6-xt>cHS z4fee$XhI5dcWUJ*LsE!Q9GiV3wOOe8uq^jF2S{*yLu90s}CA zU+dk(yM;0z>UI+-h3?;Y!=EME&I6OBv{>^43?Q}%4HO4xO&s?QLwRW)#nt5dj7kRL`15u}OuJ6|Ws6uR7TwzgEs>rfIAc8mrnX^7%hAS3BMFeYiJ% z3)9l0U+4rM=!-w@;QGP6+9Y)l_-@jXuy|bv@Mb0}Lo-astY@%moWcGY=58lzuktS< zG|5p0hgPNNGjsW>(WNTq`_(+mYmixsgW*B9x1(>_KkvSNe?a=Zx+&W0{m0?!SI-#Or-xB@`}N`bpB}uYleqZ2 z)q8cA^NH;0!GCsty`F%Jre^oGR`+?U`&y&>Qv=&wcLaz(T4z;LoWfS8|Fepe=hGEuCq7nTc`gI?93tWFXuBmT@# z`tv>yU}3-ZZs++0e1qx!}EtVZ06>EA!lV&=K>5@%=|1(c2{=PAT_wOrkT&B)v8) zb~c1XnHqT3#KmhDungVV{!N7>`6{eZm{Y%h9$77%iE*+w%HXO{C)OsOKyyLTvM^$} z$-!`FD^vTzs3(1XlBZ%PkXri~$iJMx<%p2n6P6^prq&8lN z(`?P6z#q=pmU--k$<${Tg^}=xPC0@% zYkx)K_jTF1zl2G6ZTS788h+Oip4JhbZX&|dwZ#AF)W?{?xIg#rSH=Hf@p82IKk#*b z``@hlUq1ZJzkK|ktM>nbkWboQef*~f+dKCQ@t?Nt?`&k!zIqvm8nZY$Lu-UbtK$^9h?gE{l0 zb3?q(dEnhr@5CJWaSS{g%rT@5pfK@hS6H4O0BN(S_sBb+ zVROQh-KWuX;D=ss>mZ!JL8eb8Ui|C){NSK_aG&gUum5~LeV-m2uw~cVkHL%2^3Y=# zG$jVteYpJE+gd_+?T+{5-0@)eGI}R@^ekx%6!IvSIpa8*8l>7vcZ;h*vM>@$;<4~s z{EQSHKyW{JQqFL}li-b^Fb&S5%wnv;#IINSye3omUjt9(kgDTv9Zj_*D*%m`e)5ST=RK!EG1UYwFf^} zLxqi(RZqrCaklc=TNoh51I#stT@x=DUtgO6o*#awifs1DeDWC2z)xX9stk(u0iCv0 zWJ(APdyU7Pj`b5AgtY!4Hy;1du51I~b6I&38nh+PKlS)c<}367 zo#-#f+p;)FuM!BM3d1T%ToY}fRW)!nmFAW)P<83+B5`E^iHdM6buJ-`yRalDNwZr> z@)crgUTITn9R)(pk2*EF;S zWba>R=`2eX8yqSHV&bn^qb`;M3?i=X7?>BXA7rs=?kj^|N-{2tt?)-VQ(9pgsSM z?E#`9Kw*J`K7`R3?QV=o7^Jy5*4l7qUH7%sOi;(G{#jOOM!_HIH0*Zu;6r zm2bdoaZ_u&YtbUstGh4g<HB%|fW;Vlt#AGhzo45#j={}&JY2QiW|s%0 z1#1_G^-A$y(FI~$v1a;%`$l{lZV~@t9udp$`3qh&?`G+{{v|}t{B$_E0_24&xevIs zNh+hwSN7gm=szp0{2Py9VyaxNdQ2xWQ@dZ=h{X%%>uo%@5nW^BvkK;1we6qf4^sVN z?M?B0t&`W@6w0`(@usM|i>2U)wj_SgE&uK%Lw8oy>^i&XTUC&MXZ{)252yS07s zOZeeb2&nge5PRGA>+o}9R=TwvY;7+oX8PXkCD);PudOT9<<|FQ2~5`aWhwn!dtcTc z?eBW-|0>^Cpw>};|I^m)Zm*}`|Fpfe`=GnN|LG?Fu5|yC*4>tJ1;jPo1$AxLL0#94 zP*=Vb>dN;*UGZwD&%7P#i(L?fJfcg9Wp9aEg4eG3#;C7(Y1F^gy-}ZkbyV%`QA@Cn zZ0`4Slhn6#nbcRiPwFdQDfP|XD)oI|EcK1uE%nu}m-P<=PIP<9fxIyiDE6S3C*yJn(P}tCK^#{^LMbXo`l;`Y6z~9|b}`JS7s3 zQTX5xPBOMeV`ChYqy(f%jQ)Cb?q=)<9-h(h1Ma3bn^|!d;+1psoL8|924P)c`l~rD zfWF!}c~?3ZkkU%GI@Zn&x%z&O=QL|X+3v_2yIGLV54JvA8go!LCWec+^T)Nwy=IZi z=~^LgDJ&a5E(l6l0y-iFLL2#@qp-txLw7h?$JJp)uTPYM$oq%!V9Tj85{#1aA8Sb| zUacT0A9*u0k;QIs9kNmayD@25#$P6^CFV6s%;$ot1vxp2yd?bZ|MOok-Z6kUlZuIr z7Zh`I5qkkic)U5B3wgU4djUD$lk$p?K(t!Tw+Fw_f$`Q_vRc=yq-sOsdlHrF<0DW$E)DB|rM*>!?5f(d*vd-PO;3Y~Anndh7EaH}Ti`!NTnfKgC!l`5;Qtwlb2= zU|x!|ovm(XtGn}X>*22TL+4gIm%^WbEfG*OMP9*|^h}<2^65Xl`B@Z?H&nJQOAs>8#w?AC@va zpUx)bM6Hz~6?e_h9#u?#8G-;bRW4ps*Us)4C?&s%qv@=ie3-_Oq5i{cFsVT89jHDY z+HQ(n)&{|VvAWXI3q?~Xy?c{**(fR{zvVMP=>=|c%EX^x832=W`&Bj_cyTG2*@8zKhviiK00m=M z!0Me_!2VYea;G>v+P|rT<{iu@?cXLq1|6tQul9=|a?`4pKY8a>uU^6gaAKf0fBkw` z2Fkjk{Uh)V%vK+&-annVRo&QrrVQ!Qt4t+I;q7yb#8CP6C){AF290fvXHih~{xu!r zu6X$t$W*2xe_0Sm#kce6K&e$_(&CuWIK#xW^4*_rap1@8QEeN*jaDut{g}`j(%%fj`_UmG|Pf0Kt9G+wJW#2)VU* zQ@r-JM_Z$5ILjuXx{=oaWexp19*^M92&a9%DkvBJ44}M4oxP|{C7yK&Ksn>YOw@8lf3>EKMo1?koK>mh zx=1GjsN#@#NPmWmMb^Dfe};^L#g^dbldMGIiq1@z?28XYQMKX_|4_%s%akvYY1Q&Y zrdzdqkx)B3_wSqfvna~CT{F)X1;(hiQ_d8+C1?-fKSRbrIpc#Lw+$JK{m9#~EFHqK zsIS1NI3^!zt&RopUwZeuMf=~*R(EG@|GSAlG#=X)T9j>T`wh) z-nV}8f>RG6+SWMsyaZ6RtpivxL(A}CGx1`7EQ=-nN5HGMGdss5m|2GmRi;xBbwY<}}(I zL@A6`Oy6ed+ML{DGc|AZAOJ$}3J9>$h^_X0C{ORUO79qC)igf4VS?>=wREcV!Fk=SF8Jpz(jzj$E~+14}) zBQoC=o1!yH7{yaJU@-acLpKQl*1`ei2nR4lRl(J}T%aemH@lloH4+P%GLDym6|~E?`q?fqfow zhQJswY>b?5p82D6LVfW+m;k_j{bv@Xo;r*e_<}HjLK;n2rk$L{hr=P`szTTo1u}wh zvoxYEW2iiO*cD7oCuWMw3#0iy<6fO`Hy)3*_d+EbqZPVuA$|9XI+|9X zt%gg|3sVv+t@Wuu>eio>Fhh%H0MRBAKnfp{RO;>W#O0~IRg`ShozylBu|H9SBHlDf z*sdUT&QxL~w0St8$|gO+|J2#EETeHkh3*APo^67V6Z|UE0RM?U8hK$wqp3l=a}EYTRjYR)y>^Xs3mViY6~YL-Av@3OK0+_)S3t)o%w;q7Rb}ze$ZX zHm+g`D->VD3PfAj>blEAK~lr8D9#i@NzmuR2bu=UG8)%tN)?*o&BTI+2V$PP%{0%mJW?fm)D~kp^Op8b(Fm7M`-%$MlcIO2`rKTg7GUQ?41Ms+ z-11PHf`uw<)=U@y2#$e|zKkTM+G-_ZVGtMBy8=d=T<>l1H1cC0pvpaFPGk&(OJnRA zY~1FSL|Pxd+j?6>>V1){Dy+TsBauw_3%(5kYrET>CS}YwqnQ`#a}U?ba#dC|Eg42x z?4Ec+lPE3ise$PP=y)>G%jR-;Gt4z01$DXLEtzAgw%~8IOUDD2R`OXBH@CKRc`3_m z7Zp-CCDd9-c3D4^WEIlEspH8D=f000a5Cv zUUTRE$UA9Ko@w;4K0{Rdy6&A>VhXx#NhP6hB7_Ji$BPhOqOb02eI?b6h26wuPiYy! zw_b`kXu3^he=f&nCFHAxcL7_I)~qFqdZoriha^A_iL({DZuUUYu7pg)XErNo+<8B5 z$%y_m^=e+AA63i0*bxmC2Q|Gs=B2C(JiK0yR;I!hsYpnL(=s%z;ZY4UF|;XGJ}Mp~ zEI|y9EWt`Wj6I=EMXXJ;e&C9wliDUV-K?~8rA6zBDiRMz-lMVD)U2bMH1rJ~y5oV; z=bLA4jMvZDqSVNn!6bx7AY@V&=2123uo;gZz@JJ60lnD8#j4Ej)p~2%G#(58hFfiZ z$B~LAWDDF`0vscL6~{M2SQORQQj!nI@I*T*+QtgY3f;#6-p?mK0WcLEUAr(*h8x*} z@B{zlgSTiuox(^8ykccB)Ms2s(`evD6kRfFfaO0aQeRiahpU^@nm~SSK zCombPA8|wbpV)z*8eLqIU~-J8vPh^La-lAOR`g_PMC+z=u_u&HgEk(d ztD3HvQuV1w2U#|SX{P;R(-bkQ*yD7WpRXs%a;;E#{mdyBJ8BU{=QHhk6mpw(GdQ|Z z^;f8A^Km8)tfy^rW319oGER}1`wo+2X ziC>k0T|==O;}ZdpT*^i8$}f}2rc zv>AId&#fe5J54vIUYME3lOp|KnIIc!u(a#u>t$r3Tzl@+;ilVWDm}=|g_G>$#7h*V zZFNR5Y};$9=EK}-xey0BJt{g?4ob2KZw|eHi`*J>{1SDb8_p(Mo$8j)k{($(Z4`*C zP6y_F1y$qHH`W#-+@GKZX)lozpN3hSMAAu&9{R!rQRGc!2lV0ga7SlSx!brLekHQ5 hh;T)(6tMZ)ZanM1_22q${kQVp{|}}k;bQ=l3;-O&qxS#+ literal 73200 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 E1AF~tga7~l diff --git a/Documentation/img/spinner.gif b/Documentation/img/spinner.gif new file mode 100644 index 0000000000000000000000000000000000000000..e3038d0a42c55b1a07caecb7c7a6cbac982ec09d GIT binary patch literal 1849 zcmb8wZBSF$83*voz31lM+?V7Kkqwb`LI|3K#DupH#kDs91c6du6?SMB!bsTr6|ge_{#vAVj^!DyNA-l zJ&$jDFNv;BTZXX@Qk-7+S5ErF>mkOcZ@lQv>F1VyCEMe2Ud@f<|L%#&QJi${E`2lR zqKFaW2Y$aTRxUY&ae$IHsN;Z;rdZ%CjYLTv!tMi234j-ON=CnvK-1QU|MG$YErn{gHZ@0Q6&?xSyply?S$EVNXH;gp?S5kV2-)$ga^gw`(f4Mm_Y(`RbgRkQTHF2@zL}dCiLk$RoZIc{xZL z_J*d5)Kb;#oKCFyfL*NGSs?y;e(QKvPJe1#G)h5*6E(?L9$nt?UaQJfP^$GDL0PU; z?r}C|);JQ4HES3w5VMlY7x6xfJAzDKlHE~>x;D`Fa=WygYot{pfFehH69o9pK|72W zwC6?t^AnATIJa=kewn=ep?Nk(aZ*pZo}51`S=^)jPRb`~l^VE}08>P3OJtQlXx1K8 z8Q}_u=F*fS;=k=?(fIv#+%811NTx8^}rHwvH%LbYmpFl9p1A{Idh@2x$ zuVp7)VD9}Uc(*(C**!QOdS(6B)$5^Tq5p3q*7un&_Z-NKEiEYg$D{Uq&sa>wj|za5 zJ6M~p)z+E6*X${8j6Ci+sqZ}zxeCAo0gZmZuhl+)Q%1U$Br_`NXcA-3yBdYMha+{o z{?q0Q(kaR2n`M29{!pwpgX6+CPQEgIO%x*0#!TC=c-ZPSkLO>OcmQUao5%-3w)U`F zRz?uGCEKQDh!TQPDmyd;iDX$TkMIe)%61q51Y2b-ie4r00!csilXgKL$txqj|6D(# z@(#!nQ}3R1JGeB3B5Tuqdvyg@*!-bq`9`pmasNGvy9^*+cd1Y*g>HK#rl7i79QQAG zl4SL_wW@WY1d+F?j0gFInGhsRrqvV3SKl{oqW+;9!fu|u@J)h4WM!0Cu02l@p60b#5M9c{dKh=_eRw~yl zWT0gw8RePzf%i8X&twiB|LF0bI@CYE{x1PI;Ylr4RJzU#Zc0j!c07g&q7=_eSd(sH z9VKChd?}^52IKcMqolAWiQH;HSp1Ploa$t zQhg|2sK;%Eb!By`)j9G1w?>`Wt6IK3gB}~uoue(MlRiIoZ#d{pgJZ8b{^{HO8)@%= zX)og3`*D5v1g;*Lz8@Sm(Q|&}PUytlb@Q_dzKFOzKK!Z_&?GO4+JO-)iPH=fs{(`& zZ9{oNn~LUZaeN!>i9p*0N^sHye8nw4xSi!REaP@@^Jy66|)Y9_AFoLlrlkg(42 zVq2J??I(+1*BcSKsTyO7LCho{8tVQm1b>*GQ*H~Mn71Lhy`alw%;D@CU^0)5Ng{cHz@LS7QZ o8uGHYt7)tmZjae5ge5$b`e_;HIklOseoIbqeod19BU-8d00{dbSpWb4 literal 0 HcmV?d00001 diff --git a/Documentation/index.html b/Documentation/index.html index 2a7bcd8..4e30c42 100644 --- a/Documentation/index.html +++ b/Documentation/index.html @@ -8,12 +8,20 @@ + + +
    -

    Atom Docs (99% documented)

    +

    Atom Docs (98% documented)

    +

    +

    + +
    +

    @@ -33,40 +41,13 @@ Atom - - - - - - - - - @@ -76,6 +57,12 @@ + + @@ -85,10 +72,10 @@ Extensions +
    @@ -134,125 +162,140 @@

    Overview

    The lightweight & delightful networking library.

    -

    Atom is a wrapper library built around a subset of features offered by URLSession with added ability to decode data into models, handle access token refresh and authorization headers on behalf of the client, and more. It takes advantage of Swift features such as default implementation for protocols, generics and Decodable to make it extremely easy to integrate and use in an existing project. Atom offers support for any endpoint, a much stricter URL host and path validation, comprehensive documentation and an example application to eliminate any guesswork.

    +

    Atom is a wrapper library built around a subset of features offered by URLSession with added ability to decode data into models, handle access token refresh and authorization headers on behalf of the client, and more. It takes advantage of Swift features such as default implementation for protocols, generics and Decodable to make it extremely easy to integrate and use in an existing project. Atom offers support for any endpoint, a much stricter URL host and path validation, comprehensive documentation and an example application to eliminate any guesswork.

    Features

    • [x] Simple to setup, easy to use & efficient
    • [x] Supports any endpoint
    • +
    • [x] Supports Combine publishers
    • +
    • [x] Supports Multipath TCP configuration
    • [x] Handles object decoding from data returned by the service
    • [x] Handles token refresh
    • [x] Handles and applies authorization headers on behalf of the client
    • [x] Handles URL host validation
    • [x] Handles URL path validation
    • -
    • [x] Complete Documentation
    • +
    • [x] Complete Documentation

    Requirements

      -
    • iOS 11.0+
    • -
    • Xcode 11.0+
    • +
    • iOS 12.0+
    • +
    • Xcode 12.0+
    • Swift 5.0+

    Installation

    -

    Carthage

    - -

    Carthage is a decentralized dependency manager that builds your dependencies and provides you with binary frameworks. To integrate Atom into your Xcode project using Carthage, specify it in your Cartfile:

    -
    git "https://github.com/AlaskaAirlines/atom" ~> 1.0.0
    -
    - -

    For more information on getting started with Carthage, visit the repo.

    Swift Package Manager

    The Swift Package Manager is a tool for automating the distribution of Swift code and is integrated into the swift compiler.

    Once you have your Swift package set up, adding Atom as a dependency is as easy as adding it to the dependencies value of your Package.swift.

    + +

    If you are using Xcode, adding Atom as a dependency is even easier. First, select your application, then your application project. Once you see Swift Packages tab at the top of the Project Editor, click on it. Click + button and add the following URL:

    + +

    https://github.com/alaskaairlines/atom/

    + +

    At this point you can setup your project to either use a branch or tagged version of the package.

    Usage

    Getting started is easy. First, create an instance of Atom.

    -
    let atom = Atom()
    +
    let atom = Atom()
     

    In the above example, default configuration will be used. Default configuration will setup URLSessionto use ephemeral configuration as well as ensure that the data returned by the service is available on the main thread.

    -

    Any network request needs to conform and implement Requestable protocol. The Requestable protocol provides default implementation for all of its properties - except for the func baseURL() throws -> Atom.BaseURL. See documentation for more information.

    -
    extension Seatmap {
    -    enum Endpoint: Requestable {
    -        case refresh
    +

    Any endpoint needs to conform and implement Requestable protocol. The Requestable protocol provides default implementation for all of its properties - except for the func baseURL() throws -> BaseURL. See documentation for more information.

    +
    extension Seatmap {
    +    enum Endpoint: Requestable {
    +        case refresh
     
    -        func baseURL() throws -> Atom.BaseURL {
    -            try Atom.BaseURL(host: "api.alaskaair.net")
    -        }
    -    }
    -}
    +        func baseURL() throws -> Atom.BaseURL {
    +            try Atom.BaseURL(host: "api.alaskaair.net")
    +        }
    +    }
    +}
     

    Atom offers a handful of methods with support for fully decoded model objects, raw data, or status indicating success / failure of a request.

    -
    typealias Endpoint = Seatmap.Endpoint
    -
    -service.load(Endpoint.refresh).execute(expecting: Seatmap.self) { [weak self] result in
    -    switch result {
    -        case .failure(let error):
    -        // Handle error.
    -
    -        case .success(let seatmap):
    -        // Handle seatmap model.
    -    }
    -}
    +
    // Completion based.
    +
    +typealias Endpoint = Seatmap.Endpoint
    +
    +atom.enqueue(Endpoint.refresh).resume(expecting: Seatmap.self) { result in
    +    switch result {
    +        case .failure(let error):
    +        // Handle error.
    +
    +        case .success(let seatmap):
    +        // Handle seatmap model.
    +    }
    +}
    +
    +// Publisher based.
    +
    +atom
    +    .enqueue(Endpoint.refresh)
    +    .resume(expecting: Seatmap.self)
    +    .sink { completion in
    +        // Handle `AtomError`.
    +    } receiveValue: { seatmap in
    +        // Handle decoded `Seatmap` instance.
    +    }
    +    .store(in: &cancelables)
     
    -

    The above example demonstrates how to use execute() method to get a fully decoded Seatmap model object.

    +

    The above example demonstrates how to use resume(expecting:) function to get a fully decoded Seatmap model object.

    -

    For more information, please see documentation.

    +

    For more information, please see documentation.

    Authentication

    Atom can be configured to apply authorization headers on behalf of the client.

    -

    Atom supports Basic and Bearer authentication methods. When configured properly, Atom will perform automatic token refresh on behalf of the client if it determines that the access token being used has expired. Any in-flight calls will be enqueued and executed once a new token is obtained.

    +

    Atom supports Basic and Bearer authentication methods. When configured properly, Atom will perform automatic token refresh on behalf of the client if it determines that the access token being used has expired. Any in-flight calls will be enqueued and resumed once a new token is obtained.

    If the token refresh call fails, all enqueued network calls will be executed at once with completions set to AtomError failure.

    Basic

    You can configure Atom to apply Basic authorization header like this:

    -
    let atom: Atom = {
    -    let credential = Atom.BasicCredential(password: "password", username: "username")
    -    let basic = Atom.AuthenticationMethod.basic(credential)
    -    let configuration = Atom.ServiceConfiguration(authenticationMethod: basic)
    +
    let atom: Atom = {
    +    let credential = Atom.BasicCredential(password: "password", username: "username")
    +    let basic = Atom.AuthenticationMethod.basic(credential)
    +    let configuration = Atom.ServiceConfiguration(authenticationMethod: basic)
     
    -    return Atom(serviceConfiguration: configuration)
    -}()
    +    return Atom(serviceConfiguration: configuration)
    +}()
     
     

    An existing implementation can be extended by conforming and implementing BasicCredentialConvertible protocol. A hypothetical configuration can look something like this:

    -
    final class CredentialManager {
    -    private(set) var username = String()
    -    private(set) var password = String()
    +
    final class CredentialManager {
    +    private(set) var username = String()
    +    private(set) var password = String()
     
    -    static let shared = CredentialManager()
    -    private init() { }
    +    static let shared = CredentialManager()
    +    private init() { }
     
    -    func update(username aUsername: String) {
    -        username = aUsername
    -    }
    +    func update(username aUsername: String) {
    +        username = aUsername
    +    }
     
    -    func update(password aPassword: String) {
    -        password = aPassword
    -    }
    -}
    +    func update(password aPassword: String) {
    +        password = aPassword
    +    }
    +}
     
    -extension CredentialManager: BasicCredentialConvertible {
    -    var basicCredential: Atom.BasicCredential {
    -        .init(password: password, username: username)
    -    }
    -}
    +extension CredentialManager: BasicCredentialConvertible {
    +    var basicCredential: Atom.BasicCredential {
    +        .init(password: password, username: username)
    +    }
    +}
     
    -let atom: Atom = {
    -    let basic = Atom.AuthenticationMethod.basic(CredentialManager.shared.basicCredential)
    -    let configuration = Atom.ServiceConfiguration(authenticationMethod: basic)
    +let atom: Atom = {
    +    let basic = Atom.AuthenticationMethod.basic(CredentialManager.shared.basicCredential)
    +    let configuration = Atom.ServiceConfiguration(authenticationMethod: basic)
     
    -    return Atom(serviceConfiguration: configuration)
    -}()
    +    return Atom(serviceConfiguration: configuration)
    +}()
     
     
    @@ -260,26 +303,26 @@

    Basic

    Bearer

    You can configure Atom to apply Bearer authorization header. Here is an example:

    -
    class TokenManager: TokenCredentialWritable {
    -    var tokenCredential: Atom.TokenCredential {
    -        // Read values from the keychain.
    -        get { keychain.tokenCredential() }
    -
    -        // Save new value to the keychain.  
    -        set { keychain.save(tokenCredential: newValue)  }
    -    }
    -}
    -
    -let atom: Atom = {
    -    let endpoint = Atom.AuthorizationEndpoint(host: "api.alaskaair.net", path: "/oauth2")
    -    let clientCredential = Atom.ClientCredential(id: "client-id", secret: "client-secret")
    -    let tokenManager = TokenManager()
    -
    -    let bearer = Atom.AuthenticationMethod.bearer(endpoint, clientCredential, tokenManager)
    -    let configuration = Atom.ServiceConfiguration(authenticationMethod: bearer)
    -
    -    return Atom(serviceConfiguration: configuration)
    -}()
    +
    class TokenManager: TokenCredentialWritable {
    +    var tokenCredential: Atom.TokenCredential {
    +        // Read values from the keychain.
    +        get { keychain.tokenCredential() }
    +
    +        // Save new value to the keychain.  
    +        set { keychain.save(tokenCredential: newValue)  }
    +    }
    +}
    +
    +let atom: Atom = {
    +    let endpoint = Atom.AuthorizationEndpoint(host: "api.alaskaair.net", path: "/oauth2")
    +    let clientCredential = Atom.ClientCredential(id: "client-id", secret: "client-secret")
    +    let tokenManager = TokenManager()
    +
    +    let bearer = Atom.AuthenticationMethod.bearer(endpoint, clientCredential, tokenManager)
    +    let configuration = Atom.ServiceConfiguration(authenticationMethod: bearer)
    +
    +    return Atom(serviceConfiguration: configuration)
    +}()
     

    The setup is hopefully easy to understand. Atom requires a few pieces of information from the client:

    @@ -293,16 +336,16 @@

    Bearer

    Once configured, Atom will apply authorization header to a request as Authorization: Bearer ... header key-value.

    Please note, Atom will only decode token credential from a JSON objecting returned in this form:

    -
    {
    -    "access_token": "2YotnFZFEjr1zCsicMWpAA",
    -    "expires_in": 3600,
    -    "refresh_token": "tGzv3JOkF0XG5Qx2TlKWIA"
    -}
    -
    +
    {
    +    "access_token": "2YotnFZFEjr1zCsicMWpAA",
    +    "expires_in": 3600,
    +    "refresh_token": "tGzv3JOkF0XG5Qx2TlKWIA"
    +}
    +

    The above response is in accordance with RFC 6749, section 1.5.

    -

    For more information and Atom usage example, please see documentation and the provided Example application.

    +

    For more information and Atom usage example, please see documentation and the provided Example application.

    Communication

      @@ -319,8 +362,8 @@

      Authors

    diff --git a/Documentation/js/jazzy.js b/Documentation/js/jazzy.js index c31dc05..1e55d6e 100755 --- a/Documentation/js/jazzy.js +++ b/Documentation/js/jazzy.js @@ -23,7 +23,7 @@ function openCurrentItemIfClosed() { if (window.jazzy.docset) { return; } - var $link = $(`.token[href="${location.hash}"]`); + var $link = $(`a[name="${location.hash.substring(1)}"]`).nextAll('.token'); $content = itemLinkToContent($link); if ($content.is(':hidden')) { toggleItem($link, $content); @@ -57,3 +57,14 @@ $("a:not('.token')").on('click', function() { openCurrentItemIfClosed(); } }); + +// KaTeX rendering +if ("katex" in window) { + $($('.math').each( (_, element) => { + katex.render(element.textContent, element, { + displayMode: $(element).hasClass('m-block'), + throwOnError: false, + trust: true + }); + })) +} diff --git a/Documentation/js/jazzy.search.js b/Documentation/js/jazzy.search.js new file mode 100644 index 0000000..e3d1ab9 --- /dev/null +++ b/Documentation/js/jazzy.search.js @@ -0,0 +1,70 @@ +$(function(){ + var $typeahead = $('[data-typeahead]'); + var $form = $typeahead.parents('form'); + var searchURL = $form.attr('action'); + + function displayTemplate(result) { + return result.name; + } + + function suggestionTemplate(result) { + var t = '
    '; + t += '' + result.name + ''; + if (result.parent_name) { + t += '' + result.parent_name + ''; + } + t += '
    '; + return t; + } + + $typeahead.one('focus', function() { + $form.addClass('loading'); + + $.getJSON(searchURL).then(function(searchData) { + const searchIndex = lunr(function() { + this.ref('url'); + this.field('name'); + this.field('abstract'); + for (const [url, doc] of Object.entries(searchData)) { + this.add({url: url, name: doc.name, abstract: doc.abstract}); + } + }); + + $typeahead.typeahead( + { + highlight: true, + minLength: 3, + autoselect: true + }, + { + limit: 10, + display: displayTemplate, + templates: { suggestion: suggestionTemplate }, + source: function(query, sync) { + const lcSearch = query.toLowerCase(); + const results = searchIndex.query(function(q) { + q.term(lcSearch, { boost: 100 }); + q.term(lcSearch, { + boost: 10, + wildcard: lunr.Query.wildcard.TRAILING + }); + }).map(function(result) { + var doc = searchData[result.ref]; + doc.url = result.ref; + return doc; + }); + sync(results); + } + } + ); + $form.removeClass('loading'); + $typeahead.trigger('focus'); + }); + }); + + var baseURL = searchURL.slice(0, -"search.json".length); + + $typeahead.on('typeahead:select', function(e, result) { + window.location = baseURL + result.url; + }); +}); diff --git a/Documentation/js/jquery.min.js b/Documentation/js/jquery.min.js index a1c07fd..b061403 100755 --- a/Documentation/js/jquery.min.js +++ b/Documentation/js/jquery.min.js @@ -1,2 +1,2 @@ -/*! jQuery v3.4.1 | (c) JS Foundation and other contributors | jquery.org/license */ -!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(C,e){"use strict";var t=[],E=C.document,r=Object.getPrototypeOf,s=t.slice,g=t.concat,u=t.push,i=t.indexOf,n={},o=n.toString,v=n.hasOwnProperty,a=v.toString,l=a.call(Object),y={},m=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType},x=function(e){return null!=e&&e===e.window},c={type:!0,src:!0,nonce:!0,noModule:!0};function b(e,t,n){var r,i,o=(n=n||E).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function w(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e}var f="3.4.1",k=function(e,t){return new k.fn.init(e,t)},p=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g;function d(e){var t=!!e&&"length"in e&&e.length,n=w(e);return!m(e)&&!x(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+M+")"+M+"*"),U=new RegExp(M+"|>"),X=new RegExp($),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+$),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+R+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\d$/i,K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\([\\da-f]{1,6}"+M+"?|("+M+")|.)","ig"),ne=function(e,t,n){var r="0x"+t-65536;return r!=r||n?t:r<0?String.fromCharCode(r+65536):String.fromCharCode(r>>10|55296,1023&r|56320)},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{H.apply(t=O.call(m.childNodes),m.childNodes),t[m.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&((e?e.ownerDocument||e:m)!==C&&T(e),e=e||C,E)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!A[t+" "]&&(!v||!v.test(t))&&(1!==p||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&U.test(t)){(s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=k),o=(l=h(t)).length;while(o--)l[o]="#"+s+" "+xe(l[o]);c=l.join(","),f=ee.test(t)&&ye(e.parentNode)||e}try{return H.apply(n,f.querySelectorAll(c)),n}catch(e){A(t,!0)}finally{s===k&&e.removeAttribute("id")}}}return g(t.replace(B,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[k]=!0,e}function ce(e){var t=C.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e.namespaceURI,n=(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:m;return r!==C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,E=!i(C),m!==C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),d.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment("")),!e.getElementsByTagName("*").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=k,!C.getElementsByName||!C.getElementsByName(k).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){a.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+k+"-]").length||v.push("~="),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+k+"+*").length||v.push(".#.+[+~]")}),ce(function(e){e.innerHTML="";var t=C.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",$)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=K.test(a.compareDocumentPosition),y=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},D=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)===(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e===C||e.ownerDocument===m&&y(m,e)?-1:t===C||t.ownerDocument===m&&y(m,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e===C?-1:t===C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]===m?-1:s[r]===m?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if((e.ownerDocument||e)!==C&&T(e),d.matchesSelector&&E&&!A[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){A(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=p[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&p(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function j(e,n,r){return m(n)?k.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?k.grep(e,function(e){return e===n!==r}):"string"!=typeof n?k.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(k.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||q,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:L.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof k?t[0]:t,k.merge(this,k.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),D.test(r[1])&&k.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(k):k.makeArray(e,this)}).prototype=k.fn,q=k(E);var H=/^(?:parents|prev(?:Until|All))/,O={children:!0,contents:!0,next:!0,prev:!0};function P(e,t){while((e=e[t])&&1!==e.nodeType);return e}k.fn.extend({has:function(e){var t=k(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,he=/^$|^module$|\/(?:java|ecma)script/i,ge={option:[1,""],thead:[1,"","
    "],col:[2,"","
    "],tr:[2,"","
    "],td:[3,"","
    "],_default:[0,"",""]};function ve(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&A(e,t)?k.merge([e],n):n}function ye(e,t){for(var n=0,r=e.length;nx",y.noCloneChecked=!!me.cloneNode(!0).lastChild.defaultValue;var Te=/^key/,Ce=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,Ee=/^([^.]*)(?:\.(.+)|)/;function ke(){return!0}function Se(){return!1}function Ne(e,t){return e===function(){try{return E.activeElement}catch(e){}}()==("focus"===t)}function Ae(e,t,n,r,i,o){var a,s;if("object"==typeof t){for(s in"string"!=typeof n&&(r=r||n,n=void 0),t)Ae(e,s,n,r,t[s],o);return e}if(null==r&&null==i?(i=n,r=n=void 0):null==i&&("string"==typeof n?(i=r,r=void 0):(i=r,r=n,n=void 0)),!1===i)i=Se;else if(!i)return e;return 1===o&&(a=i,(i=function(e){return k().off(e),a.apply(this,arguments)}).guid=a.guid||(a.guid=k.guid++)),e.each(function(){k.event.add(this,t,i,r,n)})}function De(e,i,o){o?(Q.set(e,i,!1),k.event.add(e,i,{namespace:!1,handler:function(e){var t,n,r=Q.get(this,i);if(1&e.isTrigger&&this[i]){if(r.length)(k.event.special[i]||{}).delegateType&&e.stopPropagation();else if(r=s.call(arguments),Q.set(this,i,r),t=o(this,i),this[i](),r!==(n=Q.get(this,i))||t?Q.set(this,i,!1):n={},r!==n)return e.stopImmediatePropagation(),e.preventDefault(),n.value}else r.length&&(Q.set(this,i,{value:k.event.trigger(k.extend(r[0],k.Event.prototype),r.slice(1),this)}),e.stopImmediatePropagation())}})):void 0===Q.get(e,i)&&k.event.add(e,i,ke)}k.event={global:{},add:function(t,e,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=Q.get(t);if(v){n.handler&&(n=(o=n).handler,i=o.selector),i&&k.find.matchesSelector(ie,i),n.guid||(n.guid=k.guid++),(u=v.events)||(u=v.events={}),(a=v.handle)||(a=v.handle=function(e){return"undefined"!=typeof k&&k.event.triggered!==e.type?k.event.dispatch.apply(t,arguments):void 0}),l=(e=(e||"").match(R)||[""]).length;while(l--)d=g=(s=Ee.exec(e[l])||[])[1],h=(s[2]||"").split(".").sort(),d&&(f=k.event.special[d]||{},d=(i?f.delegateType:f.bindType)||d,f=k.event.special[d]||{},c=k.extend({type:d,origType:g,data:r,handler:n,guid:n.guid,selector:i,needsContext:i&&k.expr.match.needsContext.test(i),namespace:h.join(".")},o),(p=u[d])||((p=u[d]=[]).delegateCount=0,f.setup&&!1!==f.setup.call(t,r,h,a)||t.addEventListener&&t.addEventListener(d,a)),f.add&&(f.add.call(t,c),c.handler.guid||(c.handler.guid=n.guid)),i?p.splice(p.delegateCount++,0,c):p.push(c),k.event.global[d]=!0)}},remove:function(e,t,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=Q.hasData(e)&&Q.get(e);if(v&&(u=v.events)){l=(t=(t||"").match(R)||[""]).length;while(l--)if(d=g=(s=Ee.exec(t[l])||[])[1],h=(s[2]||"").split(".").sort(),d){f=k.event.special[d]||{},p=u[d=(r?f.delegateType:f.bindType)||d]||[],s=s[2]&&new RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),a=o=p.length;while(o--)c=p[o],!i&&g!==c.origType||n&&n.guid!==c.guid||s&&!s.test(c.namespace)||r&&r!==c.selector&&("**"!==r||!c.selector)||(p.splice(o,1),c.selector&&p.delegateCount--,f.remove&&f.remove.call(e,c));a&&!p.length&&(f.teardown&&!1!==f.teardown.call(e,h,v.handle)||k.removeEvent(e,d,v.handle),delete u[d])}else for(d in u)k.event.remove(e,d+t[l],n,r,!0);k.isEmptyObject(u)&&Q.remove(e,"handle events")}},dispatch:function(e){var t,n,r,i,o,a,s=k.event.fix(e),u=new Array(arguments.length),l=(Q.get(this,"events")||{})[s.type]||[],c=k.event.special[s.type]||{};for(u[0]=s,t=1;t\x20\t\r\n\f]*)[^>]*)\/>/gi,qe=/\s*$/g;function Oe(e,t){return A(e,"table")&&A(11!==t.nodeType?t:t.firstChild,"tr")&&k(e).children("tbody")[0]||e}function Pe(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function Re(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Me(e,t){var n,r,i,o,a,s,u,l;if(1===t.nodeType){if(Q.hasData(e)&&(o=Q.access(e),a=Q.set(t,o),l=o.events))for(i in delete a.handle,a.events={},l)for(n=0,r=l[i].length;n")},clone:function(e,t,n){var r,i,o,a,s,u,l,c=e.cloneNode(!0),f=oe(e);if(!(y.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||k.isXMLDoc(e)))for(a=ve(c),r=0,i=(o=ve(e)).length;r").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),E.head.appendChild(r[0])},abort:function(){i&&i()}}});var Vt,Gt=[],Yt=/(=)\?(?=&|$)|\?\?/;k.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Gt.pop()||k.expando+"_"+kt++;return this[e]=!0,e}}),k.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Yt.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Yt.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Yt,"$1"+r):!1!==e.jsonp&&(e.url+=(St.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||k.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=C[r],C[r]=function(){o=arguments},n.always(function(){void 0===i?k(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,Gt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),"script"}),y.createHTMLDocument=((Vt=E.implementation.createHTMLDocument("").body).innerHTML="
    ",2===Vt.childNodes.length),k.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(y.createHTMLDocument?((r=(t=E.implementation.createHTMLDocument("")).createElement("base")).href=E.location.href,t.head.appendChild(r)):t=E),o=!n&&[],(i=D.exec(e))?[t.createElement(i[1])]:(i=we([e],t,o),o&&o.length&&k(o).remove(),k.merge([],i.childNodes)));var r,i,o},k.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(k.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},k.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){k.fn[t]=function(e){return this.on(t,e)}}),k.expr.pseudos.animated=function(t){return k.grep(k.timers,function(e){return t===e.elem}).length},k.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=k.css(e,"position"),c=k(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=k.css(e,"top"),u=k.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,k.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},k.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){k.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===k.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===k.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=k(e).offset()).top+=k.css(e,"borderTopWidth",!0),i.left+=k.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-k.css(r,"marginTop",!0),left:t.left-i.left-k.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===k.css(e,"position"))e=e.offsetParent;return e||ie})}}),k.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;k.fn[t]=function(e){return _(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),k.each(["top","left"],function(e,n){k.cssHooks[n]=ze(y.pixelPosition,function(e,t){if(t)return t=_e(e,n),$e.test(t)?k(e).position()[n]+"px":t})}),k.each({Height:"height",Width:"width"},function(a,s){k.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){k.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return _(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?k.css(e,t,i):k.style(e,t,n,i)},s,n?e:void 0,n)}})}),k.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){k.fn[n]=function(e,t){return 0+~]|"+M+")"+M+"*"),U=new RegExp(M+"|>"),X=new RegExp(F),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+F),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+R+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\d$/i,K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\[\\da-fA-F]{1,6}"+M+"?|\\\\([^\\r\\n\\f])","g"),ne=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{H.apply(t=O.call(p.childNodes),p.childNodes),t[p.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&(T(e),e=e||C,E)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!N[t+" "]&&(!v||!v.test(t))&&(1!==p||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&(U.test(t)||z.test(t))){(f=ee.test(t)&&ye(e.parentNode)||e)===e&&d.scope||((s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=S)),o=(l=h(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+xe(l[o]);c=l.join(",")}try{return H.apply(n,f.querySelectorAll(c)),n}catch(e){N(t,!0)}finally{s===S&&e.removeAttribute("id")}}}return g(t.replace($,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[S]=!0,e}function ce(e){var t=C.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e.namespaceURI,n=(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:p;return r!=C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,E=!i(C),p!=C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),d.scope=ce(function(e){return a.appendChild(e).appendChild(C.createElement("div")),"undefined"!=typeof e.querySelectorAll&&!e.querySelectorAll(":scope fieldset div").length}),d.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment("")),!e.getElementsByTagName("*").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=S,!C.getElementsByName||!C.getElementsByName(S).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){var t;a.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+S+"-]").length||v.push("~="),(t=C.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||v.push("\\["+M+"*name"+M+"*="+M+"*(?:''|\"\")"),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+S+"+*").length||v.push(".#.+[+~]"),e.querySelectorAll("\\\f"),v.push("[\\r\\n\\f]")}),ce(function(e){e.innerHTML="";var t=C.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",F)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=K.test(a.compareDocumentPosition),y=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},D=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e==C||e.ownerDocument==p&&y(p,e)?-1:t==C||t.ownerDocument==p&&y(p,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e==C?-1:t==C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]==p?-1:s[r]==p?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if(T(e),d.matchesSelector&&E&&!N[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){N(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=m[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&m(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function D(e,n,r){return m(n)?S.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?S.grep(e,function(e){return e===n!==r}):"string"!=typeof n?S.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(S.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||j,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:q.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof S?t[0]:t,S.merge(this,S.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),N.test(r[1])&&S.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(S):S.makeArray(e,this)}).prototype=S.fn,j=S(E);var L=/^(?:parents|prev(?:Until|All))/,H={children:!0,contents:!0,next:!0,prev:!0};function O(e,t){while((e=e[t])&&1!==e.nodeType);return e}S.fn.extend({has:function(e){var t=S(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,he=/^$|^module$|\/(?:java|ecma)script/i;ce=E.createDocumentFragment().appendChild(E.createElement("div")),(fe=E.createElement("input")).setAttribute("type","radio"),fe.setAttribute("checked","checked"),fe.setAttribute("name","t"),ce.appendChild(fe),y.checkClone=ce.cloneNode(!0).cloneNode(!0).lastChild.checked,ce.innerHTML="",y.noCloneChecked=!!ce.cloneNode(!0).lastChild.defaultValue,ce.innerHTML="",y.option=!!ce.lastChild;var ge={thead:[1,"","
    "],col:[2,"","
    "],tr:[2,"","
    "],td:[3,"","
    "],_default:[0,"",""]};function ve(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&A(e,t)?S.merge([e],n):n}function ye(e,t){for(var n=0,r=e.length;n",""]);var me=/<|&#?\w+;/;function xe(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d\s*$/g;function qe(e,t){return A(e,"table")&&A(11!==t.nodeType?t:t.firstChild,"tr")&&S(e).children("tbody")[0]||e}function Le(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function He(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Oe(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(Y.hasData(e)&&(s=Y.get(e).events))for(i in Y.remove(t,"handle events"),s)for(n=0,r=s[i].length;n").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),E.head.appendChild(r[0])},abort:function(){i&&i()}}});var Ut,Xt=[],Vt=/(=)\?(?=&|$)|\?\?/;S.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Xt.pop()||S.expando+"_"+Ct.guid++;return this[e]=!0,e}}),S.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Vt.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Vt.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Vt,"$1"+r):!1!==e.jsonp&&(e.url+=(Et.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||S.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=C[r],C[r]=function(){o=arguments},n.always(function(){void 0===i?S(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,Xt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),"script"}),y.createHTMLDocument=((Ut=E.implementation.createHTMLDocument("").body).innerHTML="
    ",2===Ut.childNodes.length),S.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(y.createHTMLDocument?((r=(t=E.implementation.createHTMLDocument("")).createElement("base")).href=E.location.href,t.head.appendChild(r)):t=E),o=!n&&[],(i=N.exec(e))?[t.createElement(i[1])]:(i=xe([e],t,o),o&&o.length&&S(o).remove(),S.merge([],i.childNodes)));var r,i,o},S.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(S.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},S.expr.pseudos.animated=function(t){return S.grep(S.timers,function(e){return t===e.elem}).length},S.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=S.css(e,"position"),c=S(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=S.css(e,"top"),u=S.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,S.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):("number"==typeof f.top&&(f.top+="px"),"number"==typeof f.left&&(f.left+="px"),c.css(f))}},S.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){S.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===S.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===S.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=S(e).offset()).top+=S.css(e,"borderTopWidth",!0),i.left+=S.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-S.css(r,"marginTop",!0),left:t.left-i.left-S.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===S.css(e,"position"))e=e.offsetParent;return e||re})}}),S.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;S.fn[t]=function(e){return $(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),S.each(["top","left"],function(e,n){S.cssHooks[n]=$e(y.pixelPosition,function(e,t){if(t)return t=Be(e,n),Me.test(t)?S(e).position()[n]+"px":t})}),S.each({Height:"height",Width:"width"},function(a,s){S.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){S.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return $(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?S.css(e,t,i):S.style(e,t,n,i)},s,n?e:void 0,n)}})}),S.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){S.fn[t]=function(e){return this.on(t,e)}}),S.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),S.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){S.fn[n]=function(e,t){return 00){var c=e.utils.clone(r)||{};c.position=[a,l],c.index=s.length,s.push(new e.Token(i.slice(a,o),c))}a=o+1}}return s},e.tokenizer.separator=/[\s\-]+/,e.Pipeline=function(){this._stack=[]},e.Pipeline.registeredFunctions=Object.create(null),e.Pipeline.registerFunction=function(t,r){r in this.registeredFunctions&&e.utils.warn("Overwriting existing registered function: "+r),t.label=r,e.Pipeline.registeredFunctions[t.label]=t},e.Pipeline.warnIfFunctionNotRegistered=function(t){var r=t.label&&t.label in this.registeredFunctions;r||e.utils.warn("Function is not registered with pipeline. This may cause problems when serialising the index.\n",t)},e.Pipeline.load=function(t){var r=new e.Pipeline;return t.forEach(function(t){var i=e.Pipeline.registeredFunctions[t];if(!i)throw new Error("Cannot load unregistered function: "+t);r.add(i)}),r},e.Pipeline.prototype.add=function(){var t=Array.prototype.slice.call(arguments);t.forEach(function(t){e.Pipeline.warnIfFunctionNotRegistered(t),this._stack.push(t)},this)},e.Pipeline.prototype.after=function(t,r){e.Pipeline.warnIfFunctionNotRegistered(r);var i=this._stack.indexOf(t);if(i==-1)throw new Error("Cannot find existingFn");i+=1,this._stack.splice(i,0,r)},e.Pipeline.prototype.before=function(t,r){e.Pipeline.warnIfFunctionNotRegistered(r);var i=this._stack.indexOf(t);if(i==-1)throw new Error("Cannot find existingFn");this._stack.splice(i,0,r)},e.Pipeline.prototype.remove=function(e){var t=this._stack.indexOf(e);t!=-1&&this._stack.splice(t,1)},e.Pipeline.prototype.run=function(e){for(var t=this._stack.length,r=0;r1&&(se&&(r=n),s!=e);)i=r-t,n=t+Math.floor(i/2),s=this.elements[2*n];return s==e?2*n:s>e?2*n:sa?l+=2:o==a&&(t+=r[u+1]*i[l+1],u+=2,l+=2);return t},e.Vector.prototype.similarity=function(e){return this.dot(e)/this.magnitude()||0},e.Vector.prototype.toArray=function(){for(var e=new Array(this.elements.length/2),t=1,r=0;t0){var o,a=s.str.charAt(0);a in s.node.edges?o=s.node.edges[a]:(o=new e.TokenSet,s.node.edges[a]=o),1==s.str.length&&(o["final"]=!0),n.push({node:o,editsRemaining:s.editsRemaining,str:s.str.slice(1)})}if(0!=s.editsRemaining){if("*"in s.node.edges)var u=s.node.edges["*"];else{var u=new e.TokenSet;s.node.edges["*"]=u}if(0==s.str.length&&(u["final"]=!0),n.push({node:u,editsRemaining:s.editsRemaining-1,str:s.str}),s.str.length>1&&n.push({node:s.node,editsRemaining:s.editsRemaining-1,str:s.str.slice(1)}),1==s.str.length&&(s.node["final"]=!0),s.str.length>=1){if("*"in s.node.edges)var l=s.node.edges["*"];else{var l=new e.TokenSet;s.node.edges["*"]=l}1==s.str.length&&(l["final"]=!0),n.push({node:l,editsRemaining:s.editsRemaining-1,str:s.str.slice(1)})}if(s.str.length>1){var c,h=s.str.charAt(0),d=s.str.charAt(1);d in s.node.edges?c=s.node.edges[d]:(c=new e.TokenSet,s.node.edges[d]=c),1==s.str.length&&(c["final"]=!0),n.push({node:c,editsRemaining:s.editsRemaining-1,str:h+s.str.slice(2)})}}}return i},e.TokenSet.fromString=function(t){for(var r=new e.TokenSet,i=r,n=0,s=t.length;n=e;t--){var r=this.uncheckedNodes[t],i=r.child.toString();i in this.minimizedNodes?r.parent.edges[r["char"]]=this.minimizedNodes[i]:(r.child._str=i,this.minimizedNodes[i]=r.child),this.uncheckedNodes.pop()}},e.Index=function(e){this.invertedIndex=e.invertedIndex,this.fieldVectors=e.fieldVectors,this.tokenSet=e.tokenSet,this.fields=e.fields,this.pipeline=e.pipeline},e.Index.prototype.search=function(t){return this.query(function(r){var i=new e.QueryParser(t,r);i.parse()})},e.Index.prototype.query=function(t){for(var r=new e.Query(this.fields),i=Object.create(null),n=Object.create(null),s=Object.create(null),o=Object.create(null),a=Object.create(null),u=0;u1?this._b=1:this._b=e},e.Builder.prototype.k1=function(e){this._k1=e},e.Builder.prototype.add=function(t,r){var i=t[this._ref],n=Object.keys(this._fields);this._documents[i]=r||{},this.documentCount+=1;for(var s=0;s=this.length)return e.QueryLexer.EOS;var t=this.str.charAt(this.pos);return this.pos+=1,t},e.QueryLexer.prototype.width=function(){return this.pos-this.start},e.QueryLexer.prototype.ignore=function(){this.start==this.pos&&(this.pos+=1),this.start=this.pos},e.QueryLexer.prototype.backup=function(){this.pos-=1},e.QueryLexer.prototype.acceptDigitRun=function(){var t,r;do t=this.next(),r=t.charCodeAt(0);while(r>47&&r<58);t!=e.QueryLexer.EOS&&this.backup()},e.QueryLexer.prototype.more=function(){return this.pos1&&(t.backup(),t.emit(e.QueryLexer.TERM)),t.ignore(),t.more())return e.QueryLexer.lexText},e.QueryLexer.lexEditDistance=function(t){return t.ignore(),t.acceptDigitRun(),t.emit(e.QueryLexer.EDIT_DISTANCE),e.QueryLexer.lexText},e.QueryLexer.lexBoost=function(t){return t.ignore(),t.acceptDigitRun(),t.emit(e.QueryLexer.BOOST),e.QueryLexer.lexText},e.QueryLexer.lexEOS=function(t){t.width()>0&&t.emit(e.QueryLexer.TERM)},e.QueryLexer.termSeparator=e.tokenizer.separator,e.QueryLexer.lexText=function(t){for(;;){var r=t.next();if(r==e.QueryLexer.EOS)return e.QueryLexer.lexEOS;if(92!=r.charCodeAt(0)){if(":"==r)return e.QueryLexer.lexField;if("~"==r)return t.backup(),t.width()>0&&t.emit(e.QueryLexer.TERM),e.QueryLexer.lexEditDistance;if("^"==r)return t.backup(),t.width()>0&&t.emit(e.QueryLexer.TERM),e.QueryLexer.lexBoost;if("+"==r&&1===t.width())return t.emit(e.QueryLexer.PRESENCE),e.QueryLexer.lexText;if("-"==r&&1===t.width())return t.emit(e.QueryLexer.PRESENCE),e.QueryLexer.lexText;if(r.match(e.QueryLexer.termSeparator))return e.QueryLexer.lexTerm}else t.escapeCharacter()}},e.QueryParser=function(t,r){this.lexer=new e.QueryLexer(t),this.query=r,this.currentClause={},this.lexemeIdx=0},e.QueryParser.prototype.parse=function(){this.lexer.run(),this.lexemes=this.lexer.lexemes;for(var t=e.QueryParser.parseClause;t;)t=t(this);return this.query},e.QueryParser.prototype.peekLexeme=function(){return this.lexemes[this.lexemeIdx]},e.QueryParser.prototype.consumeLexeme=function(){var e=this.peekLexeme();return this.lexemeIdx+=1,e},e.QueryParser.prototype.nextClause=function(){var e=this.currentClause;this.query.clause(e),this.currentClause={}},e.QueryParser.parseClause=function(t){var r=t.peekLexeme();if(void 0!=r)switch(r.type){case e.QueryLexer.PRESENCE:return e.QueryParser.parsePresence;case e.QueryLexer.FIELD:return e.QueryParser.parseField;case e.QueryLexer.TERM:return e.QueryParser.parseTerm;default:var i="expected either a field or a term, found "+r.type;throw r.str.length>=1&&(i+=" with value '"+r.str+"'"),new e.QueryParseError(i,r.start,r.end)}},e.QueryParser.parsePresence=function(t){var r=t.consumeLexeme();if(void 0!=r){switch(r.str){case"-":t.currentClause.presence=e.Query.presence.PROHIBITED;break;case"+":t.currentClause.presence=e.Query.presence.REQUIRED;break;default:var i="unrecognised presence operator'"+r.str+"'";throw new e.QueryParseError(i,r.start,r.end)}var n=t.peekLexeme();if(void 0==n){var i="expecting term or field, found nothing";throw new e.QueryParseError(i,r.start,r.end)}switch(n.type){case e.QueryLexer.FIELD:return e.QueryParser.parseField;case e.QueryLexer.TERM:return e.QueryParser.parseTerm;default:var i="expecting term or field, found '"+n.type+"'";throw new e.QueryParseError(i,n.start,n.end)}}},e.QueryParser.parseField=function(t){var r=t.consumeLexeme();if(void 0!=r){if(t.query.allFields.indexOf(r.str)==-1){var i=t.query.allFields.map(function(e){return"'"+e+"'"}).join(", "),n="unrecognised field '"+r.str+"', possible fields: "+i;throw new e.QueryParseError(n,r.start,r.end)}t.currentClause.fields=[r.str];var s=t.peekLexeme();if(void 0==s){var n="expecting term, found nothing";throw new e.QueryParseError(n,r.start,r.end)}switch(s.type){case e.QueryLexer.TERM:return e.QueryParser.parseTerm;default:var n="expecting term, found '"+s.type+"'";throw new e.QueryParseError(n,s.start,s.end)}}},e.QueryParser.parseTerm=function(t){var r=t.consumeLexeme();if(void 0!=r){t.currentClause.term=r.str.toLowerCase(),r.str.indexOf("*")!=-1&&(t.currentClause.usePipeline=!1);var i=t.peekLexeme();if(void 0==i)return void t.nextClause();switch(i.type){case e.QueryLexer.TERM:return t.nextClause(),e.QueryParser.parseTerm;case e.QueryLexer.FIELD:return t.nextClause(),e.QueryParser.parseField;case e.QueryLexer.EDIT_DISTANCE:return e.QueryParser.parseEditDistance;case e.QueryLexer.BOOST:return e.QueryParser.parseBoost;case e.QueryLexer.PRESENCE:return t.nextClause(),e.QueryParser.parsePresence;default:var n="Unexpected lexeme type '"+i.type+"'";throw new e.QueryParseError(n,i.start,i.end)}}},e.QueryParser.parseEditDistance=function(t){var r=t.consumeLexeme();if(void 0!=r){var i=parseInt(r.str,10);if(isNaN(i)){var n="edit distance must be numeric";throw new e.QueryParseError(n,r.start,r.end)}t.currentClause.editDistance=i;var s=t.peekLexeme();if(void 0==s)return void t.nextClause();switch(s.type){case e.QueryLexer.TERM:return t.nextClause(),e.QueryParser.parseTerm;case e.QueryLexer.FIELD:return t.nextClause(),e.QueryParser.parseField;case e.QueryLexer.EDIT_DISTANCE:return e.QueryParser.parseEditDistance;case e.QueryLexer.BOOST:return e.QueryParser.parseBoost;case e.QueryLexer.PRESENCE:return t.nextClause(),e.QueryParser.parsePresence;default:var n="Unexpected lexeme type '"+s.type+"'";throw new e.QueryParseError(n,s.start,s.end)}}},e.QueryParser.parseBoost=function(t){var r=t.consumeLexeme();if(void 0!=r){var i=parseInt(r.str,10);if(isNaN(i)){var n="boost must be numeric";throw new e.QueryParseError(n,r.start,r.end)}t.currentClause.boost=i;var s=t.peekLexeme();if(void 0==s)return void t.nextClause();switch(s.type){case e.QueryLexer.TERM:return t.nextClause(),e.QueryParser.parseTerm;case e.QueryLexer.FIELD:return t.nextClause(),e.QueryParser.parseField;case e.QueryLexer.EDIT_DISTANCE:return e.QueryParser.parseEditDistance;case e.QueryLexer.BOOST:return e.QueryParser.parseBoost;case e.QueryLexer.PRESENCE:return t.nextClause(),e.QueryParser.parsePresence;default:var n="Unexpected lexeme type '"+s.type+"'";throw new e.QueryParseError(n,s.start,s.end)}}},function(e,t){"function"==typeof define&&define.amd?define(t):"object"==typeof exports?module.exports=t():e.lunr=t()}(this,function(){return e})}(); diff --git a/Documentation/js/typeahead.jquery.js b/Documentation/js/typeahead.jquery.js new file mode 100644 index 0000000..3a2d2ab --- /dev/null +++ b/Documentation/js/typeahead.jquery.js @@ -0,0 +1,1694 @@ +/*! + * typeahead.js 1.3.1 + * https://github.com/corejavascript/typeahead.js + * Copyright 2013-2020 Twitter, Inc. and other contributors; Licensed MIT + */ + + +(function(root, factory) { + if (typeof define === "function" && define.amd) { + define([ "jquery" ], function(a0) { + return factory(a0); + }); + } else if (typeof module === "object" && module.exports) { + module.exports = factory(require("jquery")); + } else { + factory(root["jQuery"]); + } +})(this, function($) { + var _ = function() { + "use strict"; + return { + isMsie: function() { + return /(msie|trident)/i.test(navigator.userAgent) ? navigator.userAgent.match(/(msie |rv:)(\d+(.\d+)?)/i)[2] : false; + }, + isBlankString: function(str) { + return !str || /^\s*$/.test(str); + }, + escapeRegExChars: function(str) { + return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"); + }, + isString: function(obj) { + return typeof obj === "string"; + }, + isNumber: function(obj) { + return typeof obj === "number"; + }, + isArray: $.isArray, + isFunction: $.isFunction, + isObject: $.isPlainObject, + isUndefined: function(obj) { + return typeof obj === "undefined"; + }, + isElement: function(obj) { + return !!(obj && obj.nodeType === 1); + }, + isJQuery: function(obj) { + return obj instanceof $; + }, + toStr: function toStr(s) { + return _.isUndefined(s) || s === null ? "" : s + ""; + }, + bind: $.proxy, + each: function(collection, cb) { + $.each(collection, reverseArgs); + function reverseArgs(index, value) { + return cb(value, index); + } + }, + map: $.map, + filter: $.grep, + every: function(obj, test) { + var result = true; + if (!obj) { + return result; + } + $.each(obj, function(key, val) { + if (!(result = test.call(null, val, key, obj))) { + return false; + } + }); + return !!result; + }, + some: function(obj, test) { + var result = false; + if (!obj) { + return result; + } + $.each(obj, function(key, val) { + if (result = test.call(null, val, key, obj)) { + return false; + } + }); + return !!result; + }, + mixin: $.extend, + identity: function(x) { + return x; + }, + clone: function(obj) { + return $.extend(true, {}, obj); + }, + getIdGenerator: function() { + var counter = 0; + return function() { + return counter++; + }; + }, + templatify: function templatify(obj) { + return $.isFunction(obj) ? obj : template; + function template() { + return String(obj); + } + }, + defer: function(fn) { + setTimeout(fn, 0); + }, + debounce: function(func, wait, immediate) { + var timeout, result; + return function() { + var context = this, args = arguments, later, callNow; + later = function() { + timeout = null; + if (!immediate) { + result = func.apply(context, args); + } + }; + callNow = immediate && !timeout; + clearTimeout(timeout); + timeout = setTimeout(later, wait); + if (callNow) { + result = func.apply(context, args); + } + return result; + }; + }, + throttle: function(func, wait) { + var context, args, timeout, result, previous, later; + previous = 0; + later = function() { + previous = new Date(); + timeout = null; + result = func.apply(context, args); + }; + return function() { + var now = new Date(), remaining = wait - (now - previous); + context = this; + args = arguments; + if (remaining <= 0) { + clearTimeout(timeout); + timeout = null; + previous = now; + result = func.apply(context, args); + } else if (!timeout) { + timeout = setTimeout(later, remaining); + } + return result; + }; + }, + stringify: function(val) { + return _.isString(val) ? val : JSON.stringify(val); + }, + guid: function() { + function _p8(s) { + var p = (Math.random().toString(16) + "000000000").substr(2, 8); + return s ? "-" + p.substr(0, 4) + "-" + p.substr(4, 4) : p; + } + return "tt-" + _p8() + _p8(true) + _p8(true) + _p8(); + }, + noop: function() {} + }; + }(); + var WWW = function() { + "use strict"; + var defaultClassNames = { + wrapper: "twitter-typeahead", + input: "tt-input", + hint: "tt-hint", + menu: "tt-menu", + dataset: "tt-dataset", + suggestion: "tt-suggestion", + selectable: "tt-selectable", + empty: "tt-empty", + open: "tt-open", + cursor: "tt-cursor", + highlight: "tt-highlight" + }; + return build; + function build(o) { + var www, classes; + classes = _.mixin({}, defaultClassNames, o); + www = { + css: buildCss(), + classes: classes, + html: buildHtml(classes), + selectors: buildSelectors(classes) + }; + return { + css: www.css, + html: www.html, + classes: www.classes, + selectors: www.selectors, + mixin: function(o) { + _.mixin(o, www); + } + }; + } + function buildHtml(c) { + return { + wrapper: '', + menu: '
    ' + }; + } + function buildSelectors(classes) { + var selectors = {}; + _.each(classes, function(v, k) { + selectors[k] = "." + v; + }); + return selectors; + } + function buildCss() { + var css = { + wrapper: { + position: "relative", + display: "inline-block" + }, + hint: { + position: "absolute", + top: "0", + left: "0", + borderColor: "transparent", + boxShadow: "none", + opacity: "1" + }, + input: { + position: "relative", + verticalAlign: "top", + backgroundColor: "transparent" + }, + inputWithNoHint: { + position: "relative", + verticalAlign: "top" + }, + menu: { + position: "absolute", + top: "100%", + left: "0", + zIndex: "100", + display: "none" + }, + ltr: { + left: "0", + right: "auto" + }, + rtl: { + left: "auto", + right: " 0" + } + }; + if (_.isMsie()) { + _.mixin(css.input, { + backgroundImage: "url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)" + }); + } + return css; + } + }(); + var EventBus = function() { + "use strict"; + var namespace, deprecationMap; + namespace = "typeahead:"; + deprecationMap = { + render: "rendered", + cursorchange: "cursorchanged", + select: "selected", + autocomplete: "autocompleted" + }; + function EventBus(o) { + if (!o || !o.el) { + $.error("EventBus initialized without el"); + } + this.$el = $(o.el); + } + _.mixin(EventBus.prototype, { + _trigger: function(type, args) { + var $e = $.Event(namespace + type); + this.$el.trigger.call(this.$el, $e, args || []); + return $e; + }, + before: function(type) { + var args, $e; + args = [].slice.call(arguments, 1); + $e = this._trigger("before" + type, args); + return $e.isDefaultPrevented(); + }, + trigger: function(type) { + var deprecatedType; + this._trigger(type, [].slice.call(arguments, 1)); + if (deprecatedType = deprecationMap[type]) { + this._trigger(deprecatedType, [].slice.call(arguments, 1)); + } + } + }); + return EventBus; + }(); + var EventEmitter = function() { + "use strict"; + var splitter = /\s+/, nextTick = getNextTick(); + return { + onSync: onSync, + onAsync: onAsync, + off: off, + trigger: trigger + }; + function on(method, types, cb, context) { + var type; + if (!cb) { + return this; + } + types = types.split(splitter); + cb = context ? bindContext(cb, context) : cb; + this._callbacks = this._callbacks || {}; + while (type = types.shift()) { + this._callbacks[type] = this._callbacks[type] || { + sync: [], + async: [] + }; + this._callbacks[type][method].push(cb); + } + return this; + } + function onAsync(types, cb, context) { + return on.call(this, "async", types, cb, context); + } + function onSync(types, cb, context) { + return on.call(this, "sync", types, cb, context); + } + function off(types) { + var type; + if (!this._callbacks) { + return this; + } + types = types.split(splitter); + while (type = types.shift()) { + delete this._callbacks[type]; + } + return this; + } + function trigger(types) { + var type, callbacks, args, syncFlush, asyncFlush; + if (!this._callbacks) { + return this; + } + types = types.split(splitter); + args = [].slice.call(arguments, 1); + while ((type = types.shift()) && (callbacks = this._callbacks[type])) { + syncFlush = getFlush(callbacks.sync, this, [ type ].concat(args)); + asyncFlush = getFlush(callbacks.async, this, [ type ].concat(args)); + syncFlush() && nextTick(asyncFlush); + } + return this; + } + function getFlush(callbacks, context, args) { + return flush; + function flush() { + var cancelled; + for (var i = 0, len = callbacks.length; !cancelled && i < len; i += 1) { + cancelled = callbacks[i].apply(context, args) === false; + } + return !cancelled; + } + } + function getNextTick() { + var nextTickFn; + if (window.setImmediate) { + nextTickFn = function nextTickSetImmediate(fn) { + setImmediate(function() { + fn(); + }); + }; + } else { + nextTickFn = function nextTickSetTimeout(fn) { + setTimeout(function() { + fn(); + }, 0); + }; + } + return nextTickFn; + } + function bindContext(fn, context) { + return fn.bind ? fn.bind(context) : function() { + fn.apply(context, [].slice.call(arguments, 0)); + }; + } + }(); + var highlight = function(doc) { + "use strict"; + var defaults = { + node: null, + pattern: null, + tagName: "strong", + className: null, + wordsOnly: false, + caseSensitive: false, + diacriticInsensitive: false + }; + var accented = { + A: "[AaªÀ-Åà-åĀ-ąǍǎȀ-ȃȦȧᴬᵃḀḁẚẠ-ảₐ℀℁℻⒜Ⓐⓐ㍱-㍴㎀-㎄㎈㎉㎩-㎯㏂㏊㏟㏿Aa]", + B: "[BbᴮᵇḂ-ḇℬ⒝Ⓑⓑ㍴㎅-㎇㏃㏈㏔㏝Bb]", + C: "[CcÇçĆ-čᶜ℀ℂ℃℅℆ℭⅭⅽ⒞Ⓒⓒ㍶㎈㎉㎝㎠㎤㏄-㏇Cc]", + D: "[DdĎďDŽ-džDZ-dzᴰᵈḊ-ḓⅅⅆⅮⅾ⒟Ⓓⓓ㋏㍲㍷-㍹㎗㎭-㎯㏅㏈Dd]", + E: "[EeÈ-Ëè-ëĒ-ěȄ-ȇȨȩᴱᵉḘ-ḛẸ-ẽₑ℡ℯℰⅇ⒠Ⓔⓔ㉐㋍㋎Ee]", + F: "[FfᶠḞḟ℉ℱ℻⒡Ⓕⓕ㎊-㎌㎙ff-fflFf]", + G: "[GgĜ-ģǦǧǴǵᴳᵍḠḡℊ⒢Ⓖⓖ㋌㋍㎇㎍-㎏㎓㎬㏆㏉㏒㏿Gg]", + H: "[HhĤĥȞȟʰᴴḢ-ḫẖℋ-ℎ⒣Ⓗⓗ㋌㍱㎐-㎔㏊㏋㏗Hh]", + I: "[IiÌ-Ïì-ïĨ-İIJijǏǐȈ-ȋᴵᵢḬḭỈ-ịⁱℐℑℹⅈⅠ-ⅣⅥ-ⅨⅪⅫⅰ-ⅳⅵ-ⅸⅺⅻ⒤Ⓘⓘ㍺㏌㏕fiffiIi]", + J: "[JjIJ-ĵLJ-njǰʲᴶⅉ⒥ⒿⓙⱼJj]", + K: "[KkĶķǨǩᴷᵏḰ-ḵK⒦Ⓚⓚ㎄㎅㎉㎏㎑㎘㎞㎢㎦㎪㎸㎾㏀㏆㏍-㏏Kk]", + L: "[LlĹ-ŀLJ-ljˡᴸḶḷḺ-ḽℒℓ℡Ⅼⅼ⒧Ⓛⓛ㋏㎈㎉㏐-㏓㏕㏖㏿flfflLl]", + M: "[MmᴹᵐḾ-ṃ℠™ℳⅯⅿ⒨Ⓜⓜ㍷-㍹㎃㎆㎎㎒㎖㎙-㎨㎫㎳㎷㎹㎽㎿㏁㏂㏎㏐㏔-㏖㏘㏙㏞㏟Mm]", + N: "[NnÑñŃ-ʼnNJ-njǸǹᴺṄ-ṋⁿℕ№⒩Ⓝⓝ㎁㎋㎚㎱㎵㎻㏌㏑Nn]", + O: "[OoºÒ-Öò-öŌ-őƠơǑǒǪǫȌ-ȏȮȯᴼᵒỌ-ỏₒ℅№ℴ⒪Ⓞⓞ㍵㏇㏒㏖Oo]", + P: "[PpᴾᵖṔ-ṗℙ⒫Ⓟⓟ㉐㍱㍶㎀㎊㎩-㎬㎰㎴㎺㏋㏗-㏚Pp]", + Q: "[Qqℚ⒬Ⓠⓠ㏃Qq]", + R: "[RrŔ-řȐ-ȓʳᴿᵣṘ-ṛṞṟ₨ℛ-ℝ⒭Ⓡⓡ㋍㍴㎭-㎯㏚㏛Rr]", + S: "[SsŚ-šſȘșˢṠ-ṣ₨℁℠⒮Ⓢⓢ㎧㎨㎮-㎳㏛㏜stSs]", + T: "[TtŢ-ťȚțᵀᵗṪ-ṱẗ℡™⒯Ⓣⓣ㉐㋏㎔㏏ſtstTt]", + U: "[UuÙ-Üù-üŨ-ųƯưǓǔȔ-ȗᵁᵘᵤṲ-ṷỤ-ủ℆⒰Ⓤⓤ㍳㍺Uu]", + V: "[VvᵛᵥṼ-ṿⅣ-Ⅷⅳ-ⅷ⒱Ⓥⓥⱽ㋎㍵㎴-㎹㏜㏞Vv]", + W: "[WwŴŵʷᵂẀ-ẉẘ⒲Ⓦⓦ㎺-㎿㏝Ww]", + X: "[XxˣẊ-ẍₓ℻Ⅸ-Ⅻⅸ-ⅻ⒳Ⓧⓧ㏓Xx]", + Y: "[YyÝýÿŶ-ŸȲȳʸẎẏẙỲ-ỹ⒴Ⓨⓨ㏉Yy]", + Z: "[ZzŹ-žDZ-dzᶻẐ-ẕℤℨ⒵Ⓩⓩ㎐-㎔Zz]" + }; + return function hightlight(o) { + var regex; + o = _.mixin({}, defaults, o); + if (!o.node || !o.pattern) { + return; + } + o.pattern = _.isArray(o.pattern) ? o.pattern : [ o.pattern ]; + regex = getRegex(o.pattern, o.caseSensitive, o.wordsOnly, o.diacriticInsensitive); + traverse(o.node, hightlightTextNode); + function hightlightTextNode(textNode) { + var match, patternNode, wrapperNode; + if (match = regex.exec(textNode.data)) { + wrapperNode = doc.createElement(o.tagName); + o.className && (wrapperNode.className = o.className); + patternNode = textNode.splitText(match.index); + patternNode.splitText(match[0].length); + wrapperNode.appendChild(patternNode.cloneNode(true)); + textNode.parentNode.replaceChild(wrapperNode, patternNode); + } + return !!match; + } + function traverse(el, hightlightTextNode) { + var childNode, TEXT_NODE_TYPE = 3; + for (var i = 0; i < el.childNodes.length; i++) { + childNode = el.childNodes[i]; + if (childNode.nodeType === TEXT_NODE_TYPE) { + i += hightlightTextNode(childNode) ? 1 : 0; + } else { + traverse(childNode, hightlightTextNode); + } + } + } + }; + function accent_replacer(chr) { + return accented[chr.toUpperCase()] || chr; + } + function getRegex(patterns, caseSensitive, wordsOnly, diacriticInsensitive) { + var escapedPatterns = [], regexStr; + for (var i = 0, len = patterns.length; i < len; i++) { + var escapedWord = _.escapeRegExChars(patterns[i]); + if (diacriticInsensitive) { + escapedWord = escapedWord.replace(/\S/g, accent_replacer); + } + escapedPatterns.push(escapedWord); + } + regexStr = wordsOnly ? "\\b(" + escapedPatterns.join("|") + ")\\b" : "(" + escapedPatterns.join("|") + ")"; + return caseSensitive ? new RegExp(regexStr) : new RegExp(regexStr, "i"); + } + }(window.document); + var Input = function() { + "use strict"; + var specialKeyCodeMap; + specialKeyCodeMap = { + 9: "tab", + 27: "esc", + 37: "left", + 39: "right", + 13: "enter", + 38: "up", + 40: "down" + }; + function Input(o, www) { + var id; + o = o || {}; + if (!o.input) { + $.error("input is missing"); + } + www.mixin(this); + this.$hint = $(o.hint); + this.$input = $(o.input); + this.$menu = $(o.menu); + id = this.$input.attr("id") || _.guid(); + this.$menu.attr("id", id + "_listbox"); + this.$hint.attr({ + "aria-hidden": true + }); + this.$input.attr({ + "aria-owns": id + "_listbox", + role: "combobox", + "aria-autocomplete": "list", + "aria-expanded": false + }); + this.query = this.$input.val(); + this.queryWhenFocused = this.hasFocus() ? this.query : null; + this.$overflowHelper = buildOverflowHelper(this.$input); + this._checkLanguageDirection(); + if (this.$hint.length === 0) { + this.setHint = this.getHint = this.clearHint = this.clearHintIfInvalid = _.noop; + } + this.onSync("cursorchange", this._updateDescendent); + } + Input.normalizeQuery = function(str) { + return _.toStr(str).replace(/^\s*/g, "").replace(/\s{2,}/g, " "); + }; + _.mixin(Input.prototype, EventEmitter, { + _onBlur: function onBlur() { + this.resetInputValue(); + this.trigger("blurred"); + }, + _onFocus: function onFocus() { + this.queryWhenFocused = this.query; + this.trigger("focused"); + }, + _onKeydown: function onKeydown($e) { + var keyName = specialKeyCodeMap[$e.which || $e.keyCode]; + this._managePreventDefault(keyName, $e); + if (keyName && this._shouldTrigger(keyName, $e)) { + this.trigger(keyName + "Keyed", $e); + } + }, + _onInput: function onInput() { + this._setQuery(this.getInputValue()); + this.clearHintIfInvalid(); + this._checkLanguageDirection(); + }, + _managePreventDefault: function managePreventDefault(keyName, $e) { + var preventDefault; + switch (keyName) { + case "up": + case "down": + preventDefault = !withModifier($e); + break; + + default: + preventDefault = false; + } + preventDefault && $e.preventDefault(); + }, + _shouldTrigger: function shouldTrigger(keyName, $e) { + var trigger; + switch (keyName) { + case "tab": + trigger = !withModifier($e); + break; + + default: + trigger = true; + } + return trigger; + }, + _checkLanguageDirection: function checkLanguageDirection() { + var dir = (this.$input.css("direction") || "ltr").toLowerCase(); + if (this.dir !== dir) { + this.dir = dir; + this.$hint.attr("dir", dir); + this.trigger("langDirChanged", dir); + } + }, + _setQuery: function setQuery(val, silent) { + var areEquivalent, hasDifferentWhitespace; + areEquivalent = areQueriesEquivalent(val, this.query); + hasDifferentWhitespace = areEquivalent ? this.query.length !== val.length : false; + this.query = val; + if (!silent && !areEquivalent) { + this.trigger("queryChanged", this.query); + } else if (!silent && hasDifferentWhitespace) { + this.trigger("whitespaceChanged", this.query); + } + }, + _updateDescendent: function updateDescendent(event, id) { + this.$input.attr("aria-activedescendant", id); + }, + bind: function() { + var that = this, onBlur, onFocus, onKeydown, onInput; + onBlur = _.bind(this._onBlur, this); + onFocus = _.bind(this._onFocus, this); + onKeydown = _.bind(this._onKeydown, this); + onInput = _.bind(this._onInput, this); + this.$input.on("blur.tt", onBlur).on("focus.tt", onFocus).on("keydown.tt", onKeydown); + if (!_.isMsie() || _.isMsie() > 9) { + this.$input.on("input.tt", onInput); + } else { + this.$input.on("keydown.tt keypress.tt cut.tt paste.tt", function($e) { + if (specialKeyCodeMap[$e.which || $e.keyCode]) { + return; + } + _.defer(_.bind(that._onInput, that, $e)); + }); + } + return this; + }, + focus: function focus() { + this.$input.focus(); + }, + blur: function blur() { + this.$input.blur(); + }, + getLangDir: function getLangDir() { + return this.dir; + }, + getQuery: function getQuery() { + return this.query || ""; + }, + setQuery: function setQuery(val, silent) { + this.setInputValue(val); + this._setQuery(val, silent); + }, + hasQueryChangedSinceLastFocus: function hasQueryChangedSinceLastFocus() { + return this.query !== this.queryWhenFocused; + }, + getInputValue: function getInputValue() { + return this.$input.val(); + }, + setInputValue: function setInputValue(value) { + this.$input.val(value); + this.clearHintIfInvalid(); + this._checkLanguageDirection(); + }, + resetInputValue: function resetInputValue() { + this.setInputValue(this.query); + }, + getHint: function getHint() { + return this.$hint.val(); + }, + setHint: function setHint(value) { + this.$hint.val(value); + }, + clearHint: function clearHint() { + this.setHint(""); + }, + clearHintIfInvalid: function clearHintIfInvalid() { + var val, hint, valIsPrefixOfHint, isValid; + val = this.getInputValue(); + hint = this.getHint(); + valIsPrefixOfHint = val !== hint && hint.indexOf(val) === 0; + isValid = val !== "" && valIsPrefixOfHint && !this.hasOverflow(); + !isValid && this.clearHint(); + }, + hasFocus: function hasFocus() { + return this.$input.is(":focus"); + }, + hasOverflow: function hasOverflow() { + var constraint = this.$input.width() - 2; + this.$overflowHelper.text(this.getInputValue()); + return this.$overflowHelper.width() >= constraint; + }, + isCursorAtEnd: function() { + var valueLength, selectionStart, range; + valueLength = this.$input.val().length; + selectionStart = this.$input[0].selectionStart; + if (_.isNumber(selectionStart)) { + return selectionStart === valueLength; + } else if (document.selection) { + range = document.selection.createRange(); + range.moveStart("character", -valueLength); + return valueLength === range.text.length; + } + return true; + }, + destroy: function destroy() { + this.$hint.off(".tt"); + this.$input.off(".tt"); + this.$overflowHelper.remove(); + this.$hint = this.$input = this.$overflowHelper = $("
    "); + }, + setAriaExpanded: function setAriaExpanded(value) { + this.$input.attr("aria-expanded", value); + } + }); + return Input; + function buildOverflowHelper($input) { + return $('').css({ + position: "absolute", + visibility: "hidden", + whiteSpace: "pre", + fontFamily: $input.css("font-family"), + fontSize: $input.css("font-size"), + fontStyle: $input.css("font-style"), + fontVariant: $input.css("font-variant"), + fontWeight: $input.css("font-weight"), + wordSpacing: $input.css("word-spacing"), + letterSpacing: $input.css("letter-spacing"), + textIndent: $input.css("text-indent"), + textRendering: $input.css("text-rendering"), + textTransform: $input.css("text-transform") + }).insertAfter($input); + } + function areQueriesEquivalent(a, b) { + return Input.normalizeQuery(a) === Input.normalizeQuery(b); + } + function withModifier($e) { + return $e.altKey || $e.ctrlKey || $e.metaKey || $e.shiftKey; + } + }(); + var Dataset = function() { + "use strict"; + var keys, nameGenerator; + keys = { + dataset: "tt-selectable-dataset", + val: "tt-selectable-display", + obj: "tt-selectable-object" + }; + nameGenerator = _.getIdGenerator(); + function Dataset(o, www) { + o = o || {}; + o.templates = o.templates || {}; + o.templates.notFound = o.templates.notFound || o.templates.empty; + if (!o.source) { + $.error("missing source"); + } + if (!o.node) { + $.error("missing node"); + } + if (o.name && !isValidName(o.name)) { + $.error("invalid dataset name: " + o.name); + } + www.mixin(this); + this.highlight = !!o.highlight; + this.name = _.toStr(o.name || nameGenerator()); + this.limit = o.limit || 5; + this.displayFn = getDisplayFn(o.display || o.displayKey); + this.templates = getTemplates(o.templates, this.displayFn); + this.source = o.source.__ttAdapter ? o.source.__ttAdapter() : o.source; + this.async = _.isUndefined(o.async) ? this.source.length > 2 : !!o.async; + this._resetLastSuggestion(); + this.$el = $(o.node).attr("role", "presentation").addClass(this.classes.dataset).addClass(this.classes.dataset + "-" + this.name); + } + Dataset.extractData = function extractData(el) { + var $el = $(el); + if ($el.data(keys.obj)) { + return { + dataset: $el.data(keys.dataset) || "", + val: $el.data(keys.val) || "", + obj: $el.data(keys.obj) || null + }; + } + return null; + }; + _.mixin(Dataset.prototype, EventEmitter, { + _overwrite: function overwrite(query, suggestions) { + suggestions = suggestions || []; + if (suggestions.length) { + this._renderSuggestions(query, suggestions); + } else if (this.async && this.templates.pending) { + this._renderPending(query); + } else if (!this.async && this.templates.notFound) { + this._renderNotFound(query); + } else { + this._empty(); + } + this.trigger("rendered", suggestions, false, this.name); + }, + _append: function append(query, suggestions) { + suggestions = suggestions || []; + if (suggestions.length && this.$lastSuggestion.length) { + this._appendSuggestions(query, suggestions); + } else if (suggestions.length) { + this._renderSuggestions(query, suggestions); + } else if (!this.$lastSuggestion.length && this.templates.notFound) { + this._renderNotFound(query); + } + this.trigger("rendered", suggestions, true, this.name); + }, + _renderSuggestions: function renderSuggestions(query, suggestions) { + var $fragment; + $fragment = this._getSuggestionsFragment(query, suggestions); + this.$lastSuggestion = $fragment.children().last(); + this.$el.html($fragment).prepend(this._getHeader(query, suggestions)).append(this._getFooter(query, suggestions)); + }, + _appendSuggestions: function appendSuggestions(query, suggestions) { + var $fragment, $lastSuggestion; + $fragment = this._getSuggestionsFragment(query, suggestions); + $lastSuggestion = $fragment.children().last(); + this.$lastSuggestion.after($fragment); + this.$lastSuggestion = $lastSuggestion; + }, + _renderPending: function renderPending(query) { + var template = this.templates.pending; + this._resetLastSuggestion(); + template && this.$el.html(template({ + query: query, + dataset: this.name + })); + }, + _renderNotFound: function renderNotFound(query) { + var template = this.templates.notFound; + this._resetLastSuggestion(); + template && this.$el.html(template({ + query: query, + dataset: this.name + })); + }, + _empty: function empty() { + this.$el.empty(); + this._resetLastSuggestion(); + }, + _getSuggestionsFragment: function getSuggestionsFragment(query, suggestions) { + var that = this, fragment; + fragment = document.createDocumentFragment(); + _.each(suggestions, function getSuggestionNode(suggestion) { + var $el, context; + context = that._injectQuery(query, suggestion); + $el = $(that.templates.suggestion(context)).data(keys.dataset, that.name).data(keys.obj, suggestion).data(keys.val, that.displayFn(suggestion)).addClass(that.classes.suggestion + " " + that.classes.selectable); + fragment.appendChild($el[0]); + }); + this.highlight && highlight({ + className: this.classes.highlight, + node: fragment, + pattern: query + }); + return $(fragment); + }, + _getFooter: function getFooter(query, suggestions) { + return this.templates.footer ? this.templates.footer({ + query: query, + suggestions: suggestions, + dataset: this.name + }) : null; + }, + _getHeader: function getHeader(query, suggestions) { + return this.templates.header ? this.templates.header({ + query: query, + suggestions: suggestions, + dataset: this.name + }) : null; + }, + _resetLastSuggestion: function resetLastSuggestion() { + this.$lastSuggestion = $(); + }, + _injectQuery: function injectQuery(query, obj) { + return _.isObject(obj) ? _.mixin({ + _query: query + }, obj) : obj; + }, + update: function update(query) { + var that = this, canceled = false, syncCalled = false, rendered = 0; + this.cancel(); + this.cancel = function cancel() { + canceled = true; + that.cancel = $.noop; + that.async && that.trigger("asyncCanceled", query, that.name); + }; + this.source(query, sync, async); + !syncCalled && sync([]); + function sync(suggestions) { + if (syncCalled) { + return; + } + syncCalled = true; + suggestions = (suggestions || []).slice(0, that.limit); + rendered = suggestions.length; + that._overwrite(query, suggestions); + if (rendered < that.limit && that.async) { + that.trigger("asyncRequested", query, that.name); + } + } + function async(suggestions) { + suggestions = suggestions || []; + if (!canceled && rendered < that.limit) { + that.cancel = $.noop; + var idx = Math.abs(rendered - that.limit); + rendered += idx; + that._append(query, suggestions.slice(0, idx)); + that.async && that.trigger("asyncReceived", query, that.name); + } + } + }, + cancel: $.noop, + clear: function clear() { + this._empty(); + this.cancel(); + this.trigger("cleared"); + }, + isEmpty: function isEmpty() { + return this.$el.is(":empty"); + }, + destroy: function destroy() { + this.$el = $("
    "); + } + }); + return Dataset; + function getDisplayFn(display) { + display = display || _.stringify; + return _.isFunction(display) ? display : displayFn; + function displayFn(obj) { + return obj[display]; + } + } + function getTemplates(templates, displayFn) { + return { + notFound: templates.notFound && _.templatify(templates.notFound), + pending: templates.pending && _.templatify(templates.pending), + header: templates.header && _.templatify(templates.header), + footer: templates.footer && _.templatify(templates.footer), + suggestion: templates.suggestion ? userSuggestionTemplate : suggestionTemplate + }; + function userSuggestionTemplate(context) { + var template = templates.suggestion; + return $(template(context)).attr("id", _.guid()); + } + function suggestionTemplate(context) { + return $('
    ').attr("id", _.guid()).text(displayFn(context)); + } + } + function isValidName(str) { + return /^[_a-zA-Z0-9-]+$/.test(str); + } + }(); + var Menu = function() { + "use strict"; + function Menu(o, www) { + var that = this; + o = o || {}; + if (!o.node) { + $.error("node is required"); + } + www.mixin(this); + this.$node = $(o.node); + this.query = null; + this.datasets = _.map(o.datasets, initializeDataset); + function initializeDataset(oDataset) { + var node = that.$node.find(oDataset.node).first(); + oDataset.node = node.length ? node : $("
    ").appendTo(that.$node); + return new Dataset(oDataset, www); + } + } + _.mixin(Menu.prototype, EventEmitter, { + _onSelectableClick: function onSelectableClick($e) { + this.trigger("selectableClicked", $($e.currentTarget)); + }, + _onRendered: function onRendered(type, dataset, suggestions, async) { + this.$node.toggleClass(this.classes.empty, this._allDatasetsEmpty()); + this.trigger("datasetRendered", dataset, suggestions, async); + }, + _onCleared: function onCleared() { + this.$node.toggleClass(this.classes.empty, this._allDatasetsEmpty()); + this.trigger("datasetCleared"); + }, + _propagate: function propagate() { + this.trigger.apply(this, arguments); + }, + _allDatasetsEmpty: function allDatasetsEmpty() { + return _.every(this.datasets, _.bind(function isDatasetEmpty(dataset) { + var isEmpty = dataset.isEmpty(); + this.$node.attr("aria-expanded", !isEmpty); + return isEmpty; + }, this)); + }, + _getSelectables: function getSelectables() { + return this.$node.find(this.selectors.selectable); + }, + _removeCursor: function _removeCursor() { + var $selectable = this.getActiveSelectable(); + $selectable && $selectable.removeClass(this.classes.cursor); + }, + _ensureVisible: function ensureVisible($el) { + var elTop, elBottom, nodeScrollTop, nodeHeight; + elTop = $el.position().top; + elBottom = elTop + $el.outerHeight(true); + nodeScrollTop = this.$node.scrollTop(); + nodeHeight = this.$node.height() + parseInt(this.$node.css("paddingTop"), 10) + parseInt(this.$node.css("paddingBottom"), 10); + if (elTop < 0) { + this.$node.scrollTop(nodeScrollTop + elTop); + } else if (nodeHeight < elBottom) { + this.$node.scrollTop(nodeScrollTop + (elBottom - nodeHeight)); + } + }, + bind: function() { + var that = this, onSelectableClick; + onSelectableClick = _.bind(this._onSelectableClick, this); + this.$node.on("click.tt", this.selectors.selectable, onSelectableClick); + this.$node.on("mouseover", this.selectors.selectable, function() { + that.setCursor($(this)); + }); + this.$node.on("mouseleave", function() { + that._removeCursor(); + }); + _.each(this.datasets, function(dataset) { + dataset.onSync("asyncRequested", that._propagate, that).onSync("asyncCanceled", that._propagate, that).onSync("asyncReceived", that._propagate, that).onSync("rendered", that._onRendered, that).onSync("cleared", that._onCleared, that); + }); + return this; + }, + isOpen: function isOpen() { + return this.$node.hasClass(this.classes.open); + }, + open: function open() { + this.$node.scrollTop(0); + this.$node.addClass(this.classes.open); + }, + close: function close() { + this.$node.attr("aria-expanded", false); + this.$node.removeClass(this.classes.open); + this._removeCursor(); + }, + setLanguageDirection: function setLanguageDirection(dir) { + this.$node.attr("dir", dir); + }, + selectableRelativeToCursor: function selectableRelativeToCursor(delta) { + var $selectables, $oldCursor, oldIndex, newIndex; + $oldCursor = this.getActiveSelectable(); + $selectables = this._getSelectables(); + oldIndex = $oldCursor ? $selectables.index($oldCursor) : -1; + newIndex = oldIndex + delta; + newIndex = (newIndex + 1) % ($selectables.length + 1) - 1; + newIndex = newIndex < -1 ? $selectables.length - 1 : newIndex; + return newIndex === -1 ? null : $selectables.eq(newIndex); + }, + setCursor: function setCursor($selectable) { + this._removeCursor(); + if ($selectable = $selectable && $selectable.first()) { + $selectable.addClass(this.classes.cursor); + this._ensureVisible($selectable); + } + }, + getSelectableData: function getSelectableData($el) { + return $el && $el.length ? Dataset.extractData($el) : null; + }, + getActiveSelectable: function getActiveSelectable() { + var $selectable = this._getSelectables().filter(this.selectors.cursor).first(); + return $selectable.length ? $selectable : null; + }, + getTopSelectable: function getTopSelectable() { + var $selectable = this._getSelectables().first(); + return $selectable.length ? $selectable : null; + }, + update: function update(query) { + var isValidUpdate = query !== this.query; + if (isValidUpdate) { + this.query = query; + _.each(this.datasets, updateDataset); + } + return isValidUpdate; + function updateDataset(dataset) { + dataset.update(query); + } + }, + empty: function empty() { + _.each(this.datasets, clearDataset); + this.query = null; + this.$node.addClass(this.classes.empty); + function clearDataset(dataset) { + dataset.clear(); + } + }, + destroy: function destroy() { + this.$node.off(".tt"); + this.$node = $("
    "); + _.each(this.datasets, destroyDataset); + function destroyDataset(dataset) { + dataset.destroy(); + } + } + }); + return Menu; + }(); + var Status = function() { + "use strict"; + function Status(options) { + this.$el = $("", { + role: "status", + "aria-live": "polite" + }).css({ + position: "absolute", + padding: "0", + border: "0", + height: "1px", + width: "1px", + "margin-bottom": "-1px", + "margin-right": "-1px", + overflow: "hidden", + clip: "rect(0 0 0 0)", + "white-space": "nowrap" + }); + options.$input.after(this.$el); + _.each(options.menu.datasets, _.bind(function(dataset) { + if (dataset.onSync) { + dataset.onSync("rendered", _.bind(this.update, this)); + dataset.onSync("cleared", _.bind(this.cleared, this)); + } + }, this)); + } + _.mixin(Status.prototype, { + update: function update(event, suggestions) { + var length = suggestions.length; + var words; + if (length === 1) { + words = { + result: "result", + is: "is" + }; + } else { + words = { + result: "results", + is: "are" + }; + } + this.$el.text(length + " " + words.result + " " + words.is + " available, use up and down arrow keys to navigate."); + }, + cleared: function() { + this.$el.text(""); + } + }); + return Status; + }(); + var DefaultMenu = function() { + "use strict"; + var s = Menu.prototype; + function DefaultMenu() { + Menu.apply(this, [].slice.call(arguments, 0)); + } + _.mixin(DefaultMenu.prototype, Menu.prototype, { + open: function open() { + !this._allDatasetsEmpty() && this._show(); + return s.open.apply(this, [].slice.call(arguments, 0)); + }, + close: function close() { + this._hide(); + return s.close.apply(this, [].slice.call(arguments, 0)); + }, + _onRendered: function onRendered() { + if (this._allDatasetsEmpty()) { + this._hide(); + } else { + this.isOpen() && this._show(); + } + return s._onRendered.apply(this, [].slice.call(arguments, 0)); + }, + _onCleared: function onCleared() { + if (this._allDatasetsEmpty()) { + this._hide(); + } else { + this.isOpen() && this._show(); + } + return s._onCleared.apply(this, [].slice.call(arguments, 0)); + }, + setLanguageDirection: function setLanguageDirection(dir) { + this.$node.css(dir === "ltr" ? this.css.ltr : this.css.rtl); + return s.setLanguageDirection.apply(this, [].slice.call(arguments, 0)); + }, + _hide: function hide() { + this.$node.hide(); + }, + _show: function show() { + this.$node.css("display", "block"); + } + }); + return DefaultMenu; + }(); + var Typeahead = function() { + "use strict"; + function Typeahead(o, www) { + var onFocused, onBlurred, onEnterKeyed, onTabKeyed, onEscKeyed, onUpKeyed, onDownKeyed, onLeftKeyed, onRightKeyed, onQueryChanged, onWhitespaceChanged; + o = o || {}; + if (!o.input) { + $.error("missing input"); + } + if (!o.menu) { + $.error("missing menu"); + } + if (!o.eventBus) { + $.error("missing event bus"); + } + www.mixin(this); + this.eventBus = o.eventBus; + this.minLength = _.isNumber(o.minLength) ? o.minLength : 1; + this.input = o.input; + this.menu = o.menu; + this.enabled = true; + this.autoselect = !!o.autoselect; + this.active = false; + this.input.hasFocus() && this.activate(); + this.dir = this.input.getLangDir(); + this._hacks(); + this.menu.bind().onSync("selectableClicked", this._onSelectableClicked, this).onSync("asyncRequested", this._onAsyncRequested, this).onSync("asyncCanceled", this._onAsyncCanceled, this).onSync("asyncReceived", this._onAsyncReceived, this).onSync("datasetRendered", this._onDatasetRendered, this).onSync("datasetCleared", this._onDatasetCleared, this); + onFocused = c(this, "activate", "open", "_onFocused"); + onBlurred = c(this, "deactivate", "_onBlurred"); + onEnterKeyed = c(this, "isActive", "isOpen", "_onEnterKeyed"); + onTabKeyed = c(this, "isActive", "isOpen", "_onTabKeyed"); + onEscKeyed = c(this, "isActive", "_onEscKeyed"); + onUpKeyed = c(this, "isActive", "open", "_onUpKeyed"); + onDownKeyed = c(this, "isActive", "open", "_onDownKeyed"); + onLeftKeyed = c(this, "isActive", "isOpen", "_onLeftKeyed"); + onRightKeyed = c(this, "isActive", "isOpen", "_onRightKeyed"); + onQueryChanged = c(this, "_openIfActive", "_onQueryChanged"); + onWhitespaceChanged = c(this, "_openIfActive", "_onWhitespaceChanged"); + this.input.bind().onSync("focused", onFocused, this).onSync("blurred", onBlurred, this).onSync("enterKeyed", onEnterKeyed, this).onSync("tabKeyed", onTabKeyed, this).onSync("escKeyed", onEscKeyed, this).onSync("upKeyed", onUpKeyed, this).onSync("downKeyed", onDownKeyed, this).onSync("leftKeyed", onLeftKeyed, this).onSync("rightKeyed", onRightKeyed, this).onSync("queryChanged", onQueryChanged, this).onSync("whitespaceChanged", onWhitespaceChanged, this).onSync("langDirChanged", this._onLangDirChanged, this); + } + _.mixin(Typeahead.prototype, { + _hacks: function hacks() { + var $input, $menu; + $input = this.input.$input || $("
    "); + $menu = this.menu.$node || $("
    "); + $input.on("blur.tt", function($e) { + var active, isActive, hasActive; + active = document.activeElement; + isActive = $menu.is(active); + hasActive = $menu.has(active).length > 0; + if (_.isMsie() && (isActive || hasActive)) { + $e.preventDefault(); + $e.stopImmediatePropagation(); + _.defer(function() { + $input.focus(); + }); + } + }); + $menu.on("mousedown.tt", function($e) { + $e.preventDefault(); + }); + }, + _onSelectableClicked: function onSelectableClicked(type, $el) { + this.select($el); + }, + _onDatasetCleared: function onDatasetCleared() { + this._updateHint(); + }, + _onDatasetRendered: function onDatasetRendered(type, suggestions, async, dataset) { + this._updateHint(); + if (this.autoselect) { + var cursorClass = this.selectors.cursor.substr(1); + this.menu.$node.find(this.selectors.suggestion).first().addClass(cursorClass); + } + this.eventBus.trigger("render", suggestions, async, dataset); + }, + _onAsyncRequested: function onAsyncRequested(type, dataset, query) { + this.eventBus.trigger("asyncrequest", query, dataset); + }, + _onAsyncCanceled: function onAsyncCanceled(type, dataset, query) { + this.eventBus.trigger("asynccancel", query, dataset); + }, + _onAsyncReceived: function onAsyncReceived(type, dataset, query) { + this.eventBus.trigger("asyncreceive", query, dataset); + }, + _onFocused: function onFocused() { + this._minLengthMet() && this.menu.update(this.input.getQuery()); + }, + _onBlurred: function onBlurred() { + if (this.input.hasQueryChangedSinceLastFocus()) { + this.eventBus.trigger("change", this.input.getQuery()); + } + }, + _onEnterKeyed: function onEnterKeyed(type, $e) { + var $selectable; + if ($selectable = this.menu.getActiveSelectable()) { + if (this.select($selectable)) { + $e.preventDefault(); + $e.stopPropagation(); + } + } else if (this.autoselect) { + if (this.select(this.menu.getTopSelectable())) { + $e.preventDefault(); + $e.stopPropagation(); + } + } + }, + _onTabKeyed: function onTabKeyed(type, $e) { + var $selectable; + if ($selectable = this.menu.getActiveSelectable()) { + this.select($selectable) && $e.preventDefault(); + } else if (this.autoselect) { + if ($selectable = this.menu.getTopSelectable()) { + this.autocomplete($selectable) && $e.preventDefault(); + } + } + }, + _onEscKeyed: function onEscKeyed() { + this.close(); + }, + _onUpKeyed: function onUpKeyed() { + this.moveCursor(-1); + }, + _onDownKeyed: function onDownKeyed() { + this.moveCursor(+1); + }, + _onLeftKeyed: function onLeftKeyed() { + if (this.dir === "rtl" && this.input.isCursorAtEnd()) { + this.autocomplete(this.menu.getActiveSelectable() || this.menu.getTopSelectable()); + } + }, + _onRightKeyed: function onRightKeyed() { + if (this.dir === "ltr" && this.input.isCursorAtEnd()) { + this.autocomplete(this.menu.getActiveSelectable() || this.menu.getTopSelectable()); + } + }, + _onQueryChanged: function onQueryChanged(e, query) { + this._minLengthMet(query) ? this.menu.update(query) : this.menu.empty(); + }, + _onWhitespaceChanged: function onWhitespaceChanged() { + this._updateHint(); + }, + _onLangDirChanged: function onLangDirChanged(e, dir) { + if (this.dir !== dir) { + this.dir = dir; + this.menu.setLanguageDirection(dir); + } + }, + _openIfActive: function openIfActive() { + this.isActive() && this.open(); + }, + _minLengthMet: function minLengthMet(query) { + query = _.isString(query) ? query : this.input.getQuery() || ""; + return query.length >= this.minLength; + }, + _updateHint: function updateHint() { + var $selectable, data, val, query, escapedQuery, frontMatchRegEx, match; + $selectable = this.menu.getTopSelectable(); + data = this.menu.getSelectableData($selectable); + val = this.input.getInputValue(); + if (data && !_.isBlankString(val) && !this.input.hasOverflow()) { + query = Input.normalizeQuery(val); + escapedQuery = _.escapeRegExChars(query); + frontMatchRegEx = new RegExp("^(?:" + escapedQuery + ")(.+$)", "i"); + match = frontMatchRegEx.exec(data.val); + match && this.input.setHint(val + match[1]); + } else { + this.input.clearHint(); + } + }, + isEnabled: function isEnabled() { + return this.enabled; + }, + enable: function enable() { + this.enabled = true; + }, + disable: function disable() { + this.enabled = false; + }, + isActive: function isActive() { + return this.active; + }, + activate: function activate() { + if (this.isActive()) { + return true; + } else if (!this.isEnabled() || this.eventBus.before("active")) { + return false; + } else { + this.active = true; + this.eventBus.trigger("active"); + return true; + } + }, + deactivate: function deactivate() { + if (!this.isActive()) { + return true; + } else if (this.eventBus.before("idle")) { + return false; + } else { + this.active = false; + this.close(); + this.eventBus.trigger("idle"); + return true; + } + }, + isOpen: function isOpen() { + return this.menu.isOpen(); + }, + open: function open() { + if (!this.isOpen() && !this.eventBus.before("open")) { + this.input.setAriaExpanded(true); + this.menu.open(); + this._updateHint(); + this.eventBus.trigger("open"); + } + return this.isOpen(); + }, + close: function close() { + if (this.isOpen() && !this.eventBus.before("close")) { + this.input.setAriaExpanded(false); + this.menu.close(); + this.input.clearHint(); + this.input.resetInputValue(); + this.eventBus.trigger("close"); + } + return !this.isOpen(); + }, + setVal: function setVal(val) { + this.input.setQuery(_.toStr(val)); + }, + getVal: function getVal() { + return this.input.getQuery(); + }, + select: function select($selectable) { + var data = this.menu.getSelectableData($selectable); + if (data && !this.eventBus.before("select", data.obj, data.dataset)) { + this.input.setQuery(data.val, true); + this.eventBus.trigger("select", data.obj, data.dataset); + this.close(); + return true; + } + return false; + }, + autocomplete: function autocomplete($selectable) { + var query, data, isValid; + query = this.input.getQuery(); + data = this.menu.getSelectableData($selectable); + isValid = data && query !== data.val; + if (isValid && !this.eventBus.before("autocomplete", data.obj, data.dataset)) { + this.input.setQuery(data.val); + this.eventBus.trigger("autocomplete", data.obj, data.dataset); + return true; + } + return false; + }, + moveCursor: function moveCursor(delta) { + var query, $candidate, data, suggestion, datasetName, cancelMove, id; + query = this.input.getQuery(); + $candidate = this.menu.selectableRelativeToCursor(delta); + data = this.menu.getSelectableData($candidate); + suggestion = data ? data.obj : null; + datasetName = data ? data.dataset : null; + id = $candidate ? $candidate.attr("id") : null; + this.input.trigger("cursorchange", id); + cancelMove = this._minLengthMet() && this.menu.update(query); + if (!cancelMove && !this.eventBus.before("cursorchange", suggestion, datasetName)) { + this.menu.setCursor($candidate); + if (data) { + if (typeof data.val === "string") { + this.input.setInputValue(data.val); + } + } else { + this.input.resetInputValue(); + this._updateHint(); + } + this.eventBus.trigger("cursorchange", suggestion, datasetName); + return true; + } + return false; + }, + destroy: function destroy() { + this.input.destroy(); + this.menu.destroy(); + } + }); + return Typeahead; + function c(ctx) { + var methods = [].slice.call(arguments, 1); + return function() { + var args = [].slice.call(arguments); + _.each(methods, function(method) { + return ctx[method].apply(ctx, args); + }); + }; + } + }(); + (function() { + "use strict"; + var old, keys, methods; + old = $.fn.typeahead; + keys = { + www: "tt-www", + attrs: "tt-attrs", + typeahead: "tt-typeahead" + }; + methods = { + initialize: function initialize(o, datasets) { + var www; + datasets = _.isArray(datasets) ? datasets : [].slice.call(arguments, 1); + o = o || {}; + www = WWW(o.classNames); + return this.each(attach); + function attach() { + var $input, $wrapper, $hint, $menu, defaultHint, defaultMenu, eventBus, input, menu, status, typeahead, MenuConstructor; + _.each(datasets, function(d) { + d.highlight = !!o.highlight; + }); + $input = $(this); + $wrapper = $(www.html.wrapper); + $hint = $elOrNull(o.hint); + $menu = $elOrNull(o.menu); + defaultHint = o.hint !== false && !$hint; + defaultMenu = o.menu !== false && !$menu; + defaultHint && ($hint = buildHintFromInput($input, www)); + defaultMenu && ($menu = $(www.html.menu).css(www.css.menu)); + $hint && $hint.val(""); + $input = prepInput($input, www); + if (defaultHint || defaultMenu) { + $wrapper.css(www.css.wrapper); + $input.css(defaultHint ? www.css.input : www.css.inputWithNoHint); + $input.wrap($wrapper).parent().prepend(defaultHint ? $hint : null).append(defaultMenu ? $menu : null); + } + MenuConstructor = defaultMenu ? DefaultMenu : Menu; + eventBus = new EventBus({ + el: $input + }); + input = new Input({ + hint: $hint, + input: $input, + menu: $menu + }, www); + menu = new MenuConstructor({ + node: $menu, + datasets: datasets + }, www); + status = new Status({ + $input: $input, + menu: menu + }); + typeahead = new Typeahead({ + input: input, + menu: menu, + eventBus: eventBus, + minLength: o.minLength, + autoselect: o.autoselect + }, www); + $input.data(keys.www, www); + $input.data(keys.typeahead, typeahead); + } + }, + isEnabled: function isEnabled() { + var enabled; + ttEach(this.first(), function(t) { + enabled = t.isEnabled(); + }); + return enabled; + }, + enable: function enable() { + ttEach(this, function(t) { + t.enable(); + }); + return this; + }, + disable: function disable() { + ttEach(this, function(t) { + t.disable(); + }); + return this; + }, + isActive: function isActive() { + var active; + ttEach(this.first(), function(t) { + active = t.isActive(); + }); + return active; + }, + activate: function activate() { + ttEach(this, function(t) { + t.activate(); + }); + return this; + }, + deactivate: function deactivate() { + ttEach(this, function(t) { + t.deactivate(); + }); + return this; + }, + isOpen: function isOpen() { + var open; + ttEach(this.first(), function(t) { + open = t.isOpen(); + }); + return open; + }, + open: function open() { + ttEach(this, function(t) { + t.open(); + }); + return this; + }, + close: function close() { + ttEach(this, function(t) { + t.close(); + }); + return this; + }, + select: function select(el) { + var success = false, $el = $(el); + ttEach(this.first(), function(t) { + success = t.select($el); + }); + return success; + }, + autocomplete: function autocomplete(el) { + var success = false, $el = $(el); + ttEach(this.first(), function(t) { + success = t.autocomplete($el); + }); + return success; + }, + moveCursor: function moveCursoe(delta) { + var success = false; + ttEach(this.first(), function(t) { + success = t.moveCursor(delta); + }); + return success; + }, + val: function val(newVal) { + var query; + if (!arguments.length) { + ttEach(this.first(), function(t) { + query = t.getVal(); + }); + return query; + } else { + ttEach(this, function(t) { + t.setVal(_.toStr(newVal)); + }); + return this; + } + }, + destroy: function destroy() { + ttEach(this, function(typeahead, $input) { + revert($input); + typeahead.destroy(); + }); + return this; + } + }; + $.fn.typeahead = function(method) { + if (methods[method]) { + return methods[method].apply(this, [].slice.call(arguments, 1)); + } else { + return methods.initialize.apply(this, arguments); + } + }; + $.fn.typeahead.noConflict = function noConflict() { + $.fn.typeahead = old; + return this; + }; + function ttEach($els, fn) { + $els.each(function() { + var $input = $(this), typeahead; + (typeahead = $input.data(keys.typeahead)) && fn(typeahead, $input); + }); + } + function buildHintFromInput($input, www) { + return $input.clone().addClass(www.classes.hint).removeData().css(www.css.hint).css(getBackgroundStyles($input)).prop({ + readonly: true, + required: false + }).removeAttr("id name placeholder").removeClass("required").attr({ + spellcheck: "false", + tabindex: -1 + }); + } + function prepInput($input, www) { + $input.data(keys.attrs, { + dir: $input.attr("dir"), + autocomplete: $input.attr("autocomplete"), + spellcheck: $input.attr("spellcheck"), + style: $input.attr("style") + }); + $input.addClass(www.classes.input).attr({ + spellcheck: false + }); + try { + !$input.attr("dir") && $input.attr("dir", "auto"); + } catch (e) {} + return $input; + } + function getBackgroundStyles($el) { + return { + backgroundAttachment: $el.css("background-attachment"), + backgroundClip: $el.css("background-clip"), + backgroundColor: $el.css("background-color"), + backgroundImage: $el.css("background-image"), + backgroundOrigin: $el.css("background-origin"), + backgroundPosition: $el.css("background-position"), + backgroundRepeat: $el.css("background-repeat"), + backgroundSize: $el.css("background-size") + }; + } + function revert($input) { + var www, $wrapper; + www = $input.data(keys.www); + $wrapper = $input.parent().filter(www.selectors.wrapper); + _.each($input.data(keys.attrs), function(val, key) { + _.isUndefined(val) ? $input.removeAttr(key) : $input.attr(key, val); + }); + $input.removeData(keys.typeahead).removeData(keys.www).removeData(keys.attr).removeClass(www.classes.input); + if ($wrapper.length) { + $input.detach().insertAfter($wrapper); + $wrapper.remove(); + } + } + function $elOrNull(obj) { + var isValid, $el; + isValid = _.isJQuery(obj) || _.isElement(obj); + $el = isValid ? $(obj).first() : []; + return $el.length ? $el : null; + } + })(); +}); \ No newline at end of file diff --git a/Documentation/search.json b/Documentation/search.json index 5f869d8..9ad06df 100644 --- a/Documentation/search.json +++ b/Documentation/search.json @@ -1 +1 @@ -{"Protocols/TokenCredentialWritable.html#/s:4Atom23TokenCredentialWritableP05tokenC0A2AC0bC0Vvp":{"name":"tokenCredential","abstract":"

    Returns conforming type as Atom.TokenCredential.

    ","parent_name":"TokenCredentialWritable"},"Protocols/Requestable.html#/s:4Atom11RequestableP11headerItemsSayA2AC10HeaderItemVGSgvp":{"name":"headerItems","abstract":"

    The array of header items to apply to a URLRequest.

    ","parent_name":"Requestable"},"Protocols/Requestable.html#/s:4Atom11RequestableP6methodA2AC6MethodOvp":{"name":"method","abstract":"

    The HTTP method to apply to a URLRequest.

    ","parent_name":"Requestable"},"Protocols/Requestable.html#/s:4Atom11RequestableP10queryItemsSay10Foundation12URLQueryItemVGSgvp":{"name":"queryItems","abstract":"

    The array of query items to apply to a URL.

    ","parent_name":"Requestable"},"Protocols/Requestable.html#/s:4Atom11RequestableP22requiresAuthenticationSbvp":{"name":"requiresAuthentication","abstract":"

    The Bool indicating whether or not authorization header should be applied","parent_name":"Requestable"},"Protocols/Requestable.html#/s:4Atom11RequestableP7baseURLA2AC04BaseD0VyKF":{"name":"baseURL()","abstract":"

    The base url to initialize URLRequest with.

    ","parent_name":"Requestable"},"Protocols/Requestable.html#/s:4Atom11RequestableP4pathA2AC7URLPathVyKF":{"name":"path()","abstract":"

    The URL path to append to a base URL.

    ","parent_name":"Requestable"},"Protocols/ClientCredentialConvertible.html#/s:4Atom27ClientCredentialConvertibleP06clientC0A2AC0bC0Vvp":{"name":"clientCredential","abstract":"

    Returns conforming type as Atom.ClientCredential.

    ","parent_name":"ClientCredentialConvertible"},"Protocols/BasicCredentialConvertible.html#/s:4Atom26BasicCredentialConvertibleP05basicC0A2AC0bC0Vvp":{"name":"basicCredential","abstract":"

    Returns conforming type as Atom.BasicCredential.

    ","parent_name":"BasicCredentialConvertible"},"Protocols/BasicCredentialConvertible.html":{"name":"BasicCredentialConvertible","abstract":"

    The BasicCredentialConvertible protocol declares an interface used for converting conforming type to Atom.BasicCredential.

    "},"Protocols/ClientCredentialConvertible.html":{"name":"ClientCredentialConvertible","abstract":"

    The ClientCredentialConvertible protocol declares an interface used for converting conforming type to Atom.ClientCredential.

    "},"Protocols.html#/s:4Atom5ModelP":{"name":"Model","abstract":"

    The Model protocol declares an interface used as a generic constraint on Atom.Service methods.

    "},"Protocols/Requestable.html":{"name":"Requestable","abstract":"

    The Requestable protocol declares an interface used for initializing network request object.

    "},"Protocols/TokenCredentialWritable.html":{"name":"TokenCredentialWritable","abstract":"

    The TokenCredentialWritable protocol declares an interface used for reading from / writing to Atom.TokenCredential.

    "},"Extensions/URLSessionTaskMetrics.html#/c:@CM@Atom@@objc(cs)NSURLSessionTaskMetrics(py)debugDescription":{"name":"debugDescription","abstract":"

    Returns a textual representation of this instance, suitable for debugging.

    ","parent_name":"URLSessionTaskMetrics"},"Extensions/URLSessionTask.html#/c:@CM@Atom@@objc(cs)NSURLSessionTask(py)debugDescription":{"name":"debugDescription","abstract":"

    Returns a textual representation of this instance, suitable for debugging.

    ","parent_name":"URLSessionTask"},"Extensions/URLResponse.html#/s:So13NSURLResponseC4AtomE9isFailureSbvp":{"name":"isFailure","abstract":"

    Returns true if the status code of the HTTPURLResponse is not in 200...299 range.

    ","parent_name":"URLResponse"},"Extensions/URLResponse.html#/s:So13NSURLResponseC4AtomE12isSuccessfulSbvp":{"name":"isSuccessful","abstract":"

    Returns true if the status code of the HTTPURLResponse is in 200...299 range.

    ","parent_name":"URLResponse"},"Extensions/URLResponse.html#/c:@CM@Atom@@objc(cs)NSURLResponse(py)debugDescription":{"name":"debugDescription","abstract":"

    Returns a textual representation of this instance, suitable for debugging.

    ","parent_name":"URLResponse"},"Extensions/URLRequest.html#/s:10Foundation10URLRequestV4AtomE16debugDescriptionSSvp":{"name":"debugDescription","abstract":"

    Returns a textual representation of this instance, suitable for debugging.

    ","parent_name":"URLRequest"},"Extensions/Optional.html#/s:Sq4AtomE6unwrap_4file4linexSSycSg_s12StaticStringVSutF":{"name":"unwrap(_:file:line:)","abstract":"

    Unwraps an optional value. Terminates the process if the value is nil.

    ","parent_name":"Optional"},"Extensions/Bool.html#/s:Sb4AtomE2onSbvpZ":{"name":"on","abstract":"

    Convenience property for returning true.

    ","parent_name":"Bool"},"Extensions/Bool.html#/s:Sb4AtomE3offSbvpZ":{"name":"off","abstract":"

    Convenience property for returning false.

    ","parent_name":"Bool"},"Extensions/Bool.html":{"name":"Bool"},"Extensions/Optional.html":{"name":"Optional"},"Extensions/URLRequest.html":{"name":"URLRequest"},"Extensions/URLResponse.html":{"name":"URLResponse"},"Extensions/URLSessionTask.html":{"name":"URLSessionTask"},"Extensions/URLSessionTaskMetrics.html":{"name":"URLSessionTaskMetrics"},"Enums/RequestableError.html#/s:4Atom16RequestableErrorO14invalidBaseURLyA2CmF":{"name":"invalidBaseURL","abstract":"

    Base URL failed validation. Most probable cause is invalid URL host.

    ","parent_name":"RequestableError"},"Enums/RequestableError.html#/s:4Atom16RequestableErrorO10invalidURLyA2CmF":{"name":"invalidURL","abstract":"

    URLComponents initialization with provided URL string failed.

    ","parent_name":"RequestableError"},"Enums/RequestableError.html#/s:4Atom16RequestableErrorO14invalidURLPathyA2CmF":{"name":"invalidURLPath","abstract":"

    URL path failed validation.

    ","parent_name":"RequestableError"},"Enums/AtomError.html#/s:4Atom0A5ErrorO7decoderyACs0B0_pcACmF":{"name":"decoder(_:)","abstract":"

    Decoder failed to decode data.

    ","parent_name":"AtomError"},"Enums/AtomError.html#/s:4Atom0A5ErrorO4datayACs0B0_pcACmF":{"name":"data(_:)","abstract":"

    Failed to initialize Data instance from URL.

    ","parent_name":"AtomError"},"Enums/AtomError.html#/s:4Atom0A5ErrorO11requestableyAcA011RequestableB0OcACmF":{"name":"requestable(_:)","abstract":"

    Failed to initialize URLRequest with Requestable instance.

    ","parent_name":"AtomError"},"Enums/AtomError.html#/s:4Atom0A5ErrorO8responseyAc2AC8ResponseVcACmF":{"name":"response(_:)","abstract":"

    Service returned invalid response where the status code is not in 200...299 range.

    ","parent_name":"AtomError"},"Enums/AtomError.html#/s:4Atom0A5ErrorO7sessionyACs0B0_pcACmF":{"name":"session(_:)","abstract":"

    URLSession failed with error.

    ","parent_name":"AtomError"},"Enums/AtomError.html#/s:4Atom0A5ErrorO10unexpectedyA2CmF":{"name":"unexpected","abstract":"

    Unexpected, logic error.

    ","parent_name":"AtomError"},"Enums/AtomError.html#/s:4Atom0A5ErrorO7unknownyA2CmF":{"name":"unknown","abstract":"

    Unknown error occurred.

    ","parent_name":"AtomError"},"Enums/AtomError.html#/s:4Atom0A5ErrorO22isAuthorizationFailureSbvp":{"name":"isAuthorizationFailure","abstract":"

    Returns Bool indicating whether the error is due to an invalid or expired access token.

    ","parent_name":"AtomError"},"Enums/AtomError.html#/s:4Atom0A5ErrorO27isAccessTokenRefreshFailureSbvp":{"name":"isAccessTokenRefreshFailure","abstract":"

    Returns Bool indicating whether the error is due to a failed attempt to refresh an access token.

    ","parent_name":"AtomError"},"Enums/AtomError.html#/s:4Atom0A5ErrorO15decodeIfPresent2asxSgxm_tKSeRzlF":{"name":"decodeIfPresent(as:)","abstract":"

    Convenience method for decoding error object or message returned by the service.

    ","parent_name":"AtomError"},"Enums/AtomError.html":{"name":"AtomError","abstract":"

    List of all possible error cases thrown by Atom framework.

    "},"Enums/RequestableError.html":{"name":"RequestableError","abstract":"

    List of all possible error cases thrown when conversion from Requestable to URLRequest fails.

    "},"Classes/Atom/ServiceConfiguration/Configuration.html#/s:4AtomAAC20ServiceConfigurationC0C0O10backgroundyAFSScAFmF":{"name":"background(_:)","abstract":"

    The background session configuration is suitable for transferring data files while the app runs in the background.

    ","parent_name":"Configuration"},"Classes/Atom/ServiceConfiguration/Configuration.html#/s:4AtomAAC20ServiceConfigurationC0C0O7defaultyA2FmF":{"name":"default","abstract":"

    The default session configuration that uses a persistent disk-based cache.

    ","parent_name":"Configuration"},"Classes/Atom/ServiceConfiguration/Configuration.html#/s:4AtomAAC20ServiceConfigurationC0C0O9ephemeralyA2FmF":{"name":"ephemeral","abstract":"

    Ephemeral configuration doesn’t store caches, credential stores, or any session-related data on disk (RAM only).

    ","parent_name":"Configuration"},"Classes/Atom/ServiceConfiguration/Configuration.html":{"name":"Configuration","abstract":"

    List of supported session configurations.

    ","parent_name":"ServiceConfiguration"},"Classes/Atom/ServiceConfiguration.html#/s:4AtomAAC20ServiceConfigurationC20authenticationMethod13configuration7decoder13dispatchQueueAdB014AuthenticationE0O_AD0C0O10Foundation11JSONDecoderCSo03OS_H6_queueCtcfc":{"name":"init(authenticationMethod:configuration:decoder:dispatchQueue:)","abstract":"

    Creates a ServiceConfiguration instance given the provided parameter(s).

    ","parent_name":"ServiceConfiguration"},"Classes/Atom/Service.html#/s:4AtomAAC7ServiceC7execute9expecting10completionyxm_ys6ResultOyxAA0A5ErrorOGctAA5ModelRzlF":{"name":"execute(expecting:completion:)","abstract":"

    Creates and executes URLRequest initialized from Requestable.

    ","parent_name":"Service"},"Classes/Atom/Service.html#/s:4AtomAAC7ServiceC7executeyyys6ResultOyAB8ResponseVAA0A5ErrorOGcF":{"name":"execute(_:)","abstract":"

    Creates and executes URLRequest initialized from Requestable.

    ","parent_name":"Service"},"Classes/Atom/URLPath.html#/s:4AtomAAC7URLPathVyADSSKcfc":{"name":"init(_:)","abstract":"

    Creates a URLPath instance given the provided parameter(s).

    ","parent_name":"URLPath"},"Classes/Atom/TokenCredential.html#/s:4AtomAAC15TokenCredentialV06accessB0SSvp":{"name":"accessToken","abstract":"

    The access token as defined in OAuth 2.0 spec.

    ","parent_name":"TokenCredential"},"Classes/Atom/TokenCredential.html#/s:4AtomAAC15TokenCredentialV9expiresInSivp":{"name":"expiresIn","abstract":"

    The number of seconds access token is valid for.

    ","parent_name":"TokenCredential"},"Classes/Atom/TokenCredential.html#/s:4AtomAAC15TokenCredentialV9expiresAt10Foundation4DateVvp":{"name":"expiresAt","abstract":"

    The expiration date of the access token.

    ","parent_name":"TokenCredential"},"Classes/Atom/TokenCredential.html#/s:4AtomAAC15TokenCredentialV07refreshB0SSvp":{"name":"refreshToken","abstract":"

    The refresh token as defined in OAuth 2.0 spec.

    ","parent_name":"TokenCredential"},"Classes/Atom/TokenCredential.html#/s:4AtomAAC15TokenCredentialV06accessB09expiresIn0E2At07refreshB0ADSS_Si10Foundation4DateVSStcfc":{"name":"init(accessToken:expiresIn:expiresAt:refreshToken:)","abstract":"

    Creates a TokenCredential instance given the provided parameter(s).

    ","parent_name":"TokenCredential"},"Classes/Atom/TokenCredential.html#/s:Se4fromxs7Decoder_p_tKcfc":{"name":"init(from:)","parent_name":"TokenCredential"},"Classes/Atom/Response.html#/s:4AtomAAC8ResponseV12HeaderFieldsa":{"name":"HeaderFields","abstract":"

    Undocumented

    ","parent_name":"Response"},"Classes/Atom/Response.html#/s:4AtomAAC8ResponseV15allHeaderFieldsSo12NSDictionaryCSgvp":{"name":"allHeaderFields","abstract":"

    All HTTP header fields of the response.

    ","parent_name":"Response"},"Classes/Atom/Response.html#/s:4AtomAAC8ResponseV21expectedContentLengths5Int64VSgvp":{"name":"expectedContentLength","abstract":"

    The expected length of the response’s content.

    ","parent_name":"Response"},"Classes/Atom/Response.html#/s:4AtomAAC8ResponseV4data10Foundation4DataVSgvp":{"name":"data","abstract":"

    The data returned by the server.

    ","parent_name":"Response"},"Classes/Atom/Response.html#/s:4AtomAAC8ResponseV8mimeTypeSSSgvp":{"name":"mimeType","abstract":"

    The MIME type of the response.

    ","parent_name":"Response"},"Classes/Atom/Response.html#/s:4AtomAAC8ResponseV10statusCodeSiSgvp":{"name":"statusCode","abstract":"

    The response’s HTTP status code.

    ","parent_name":"Response"},"Classes/Atom/Response.html#/s:4AtomAAC8ResponseV17suggestedFilenameSSSgvp":{"name":"suggestedFilename","abstract":"

    A suggested filename for the response data.

    ","parent_name":"Response"},"Classes/Atom/Response.html#/s:4AtomAAC8ResponseV16textEncodingNameSSSgvp":{"name":"textEncodingName","abstract":"

    The name of the text encoding provided by the response’s originating source.

    ","parent_name":"Response"},"Classes/Atom/Response.html#/s:4AtomAAC8ResponseV3url10Foundation3URLVSgvp":{"name":"url","abstract":"

    The URL for the response.

    ","parent_name":"Response"},"Classes/Atom/Response.html#/s:4AtomAAC8ResponseV7successADvpZ":{"name":"success","abstract":"

    Returns default, success response where status code is 200.

    ","parent_name":"Response"},"Classes/Atom/Method.html#/s:4AtomAAC6MethodO6deleteyA2DmF":{"name":"delete","abstract":"

    Use for deleting a resource identified by a URI.

    ","parent_name":"Method"},"Classes/Atom/Method.html#/s:4AtomAAC6MethodO3getyA2DmF":{"name":"get","abstract":"

    Use for reading (or retrieving) a representation of a resource.

    ","parent_name":"Method"},"Classes/Atom/Method.html#/s:4AtomAAC6MethodO5patchyAD10Foundation4DataVcADmF":{"name":"patch(_:)","abstract":"

    Use for modifying capabilities.

    ","parent_name":"Method"},"Classes/Atom/Method.html#/s:4AtomAAC6MethodO4postyAD10Foundation4DataVcADmF":{"name":"post(_:)","abstract":"

    Use for creating new resources.

    ","parent_name":"Method"},"Classes/Atom/Method.html#/s:4AtomAAC6MethodO3putyAD10Foundation4DataVcADmF":{"name":"put(_:)","abstract":"

    Use for replacing a resource.

    ","parent_name":"Method"},"Classes/Atom/HeaderItem.html#/s:4AtomAAC10HeaderItemV4name5valueADSS_SStcfc":{"name":"init(name:value:)","abstract":"

    Creates a HeaderItem instance given the provided parameter(s).

    ","parent_name":"HeaderItem"},"Classes/Atom/ClientCredential/GrantType.html#/s:4AtomAAC16ClientCredentialV9GrantTypeO12refreshTokenyA2FmF":{"name":"refreshToken","abstract":"

    The refresh_token grant type as defined in Sections 6.0, RFC 6749.

    ","parent_name":"GrantType"},"Classes/Atom/ClientCredential.html#/s:4AtomAAC16ClientCredentialV9grantType2id6secretA2D05GrantE0O_S2Stcfc":{"name":"init(grantType:id:secret:)","abstract":"

    Creates a ClientCredential instance given the provided parameter(s).

    ","parent_name":"ClientCredential"},"Classes/Atom/ClientCredential/GrantType.html":{"name":"GrantType","abstract":"

    List of supported grant types by Atom.

    ","parent_name":"ClientCredential"},"Classes/Atom/BasicCredential.html#/s:4AtomAAC15BasicCredentialV8password8usernameADSS_SStcfc":{"name":"init(password:username:)","abstract":"

    Creates a BasicCredential instance given the provided parameter(s).

    ","parent_name":"BasicCredential"},"Classes/Atom/BaseURL/Scheme.html#/s:4AtomAAC7BaseURLV6SchemeO4httpyA2FmF":{"name":"http","abstract":"

    The hyper text transfer protocol.

    ","parent_name":"Scheme"},"Classes/Atom/BaseURL/Scheme.html#/s:4AtomAAC7BaseURLV6SchemeO5httpsyA2FmF":{"name":"https","abstract":"

    The hyper text transfer protocol secure.

    ","parent_name":"Scheme"},"Classes/Atom/BaseURL.html#/s:4AtomAAC7BaseURLV6scheme4hostA2D6SchemeO_SStKcfc":{"name":"init(scheme:host:)","abstract":"

    Creates a BaseURL instance given the provided parameter(s).

    ","parent_name":"BaseURL"},"Classes/Atom/BaseURL/Scheme.html":{"name":"Scheme","abstract":"

    List of supported scheme types.

    ","parent_name":"BaseURL"},"Classes/Atom/AuthorizationEndpoint.html#/s:4AtomAAC21AuthorizationEndpointV4host4pathADSS_SStcfc":{"name":"init(host:path:)","abstract":"

    Creates a AuthorizationEndpoint instance given the provided parameter(s).

    ","parent_name":"AuthorizationEndpoint"},"Classes/Atom/AuthenticationMethod.html#/s:4AtomAAC20AuthenticationMethodO5basicyAdB15BasicCredentialVcADmF":{"name":"basic(_:)","abstract":"

    Atom will apply basic authorization header to a request on behalf of the client.

    ","parent_name":"AuthenticationMethod"},"Classes/Atom/AuthenticationMethod.html#/s:4AtomAAC20AuthenticationMethodO6beareryAdB21AuthorizationEndpointV_AB16ClientCredentialVAA05TokenH8Writable_ptcADmF":{"name":"bearer(_:_:_:)","abstract":"

    Atom will manage access token expiration and apply authorization header to a request on behalf of the client.

    ","parent_name":"AuthenticationMethod"},"Classes/Atom/AuthenticationMethod.html#/s:4AtomAAC20AuthenticationMethodO4noneyA2DmF":{"name":"none","abstract":"

    Application will manage its own authorization headers.

    ","parent_name":"AuthenticationMethod"},"Classes/Atom.html#/s:4AtomAAC3logSbvp":{"name":"log","abstract":"

    A Bool indicating whether or not all service requests should be logged to the console.

    ","parent_name":"Atom"},"Classes/Atom.html#/s:4AtomAAC20serviceConfigurationA2B07ServiceC0C_tcfc":{"name":"init(serviceConfiguration:)","abstract":"

    Creates a Atom instance given the provided parameter(s).

    ","parent_name":"Atom"},"Classes/Atom.html#/s:4AtomAAC21cancelAllSessionTasksyyF":{"name":"cancelAllSessionTasks()","abstract":"

    Cancels all currently running and suspended tasks.

    ","parent_name":"Atom"},"Classes/Atom.html#/s:4AtomAAC4loadyAB7ServiceCAA11Requestable_pF":{"name":"load(_:)","abstract":"

    Prepares Atom.Service for a network call.

    ","parent_name":"Atom"},"Classes/Atom.html#/s:4AtomAAC27didFailToRefreshAccessTokenSo18NSNotificationNameavpZ":{"name":"didFailToRefreshAccessToken","abstract":"

    Posted when Atom fails to refresh access token.

    ","parent_name":"Atom"},"Classes/Atom/AuthenticationMethod.html":{"name":"AuthenticationMethod","abstract":"

    List of authentication methods a client can choose from for Atom configuration.

    ","parent_name":"Atom"},"Classes/Atom/AuthorizationEndpoint.html":{"name":"AuthorizationEndpoint","abstract":"

    Model object representing the location of the authorization server.

    ","parent_name":"Atom"},"Classes/Atom/BaseURL.html":{"name":"BaseURL","abstract":"

    Model object representing base URL composed from URL scheme and host.

    ","parent_name":"Atom"},"Classes/Atom/BasicCredential.html":{"name":"BasicCredential","abstract":"

    The BasicCredential type declares an object used by Atom in network requests that require basic authentication. Before","parent_name":"Atom"},"Classes/Atom/ClientCredential.html":{"name":"ClientCredential","abstract":"

    The ClientCredential type declares an object used by Atom for automated refreshing of the access token.","parent_name":"Atom"},"Classes/Atom/HeaderItem.html":{"name":"HeaderItem","abstract":"

    A single name-value pair for specifying HTTP header value modeled after URLQueryItem.

    ","parent_name":"Atom"},"Classes/Atom/Method.html":{"name":"Method","abstract":"

    List of primary HTTP methods.

    ","parent_name":"Atom"},"Classes/Atom.html#/s:4AtomAAC9QueryItema":{"name":"QueryItem","abstract":"

    A single name-value pair from the query portion of a URL.

    ","parent_name":"Atom"},"Classes/Atom/Response.html":{"name":"Response","abstract":"

    The metadata associated with the response to a URL load request, independent of protocol and URL scheme.

    ","parent_name":"Atom"},"Classes/Atom/TokenCredential.html":{"name":"TokenCredential","abstract":"

    The TokenCredential type declares an object used by Atom in network requests that require bearer authentication.

    ","parent_name":"Atom"},"Classes/Atom/URLPath.html":{"name":"URLPath","abstract":"

    Model object representing URL path.

    ","parent_name":"Atom"},"Classes/Atom/Service.html":{"name":"Service","abstract":"

    Service is a public facing class responsible for managing","parent_name":"Atom"},"Classes/Atom/ServiceConfiguration.html":{"name":"ServiceConfiguration","abstract":"

    Model object representing Service configuration.

    ","parent_name":"Atom"},"Classes/Atom.html":{"name":"Atom","abstract":"

    The lightweight & delightful networking library.

    "},"Classes.html":{"name":"Classes","abstract":"

    The following classes are available globally.

    "},"Enums.html":{"name":"Enumerations","abstract":"

    The following enumerations are available globally.

    "},"Extensions.html":{"name":"Extensions","abstract":"

    The following extensions are available globally.

    "},"Protocols.html":{"name":"Protocols","abstract":"

    The following protocols are available globally.

    "}} \ No newline at end of file +{"Structs/URLPath.html#/s:4Atom7URLPathVyACSSKcfc":{"name":"init(_:)","abstract":"

    Creates a URLPath instance given the provided parameter(s).

    ","parent_name":"URLPath"},"Structs/TokenCredential.html#/s:4Atom15TokenCredentialV06accessB0SSvp":{"name":"accessToken","abstract":"

    The access token as defined in OAuth 2.0 spec.

    ","parent_name":"TokenCredential"},"Structs/TokenCredential.html#/s:4Atom15TokenCredentialV9expiresInSivp":{"name":"expiresIn","abstract":"

    The number of seconds access token is valid for.

    ","parent_name":"TokenCredential"},"Structs/TokenCredential.html#/s:4Atom15TokenCredentialV9expiresAt10Foundation4DateVvp":{"name":"expiresAt","abstract":"

    The expiration date of the access token.

    ","parent_name":"TokenCredential"},"Structs/TokenCredential.html#/s:4Atom15TokenCredentialV07refreshB0SSvp":{"name":"refreshToken","abstract":"

    The refresh token as defined in OAuth 2.0 spec.

    ","parent_name":"TokenCredential"},"Structs/TokenCredential.html#/s:4Atom15TokenCredentialV06accessB09expiresIn0E2At07refreshB0ACSS_Si10Foundation4DateVSStcfc":{"name":"init(accessToken:expiresIn:expiresAt:refreshToken:)","abstract":"

    Creates a TokenCredential instance given the provided parameter(s).

    ","parent_name":"TokenCredential"},"Structs/TokenCredential.html#/s:Se4fromxs7Decoder_p_tKcfc":{"name":"init(from:)","parent_name":"TokenCredential"},"Structs/QueryItem.html#/s:4Atom9QueryItemV4nameSSvp":{"name":"name","abstract":"

    The name of the query item.

    ","parent_name":"QueryItem"},"Structs/QueryItem.html#/s:4Atom9QueryItemV5valueSSvp":{"name":"value","abstract":"

    The value of the query item.

    ","parent_name":"QueryItem"},"Structs/QueryItem.html#/s:4Atom9QueryItemV4name5valueACSS_SStcfc":{"name":"init(name:value:)","abstract":"

    Creates a QueryItem instance given the provided parameter(s).

    ","parent_name":"QueryItem"},"Structs/HeaderItem.html#/s:4Atom10HeaderItemV4nameSSvp":{"name":"name","abstract":"

    The name of the header item.

    ","parent_name":"HeaderItem"},"Structs/HeaderItem.html#/s:4Atom10HeaderItemV5valueSSvp":{"name":"value","abstract":"

    The value of the header item.

    ","parent_name":"HeaderItem"},"Structs/HeaderItem.html#/s:4Atom10HeaderItemV4name5valueACSS_SStcfc":{"name":"init(name:value:)","abstract":"

    Creates a HeaderItem instance given the provided parameter(s).

    ","parent_name":"HeaderItem"},"Structs/ClientCredential/GrantType.html#/s:4Atom16ClientCredentialV9GrantTypeO12refreshTokenyA2EmF":{"name":"refreshToken","abstract":"

    The refresh_token grant type as defined in Sections 6.0, RFC 6749.

    ","parent_name":"GrantType"},"Structs/ClientCredential.html#/s:4Atom16ClientCredentialV9grantType2id6secretA2C05GrantE0O_S2Stcfc":{"name":"init(grantType:id:secret:)","abstract":"

    Creates a ClientCredential instance given the provided parameter(s).

    ","parent_name":"ClientCredential"},"Structs/ClientCredential/GrantType.html":{"name":"GrantType","abstract":"

    List of supported grant types by Atom.

    ","parent_name":"ClientCredential"},"Structs/BasicCredential.html#/s:4Atom15BasicCredentialV8password8usernameACSS_SStcfc":{"name":"init(password:username:)","abstract":"

    Creates a BasicCredential instance given the provided parameter(s).

    ","parent_name":"BasicCredential"},"Structs/BaseURL/Scheme.html#/s:4Atom7BaseURLV6SchemeO4httpyA2EmF":{"name":"http","abstract":"

    The hyper text transfer protocol.

    ","parent_name":"Scheme"},"Structs/BaseURL/Scheme.html#/s:4Atom7BaseURLV6SchemeO5httpsyA2EmF":{"name":"https","abstract":"

    The hyper text transfer protocol secure.

    ","parent_name":"Scheme"},"Structs/BaseURL.html#/s:4Atom7BaseURLV6scheme4hostA2C6SchemeO_SStKcfc":{"name":"init(scheme:host:)","abstract":"

    Creates a BaseURL instance given the provided parameter(s).

    ","parent_name":"BaseURL"},"Structs/BaseURL/Scheme.html":{"name":"Scheme","abstract":"

    List of supported scheme types.

    ","parent_name":"BaseURL"},"Structs/AuthorizationEndpoint.html#/s:4Atom21AuthorizationEndpointV4host4pathACSS_SStcfc":{"name":"init(host:path:)","abstract":"

    Creates a AuthorizationEndpoint instance given the provided parameter(s).

    ","parent_name":"AuthorizationEndpoint"},"Structs/AtomResponse.html#/s:4Atom0A8ResponseV12HeaderFieldsa":{"name":"HeaderFields","abstract":"

    Undocumented

    ","parent_name":"AtomResponse"},"Structs/AtomResponse.html#/s:4Atom0A8ResponseV15allHeaderFieldsSo12NSDictionaryCSgvp":{"name":"allHeaderFields","abstract":"

    All HTTP header fields of the response.

    ","parent_name":"AtomResponse"},"Structs/AtomResponse.html#/s:4Atom0A8ResponseV21expectedContentLengths5Int64VSgvp":{"name":"expectedContentLength","abstract":"

    The expected length of the response’s content.

    ","parent_name":"AtomResponse"},"Structs/AtomResponse.html#/s:4Atom0A8ResponseV4data10Foundation4DataVSgvp":{"name":"data","abstract":"

    The data returned by the server.

    ","parent_name":"AtomResponse"},"Structs/AtomResponse.html#/s:4Atom0A8ResponseV8mimeTypeSSSgvp":{"name":"mimeType","abstract":"

    The MIME type of the response.

    ","parent_name":"AtomResponse"},"Structs/AtomResponse.html#/s:4Atom0A8ResponseV10statusCodeSiSgvp":{"name":"statusCode","abstract":"

    The response’s HTTP status code.

    ","parent_name":"AtomResponse"},"Structs/AtomResponse.html#/s:4Atom0A8ResponseV17suggestedFilenameSSSgvp":{"name":"suggestedFilename","abstract":"

    A suggested filename for the response data.

    ","parent_name":"AtomResponse"},"Structs/AtomResponse.html#/s:4Atom0A8ResponseV16textEncodingNameSSSgvp":{"name":"textEncodingName","abstract":"

    The name of the text encoding provided by the response’s originating source.

    ","parent_name":"AtomResponse"},"Structs/AtomResponse.html#/s:4Atom0A8ResponseV3url10Foundation3URLVSgvp":{"name":"url","abstract":"

    The URL for the response.

    ","parent_name":"AtomResponse"},"Structs/AtomResponse.html#/s:4Atom0A8ResponseV9isFailureSbvp":{"name":"isFailure","abstract":"

    Returns true if the status code of the AtomResponse is not in 200...299 range.

    ","parent_name":"AtomResponse"},"Structs/AtomResponse.html#/s:4Atom0A8ResponseV12isSuccessfulSbvp":{"name":"isSuccessful","abstract":"

    Returns true if the status code of the AtomResponse is in 200...299 range.

    ","parent_name":"AtomResponse"},"Structs/AtomResponse.html#/s:4Atom0A8ResponseV7successACvpZ":{"name":"success","abstract":"

    Returns default, success response where status code is 200.

    ","parent_name":"AtomResponse"},"Structs/AtomResponse.html":{"name":"AtomResponse","abstract":"

    The metadata associated with the response to a URL load request, independent of protocol and URL scheme.

    "},"Structs/AuthorizationEndpoint.html":{"name":"AuthorizationEndpoint","abstract":"

    Model object representing the location of the authorization server.

    "},"Structs/BaseURL.html":{"name":"BaseURL","abstract":"

    Model object representing base URL composed from URL scheme and host.

    "},"Structs/BasicCredential.html":{"name":"BasicCredential","abstract":"

    The BasicCredential type declares an object used by Atom in network requests that require basic authentication. Before"},"Structs/ClientCredential.html":{"name":"ClientCredential","abstract":"

    The ClientCredential type declares an object used by Atom for automated refreshing of the access token."},"Structs/HeaderItem.html":{"name":"HeaderItem","abstract":"

    A single name-value pair from the header portion of a request.

    "},"Structs/QueryItem.html":{"name":"QueryItem","abstract":"

    A single name-value pair from the query portion of a URL.

    "},"Structs/TokenCredential.html":{"name":"TokenCredential","abstract":"

    The TokenCredential type declares an object used by Atom in network requests that require bearer authentication.

    "},"Structs/URLPath.html":{"name":"URLPath","abstract":"

    Model object representing URL path.

    "},"Protocols/TokenCredentialWritable.html#/s:4Atom23TokenCredentialWritableP05tokenC0AA0bC0Vvp":{"name":"tokenCredential","abstract":"

    Returns conforming type as TokenCredential.

    ","parent_name":"TokenCredentialWritable"},"Protocols/RequestableItem.html#/s:4Atom15RequestableItemP4nameSSvp":{"name":"name","abstract":"

    The name of the requestable item.

    ","parent_name":"RequestableItem"},"Protocols/RequestableItem.html#/s:4Atom15RequestableItemP5valueSSvp":{"name":"value","abstract":"

    The value of the requestable item.

    ","parent_name":"RequestableItem"},"Protocols/RequestableItem.html#/s:4Atom15RequestableItemP4name5valuexSS_SStcfc":{"name":"init(name:value:)","parent_name":"RequestableItem"},"Protocols/ClientCredentialConvertible.html#/s:4Atom27ClientCredentialConvertibleP06clientC0AA0bC0Vvp":{"name":"clientCredential","abstract":"

    Returns conforming type as ClientCredential.

    ","parent_name":"ClientCredentialConvertible"},"Protocols/BasicCredentialConvertible.html#/s:4Atom26BasicCredentialConvertibleP05basicC0AA0bC0Vvp":{"name":"basicCredential","abstract":"

    Returns conforming type as BasicCredential.

    ","parent_name":"BasicCredentialConvertible"},"Protocols/Requestable.html#/s:4Atom11RequestableP11headerItemsSayAA10HeaderItemVGSgvp":{"name":"headerItems","abstract":"

    The array of header items to apply to a URLRequest.

    ","parent_name":"Requestable"},"Protocols/Requestable.html#/s:4Atom11RequestableP6methodAA10HTTPMethodOvp":{"name":"method","abstract":"

    The HTTP method to apply to a URLRequest.

    ","parent_name":"Requestable"},"Protocols/Requestable.html#/s:4Atom11RequestableP10queryItemsSayAA9QueryItemVGSgvp":{"name":"queryItems","abstract":"

    The array of query items to apply to a URL.

    ","parent_name":"Requestable"},"Protocols/Requestable.html#/s:4Atom11RequestableP22requiresAuthenticationSbvp":{"name":"requiresAuthentication","abstract":"

    The Bool indicating whether or not authorization header should be applied","parent_name":"Requestable"},"Protocols/Requestable.html#/s:4Atom11RequestableP7baseURLAA04BaseD0VyKF":{"name":"baseURL()","abstract":"

    The base url to initialize URLRequest with.

    ","parent_name":"Requestable"},"Protocols/Requestable.html#/s:4Atom11RequestableP4pathAA7URLPathVyKF":{"name":"path()","abstract":"

    The URL path to append to a base URL.

    ","parent_name":"Requestable"},"Protocols/Requestable.html":{"name":"Requestable","abstract":"

    The Requestable protocol declares an interface used for initializing network request object.

    "},"Protocols/BasicCredentialConvertible.html":{"name":"BasicCredentialConvertible","abstract":"

    The BasicCredentialConvertible protocol declares an interface used for converting conforming type to BasicCredential.

    "},"Protocols/ClientCredentialConvertible.html":{"name":"ClientCredentialConvertible","abstract":"

    The ClientCredentialConvertible protocol declares an interface used for converting conforming type to ClientCredential.

    "},"Protocols.html#/s:4Atom5ModelP":{"name":"Model","abstract":"

    The Model protocol declares an interface used as a generic constraint on Service methods.

    "},"Protocols/RequestableItem.html":{"name":"RequestableItem","abstract":"

    The RequestableItem protocol declares an interface used for specifying HTTP header values & request queries.

    "},"Protocols/TokenCredentialWritable.html":{"name":"TokenCredentialWritable","abstract":"

    The TokenCredentialWritable protocol declares an interface used for reading from / writing to TokenCredential.

    "},"Extensions/URLSessionTaskMetrics.html#/c:@CM@Atom@@objc(cs)NSURLSessionTaskMetrics(py)debugDescription":{"name":"debugDescription","abstract":"

    Returns a textual representation of this instance, suitable for debugging.

    ","parent_name":"URLSessionTaskMetrics"},"Extensions/URLSessionTask.html#/c:@CM@Atom@@objc(cs)NSURLSessionTask(py)debugDescription":{"name":"debugDescription","abstract":"

    Returns a textual representation of this instance, suitable for debugging.

    ","parent_name":"URLSessionTask"},"Extensions/URLResponse.html#/s:So13NSURLResponseC4AtomE9isFailureSbvp":{"name":"isFailure","abstract":"

    Returns true if the status code of the HTTPURLResponse is not in 200...299 range.

    ","parent_name":"URLResponse"},"Extensions/URLResponse.html#/s:So13NSURLResponseC4AtomE12isSuccessfulSbvp":{"name":"isSuccessful","abstract":"

    Returns true if the status code of the HTTPURLResponse is in 200...299 range.

    ","parent_name":"URLResponse"},"Extensions/URLResponse.html#/c:@CM@Atom@@objc(cs)NSURLResponse(py)debugDescription":{"name":"debugDescription","abstract":"

    Returns a textual representation of this instance, suitable for debugging.

    ","parent_name":"URLResponse"},"Extensions/URLRequest.html#/s:10Foundation10URLRequestV4AtomE16debugDescriptionSSvp":{"name":"debugDescription","abstract":"

    Returns a textual representation of this instance, suitable for debugging.

    ","parent_name":"URLRequest"},"Extensions/Array.html#/s:s30ExpressibleByDictionaryLiteralP010dictionaryD0x3KeyQz_5ValueQztd_tcfc":{"name":"init(dictionaryLiteral:)","parent_name":"Array"},"Extensions/Array.html":{"name":"Array","abstract":"

    Adds the ability to specify an array as the expected decoded type.

    "},"Extensions.html#/s:10Foundation4DataV":{"name":"Data","abstract":"

    Conforming Data type to Model protocol allows it to be used where Model is expected.

    "},"Extensions/URLRequest.html":{"name":"URLRequest"},"Extensions/URLResponse.html":{"name":"URLResponse"},"Extensions/URLSessionTask.html":{"name":"URLSessionTask"},"Extensions/URLSessionTaskMetrics.html":{"name":"URLSessionTaskMetrics"},"Enums/HTTPMethod.html#/s:4Atom10HTTPMethodO6deleteyA2CmF":{"name":"delete","abstract":"

    Use for deleting a resource identified by a URI.

    ","parent_name":"HTTPMethod"},"Enums/HTTPMethod.html#/s:4Atom10HTTPMethodO3getyA2CmF":{"name":"get","abstract":"

    Use for reading (or retrieving) a representation of a resource.

    ","parent_name":"HTTPMethod"},"Enums/HTTPMethod.html#/s:4Atom10HTTPMethodO5patchyAC10Foundation4DataVcACmF":{"name":"patch(_:)","abstract":"

    Use for modifying capabilities.

    ","parent_name":"HTTPMethod"},"Enums/HTTPMethod.html#/s:4Atom10HTTPMethodO4postyAC10Foundation4DataVcACmF":{"name":"post(_:)","abstract":"

    Use for creating new resources.

    ","parent_name":"HTTPMethod"},"Enums/HTTPMethod.html#/s:4Atom10HTTPMethodO3putyAC10Foundation4DataVcACmF":{"name":"put(_:)","abstract":"

    Use for replacing a resource.

    ","parent_name":"HTTPMethod"},"Enums/AuthenticationMethod.html#/s:4Atom20AuthenticationMethodO5basicyAcA15BasicCredentialVcACmF":{"name":"basic(_:)","abstract":"

    Atom will apply basic authorization header to a request on behalf of the client.

    ","parent_name":"AuthenticationMethod"},"Enums/AuthenticationMethod.html#/s:4Atom20AuthenticationMethodO6beareryAcA21AuthorizationEndpointV_AA16ClientCredentialVAA05TokenH8Writable_ptcACmF":{"name":"bearer(_:_:_:)","abstract":"

    Atom will manage access token expiration and apply authorization header to a request on behalf of the client.

    ","parent_name":"AuthenticationMethod"},"Enums/AuthenticationMethod.html#/s:4Atom20AuthenticationMethodO4noneyA2CmF":{"name":"none","abstract":"

    Application will manage its own authorization headers.

    ","parent_name":"AuthenticationMethod"},"Enums/RequestableError.html#/s:4Atom16RequestableErrorO14invalidBaseURLyA2CmF":{"name":"invalidBaseURL","abstract":"

    Base URL failed validation. Most probable cause is invalid URL host.

    ","parent_name":"RequestableError"},"Enums/RequestableError.html#/s:4Atom16RequestableErrorO10invalidURLyA2CmF":{"name":"invalidURL","abstract":"

    URLComponents initialization with provided URL string failed.

    ","parent_name":"RequestableError"},"Enums/RequestableError.html#/s:4Atom16RequestableErrorO14invalidURLPathyA2CmF":{"name":"invalidURLPath","abstract":"

    URL path failed validation.

    ","parent_name":"RequestableError"},"Enums/AtomError.html#/s:4Atom0A5ErrorO7decoderyACs0B0_pcACmF":{"name":"decoder(_:)","abstract":"

    Decoder failed to decode data.

    ","parent_name":"AtomError"},"Enums/AtomError.html#/s:4Atom0A5ErrorO4datayACs0B0_pcACmF":{"name":"data(_:)","abstract":"

    Failed to initialize Data instance from URL.

    ","parent_name":"AtomError"},"Enums/AtomError.html#/s:4Atom0A5ErrorO11requestableyAcA011RequestableB0OcACmF":{"name":"requestable(_:)","abstract":"

    Failed to initialize URLRequest with Requestable instance.

    ","parent_name":"AtomError"},"Enums/AtomError.html#/s:4Atom0A5ErrorO8responseyAcA0A8ResponseVcACmF":{"name":"response(_:)","abstract":"

    Service returned invalid response where the status code is not in 200...299 range.

    ","parent_name":"AtomError"},"Enums/AtomError.html#/s:4Atom0A5ErrorO7sessionyACs0B0_pcACmF":{"name":"session(_:)","abstract":"

    URLSession failed with error.

    ","parent_name":"AtomError"},"Enums/AtomError.html#/s:4Atom0A5ErrorO10unexpectedyA2CmF":{"name":"unexpected","abstract":"

    Unexpected, logic error.

    ","parent_name":"AtomError"},"Enums/AtomError.html#/s:4Atom0A5ErrorO7unknownyA2CmF":{"name":"unknown","abstract":"

    Unknown error occurred.

    ","parent_name":"AtomError"},"Enums/AtomError.html#/s:4Atom0A5ErrorO22isAuthorizationFailureSbvp":{"name":"isAuthorizationFailure","abstract":"

    Returns Bool indicating whether the error is due to an invalid or expired access token.

    ","parent_name":"AtomError"},"Enums/AtomError.html#/s:4Atom0A5ErrorO27isAccessTokenRefreshFailureSbvp":{"name":"isAccessTokenRefreshFailure","abstract":"

    Returns Bool indicating whether the error is due to a failed attempt to refresh an access token.

    ","parent_name":"AtomError"},"Enums/AtomError.html#/s:4Atom0A5ErrorO15decodeIfPresent2asxSgxm_tKSeRzlF":{"name":"decodeIfPresent(as:)","abstract":"

    Convenience method for decoding error object or message returned by the service.

    ","parent_name":"AtomError"},"Enums/AtomError.html":{"name":"AtomError","abstract":"

    List of all possible error cases thrown by Atom framework.

    "},"Enums/RequestableError.html":{"name":"RequestableError","abstract":"

    List of all possible error cases thrown when conversion from Requestable to URLRequest fails.

    "},"Enums/AuthenticationMethod.html":{"name":"AuthenticationMethod","abstract":"

    List of authentication methods a client can choose from for Atom configuration.

    "},"Enums/HTTPMethod.html":{"name":"HTTPMethod","abstract":"

    List of primary HTTP methods.

    "},"Classes/ServiceConfiguration/Configuration.html#/s:4Atom20ServiceConfigurationC0C0O10backgroundyAESScAEmF":{"name":"background(_:)","abstract":"

    The background session configuration is suitable for transferring data files while the app runs in the background.

    ","parent_name":"Configuration"},"Classes/ServiceConfiguration/Configuration.html#/s:4Atom20ServiceConfigurationC0C0O7defaultyA2EmF":{"name":"default","abstract":"

    The default session configuration that uses a persistent disk-based cache.

    ","parent_name":"Configuration"},"Classes/ServiceConfiguration/Configuration.html#/s:4Atom20ServiceConfigurationC0C0O9ephemeralyA2EmF":{"name":"ephemeral","abstract":"

    Ephemeral configuration doesn’t store caches, credential stores, or any session-related data on disk (RAM only).

    ","parent_name":"Configuration"},"Classes/ServiceConfiguration/Configuration.html":{"name":"Configuration","abstract":"

    List of supported session configurations.

    ","parent_name":"ServiceConfiguration"},"Classes/ServiceConfiguration.html#/s:4Atom20ServiceConfigurationC09MultipathB4Typea":{"name":"MultipathServiceType","abstract":"

    Undocumented

    ","parent_name":"ServiceConfiguration"},"Classes/ServiceConfiguration.html#/s:4Atom20ServiceConfigurationC20authenticationMethod13configuration7decoder13dispatchQueue09multipathB4TypeAcA014AuthenticationE0O_AC0C0O10Foundation11JSONDecoderCSo03OS_H6_queueCSo021NSURLSessionMultipathbK0Vtcfc":{"name":"init(authenticationMethod:configuration:decoder:dispatchQueue:multipathServiceType:)","abstract":"

    Creates a ServiceConfiguration instance given the provided parameter(s).

    ","parent_name":"ServiceConfiguration"},"Classes/ServiceConfiguration.html#/init(authenticationMethod:configuration:decoder:dispatchQueue:)":{"name":"init(authenticationMethod:configuration:decoder:dispatchQueue:)","abstract":"

    Creates a ServiceConfiguration instance given the provided parameter(s).

    ","parent_name":"ServiceConfiguration"},"Classes/Service.html#/s:4Atom7ServiceC6resume9expecting7Combine12AnyPublisherVyxAA0A5ErrorOGxm_tAA5ModelRzlF":{"name":"resume(expecting:)","abstract":"

    Creates and resumes URLRequest initialized from Requestable.

    ","parent_name":"Service"},"Classes/Service.html#/s:4Atom7ServiceC6resume7Combine12AnyPublisherVyAA0A8ResponseVAA0A5ErrorOGyF":{"name":"resume()","abstract":"

    Creates and resumes URLRequest initialized from Requestable.

    ","parent_name":"Service"},"Classes/Service.html#/s:4Atom7ServiceC6resume9expecting10completionyxm_ys6ResultOyxAA0A5ErrorOGctAA5ModelRzlF":{"name":"resume(expecting:completion:)","abstract":"

    Creates and resumes URLRequest initialized from Requestable.

    ","parent_name":"Service"},"Classes/Service.html#/s:4Atom7ServiceC6resumeyyys6ResultOyAA0A8ResponseVAA0A5ErrorOGcF":{"name":"resume(_:)","abstract":"

    Creates and resumes URLRequest initialized from Requestable.

    ","parent_name":"Service"},"Classes/Atom.html#/s:4AtomAAC3logSbvp":{"name":"log","abstract":"

    A Bool indicating whether or not all service requests should be logged to the console.

    ","parent_name":"Atom"},"Classes/Atom.html#/s:4AtomAAC20serviceConfigurationAbA07ServiceC0C_tcfc":{"name":"init(serviceConfiguration:)","abstract":"

    Creates a Atom instance given the provided parameter(s).

    ","parent_name":"Atom"},"Classes/Atom.html#/s:4AtomAAC21cancelAllSessionTasksyyF":{"name":"cancelAllSessionTasks()","abstract":"

    Cancels all currently running and suspended tasks.

    ","parent_name":"Atom"},"Classes/Atom.html#/s:4AtomAAC7enqueueyAA7ServiceCAA11Requestable_pF":{"name":"enqueue(_:)","abstract":"

    Prepares Service for a network call.

    ","parent_name":"Atom"},"Classes/Atom.html#/s:4AtomAAC27didFailToRefreshAccessTokenSo18NSNotificationNameavpZ":{"name":"didFailToRefreshAccessToken","abstract":"

    Posted when Atom fails to refresh access token.

    ","parent_name":"Atom"},"Classes/Atom.html":{"name":"Atom","abstract":"

    The lightweight & delightful networking library.

    "},"Classes/Service.html":{"name":"Service","abstract":"

    Service is a public facing class responsible for managing"},"Classes/ServiceConfiguration.html":{"name":"ServiceConfiguration","abstract":"

    Model object representing Service configuration.

    "},"Classes.html":{"name":"Classes","abstract":"

    The following classes are available globally.

    "},"Enums.html":{"name":"Enumerations","abstract":"

    The following enumerations are available globally.

    "},"Extensions.html":{"name":"Extensions","abstract":"

    The following extensions are available globally.

    "},"Protocols.html":{"name":"Protocols","abstract":"

    The following protocols are available globally.

    "},"Structs.html":{"name":"Structures","abstract":"

    The following structures are available globally.

    "}} \ No newline at end of file diff --git a/Documentation/undocumented.json b/Documentation/undocumented.json index 5ab5a6a..80fbc5c 100644 --- a/Documentation/undocumented.json +++ b/Documentation/undocumented.json @@ -1,9 +1,16 @@ { "warnings": [ { - "file": "/Users/michael/Developer/Alaska/Atom/Framework/Atom/Models/Atom+Response.swift", - "line": 22, - "symbol": "Atom.Response.HeaderFields", + "file": "/Users/michael/Developer/Alaska/Atom/Framework/Atom/Models/AtomResponse.swift", + "line": 21, + "symbol": "AtomResponse.HeaderFields", + "symbol_kind": "source.lang.swift.decl.typealias", + "warning": "undocumented" + }, + { + "file": "/Users/michael/Developer/Alaska/Atom/Framework/Atom/Service/ServiceConfiguration.swift", + "line": 64, + "symbol": "ServiceConfiguration.MultipathServiceType", "symbol_kind": "source.lang.swift.decl.typealias", "warning": "undocumented" } diff --git a/Example/Example.xcodeproj/project.pbxproj b/Example/Example.xcodeproj/project.pbxproj index ab75365..09cdf5e 100644 --- a/Example/Example.xcodeproj/project.pbxproj +++ b/Example/Example.xcodeproj/project.pbxproj @@ -7,26 +7,33 @@ objects = { /* Begin PBXBuildFile section */ - 1C48198F20D034E200CB6F31 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C48198E20D034E200CB6F31 /* AppDelegate.swift */; }; - 1C48199120D034E200CB6F31 /* RESTViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C48199020D034E200CB6F31 /* RESTViewController.swift */; }; - 1C48199420D034E200CB6F31 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 1C48199220D034E200CB6F31 /* Main.storyboard */; }; - 1C48199620D034E300CB6F31 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 1C48199520D034E300CB6F31 /* Assets.xcassets */; }; - 1C48199920D034E300CB6F31 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 1C48199720D034E300CB6F31 /* LaunchScreen.storyboard */; }; - 1CC3288220D9BE2C0099644D /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1CC3288120D9BE2C0099644D /* Constants.swift */; }; - 1CC3288520D9BE5F0099644D /* Joke.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1CC3288420D9BE5F0099644D /* Joke.swift */; }; - 1CC3288920D9BEC70099644D /* Joke+Endpoint.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1CC3288820D9BEC70099644D /* Joke+Endpoint.swift */; }; - 4C015F93242027820028811D /* Atom.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1CC3288B20D9C4A80099644D /* Atom.framework */; }; - 4C015F94242027820028811D /* Atom.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 1CC3288B20D9C4A80099644D /* Atom.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 4C4E42F4258ADD2B009AF14F /* ExampleApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C4E42E1258ADD2A009AF14F /* ExampleApp.swift */; }; + 4C4E42F5258ADD2B009AF14F /* ExampleApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C4E42E1258ADD2A009AF14F /* ExampleApp.swift */; }; + 4C4E42F6258ADD2B009AF14F /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C4E42E2258ADD2A009AF14F /* ContentView.swift */; }; + 4C4E42F7258ADD2B009AF14F /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C4E42E2258ADD2A009AF14F /* ContentView.swift */; }; + 4C4E42F8258ADD2B009AF14F /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 4C4E42E3258ADD2B009AF14F /* Assets.xcassets */; }; + 4C4E42F9258ADD2B009AF14F /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 4C4E42E3258ADD2B009AF14F /* Assets.xcassets */; }; + 4C4E4307258ADD67009AF14F /* ContentViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C4E4306258ADD67009AF14F /* ContentViewModel.swift */; }; + 4C4E4308258ADD67009AF14F /* ContentViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C4E4306258ADD67009AF14F /* ContentViewModel.swift */; }; + 4C4E4312258ADE67009AF14F /* Joke.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C4E4311258ADE67009AF14F /* Joke.swift */; }; + 4C4E4313258ADE67009AF14F /* Joke.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C4E4311258ADE67009AF14F /* Joke.swift */; }; + 4C4E4318258ADEE4009AF14F /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C4E4317258ADEE4009AF14F /* Constants.swift */; }; + 4C4E4319258ADEE4009AF14F /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C4E4317258ADEE4009AF14F /* Constants.swift */; }; + 4C4E431E258ADF11009AF14F /* Joke+Endpoint.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C4E431D258ADF11009AF14F /* Joke+Endpoint.swift */; }; + 4C4E431F258ADF11009AF14F /* Joke+Endpoint.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C4E431D258ADF11009AF14F /* Joke+Endpoint.swift */; }; + 4CC6396A258AE0D100FBE425 /* Atom.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4CC63969258AE0D100FBE425 /* Atom.framework */; }; + 4CC6396B258AE0D100FBE425 /* Atom.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 4CC63969258AE0D100FBE425 /* Atom.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 4CC63972258AE1D500FBE425 /* Color+Additions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CC63971258AE1D500FBE425 /* Color+Additions.swift */; }; /* End PBXBuildFile section */ /* Begin PBXCopyFilesBuildPhase section */ - 4C015F95242027820028811D /* Embed Frameworks */ = { + 4CC6396C258AE0D100FBE425 /* Embed Frameworks */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; dstPath = ""; dstSubfolderSpec = 10; files = ( - 4C015F94242027820028811D /* Atom.framework in Embed Frameworks */, + 4CC6396B258AE0D100FBE425 /* Atom.framework in Embed Frameworks */, ); name = "Embed Frameworks"; runOnlyForDeploymentPostprocessing = 0; @@ -34,168 +41,213 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ - 1C48198B20D034E200CB6F31 /* Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Example.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 1C48198E20D034E200CB6F31 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; - 1C48199020D034E200CB6F31 /* RESTViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RESTViewController.swift; sourceTree = ""; }; - 1C48199320D034E200CB6F31 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; - 1C48199520D034E300CB6F31 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; - 1C48199820D034E300CB6F31 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; - 1C48199A20D034E300CB6F31 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 1CC3288120D9BE2C0099644D /* Constants.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Constants.swift; sourceTree = ""; }; - 1CC3288420D9BE5F0099644D /* Joke.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Joke.swift; sourceTree = ""; }; - 1CC3288820D9BEC70099644D /* Joke+Endpoint.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Joke+Endpoint.swift"; sourceTree = ""; }; - 1CC3288B20D9C4A80099644D /* Atom.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Atom.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 4C79112E24D0979E00DC6E00 /* Example.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Example.entitlements; sourceTree = ""; }; + 4C4E42E1258ADD2A009AF14F /* ExampleApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExampleApp.swift; sourceTree = ""; }; + 4C4E42E2258ADD2A009AF14F /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; + 4C4E42E3258ADD2B009AF14F /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 4C4E42E8258ADD2B009AF14F /* Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Example.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 4C4E42EB258ADD2B009AF14F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 4C4E42F0258ADD2B009AF14F /* Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Example.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 4C4E42F2258ADD2B009AF14F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 4C4E42F3258ADD2B009AF14F /* macOS.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = macOS.entitlements; sourceTree = ""; }; + 4C4E4306258ADD67009AF14F /* ContentViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentViewModel.swift; sourceTree = ""; }; + 4C4E4311258ADE67009AF14F /* Joke.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Joke.swift; sourceTree = ""; }; + 4C4E4317258ADEE4009AF14F /* Constants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Constants.swift; sourceTree = ""; }; + 4C4E431D258ADF11009AF14F /* Joke+Endpoint.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Joke+Endpoint.swift"; sourceTree = ""; }; + 4CC63969258AE0D100FBE425 /* Atom.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Atom.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 4CC63971258AE1D500FBE425 /* Color+Additions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Color+Additions.swift"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ - 1C48198820D034E200CB6F31 /* Frameworks */ = { + 4C4E42E5258ADD2B009AF14F /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 4CC6396A258AE0D100FBE425 /* Atom.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 4C4E42ED258ADD2B009AF14F /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 4C015F93242027820028811D /* Atom.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ - 1C48198220D034E200CB6F31 = { + 4C4E42DB258ADD29009AF14F = { isa = PBXGroup; children = ( - 1C48198D20D034E200CB6F31 /* Example */, - 1C48198C20D034E200CB6F31 /* Products */, - 1CC3288A20D9C4A80099644D /* Frameworks */, + 4C4E42E0258ADD2A009AF14F /* Shared */, + 4C4E42EA258ADD2B009AF14F /* iOS */, + 4C4E42F1258ADD2B009AF14F /* macOS */, + 4C4E42E9258ADD2B009AF14F /* Products */, + 4CC63968258AE0D100FBE425 /* Frameworks */, ); sourceTree = ""; }; - 1C48198C20D034E200CB6F31 /* Products */ = { + 4C4E42E0258ADD2A009AF14F /* Shared */ = { isa = PBXGroup; children = ( - 1C48198B20D034E200CB6F31 /* Example.app */, + 4C4E430C258ADDF9009AF14F /* App */, + 4C4E430D258ADE09009AF14F /* Assets */, + 4C4E431C258ADEF9009AF14F /* Endpoints */, + 4CC63970258AE1BC00FBE425 /* Extensions */, + 4C4E4316258ADEB0009AF14F /* Global */, + 4C4E4310258ADE55009AF14F /* Models */, + 4C4E430B258ADDD5009AF14F /* Views */, ); - name = Products; + path = Shared; sourceTree = ""; }; - 1C48198D20D034E200CB6F31 /* Example */ = { + 4C4E42E9258ADD2B009AF14F /* Products */ = { isa = PBXGroup; children = ( - 4C79112E24D0979E00DC6E00 /* Example.entitlements */, - 1C4819A920D0356100CB6F31 /* Controllers */, - 1CC3288620D9BEA50099644D /* Extensions */, - 1CC3288020D9BE1A0099644D /* Global */, - 1CC3288320D9BE540099644D /* Models */, - 1C4819AA20D0356E00CB6F31 /* Supporting Files */, - 1C4819AB20D037FB00CB6F31 /* Views */, + 4C4E42E8258ADD2B009AF14F /* Example.app */, + 4C4E42F0258ADD2B009AF14F /* Example.app */, ); - path = Example; + name = Products; sourceTree = ""; }; - 1C4819A920D0356100CB6F31 /* Controllers */ = { + 4C4E42EA258ADD2B009AF14F /* iOS */ = { isa = PBXGroup; children = ( - 1C48199020D034E200CB6F31 /* RESTViewController.swift */, + 4C4E42EB258ADD2B009AF14F /* Info.plist */, ); - path = Controllers; + path = iOS; sourceTree = ""; }; - 1C4819AA20D0356E00CB6F31 /* Supporting Files */ = { + 4C4E42F1258ADD2B009AF14F /* macOS */ = { isa = PBXGroup; children = ( - 1C48198E20D034E200CB6F31 /* AppDelegate.swift */, - 1C48199A20D034E300CB6F31 /* Info.plist */, + 4C4E42F2258ADD2B009AF14F /* Info.plist */, + 4C4E42F3258ADD2B009AF14F /* macOS.entitlements */, ); - name = "Supporting Files"; + path = macOS; sourceTree = ""; }; - 1C4819AB20D037FB00CB6F31 /* Views */ = { + 4C4E430B258ADDD5009AF14F /* Views */ = { isa = PBXGroup; children = ( - 1C48199520D034E300CB6F31 /* Assets.xcassets */, - 1C48199720D034E300CB6F31 /* LaunchScreen.storyboard */, - 1C48199220D034E200CB6F31 /* Main.storyboard */, + 4C4E42E2258ADD2A009AF14F /* ContentView.swift */, + 4C4E4306258ADD67009AF14F /* ContentViewModel.swift */, ); path = Views; sourceTree = ""; }; - 1CC3288020D9BE1A0099644D /* Global */ = { + 4C4E430C258ADDF9009AF14F /* App */ = { isa = PBXGroup; children = ( - 1CC3288120D9BE2C0099644D /* Constants.swift */, + 4C4E42E1258ADD2A009AF14F /* ExampleApp.swift */, ); - path = Global; + path = App; + sourceTree = ""; + }; + 4C4E430D258ADE09009AF14F /* Assets */ = { + isa = PBXGroup; + children = ( + 4C4E42E3258ADD2B009AF14F /* Assets.xcassets */, + ); + path = Assets; sourceTree = ""; }; - 1CC3288320D9BE540099644D /* Models */ = { + 4C4E4310258ADE55009AF14F /* Models */ = { isa = PBXGroup; children = ( - 1CC3288420D9BE5F0099644D /* Joke.swift */, + 4C4E4311258ADE67009AF14F /* Joke.swift */, ); path = Models; sourceTree = ""; }; - 1CC3288620D9BEA50099644D /* Extensions */ = { + 4C4E4316258ADEB0009AF14F /* Global */ = { isa = PBXGroup; children = ( - 1CC3288720D9BEBD0099644D /* Endpoints */, + 4C4E4317258ADEE4009AF14F /* Constants.swift */, ); - path = Extensions; + path = Global; sourceTree = ""; }; - 1CC3288720D9BEBD0099644D /* Endpoints */ = { + 4C4E431C258ADEF9009AF14F /* Endpoints */ = { isa = PBXGroup; children = ( - 1CC3288820D9BEC70099644D /* Joke+Endpoint.swift */, + 4C4E431D258ADF11009AF14F /* Joke+Endpoint.swift */, ); path = Endpoints; sourceTree = ""; }; - 1CC3288A20D9C4A80099644D /* Frameworks */ = { + 4CC63968258AE0D100FBE425 /* Frameworks */ = { isa = PBXGroup; children = ( - 1CC3288B20D9C4A80099644D /* Atom.framework */, + 4CC63969258AE0D100FBE425 /* Atom.framework */, ); name = Frameworks; sourceTree = ""; }; + 4CC63970258AE1BC00FBE425 /* Extensions */ = { + isa = PBXGroup; + children = ( + 4CC63971258AE1D500FBE425 /* Color+Additions.swift */, + ); + path = Extensions; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ - 1C48198A20D034E200CB6F31 /* Example */ = { + 4C4E42E7258ADD2B009AF14F /* Example (iOS) */ = { isa = PBXNativeTarget; - buildConfigurationList = 1C48199D20D034E300CB6F31 /* Build configuration list for PBXNativeTarget "Example" */; + buildConfigurationList = 4C4E42FC258ADD2B009AF14F /* Build configuration list for PBXNativeTarget "Example (iOS)" */; buildPhases = ( - 1C48198720D034E200CB6F31 /* Sources */, - 1C48198820D034E200CB6F31 /* Frameworks */, - 1C48198920D034E200CB6F31 /* Resources */, - 4C015F95242027820028811D /* Embed Frameworks */, + 4C4E42E4258ADD2B009AF14F /* Sources */, + 4C4E42E5258ADD2B009AF14F /* Frameworks */, + 4C4E42E6258ADD2B009AF14F /* Resources */, + 4CC6396C258AE0D100FBE425 /* Embed Frameworks */, ); buildRules = ( ); dependencies = ( ); - name = Example; - productName = Example; - productReference = 1C48198B20D034E200CB6F31 /* Example.app */; + name = "Example (iOS)"; + productName = "Example (iOS)"; + productReference = 4C4E42E8258ADD2B009AF14F /* Example.app */; + productType = "com.apple.product-type.application"; + }; + 4C4E42EF258ADD2B009AF14F /* Example (macOS) */ = { + isa = PBXNativeTarget; + buildConfigurationList = 4C4E42FF258ADD2B009AF14F /* Build configuration list for PBXNativeTarget "Example (macOS)" */; + buildPhases = ( + 4C4E42EC258ADD2B009AF14F /* Sources */, + 4C4E42ED258ADD2B009AF14F /* Frameworks */, + 4C4E42EE258ADD2B009AF14F /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "Example (macOS)"; + productName = "Example (macOS)"; + productReference = 4C4E42F0258ADD2B009AF14F /* Example.app */; productType = "com.apple.product-type.application"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ - 1C48198320D034E200CB6F31 /* Project object */ = { + 4C4E42DC258ADD29009AF14F /* Project object */ = { isa = PBXProject; attributes = { - LastSwiftUpdateCheck = 1000; - LastUpgradeCheck = 1000; - ORGANIZATIONNAME = "Alaska Airlines, Inc"; + LastSwiftUpdateCheck = 1220; + LastUpgradeCheck = 1220; TargetAttributes = { - 1C48198A20D034E200CB6F31 = { - CreatedOnToolsVersion = 10.0; - LastSwiftMigration = 1020; + 4C4E42E7258ADD2B009AF14F = { + CreatedOnToolsVersion = 12.2; + }; + 4C4E42EF258ADD2B009AF14F = { + CreatedOnToolsVersion = 12.2; }; }; }; - buildConfigurationList = 1C48198620D034E200CB6F31 /* Build configuration list for PBXProject "Example" */; + buildConfigurationList = 4C4E42DF258ADD29009AF14F /* Build configuration list for PBXProject "Example" */; compatibilityVersion = "Xcode 9.3"; developmentRegion = en; hasScannedForEncodings = 0; @@ -203,65 +255,68 @@ en, Base, ); - mainGroup = 1C48198220D034E200CB6F31; - productRefGroup = 1C48198C20D034E200CB6F31 /* Products */; + mainGroup = 4C4E42DB258ADD29009AF14F; + productRefGroup = 4C4E42E9258ADD2B009AF14F /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( - 1C48198A20D034E200CB6F31 /* Example */, + 4C4E42E7258ADD2B009AF14F /* Example (iOS) */, + 4C4E42EF258ADD2B009AF14F /* Example (macOS) */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ - 1C48198920D034E200CB6F31 /* Resources */ = { + 4C4E42E6258ADD2B009AF14F /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 4C4E42F8258ADD2B009AF14F /* Assets.xcassets in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 4C4E42EE258ADD2B009AF14F /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - 1C48199920D034E300CB6F31 /* LaunchScreen.storyboard in Resources */, - 1C48199620D034E300CB6F31 /* Assets.xcassets in Resources */, - 1C48199420D034E200CB6F31 /* Main.storyboard in Resources */, + 4C4E42F9258ADD2B009AF14F /* Assets.xcassets in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ - 1C48198720D034E200CB6F31 /* Sources */ = { + 4C4E42E4258ADD2B009AF14F /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 1CC3288920D9BEC70099644D /* Joke+Endpoint.swift in Sources */, - 1C48199120D034E200CB6F31 /* RESTViewController.swift in Sources */, - 1C48198F20D034E200CB6F31 /* AppDelegate.swift in Sources */, - 1CC3288520D9BE5F0099644D /* Joke.swift in Sources */, - 1CC3288220D9BE2C0099644D /* Constants.swift in Sources */, + 4CC63972258AE1D500FBE425 /* Color+Additions.swift in Sources */, + 4C4E4318258ADEE4009AF14F /* Constants.swift in Sources */, + 4C4E42F6258ADD2B009AF14F /* ContentView.swift in Sources */, + 4C4E42F4258ADD2B009AF14F /* ExampleApp.swift in Sources */, + 4C4E431E258ADF11009AF14F /* Joke+Endpoint.swift in Sources */, + 4C4E4312258ADE67009AF14F /* Joke.swift in Sources */, + 4C4E4307258ADD67009AF14F /* ContentViewModel.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXVariantGroup section */ - 1C48199220D034E200CB6F31 /* Main.storyboard */ = { - isa = PBXVariantGroup; - children = ( - 1C48199320D034E200CB6F31 /* Base */, - ); - name = Main.storyboard; - sourceTree = ""; - }; - 1C48199720D034E300CB6F31 /* LaunchScreen.storyboard */ = { - isa = PBXVariantGroup; - children = ( - 1C48199820D034E300CB6F31 /* Base */, + 4C4E42EC258ADD2B009AF14F /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 4C4E4319258ADEE4009AF14F /* Constants.swift in Sources */, + 4C4E42F7258ADD2B009AF14F /* ContentView.swift in Sources */, + 4C4E42F5258ADD2B009AF14F /* ExampleApp.swift in Sources */, + 4C4E431F258ADF11009AF14F /* Joke+Endpoint.swift in Sources */, + 4C4E4313258ADE67009AF14F /* Joke.swift in Sources */, + 4C4E4308258ADD67009AF14F /* ContentViewModel.swift in Sources */, ); - name = LaunchScreen.storyboard; - sourceTree = ""; + runOnlyForDeploymentPostprocessing = 0; }; -/* End PBXVariantGroup section */ +/* End PBXSourcesBuildPhase section */ /* Begin XCBuildConfiguration section */ - 1C48199B20D034E300CB6F31 /* Debug */ = { + 4C4E42FA258ADD2B009AF14F /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; @@ -287,13 +342,13 @@ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - CODE_SIGN_IDENTITY = "iPhone Developer"; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -312,16 +367,15 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; - SDKROOT = iphoneos; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; }; name = Debug; }; - 1C48199C20D034E300CB6F31 /* Release */ = { + 4C4E42FB258ADD2B009AF14F /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; @@ -347,13 +401,13 @@ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - CODE_SIGN_IDENTITY = "iPhone Developer"; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; @@ -366,75 +420,137 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = iphoneos; + MTL_FAST_MATH = YES; SWIFT_COMPILATION_MODE = wholemodule; SWIFT_OPTIMIZATION_LEVEL = "-O"; - VALIDATE_PRODUCT = YES; }; name = Release; }; - 1C48199E20D034E300CB6F31 /* Debug */ = { + 4C4E42FD258ADD2B009AF14F /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CODE_SIGN_ENTITLEMENTS = Example/Example.entitlements; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_STYLE = Automatic; - DEVELOPMENT_TEAM = H562758AXX; - INFOPLIST_FILE = Example/Info.plist; + DEVELOPMENT_TEAM = VV4VQB3X2M; + ENABLE_PREVIEWS = YES; + INFOPLIST_FILE = iOS/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); PRODUCT_BUNDLE_IDENTIFIER = com.alaskaair.Example; - PRODUCT_NAME = "$(TARGET_NAME)"; + PRODUCT_NAME = Example; + SDKROOT = iphoneos; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Debug; }; - 1C48199F20D034E300CB6F31 /* Release */ = { + 4C4E42FE258ADD2B009AF14F /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CODE_SIGN_ENTITLEMENTS = Example/Example.entitlements; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_STYLE = Automatic; - DEVELOPMENT_TEAM = H562758AXX; - INFOPLIST_FILE = Example/Info.plist; + DEVELOPMENT_TEAM = VV4VQB3X2M; + ENABLE_PREVIEWS = YES; + INFOPLIST_FILE = iOS/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); PRODUCT_BUNDLE_IDENTIFIER = com.alaskaair.Example; - PRODUCT_NAME = "$(TARGET_NAME)"; + PRODUCT_NAME = Example; + SDKROOT = iphoneos; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 4C4E4300258ADD2B009AF14F /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_ENTITLEMENTS = macOS/macOS.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + DEVELOPMENT_TEAM = VV4VQB3X2M; + ENABLE_HARDENED_RUNTIME = YES; + ENABLE_PREVIEWS = YES; + INFOPLIST_FILE = macOS/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + MACOSX_DEPLOYMENT_TARGET = 11.0; + PRODUCT_BUNDLE_IDENTIFIER = com.alaskaair.Example; + PRODUCT_NAME = Example; + SDKROOT = macosx; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + 4C4E4301258ADD2B009AF14F /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_ENTITLEMENTS = macOS/macOS.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + DEVELOPMENT_TEAM = VV4VQB3X2M; + ENABLE_HARDENED_RUNTIME = YES; + ENABLE_PREVIEWS = YES; + INFOPLIST_FILE = macOS/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + MACOSX_DEPLOYMENT_TARGET = 11.0; + PRODUCT_BUNDLE_IDENTIFIER = com.alaskaair.Example; + PRODUCT_NAME = Example; + SDKROOT = macosx; + SWIFT_VERSION = 5.0; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ - 1C48198620D034E200CB6F31 /* Build configuration list for PBXProject "Example" */ = { + 4C4E42DF258ADD29009AF14F /* Build configuration list for PBXProject "Example" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 4C4E42FA258ADD2B009AF14F /* Debug */, + 4C4E42FB258ADD2B009AF14F /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 4C4E42FC258ADD2B009AF14F /* Build configuration list for PBXNativeTarget "Example (iOS)" */ = { isa = XCConfigurationList; buildConfigurations = ( - 1C48199B20D034E300CB6F31 /* Debug */, - 1C48199C20D034E300CB6F31 /* Release */, + 4C4E42FD258ADD2B009AF14F /* Debug */, + 4C4E42FE258ADD2B009AF14F /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - 1C48199D20D034E300CB6F31 /* Build configuration list for PBXNativeTarget "Example" */ = { + 4C4E42FF258ADD2B009AF14F /* Build configuration list for PBXNativeTarget "Example (macOS)" */ = { isa = XCConfigurationList; buildConfigurations = ( - 1C48199E20D034E300CB6F31 /* Debug */, - 1C48199F20D034E300CB6F31 /* Release */, + 4C4E4300258ADD2B009AF14F /* Debug */, + 4C4E4301258ADD2B009AF14F /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; - rootObject = 1C48198320D034E200CB6F31 /* Project object */; + rootObject = 4C4E42DC258ADD29009AF14F /* Project object */; } diff --git a/Example/Example.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Example/Example.xcodeproj/project.xcworkspace/contents.xcworkspacedata index 6d2a51b..919434a 100644 --- a/Example/Example.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ b/Example/Example.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -2,6 +2,6 @@ + location = "self:"> diff --git a/Example/Example.xcodeproj/xcshareddata/xcschemes/Example.xcscheme b/Example/Example.xcodeproj/xcshareddata/xcschemes/Example.xcscheme deleted file mode 100644 index 40090c9..0000000 --- a/Example/Example.xcodeproj/xcshareddata/xcschemes/Example.xcscheme +++ /dev/null @@ -1,91 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Example/Example/AppDelegate.swift b/Example/Example/AppDelegate.swift deleted file mode 100644 index 3efb9b8..0000000 --- a/Example/Example/AppDelegate.swift +++ /dev/null @@ -1,25 +0,0 @@ -// Atom -// -// Copyright (c) 2019 Alaska Airlines -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -import UIKit - -@UIApplicationMain -class AppDelegate: UIResponder, UIApplicationDelegate { - - var window: UIWindow? - - func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { true } -} diff --git a/Example/Example/Controllers/RESTViewController.swift b/Example/Example/Controllers/RESTViewController.swift deleted file mode 100644 index e3ab4be..0000000 --- a/Example/Example/Controllers/RESTViewController.swift +++ /dev/null @@ -1,58 +0,0 @@ -// Atom -// -// Copyright (c) 2019 Alaska Airlines -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -import Atom -import UIKit - -internal class RESTViewController: UIViewController { - - // MARK: Outlets - - @IBOutlet internal weak var button: UIButton! - @IBOutlet internal weak var label: UILabel! - - override func viewDidAppear(_ animated: Bool) { - super.viewDidAppear(animated) - animateSubviews() - } - - // MARK: Actions - - @IBAction internal func refreshTapped(_ sender: Any) { - typealias Endpoint = Joke.Endpoint - - // Start a new request. - atom.load(Endpoint.random).execute(expecting: Joke.self) { [weak self] result in - switch result { - case .failure(let error): - debugPrint(error) - case .success(let joke): - self?.label.text = joke.joke - } - } - } -} - -// MARK: Animations - -private extension RESTViewController { - private func animateSubviews() { - UIView.animate(withDuration: 0.8) { - self.button.alpha = 1.0 - self.label.alpha = 1.0 - } - } -} diff --git a/Example/Example/Views/Assets.xcassets/AppIcon.appiconset/Contents.json b/Example/Example/Views/Assets.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index d8db8d6..0000000 --- a/Example/Example/Views/Assets.xcassets/AppIcon.appiconset/Contents.json +++ /dev/null @@ -1,98 +0,0 @@ -{ - "images" : [ - { - "idiom" : "iphone", - "size" : "20x20", - "scale" : "2x" - }, - { - "idiom" : "iphone", - "size" : "20x20", - "scale" : "3x" - }, - { - "idiom" : "iphone", - "size" : "29x29", - "scale" : "2x" - }, - { - "idiom" : "iphone", - "size" : "29x29", - "scale" : "3x" - }, - { - "idiom" : "iphone", - "size" : "40x40", - "scale" : "2x" - }, - { - "idiom" : "iphone", - "size" : "40x40", - "scale" : "3x" - }, - { - "idiom" : "iphone", - "size" : "60x60", - "scale" : "2x" - }, - { - "idiom" : "iphone", - "size" : "60x60", - "scale" : "3x" - }, - { - "idiom" : "ipad", - "size" : "20x20", - "scale" : "1x" - }, - { - "idiom" : "ipad", - "size" : "20x20", - "scale" : "2x" - }, - { - "idiom" : "ipad", - "size" : "29x29", - "scale" : "1x" - }, - { - "idiom" : "ipad", - "size" : "29x29", - "scale" : "2x" - }, - { - "idiom" : "ipad", - "size" : "40x40", - "scale" : "1x" - }, - { - "idiom" : "ipad", - "size" : "40x40", - "scale" : "2x" - }, - { - "idiom" : "ipad", - "size" : "76x76", - "scale" : "1x" - }, - { - "idiom" : "ipad", - "size" : "76x76", - "scale" : "2x" - }, - { - "idiom" : "ipad", - "size" : "83.5x83.5", - "scale" : "2x" - }, - { - "idiom" : "ios-marketing", - "size" : "1024x1024", - "scale" : "1x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/Example/Example/Views/Assets.xcassets/Contents.json b/Example/Example/Views/Assets.xcassets/Contents.json deleted file mode 100644 index da4a164..0000000 --- a/Example/Example/Views/Assets.xcassets/Contents.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/Example/Example/Views/Assets.xcassets/alaska-airlines-logo.imageset/Contents.json b/Example/Example/Views/Assets.xcassets/alaska-airlines-logo.imageset/Contents.json deleted file mode 100644 index 3cab88e..0000000 --- a/Example/Example/Views/Assets.xcassets/alaska-airlines-logo.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "filename" : "alaska-airlines-logo@2x.png", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/Example/Example/Views/Assets.xcassets/alaska-airlines-logo.imageset/alaska-airlines-logo@2x.png b/Example/Example/Views/Assets.xcassets/alaska-airlines-logo.imageset/alaska-airlines-logo@2x.png deleted file mode 100644 index e4c61bb7d73f900cf04da99e72f35c7045c8d022..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 60881 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 XQHhI zpylw7m+G_N8PYR=(7dLM2e}^N=3*(t>_4mUA{WPo9lvdX8KWN)5#)-#s15lRoxTP3 zDtc>`aH!^Yih>&819->%G904wgMsWt_`R<|{eidS3uD_Lr5g!cW%0Lh3_+|%nIG+6 zt6mrjG0p!Pk#X>$7c~25Rt{G>!FLkPCI)$+;clGye;^Rs0PzkIBQeJ zP$C6DD7NAZ8~@T`Pzku+eQnu5AS;@L%&mE?u-SxCJI@?7vOyu=gu3$&e0Mgz@oN5}m|r$bKe z6gKiF+Ks;xVT;?{(j+r-C_1bV4yAxxC2?)Q@`zNzyfslQQAZ24O6(Ve0~CTYebO6K z6BfT9Bw*4J65$uOOML6{fpr{wSbmM4J44nV69BK1jR2yBEC}X@X~rRv zfR0KpIydM68FD{N&C8+3#!An0EYt)uI4J%GPB5@4hU=->`p^TDd%?toK+7xtiujEv z>0=KCb?&qT{q2|x3T-H5j0ji;YsaUjclMh>eUoO+HGyb+7IqJ5JWU_iC=f<(A#ISu zlOF%WnIgvoNkJZz*6}*ejcOALTL;*eFNJ%?4Wn*9CF7GB+4MUIMvQ_pfDsqv?ig>t z8tSPZSofzaA_K3#m~iwe8GN}E(+;ltBIkD@uL_^f#QSbs49^wOv{ zl_I-CT-HKGoJ>HnR%DRJklyT|TVKP{L7ocZZ9&CUl#wSrCe?GhSi`4jwWX=!*z@;?5l9YE zy;3gyK5vye`TosmW?UV(4!Lf0niK{l0J8*E7^jVksKO^UYD5=m$ex8&)(hI7Qqzc; z!FH9hyx~!|bLfzmq&fYI5-$){Aa6N%R z!y5l^?0mH>CwM)*XMDb~;L3@&sm!2e5YtT_xIm6$R3xg41~%A>yyJ0rNdFufSiB&y z+f^f~`8KjI(g+nXxwCUkkoJ-Cmk^=U4bwW*r}&g-v>o`P17xTy16 z0zu~uckwfme~$fZbeQi!g6?Ly@5SD#)-+D-ZEfH75a13aVlga6mwu5FMD#XEb|uQL z3~=PX=M~+vJ#3oMTP!1kJ?ll0`_m7iqp&C8PfC8?ll*rOGqqOzBo1BdBNEF0jO*)- z`~#_1>|FX0ssJz1@rFDS_9iF?cz#uQjLm+rVNhjWFcaNJTnqvUP2(Xs5>nA!PIhW> zA_+22n9)D_L5VKI?Q!8NsTk729^OLUSHCnjBRe$LOC1PQ-&s2fq+W$DP9_x+V@$TU zN8B&4I%UY_SqVqT2Wn2!)=tVi>TX&cbBsyko&A0UE|IPmm!U`FGs;%K|Bwx4#|``a zZ0kayxAYbej!uv-G&)45G|VbllSPIFKQiG7q|S$Q4SFHhNHf)p3JIfy=&oba%XSt? z4@5Rvx+jy;cL|K%`yZ@9ts{88{n8*xt+(Wkt#1E^i|ZVafa6Qzr)mg8DANzq|M6*c zaODg)9|Cq4DVUm5AnGH+Pz9UU_c$LUktG3Creu^G=ETE-V2eNc&IP^k_wrJ_yzVJ{ zgd<{-M!2ibS$R;9CHF7d#Em{aI2Pg_29bV@gqMhP^&9bvc$Zv{zH!k(iMZAs;G^S0 zPj8iH%RH^X6nYT!xx9yqD3XxRq!kz;9bftbfZO4jDg?D#gGsHyZDor8SE+%0pspO) zS1{e}BUOn9&o2wEhRPUXD%%Dlk!)qu!Bx}jtt>^JiGGXR-&tS9f{b<33;B@M$T$Z1 z3a>@}3HSJ?!xjV3Owrc=_X{p02)0XpG|87ZDYfaB7UNG^t%2DS<6SohC4dkDR5)0J z)`1Tn14gf8D_q%sWe)nn|Ki3>UlX!%Px}R%4X#wBn4sWf4G_6Ex$P#-JKT9(Cl>zc zykaP=-2tu0tPTE_Nl%&3W_eP-`$+Q_YA(=b%puK z@cGBsy?tSU@bIjTw!RMWj6yK4UPQDEClEee%FL7>m}s8_98-G-oo_aMccwO8C(V1v2_-Hk0kEKdQrma|@z zKL>mMtWcAF+iEHb@;{4JxSf(2!sPyOyT!u?UWRn*s+)@ssZrerUxbS9@AKi-#2PCX zS7)NUJAJ38fBjI&?v^}Kpa+1HAS901#?Pv{`aT3xu0n#HxL%bo`}BbqwGNk2Lt>HK zh!B^3wh0s|t6k!)k89>{--qLW&wnmG$BfDLqw10*;XOOjSY*Fcbr_o|o9mWsftfBz z6sXC1;@BTOK0XG3%C07;#mIe{L%;jOBeWsxTkII#$h*qh+l7^D0(~nST>5ySti(w| z>%GECsS`d&)pVYQ<>Yy@x`}|uZgnOo;KXo0<*?rK!(iJRV3Yyrr0dFGhRVH$`;Z8F z%%Ui_mg_;Tbvo5R%qTGY$lXBgbZze_;do@RhX_UlEP96yTyzo+VLBMJksp!vKS%Kq z@{mhUd+wy68c!kQIFXzqW30lWo5}`WOAc-p?qOv^v2o%emh28~<3B)yJ0TTv!QLsF zZ4L7tL>w(Q*!p3iKrIo|^!o$is?AZ6!!Fr}%IT%it8GD@ubwNZoV2W2S=`?;bZ|Jb267?PS2Dm*$d38wauQXdXO9l~J4%7r4K?TLP!c zsHxc~xzgG|y(00l#o@lmDjOq91nj_%AXLf>HxC6wIF}#AlJ`=9I?vrtJ=end4Dh=~ zzBpE>-UoxkMhaV@>(KR0lq)QE^s^J{Tm4W>1CPmRRIQzPICQ%Xp%?4_AaYL6&1w5vL#ag2w$2@f&SMu zSgEYJ9i2*L?7UPM^C_|sEO2zZqRrs%1nRJjicG%I6?0;I-gX({Q@wRbKee7(t4;6$es5FS?e$oB*dEfIlUPmvsDOc1l&U3o-Ha8SG(dR~bo&L?_@mTG@#(^y6IW9U-yd7(rmpp(P z;D!7g4$-f%%oXN$hb~Gt*cbv1<VZje}tqTlo7uR*Gch{F#p@_$K2OLIAiBbyY76ikI>}`O;08Q+1V}s|HOPNq}fXr_>M^RmIbeENGc<1 zff4In{~YD{j#vT+4)P@OWue4-CyoT+o0W^Nl>(s;%o)Jf{QGaWV?mE`z&ZV<`~H26nbf)H`P5c*lg2Ts14?& zBa$Y!uWjYNVw6m2x{G3OWqYR<_ISyP4_ahshjpY)5lR@1Hc2@H^r(x)Xto-a34C?? z=#^vgqH|cxhf^2G`D{advfuAJX7o*9pBIBG=uV=qAqc#S3otoDsGs|ZSFBH4>_P@Y zov+16!D$A+>qRNJh^G)Z4E00v%Cx!K4~EGXwL(8BIx&h1W|zDv4Es zbGvIS41;rD#=i!PKgt7%FA93^<`L+gk;{<_z4crY{xalp369vr5}cw;iBS+tOI5}0 z=ZN&HkS%f#oqb`GFUX(!r?qiqu}Zq@hR@a&L*|AdO;Bqr$;tU9Dat^!gb8x-^Yd$q z9tHxrDHaHXTrZ12<{WyS~LQz8NCwTik6= zIl1-Qcl8T#kYoHpP`k?XRUK7VI@23RCIv$K2V^bzq>9F0AV6>lcf#Ry7?#!3mo)15 z5|GIU_MKmxJZoN$9ax^g>-10tpUI%_$4p2OlJLFPY|rm+tW=dZdiAtFsO2v#@G)P@ ztiI5;aQt}@GnD}#>^lI;rj9CPv7lVA2mRO6uahb7zU;d61hG(N#z&2K?!pWEe~|E) z?AIw)*Ms+&dh*yW=yEGtd_Hd&;y0GlM@+-5v=gp>BINyA{0#!WpHvFCD+;3t z>WN;l?iLf})-SBIwX*iV?36|cAe8%1Iln16R=(;rSC+7N)M0U4&C+ErSO1)ka^k|q zxa>ZkoWhx!2gKNg)(&Oj`ur;`)Be0aANoRRtE<05sP$(TFh<8k3kdpSqdb(ge|H`N z4D`UQf%gudS!{5`byHumXC22uCo}6$$f(p@~alE$g-c zXwQ6H7mVYG(`ClmEXoUSi#d6WyVC#MqLN%zc%W#+NtCO63xOM(^7W&sD|}FA)>spY zGvfbTja+<9+@xh-$7jW~~M|3TkV zen;E~eOw0ytP0w17rmIUJJ^4HjaIIuGtfrMt?`I7J_TA5)j z8(Pg5JF!gp>~sbx(+T@jEY)$FEfz;cYc(A$N!GH<%UprKe3!bS_(q8O=dbASQwOwt zK>XK*{Yj31_vZ&l|Hcn=hQ1uWO}=aY#|8bS%6&@dn%}+8``&MrHi_pR{hmFT?|OX! zN73C2vbdLZT;gZKj(36I81gbud!)}DlNY!4nCb!!e@iPwn$4>1dPNJD5!V0GB8K0SGEi)s35v_s}5Us_0?O&Fbw2yu>PEy}yU8Tg`w zi1_5YFiUXM75a?D&s-J>m&N(5wD%8H{A*4Cv?lOyfli{o?TFNa=M&V{ZYa8dAa5I0 zg-HJ#PmSycY=~}yIoM8FpP%3P66=&BaD*Cgnq9@prx#ipJA4PAsVZq&Y>qykIMfk9 zEk&g`zYEAf00W~Xm6Z_HfOc^3hv;k!VqW+lg3A@>oC|I%=j0_`(lt<&2xf<1y=mC? z0BO*VBHqKgO!_s3Y2=F>iT&Tm+f7onp$HiVqG2`teR~x3`}^KQ;^^aocq-80)<38; z-*1j0qTu%Fv~=leSAmxrdu;Pceq}hN8Rh>;yfu7!)1TfZmAYl>ev|>9d`QvNeNeh{wMfB)H-0 z|NQxr7?hCZ^h{dHbi;c2waJhEOjBj|<*6kOM@j+yjf)h@^c$T1x+s)^3XY_PSsFF_ zx!r8;$sO)jLIU5pw10xo!&yZ!T#Ox=JX{z|{DVp;k zeW8secT>6vQI5IR5bN%_M)%5I3QLAJ1jh>Ui`tfdC1XebPV zCjQ&)DbE?Z9*32lMf$Op@5=?xcSFodSXl>Jw|REKoW-|txj0!E&ie1O;ZVecGAvc=g+`N~qwtt*#Ptg9Y7vdj6ktEyH0tP1InVCgH$bzI30(weUf*y(*%{g|L~Yoe z&9(gmtz#nWy!*M{X7aoFzN{h7{v`<(q6`qFG|lVww7P<*m^={K#c_*6%TTLT@d`U@ zr`Py5^+*));<<1wp3jf?`T7bluyviQ#}}Ei!8ej>XgG*9Q-CQ8PNoYF=1z_+-kTT~ zb&Ri;k7}O1HQxe3NZiG@tJ;^%o;y>T>LBs-eHZBMahxKYv4s$>MxVM?I&+u(IBS0) z4jiMioH)3@kyHKrhw?gmzjY!wv%RmN(3mceNv9Rb5D=7)%k%J)WjLZ`Yf;(L&TvLn z3Re8yY_hAnGX_P#DN^S9%C3f%?i`dJJ(mUy_L1P0A+95|QhTBeM~-005PsSE&iZ<% zOHTI<0a%>{rrgO~?t{*0)5uHNy72dHAM<~{x#FP&qx3%#T<^|d3{}0|kK?R~zIyBr zV&splAlam;NwQ!E7goOdicgr!`*_yIF5=Ba5o-tYZ|zo24Aja>?C&Ttg&lV~em<%C zJ~YCb*TjO=uD;Xq7z>r7qL+P3PhWdn{2mqg#ksVP^)lrtH{r^4?0VzdD|HvsTYPenavmZ)Ef3`#<-KSbHGtBVJ`ab6hz)vbijRB_MevS{6tydPH*=c|JAlcoiC>MN{Z%<)O_mh z7WeHGPf{fS@5jaCdhSG`I}|BtU|@ zySwYaAi;vWYY6V{awqROC-=Pf7u;FBX6+Aq*X~_iT~%FO{Zz#J{^=s_tV{noj_#3c z)E)AB@?gOQ+H@3cfkQ9*wn2=$4E{O-r*J0)S$>&brZ_|eY6Wkwqz4t@Qo9V;Xo7A7>QVF%31U({`4sVB!)~uC3 zhR6xR?kP`nx5xQs{E1c4v-xwm`=)q25ZV&+koI%t9oKU9e$|j60P$#VVLre z*-!I3DjNrmYOaq>zBU>s0c)Pws@s5)%PH4ut{;is^xnIiyPvc*A}7?A*4VMOa7_t zGJgjbvxau(-Zph!d-t6AwnvO#LDZp1{LIextns0Uw6eGr$Dh*OWXzFWpL<#CIRx1G z_!+EVGcx28vfHv|}kdEr9SRZOA408qfYAyDZK!;iWx-ehH>j>e$HO%2@XVOvBCEhR$EC*Hb)&8cCV%!}*>#CaWxJ>#Za^S>(da}+rgH;(vp6!zn z%i0vgh{8fZOHE^xy8d+$wz0AgPR7oA! zb)7IVj29G#PfOSz-B)udJodIeODWkXL0NS<=H&mO4V{k=}~$UkS*1k z71|Nu3fFuor&5Ls9jL8uP1WH%8fu^)nMdd}?#S^0nfqALVBFC~Vu4-Nvp#)dh2i6& zTyxN-0(E-usT0{~cP;@*b{(vHJbm9W@|%`IQn3PIc){stAzw%!!n}uA8pd;8kBz?h z)hI^Mhm|U@3LM$1o;C+0VEnlQK#LY4VrFJT-{^T+3C2iZ4F4pa?~`aYfLPno(v>AT zFtF$!Qp{DFrhTX1D*dwEqB}VOVN)p1; zkBtPG3tt}O!7#r|36&ng3h!@7l>^VlOpc6I`5h2R)*$K zz#S(e@R>z5`s~lNBo*C`I>8VD?W01efrtd=eWqj*^59KGO98&ooqpFEKg+O6M*75o zCu84^z7#id__Gc-VeI&}UA{8ID;DdH4-V0a4U-ux#|)Ofca;){A5z<=3_>;@g@uXd z2DKdZZ&!}SgiUHE>IV(09+{D-m~J6xcioeX1xDA@f8ZM{pD~Y2(NmRV4fpQYJnnGg zSO@j1{pULq-K(^7tJEqkVKKVB+C;Y znQfIHqbyYS63zrZ@FYVMD2p3p+3})dZV7u=s9B9%L}%yowuH48tBRmQ-=lV>8>_wz zw~~$wq5!!f1hz}{RxLjdPKB-G#bJ55GHlaOv1L6&v488M{6M;P!(SUK^;nCU2hN+% z#k22OSlCUT3t*sE!9==rPnt^tmx8VCg&EmpY;E&!d-E55YCprqkJnHo`i^g*J&2yM zFj(S#h8L@L*^{>ck*#w)Auqv_92;cjXW!HjvNK7t+@rR@-%ws=p6JnUiQ@ys_9de( zgf=INeC!$S!B2xmT+tg`Cl-OsKzxwwMP0A_<<#lWN`EX-KqBa!5ge(NfiSAJd!|i- zbca(|I(M#JeR*_-Oj;I~jL!W5e$1DUyshLV|7eD^xmCn7EzHKqST?=@b|w)Kdc>TQ zx!WxpSl8l6;%>@G?|2&Y?xVRvt8S()1D?6{R`0tx?rB(<7TAcA{Smv}z+MYS_9t<2 zO3&OThAaapQ6Yd&}D7c?TZVDz%(6C~=H+qbylXvntKH%(%mx z#gxtS6D!>&JJu#aFS=3L1Fs{)I>QG4$~+nF;@wu`%z%l}C-v6p#OCXVKIDg(1L#P? zr#KC!)`8pyJU5ldNV@eqBqfiqJzO4M#R^ky*b5B1oh?mcSx5#ZN{G}-)7N6q?2DYY zaiWbqfz>p*WRVzt563U7qd$FTL>+NE&pC4^SmYes+s-dotLj8QeglKSWJ;g!Axe-6 zg3Ztxe^fzlhTRk+tX#}Y;jniuPEPi9Cj!3P=E8CeOy%~+I&Y)b;v7dmC?qb52olk& zFv2*|q-C}5EogJrZjv;$<{PxbY5AC+6Qte<{BrLRZ>=89)6~usg7BS-%TrX1@K)Lf z%k{$1Pf>L^=${4zl=UZ++>I#`$l`tZ`txVx`q}e<$z_nqO~;H4pa#5I!@i%W9Vl?3 zir0LXP95mTN;lU2S%1Yf$r#rWD}N%NVeEu|sQCrrr*;vkUnq)Y6PG%3O|pd9e&sT^ zv5a`mp_eZtv1>(q-T;N))o|Z(UqN2oBdPt29~Y{vjeQvPxU9~`NwgNR@LuUPYha{g zImH$K>})FjA~c?&=STJ$HnH`2EJdUmW@@Ok;9FL`Jff_8zWx?C=;Lep*tizjyDSo1 z5=Lf)zTkk43(XmiJ;~0Ak1>>g1oVK$*#g#<1Tosm`jW46# zd~Y*E72U`}UBwtp8*c5a<59L3O5D@?ZuvC#z8 zm+Q5b%E8Z=3)NmztcsWx%N{R8l0mvTx88DZx4YruxGUi|i_x!#1-pq&-VLr+?X<&J zgsgQonh!y#si}P^I0Zmp3XY)z*RAX&mrlSl+I#_|38Q}H&z7Q0nKJh`C(aL0V z@WkUMd{u~_*d!>n7QR*E`etUHSb6=n%1rGXtfyBr%oFewCe`{u@F`k_p+6dXq7G}9 z1!?PH*m*V63{$aOm+l~Q`fJajv{K?YDJ}c~--?ZmrNqg;o8?b%*s~-i77eF**P`!J zb&idQK@^e2xP!~@X$6%`;x>#j$FL6TI5G)M1-(lIYhLec(5$nWVOj`v@7nR>! z$$}#fsAjwS*d<|0zL}}r3mv_A2xg8wnKs06uz^d@2EGQ-JS3F8yZzMM^P(TUR%-S3;K~}o{x#3v9i$nbw;b;Km$;B`vhBBqvE>k_ zw})JYc&{?5vg8@Q)H$p}MYi?WMNfot++{TP>1dU)1f?@KM?hB)U4C1_$J5o( zBEG1qxL#N-XY}RmsmbM(z6Ls(sE9q{(j7c6L5s6lc5Ye5?z|SCyRXl;{pXKZ--qQ9 zo)_O%MC^0yWhCoeo%OQmEk_5l;kA$OsMdn?=7rhZKBz@JX3kGBT9LH zr-KNZBRr8`!|x6JkcHD~zqHqSI9plR=2Mh{uQtJ@#F2E=4xSG;k96<-B8$cv|tt2#;^ut9mlP4V{5k zh0R6Y1yywn9;1HA%QKDOQt~pX&puU(GmjfuT5BKjQh)CMZ1dxdeh05)zAOWLu>FcH zE~bJW3+apCH;K*lY)GoJrt$RjgqHH*EzoSz zUj*{E$J)d-pxFLi3<6wG-iGQe!nnw$f=EbtTkBk3pKC($aK8nR z?(ZX~+Bp!}yEqUzxj4OWa&X$Ju6NyXs;Dkb=Ifw>1YFiomVY>iby7N)n*luY@$o?^ z2)GfRtKgqm@qEU)U0(7b3JVL%K)aP=gNhodxc>`u}KU~tQCpv!uuSH)}TBH<*f%#!5 zfCZKR1yNN)JEAj_{`uW{4b_tV!KLu=5vEex_jG-rr8B>hcckv*R4#w3(e>Etw?L4p zwl3cj;v6-R;iH5aDhgjTILzy|nT4VA5?-qpce(Y!-Yga(>k0my_akv;ooiv*ah(Vg zy_UGmrpV(;eeqiY2uX##?QE#W%Iz>p%ow=DUmsxKLSy`p0lx?h$@}aZ#r+ z)RiOj&=w}gB3vy!%v#$=peJ6dT((2Z+iKc7n7)rStDkS7rjPfAAkBVc@;r}DvMF#A zKkia#qf$oZGpH3RU}?n1iWl(QoXYU113JrPglM&owmRM=_F!QSFKbnXL77DVI71@- z3!l5z>EaRt-DUJyoOX7mB&Nq!!^80CsF9|r#cPNAN~?6zy}eo|{SL2s*NSOgUS7+@ zVJ=aP`EL>}<-b<<1UgBwlY75bSC6xuCiI#WrqN!?hlS};OKuAZ|e3A zNMF3?b)!5nazJ_sA7qss{$85sgG{=#n{Yh_>sq5-2TIHq^*652X;3w|Ic@Gm(ee+hI9XudtEOJk8@srz6rjsd&*?9 zu>A%_Z?tu8jMl6f#Poxu%1>pAJx*4h^qHv<#4UMxhD zLT(Q`4zJx5JjIti-Q>W*+Dgl+Qm5ft=T?5LOD!M#4M7YZIYxZQ3L(vMmq%~nk#6Kp z5{2Z}*H#pTvxudZ!P9e8RvL&dJN?hsMSRqNoMHzl&5n;UZ(1=FyhN3iud&QjZmWa% z*Wr6sdc|AFzNbI3ONh{n$PH-_^PVn0Zk*bI`Nm3#-iY(ceR;}&p=l%?b|$w`3X4q` zBIevEfmlZMFgI-m+ct$7u)4U5eH9dcI9ioVCqWC=7^n6NI2nEl#SdqPk%XQmQ?1!{vBgwV7k(ew_dOa)2Db1*>BvM zaC&y&O14aRq}G~{qf1Lq$@(znkSihAo$h{rTCeb>2P@12%Wiwb96zR}Gk49PH!kK8 zL>T1BYk*93#*yS>xVRKj_X1xO05{rf&b{}96!lD+^^XtxS@5|0yEQ^8N)Vrog{$58 z$cTNrQ~8HT(cq2l@g3ik^KJ@kL|*chy4B2WR^jUvUoD|DnMF7bptuVhMK92EXwED+ z8tzWXB*t=JPP~ma!7eCK3t;@19BwxchcxGF>``=H=+KBdErJQ^!cQwQ(K{~q0fh;1 zlCLMr=BFRxm^m$%tDz-XLbgkLgpZn)rkUbn?UlK2me*9LUzaAY@-zJMVAU&gGHpif z#Wmzxv^!sVYA>e|zTPCL|1kcrth`sbJ|L)@PrRMHa}ZZgOU*VqIM|4Id1RGyB#hz% z_}xO@8h$)Vt6oD=B=YJx%uc(5973+QN6}h$Uy{HP+~_fV;kWsSqju^Jg89o8h3Y(? zvrcjJX!zBM?s&gH-ZWQoBjF|>h>jBy!nq$(rzg6BhxNmXRKLF$@5QnGoJ0dp{_VnV zb%KnQ%V@I3#^{~Zi9XF>`}^&G^})yI9LMsb@*poL^?8TsvJrU7NYuA6>g1u|D#fCt zJg~cNYoaShSp^#u%K)YCI*F$i8+l1)g1dTwZj&3CI3{d8B{#@GV6BU9>xol3&w;Rq zU%S2(xK9oM{%(f;h*e#=p8Z9|58@027AUjLGcnDK<%MP8OV!|7wWhn}8A-t+{m+~> z(qJ z^ak%$X-OKhO4Om9jrDe ziq|Kmlk16;RU@=Pnt`d1cj|m3FQadwoX;^!D#d|#VBrC4P!Nva`mHuXday22kD9Xap6eqUcx}`#=Q)L?z(rW99{dCvi1s!|z{2GRN7|ydAxk4G7jG8CLwSLFu#y^o0dr z>&?2_aHWGYQ6p`HQc*)|;G!T*qerNJFi|eE-D>Ny(Pokm(bc@TIDrGN5m-g|2Ut!TINf=9MZvP~SCye#()`z!w#3f8NY&q;8Ahe|ZS# z;I$!OSFi)|kVUe0_CcqUdyOqim&K|@hAlhDuss9oNIphY!^d&4+LMEzdvne3lR=h`0|I z9)BsLL94pfTOpR4ah`EEgVs~?FYpi%h$%(p0c*~oHfCPjvycbt!0x=M%j+VtGa!P@ z^ENbq%$S7E9}Q^oT(Q`>S<5J24KjLsdMtH;`B}#0P!nP)oBIifD6--S6zdRE@{*`z z;BvEpdtZQb=P$N@p8k(9)@FeWg|iS3ZD>$FaD4@^7BzIc3hK={NnVj4#)(`+CXJFOl$-k-Ux2H*Dy^ zHFuqxDup3KvO|A-LEKh_wpD%!N#%?_jPehyzb>qCuQqh|kQ^Is^;tQ&b+pr|B87j{ z9l)~+$d7P+hri56KJ9}Q2VQL4cL8{3E6tS-&eX1(=yGW$?%3**PW?%~s;ko(w-P7#Vt3L+suM0y$ zU=8_ZT#VL?=Y5bMaeDL^4fCw~7%Z+5SPCClHbkMD9WO-U>GDQ1FL#a|$cPEKp$y^* zf}soyL+5Wj;nRai@1tqwY@_l*hq2D};_Hw^ZuipaX1(cP(aN}WuRjSk!1o(!^W}Ok zOme7mN=`Rw{`tOM5je+}v|c;I8M}f6p&3v?VpW6qk1((y`0{zD!9z?xwv#euzT`Wi ztv}IP9ou|4*LW>Ymd?P8t1j}}W~!r3Sfmh+d=TFaO9?H_RP$0dt7Zt%#~ZppS%QVg zB}V)s5r6Y7gU(l>rR7T2|LupGO*<#!Fab`5I{D!ZMRd4YDM8e)emt}6JkCM?Hn$Z# zCyP&0)fbtHtZ$o4=&)&8P3dF*Uv>oGTZ!uBP08V9Ia6`%r>V{7#vrt7lJtr1 zuBaNw?fEI4mq2t`Ehw!iQ{?5gBS|0R%j;(rzMn+4wzyX;2wv$!Sllw?uvdZr7ftr! zFZci0yAYX`k-~yvtOeM$I+knwr~clxTJ3KojP8}`!{eD0zT&?Kx~1UV8A5f!!o0CC z#XnRn=H5*uB_&u|bBHbvyfqz$=LJPK=QSqFwch0MC~2wbx!Q;&H{+lA?;a;SSt)%6YLqxm9iQy|E^Bh<9eh35&TnQ_vaEXu zDbatad-O}n3+@7AlOSkA)90oZ4-K?4X9`HwS;xP!cWZ2tOXHvKv5Ly? zi9y|Dfd`HvlWxpyBo*wIk1C)l#glbKlXFntcB8`j&6)%_;@Nu;2?;$qkm-5C5v6e@ z^VdK90w8=w-Fx_DbqZTp6i)nIDn6R7k(ZB;?+0C@EI$ma^P?vd0m0@e+B+mTUqo>- z;-9?CIr2&xxOH_Y1_n+f@qG-P>PUOo3S(PYA>XO2cePI8nJkUzQyUXTGQ(%*ODM=7 q7uEXjA^wLc|LyAkf4=84>K$a9%hu4wD1Zn6|4E62BR0pkR-u zi(`n#@we0Navo6NX?btuX#Pg4OnB}F<(PPpC0my^+4K70~XDR%35ZrcC%`Mv(5IPW0n1%<9>+zf5hP$7*u|ZcTnR zYj?Ky#>>Z;5*irUB!I-f^}XF;=jZuLdIz_^UU~Cd=bK}R zbGc@7*|Pu0-q6VxU~3V+lxgv_{~DQ|H-)^dTrS^Qzd?h0^Xm*<0sbpS$Cwx{N3F?J z?VBI5?CY~I*2__QGWRBg%n)1Fnwb~{q>lP^&jpd(mk(_*(DiwJ{Xnk5J~P%GJS;JG oa}Qr!uPbT(2;vctZ}y9bn;HA?CARvs1A~mg)78&qol`;+0276a4gdfE diff --git a/Example/Example/Views/Assets.xcassets/rest.imageset/rest@3x.png b/Example/Example/Views/Assets.xcassets/rest.imageset/rest@3x.png deleted file mode 100644 index d7160bd6a63124f572bc114d4fef5ff561b06ef8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 534 zcmeAS@N?(olHy`uVBq!ia0vp^Q6S901|%(3I5Gh#&H|6fVg?39a}Z`Uj+kG?z`%II z)5S5Q;?~={7jq98h_pU@yz0FHld^%6S*H6-jgsb`OM<%`6PdoN>U#(jaA<1XpZLc^ z#Jhz7i2klvxwWrPWwy$0mES5?Eu?-oo_(ft zoO{A{hIrl@>tmbd2>)L?#dp$r747@KR~Jbn)NfyRQC`73)zrY+w$MH8i`i+wh1~egbl0Bgf$;l#=NT)x-c&cflM^X1 z7k?6V-9EEMp?}(F~0Nf`q_X=_Aj{`mOIEXuQj$gcl(0ix!a - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Example/Example/Views/Base.lproj/Main.storyboard b/Example/Example/Views/Base.lproj/Main.storyboard deleted file mode 100644 index 8925341..0000000 --- a/Example/Example/Views/Base.lproj/Main.storyboard +++ /dev/null @@ -1,75 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Framework/Atom/Extensions/Foundation/Bool+Additions.swift b/Example/Shared/App/ExampleApp.swift similarity index 74% rename from Framework/Atom/Extensions/Foundation/Bool+Additions.swift rename to Example/Shared/App/ExampleApp.swift index 713099f..0a2efff 100644 --- a/Framework/Atom/Extensions/Foundation/Bool+Additions.swift +++ b/Example/Shared/App/ExampleApp.swift @@ -14,12 +14,13 @@ // See the License for the specific language governing permissions and // limitations under the License. -import Foundation +import SwiftUI -public extension Bool { - /// Convenience property for returning `true`. - static let on: Bool = true - - /// Convenience property for returning `false`. - static let off: Bool = false +@main +struct ExampleApp: App { + var body: some Scene { + WindowGroup { + ContentView() + } + } } diff --git a/Example/Shared/Assets/Assets.xcassets/AccentColor.colorset/Contents.json b/Example/Shared/Assets/Assets.xcassets/AccentColor.colorset/Contents.json new file mode 100644 index 0000000..eb87897 --- /dev/null +++ b/Example/Shared/Assets/Assets.xcassets/AccentColor.colorset/Contents.json @@ -0,0 +1,11 @@ +{ + "colors" : [ + { + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Example/Shared/Assets/Assets.xcassets/AppIcon.appiconset/Contents.json b/Example/Shared/Assets/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..c136eaf --- /dev/null +++ b/Example/Shared/Assets/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,148 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "20x20" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "20x20" + }, + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "29x29" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "29x29" + }, + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "40x40" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "40x40" + }, + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "60x60" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "60x60" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "20x20" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "20x20" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "29x29" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "29x29" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "40x40" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "40x40" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "76x76" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "76x76" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "83.5x83.5" + }, + { + "idiom" : "ios-marketing", + "scale" : "1x", + "size" : "1024x1024" + }, + { + "idiom" : "mac", + "scale" : "1x", + "size" : "16x16" + }, + { + "idiom" : "mac", + "scale" : "2x", + "size" : "16x16" + }, + { + "idiom" : "mac", + "scale" : "1x", + "size" : "32x32" + }, + { + "idiom" : "mac", + "scale" : "2x", + "size" : "32x32" + }, + { + "idiom" : "mac", + "scale" : "1x", + "size" : "128x128" + }, + { + "idiom" : "mac", + "scale" : "2x", + "size" : "128x128" + }, + { + "idiom" : "mac", + "scale" : "1x", + "size" : "256x256" + }, + { + "idiom" : "mac", + "scale" : "2x", + "size" : "256x256" + }, + { + "idiom" : "mac", + "scale" : "1x", + "size" : "512x512" + }, + { + "idiom" : "mac", + "scale" : "2x", + "size" : "512x512" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Example/Shared/Assets/Assets.xcassets/Contents.json b/Example/Shared/Assets/Assets.xcassets/Contents.json new file mode 100644 index 0000000..73c0059 --- /dev/null +++ b/Example/Shared/Assets/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Example/Example/Extensions/Endpoints/Joke+Endpoint.swift b/Example/Shared/Endpoints/Joke+Endpoint.swift similarity index 72% rename from Example/Example/Extensions/Endpoints/Joke+Endpoint.swift rename to Example/Shared/Endpoints/Joke+Endpoint.swift index f4c1d91..6a9936f 100644 --- a/Example/Example/Extensions/Endpoints/Joke+Endpoint.swift +++ b/Example/Shared/Endpoints/Joke+Endpoint.swift @@ -1,6 +1,6 @@ // Atom // -// Copyright (c) 2019 Alaska Airlines +// Copyright (c) 2020 Alaska Airlines // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -17,17 +17,17 @@ import Atom import Foundation -internal extension Joke { +extension Joke { enum Endpoint: Requestable { /// Get a random, single, Chuck Norris joke. case random - internal func baseURL() throws -> Atom.BaseURL { - try Atom.BaseURL(host: "api.icndb.com") + func baseURL() throws -> BaseURL { + try BaseURL(host: "api.icndb.com") } - internal func path() throws -> Atom.URLPath { - try Atom.URLPath("/jokes/random") + func path() throws -> URLPath { + try URLPath("/jokes/random") } } } diff --git a/Example/Shared/Extensions/Color+Additions.swift b/Example/Shared/Extensions/Color+Additions.swift new file mode 100644 index 0000000..ca28a5e --- /dev/null +++ b/Example/Shared/Extensions/Color+Additions.swift @@ -0,0 +1,21 @@ +// Atom +// +// Copyright (c) 2020 Alaska Airlines +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import SwiftUI + +extension Color { + static let midnight = Color(#colorLiteral(red: 0.003921568627, green: 0.2588235294, blue: 0.4156862745, alpha: 1)) +} diff --git a/Example/Example/Global/Constants.swift b/Example/Shared/Global/Constants.swift similarity index 81% rename from Example/Example/Global/Constants.swift rename to Example/Shared/Global/Constants.swift index 25069eb..83fb2d1 100644 --- a/Example/Example/Global/Constants.swift +++ b/Example/Shared/Global/Constants.swift @@ -1,6 +1,6 @@ // Atom // -// Copyright (c) 2019 Alaska Airlines +// Copyright (c) 2020 Alaska Airlines // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -18,10 +18,10 @@ import Atom import Foundation /// Global instance of Atom networking library. -internal let atom: Atom = { - let configuration = Atom.ServiceConfiguration(multipathServiceType: .handover) +let atom: Atom = { + let configuration = ServiceConfiguration(multipathServiceType: .handover) let atom = Atom(serviceConfiguration: configuration) - atom.log = .on + atom.log = true return atom }() diff --git a/Example/Example/Models/Joke.swift b/Example/Shared/Models/Joke.swift similarity index 83% rename from Example/Example/Models/Joke.swift rename to Example/Shared/Models/Joke.swift index af0b9e8..caa0a22 100644 --- a/Example/Example/Models/Joke.swift +++ b/Example/Shared/Models/Joke.swift @@ -1,6 +1,6 @@ // Atom // -// Copyright (c) 2019 Alaska Airlines +// Copyright (c) 2020 Alaska Airlines // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -17,18 +17,18 @@ import Atom import Foundation -internal struct Joke { +struct Joke { /// The id of the joke. - internal let id: Int + let id: Int /// The joke itself, text. - internal let joke: String + let joke: String /// The server response indicating success or a failure. - internal let response: Joke.Response + let response: Joke.Response /// List of possible server responses. - internal enum Response: String, Decodable { + enum Response: String, Decodable { /// Indicates success of an API call. case success @@ -37,6 +37,14 @@ internal struct Joke { } } +extension Joke { + static let `default` = Joke( + id: 101, + joke: "If Chuck Norris writes code with bugs, the bugs fix themselves.", + response: .success + ) +} + // MARK: Model extension Joke: Model { @@ -53,7 +61,7 @@ extension Joke: Model { } /// Decodable conformance. - internal init(from decoder: Decoder) throws { + init(from decoder: Decoder) throws { let values = try decoder.container(keyedBy: CodingKeys.self) self.response = try values.decode(Response.self, forKey: .response) diff --git a/Example/Shared/Views/ContentView.swift b/Example/Shared/Views/ContentView.swift new file mode 100644 index 0000000..8b3f9ec --- /dev/null +++ b/Example/Shared/Views/ContentView.swift @@ -0,0 +1,63 @@ +// Atom +// +// Copyright (c) 2020 Alaska Airlines +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import Atom +import SwiftUI + +struct ContentView: View { + /// View model for this view. + @ObservedObject var model = ContentViewModel() + + var body: some View { + content + .edgesIgnoringSafeArea(.all) + .onAppear { model.random() } + } + + // MARK: Content + + private var content: some View { + ZStack { + // Set background view. + Color.midnight + + // Basic layout. + VStack { + Spacer() + Text(model.joke.joke) + .foregroundColor(.white) + .padding() + + Spacer() + + Button(action: { model.random() }) { + Text("REFRESH") + .fontWeight(.bold) + .foregroundColor(.yellow) + } + .padding(.bottom, 40.0) + } + } + } +} + +// MARK: PreviewProvider + +struct ContentView_Previews: PreviewProvider { + static var previews: some View { + ContentView() + } +} diff --git a/Example/Shared/Views/ContentViewModel.swift b/Example/Shared/Views/ContentViewModel.swift new file mode 100644 index 0000000..8f0c938 --- /dev/null +++ b/Example/Shared/Views/ContentViewModel.swift @@ -0,0 +1,33 @@ +// Atom +// +// Copyright (c) 2020 Alaska Airlines +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import Atom +import Combine +import Foundation + +final class ContentViewModel: ObservableObject { + /// The joke to display on successful fetch. + @Published var joke: Joke = .default + + /// Fetches a random joke. + func random() { + atom + .enqueue(Joke.Endpoint.random) + .resume(expecting: Joke.self) + .replaceError(with: .default) + .assign(to: &$joke) + } +} diff --git a/Example/Example/Info.plist b/Example/iOS/Info.plist similarity index 79% rename from Example/Example/Info.plist rename to Example/iOS/Info.plist index 59bd10c..efc211a 100644 --- a/Example/Example/Info.plist +++ b/Example/iOS/Info.plist @@ -13,28 +13,26 @@ CFBundleName $(PRODUCT_NAME) CFBundlePackageType - APPL + $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString 1.0 CFBundleVersion 1 LSRequiresIPhoneOS - NSAppTransportSecurity + UIApplicationSceneManifest - NSAllowsArbitraryLoads + UIApplicationSupportsMultipleScenes - UILaunchStoryboardName - LaunchScreen - UIMainStoryboardFile - Main + UIApplicationSupportsIndirectInputEvents + + UILaunchScreen + UIRequiredDeviceCapabilities armv7 - UIStatusBarStyle - UIStatusBarStyleLightContent UISupportedInterfaceOrientations UIInterfaceOrientationPortrait @@ -48,7 +46,5 @@ UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight - UIViewControllerBasedStatusBarAppearance - diff --git a/Example/macOS/Info.plist b/Example/macOS/Info.plist new file mode 100644 index 0000000..bacbc56 --- /dev/null +++ b/Example/macOS/Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIconFile + + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + $(PRODUCT_BUNDLE_PACKAGE_TYPE) + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + LSMinimumSystemVersion + $(MACOSX_DEPLOYMENT_TARGET) + + diff --git a/Example/Example/Example.entitlements b/Example/macOS/macOS.entitlements similarity index 58% rename from Example/Example/Example.entitlements rename to Example/macOS/macOS.entitlements index 01298bf..f2ef3ae 100644 --- a/Example/Example/Example.entitlements +++ b/Example/macOS/macOS.entitlements @@ -2,7 +2,9 @@ - com.apple.developer.networking.multipath - + com.apple.security.app-sandbox + + com.apple.security.files.user-selected.read-only + diff --git a/Framework/Atom.xcodeproj/project.pbxproj b/Framework/Atom.xcodeproj/project.pbxproj index b2c3dda..4c4db5f 100644 --- a/Framework/Atom.xcodeproj/project.pbxproj +++ b/Framework/Atom.xcodeproj/project.pbxproj @@ -12,27 +12,26 @@ 1C48197920D0349600CB6F31 /* Atom.h in Headers */ = {isa = PBXBuildFile; fileRef = 1C48196B20D0349600CB6F31 /* Atom.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1C4819B720D039D700CB6F31 /* Atom.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C4819B620D039D700CB6F31 /* Atom.swift */; }; 1C67F23120DB10CA00403C93 /* URLResponse+Additions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C67F23020DB10CA00403C93 /* URLResponse+Additions.swift */; }; - 1CC3280C20D813E70099644D /* Atom+ServiceConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1CC3280B20D813E70099644D /* Atom+ServiceConfiguration.swift */; }; + 1CC3280C20D813E70099644D /* ServiceConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1CC3280B20D813E70099644D /* ServiceConfiguration.swift */; }; 1CC3281120D8158E0099644D /* BaseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1CC3281020D8158E0099644D /* BaseCase.swift */; }; 1CC3281C20D83E9E0099644D /* ServiceConfigurationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1CC3281B20D83E9E0099644D /* ServiceConfigurationTests.swift */; }; - 1CC3281E20D844610099644D /* Atom+Service.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1CC3281D20D844610099644D /* Atom+Service.swift */; }; + 1CC3281E20D844610099644D /* Service.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1CC3281D20D844610099644D /* Service.swift */; }; 1CC3284120D85F3A0099644D /* ResultTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1CC3284020D85F3A0099644D /* ResultTests.swift */; }; 1CC3284420D863540099644D /* NSRegularExpression+Additions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1CC3284320D863540099644D /* NSRegularExpression+Additions.swift */; }; 1CC3284620D864210099644D /* String+Additions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1CC3284520D864210099644D /* String+Additions.swift */; }; 1CC3284820D865E00099644D /* StringTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1CC3284720D865E00099644D /* StringTests.swift */; }; - 1CC3284B20D8685C0099644D /* Atom+QueryItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1CC3284A20D8685C0099644D /* Atom+QueryItem.swift */; }; - 1CC3284D20D868BE0099644D /* QueryItemTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1CC3284C20D868BE0099644D /* QueryItemTests.swift */; }; - 1CC3284F20D86F3D0099644D /* Atom+HeaderItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1CC3284E20D86F3D0099644D /* Atom+HeaderItem.swift */; }; + 1CC3284B20D8685C0099644D /* HeaderItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1CC3284A20D8685C0099644D /* HeaderItem.swift */; }; + 1CC3284F20D86F3D0099644D /* RequestableItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1CC3284E20D86F3D0099644D /* RequestableItem.swift */; }; 1CC3285120D86FD40099644D /* HeaderItemTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1CC3285020D86FD40099644D /* HeaderItemTests.swift */; }; - 1CC3285320D875490099644D /* Atom+Method.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1CC3285220D875490099644D /* Atom+Method.swift */; }; + 1CC3285320D875490099644D /* Method.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1CC3285220D875490099644D /* Method.swift */; }; 1CC3285620D8774E0099644D /* StringConvertible.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1CC3285520D8774E0099644D /* StringConvertible.swift */; }; 1CC3285920D878480099644D /* MethodTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1CC3285820D878480099644D /* MethodTests.swift */; }; 1CC3285B20D8BB360099644D /* AtomError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1CC3285A20D8BB360099644D /* AtomError.swift */; }; 1CC3285D20D8BBE80099644D /* Array+Additions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1CC3285C20D8BBE80099644D /* Array+Additions.swift */; }; 1CC3285F20D8BD730099644D /* ArrayTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1CC3285E20D8BD730099644D /* ArrayTests.swift */; }; - 1CC3286120D9614C0099644D /* Atom+URLPath.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1CC3286020D9614C0099644D /* Atom+URLPath.swift */; }; + 1CC3286120D9614C0099644D /* URLPath.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1CC3286020D9614C0099644D /* URLPath.swift */; }; 1CC3286320D962A10099644D /* URLPathTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1CC3286220D962A10099644D /* URLPathTests.swift */; }; - 1CC3286520D965F60099644D /* Atom+BaseURL.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1CC3286420D965F60099644D /* Atom+BaseURL.swift */; }; + 1CC3286520D965F60099644D /* BaseURL.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1CC3286420D965F60099644D /* BaseURL.swift */; }; 1CC3286720D967BF0099644D /* BaseURLTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1CC3286620D967BF0099644D /* BaseURLTests.swift */; }; 1CC3286920D969400099644D /* BaseURLSchemeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1CC3286820D969400099644D /* BaseURLSchemeTests.swift */; }; 1CC3286C20D96A730099644D /* Requestable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1CC3286B20D96A730099644D /* Requestable.swift */; }; @@ -41,42 +40,45 @@ 1CC3287B20D9990F0099644D /* URLRequest+Additions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1CC3287A20D9990F0099644D /* URLRequest+Additions.swift */; }; 1CC3287D20D99D3F0099644D /* URLComponents+Additions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1CC3287C20D99D3F0099644D /* URLComponents+Additions.swift */; }; 1CC3287F20D9A3700099644D /* URLRequestTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1CC3287E20D9A3700099644D /* URLRequestTests.swift */; }; - 1CC3288E20DA010C0099644D /* Atom+Endpoint.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1CC3288D20DA010C0099644D /* Atom+Endpoint.swift */; }; + 1CC3288E20DA010C0099644D /* Endpoint.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1CC3288D20DA010C0099644D /* Endpoint.swift */; }; 1CFD5ACC2135F8870075EED1 /* AtomError+StringConvertible.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1CFD5ACB2135F8870075EED1 /* AtomError+StringConvertible.swift */; }; 1CFD5ACE213641710075EED1 /* Optional+Additions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1CFD5ACD213641710075EED1 /* Optional+Additions.swift */; }; - 4C31600D221DE0BE00E853F5 /* Atom+ServiceConfiguration+Timeout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C31600C221DE0BE00E853F5 /* Atom+ServiceConfiguration+Timeout.swift */; }; - 4C316011221E0C8300E853F5 /* Atom+Response.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C316010221E0C8300E853F5 /* Atom+Response.swift */; }; + 4C31600D221DE0BE00E853F5 /* ServiceConfiguration+Timeout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C31600C221DE0BE00E853F5 /* ServiceConfiguration+Timeout.swift */; }; + 4C316011221E0C8300E853F5 /* AtomResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C316010221E0C8300E853F5 /* AtomResponse.swift */; }; 4C316017221E0CFC00E853F5 /* Model.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C316016221E0CFC00E853F5 /* Model.swift */; }; - 4C31601B221E0DA500E853F5 /* ResponseTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C31601A221E0DA500E853F5 /* ResponseTests.swift */; }; + 4C31601B221E0DA500E853F5 /* AtomResponseTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C31601A221E0DA500E853F5 /* AtomResponseTests.swift */; }; 4C316027221F0E5400E853F5 /* Data+Additions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C316026221F0E5400E853F5 /* Data+Additions.swift */; }; 4C316029221F130500E853F5 /* AtomError+Additions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C316028221F130500E853F5 /* AtomError+Additions.swift */; }; - 4C3345A52370D23C0075ED92 /* Atom+BaseURL+Scheme.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C3345A42370D23C0075ED92 /* Atom+BaseURL+Scheme.swift */; }; - 4C3345A72371E6480075ED92 /* Atom+ClientCredential.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C3345A62371E6480075ED92 /* Atom+ClientCredential.swift */; }; - 4C3345A92371E6A90075ED92 /* Atom+ClientCredential+GrantType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C3345A82371E6A90075ED92 /* Atom+ClientCredential+GrantType.swift */; }; + 4C3345A52370D23C0075ED92 /* BaseURL+Scheme.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C3345A42370D23C0075ED92 /* BaseURL+Scheme.swift */; }; + 4C3345A72371E6480075ED92 /* ClientCredential.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C3345A62371E6480075ED92 /* ClientCredential.swift */; }; + 4C3345A92371E6A90075ED92 /* ClientCredential+GrantType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C3345A82371E6A90075ED92 /* ClientCredential+GrantType.swift */; }; 4C3345AB2371E8B20075ED92 /* ClientCredentialConvertible.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C3345AA2371E8B20075ED92 /* ClientCredentialConvertible.swift */; }; - 4C3345AD2371E9BF0075ED92 /* Atom+BasicCredential.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C3345AC2371E9BF0075ED92 /* Atom+BasicCredential.swift */; }; + 4C3345AD2371E9BF0075ED92 /* BasicCredential.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C3345AC2371E9BF0075ED92 /* BasicCredential.swift */; }; 4C3345AF2371EAEC0075ED92 /* BasicCredentialConvertible.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C3345AE2371EAEC0075ED92 /* BasicCredentialConvertible.swift */; }; - 4C3345B12371EEE70075ED92 /* Atom+TokenCredential.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C3345B02371EEE70075ED92 /* Atom+TokenCredential.swift */; }; + 4C3345B12371EEE70075ED92 /* TokenCredential.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C3345B02371EEE70075ED92 /* TokenCredential.swift */; }; 4C3345B32371F10A0075ED92 /* TokenCredentialWritable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C3345B22371F10A0075ED92 /* TokenCredentialWritable.swift */; }; - 4C3345B92371F9550075ED92 /* Atom+TokenCredential+Decodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C3345B82371F9550075ED92 /* Atom+TokenCredential+Decodable.swift */; }; - 4C3345BB237218670075ED92 /* Atom+Retryable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C3345BA237218670075ED92 /* Atom+Retryable.swift */; }; + 4C3345B92371F9550075ED92 /* TokenCredential+Decodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C3345B82371F9550075ED92 /* TokenCredential+Decodable.swift */; }; + 4C3345BB237218670075ED92 /* Retryable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C3345BA237218670075ED92 /* Retryable.swift */; }; + 4C46EF88258C63CB00A34726 /* AtomResponse+Additions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C46EF87258C63CB00A34726 /* AtomResponse+Additions.swift */; }; + 4C4E42BA258AC0F2009AF14F /* AuthenticationManagerDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C4E42B9258AC0F2009AF14F /* AuthenticationManagerDelegate.swift */; }; + 4C4E42C4258AC311009AF14F /* Service+Combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C4E42C3258AC311009AF14F /* Service+Combine.swift */; }; + 4C4E42D2258AD50E009AF14F /* QueryItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C4E42D1258AD50E009AF14F /* QueryItem.swift */; }; 4C6A0D3923DBC28300A64975 /* Atom+Notifications.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C6A0D3823DBC28300A64975 /* Atom+Notifications.swift */; }; 4C6A0D3C23DBC3C100A64975 /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C6A0D3B23DBC3C100A64975 /* Constants.swift */; }; - 4C7B85F023721F7800FA85FC /* Atom+AuthenticationMethod.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C7B85EF23721F7800FA85FC /* Atom+AuthenticationMethod.swift */; }; - 4C7B85F2237223C800FA85FC /* Atom+BasicCredential+Additions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C7B85F1237223C800FA85FC /* Atom+BasicCredential+Additions.swift */; }; + 4C7B85F023721F7800FA85FC /* AuthenticationMethod.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C7B85EF23721F7800FA85FC /* AuthenticationMethod.swift */; }; + 4C7B85F2237223C800FA85FC /* BasicCredential+Additions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C7B85F1237223C800FA85FC /* BasicCredential+Additions.swift */; }; 4C7B85F4237226EC00FA85FC /* Date+Additions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C7B85F3237226EC00FA85FC /* Date+Additions.swift */; }; - 4C7B85F6237227B900FA85FC /* Atom+TokenCredential+Additions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C7B85F5237227B900FA85FC /* Atom+TokenCredential+Additions.swift */; }; - 4C7B85FA237229F300FA85FC /* Atom+AuthenticationManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C7B85F9237229F300FA85FC /* Atom+AuthenticationManager.swift */; }; - 4C7B85FC23722C5C00FA85FC /* Atom+AuthenticationManager+Status.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C7B85FB23722C5C00FA85FC /* Atom+AuthenticationManager+Status.swift */; }; - 4C7B86002372361F00FA85FC /* Atom+AuthorizationEndpoint.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C7B85FF2372361F00FA85FC /* Atom+AuthorizationEndpoint.swift */; }; - 4C7B86022373353B00FA85FC /* Atom+Retryable+Additions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C7B86012373353B00FA85FC /* Atom+Retryable+Additions.swift */; }; + 4C7B85F6237227B900FA85FC /* TokenCredential+Additions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C7B85F5237227B900FA85FC /* TokenCredential+Additions.swift */; }; + 4C7B85FA237229F300FA85FC /* AuthenticationManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C7B85F9237229F300FA85FC /* AuthenticationManager.swift */; }; + 4C7B85FC23722C5C00FA85FC /* AuthenticationManager+Status.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C7B85FB23722C5C00FA85FC /* AuthenticationManager+Status.swift */; }; + 4C7B86002372361F00FA85FC /* AuthorizationEndpoint.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C7B85FF2372361F00FA85FC /* AuthorizationEndpoint.swift */; }; + 4C7B86022373353B00FA85FC /* Retryable+Additions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C7B86012373353B00FA85FC /* Retryable+Additions.swift */; }; 4C92FD19224E6A6100D16767 /* Result+Additions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C92FD18224E6A6100D16767 /* Result+Additions.swift */; }; - 4C96B7142360B6CB0021EDB8 /* Atom+Response+Additions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C96B7132360B6CB0021EDB8 /* Atom+Response+Additions.swift */; }; - 4C973FD3237372EC006B2736 /* Atom+AuthenticationMethod+Additions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C973FD2237372EC006B2736 /* Atom+AuthenticationMethod+Additions.swift */; }; + 4C96B7142360B6CB0021EDB8 /* Response+Additions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C96B7132360B6CB0021EDB8 /* Response+Additions.swift */; }; + 4C973FD3237372EC006B2736 /* AuthenticationMethod+Additions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C973FD2237372EC006B2736 /* AuthenticationMethod+Additions.swift */; }; 4CA6564D242189E000E35D9F /* URLSessionTaskMetrics+Additions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CA6564C242189E000E35D9F /* URLSessionTaskMetrics+Additions.swift */; }; - 4CAB5A69242012E900E4FB97 /* Atom+Interceptor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CAB5A68242012E900E4FB97 /* Atom+Interceptor.swift */; }; + 4CAB5A69242012E900E4FB97 /* Interceptor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CAB5A68242012E900E4FB97 /* Interceptor.swift */; }; 4CAB5A6C2420217E00E4FB97 /* OSLog+Additions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CAB5A6B2420217E00E4FB97 /* OSLog+Additions.swift */; }; - 4CAB5A6E2420223800E4FB97 /* Bool+Additions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CAB5A6D2420223800E4FB97 /* Bool+Additions.swift */; }; 4CAB5A702420226400E4FB97 /* URLSessionTask+Additions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CAB5A6F2420226400E4FB97 /* URLSessionTask+Additions.swift */; }; /* End PBXBuildFile section */ @@ -99,27 +101,26 @@ 1C48197820D0349600CB6F31 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 1C4819B620D039D700CB6F31 /* Atom.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Atom.swift; sourceTree = ""; }; 1C67F23020DB10CA00403C93 /* URLResponse+Additions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "URLResponse+Additions.swift"; sourceTree = ""; }; - 1CC3280B20D813E70099644D /* Atom+ServiceConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Atom+ServiceConfiguration.swift"; sourceTree = ""; }; + 1CC3280B20D813E70099644D /* ServiceConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServiceConfiguration.swift; sourceTree = ""; }; 1CC3281020D8158E0099644D /* BaseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseCase.swift; sourceTree = ""; }; 1CC3281B20D83E9E0099644D /* ServiceConfigurationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServiceConfigurationTests.swift; sourceTree = ""; }; - 1CC3281D20D844610099644D /* Atom+Service.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Atom+Service.swift"; sourceTree = ""; }; + 1CC3281D20D844610099644D /* Service.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Service.swift; sourceTree = ""; }; 1CC3284020D85F3A0099644D /* ResultTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResultTests.swift; sourceTree = ""; }; 1CC3284320D863540099644D /* NSRegularExpression+Additions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSRegularExpression+Additions.swift"; sourceTree = ""; }; 1CC3284520D864210099644D /* String+Additions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+Additions.swift"; sourceTree = ""; }; 1CC3284720D865E00099644D /* StringTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StringTests.swift; sourceTree = ""; }; - 1CC3284A20D8685C0099644D /* Atom+QueryItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Atom+QueryItem.swift"; sourceTree = ""; }; - 1CC3284C20D868BE0099644D /* QueryItemTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QueryItemTests.swift; sourceTree = ""; }; - 1CC3284E20D86F3D0099644D /* Atom+HeaderItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Atom+HeaderItem.swift"; sourceTree = ""; }; + 1CC3284A20D8685C0099644D /* HeaderItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeaderItem.swift; sourceTree = ""; }; + 1CC3284E20D86F3D0099644D /* RequestableItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RequestableItem.swift; sourceTree = ""; }; 1CC3285020D86FD40099644D /* HeaderItemTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeaderItemTests.swift; sourceTree = ""; }; - 1CC3285220D875490099644D /* Atom+Method.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Atom+Method.swift"; sourceTree = ""; }; + 1CC3285220D875490099644D /* Method.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Method.swift; sourceTree = ""; }; 1CC3285520D8774E0099644D /* StringConvertible.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StringConvertible.swift; sourceTree = ""; }; 1CC3285820D878480099644D /* MethodTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MethodTests.swift; sourceTree = ""; }; 1CC3285A20D8BB360099644D /* AtomError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AtomError.swift; sourceTree = ""; }; 1CC3285C20D8BBE80099644D /* Array+Additions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Array+Additions.swift"; sourceTree = ""; }; 1CC3285E20D8BD730099644D /* ArrayTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArrayTests.swift; sourceTree = ""; }; - 1CC3286020D9614C0099644D /* Atom+URLPath.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Atom+URLPath.swift"; sourceTree = ""; }; + 1CC3286020D9614C0099644D /* URLPath.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = URLPath.swift; sourceTree = ""; }; 1CC3286220D962A10099644D /* URLPathTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = URLPathTests.swift; sourceTree = ""; }; - 1CC3286420D965F60099644D /* Atom+BaseURL.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Atom+BaseURL.swift"; sourceTree = ""; }; + 1CC3286420D965F60099644D /* BaseURL.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseURL.swift; sourceTree = ""; }; 1CC3286620D967BF0099644D /* BaseURLTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseURLTests.swift; sourceTree = ""; }; 1CC3286820D969400099644D /* BaseURLSchemeTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseURLSchemeTests.swift; sourceTree = ""; }; 1CC3286B20D96A730099644D /* Requestable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Requestable.swift; sourceTree = ""; }; @@ -128,42 +129,45 @@ 1CC3287A20D9990F0099644D /* URLRequest+Additions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "URLRequest+Additions.swift"; sourceTree = ""; }; 1CC3287C20D99D3F0099644D /* URLComponents+Additions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "URLComponents+Additions.swift"; sourceTree = ""; }; 1CC3287E20D9A3700099644D /* URLRequestTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = URLRequestTests.swift; sourceTree = ""; }; - 1CC3288D20DA010C0099644D /* Atom+Endpoint.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Atom+Endpoint.swift"; sourceTree = ""; }; + 1CC3288D20DA010C0099644D /* Endpoint.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Endpoint.swift; sourceTree = ""; }; 1CFD5ACB2135F8870075EED1 /* AtomError+StringConvertible.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AtomError+StringConvertible.swift"; sourceTree = ""; }; 1CFD5ACD213641710075EED1 /* Optional+Additions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Optional+Additions.swift"; sourceTree = ""; }; - 4C31600C221DE0BE00E853F5 /* Atom+ServiceConfiguration+Timeout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Atom+ServiceConfiguration+Timeout.swift"; sourceTree = ""; }; - 4C316010221E0C8300E853F5 /* Atom+Response.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Atom+Response.swift"; sourceTree = ""; }; + 4C31600C221DE0BE00E853F5 /* ServiceConfiguration+Timeout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ServiceConfiguration+Timeout.swift"; sourceTree = ""; }; + 4C316010221E0C8300E853F5 /* AtomResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AtomResponse.swift; sourceTree = ""; }; 4C316016221E0CFC00E853F5 /* Model.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Model.swift; sourceTree = ""; }; - 4C31601A221E0DA500E853F5 /* ResponseTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ResponseTests.swift; sourceTree = ""; }; + 4C31601A221E0DA500E853F5 /* AtomResponseTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AtomResponseTests.swift; sourceTree = ""; }; 4C316026221F0E5400E853F5 /* Data+Additions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Data+Additions.swift"; sourceTree = ""; }; 4C316028221F130500E853F5 /* AtomError+Additions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AtomError+Additions.swift"; sourceTree = ""; }; - 4C3345A42370D23C0075ED92 /* Atom+BaseURL+Scheme.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Atom+BaseURL+Scheme.swift"; sourceTree = ""; }; - 4C3345A62371E6480075ED92 /* Atom+ClientCredential.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Atom+ClientCredential.swift"; sourceTree = ""; }; - 4C3345A82371E6A90075ED92 /* Atom+ClientCredential+GrantType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Atom+ClientCredential+GrantType.swift"; sourceTree = ""; }; + 4C3345A42370D23C0075ED92 /* BaseURL+Scheme.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "BaseURL+Scheme.swift"; sourceTree = ""; }; + 4C3345A62371E6480075ED92 /* ClientCredential.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClientCredential.swift; sourceTree = ""; }; + 4C3345A82371E6A90075ED92 /* ClientCredential+GrantType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ClientCredential+GrantType.swift"; sourceTree = ""; }; 4C3345AA2371E8B20075ED92 /* ClientCredentialConvertible.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClientCredentialConvertible.swift; sourceTree = ""; }; - 4C3345AC2371E9BF0075ED92 /* Atom+BasicCredential.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Atom+BasicCredential.swift"; sourceTree = ""; }; + 4C3345AC2371E9BF0075ED92 /* BasicCredential.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BasicCredential.swift; sourceTree = ""; }; 4C3345AE2371EAEC0075ED92 /* BasicCredentialConvertible.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BasicCredentialConvertible.swift; sourceTree = ""; }; - 4C3345B02371EEE70075ED92 /* Atom+TokenCredential.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Atom+TokenCredential.swift"; sourceTree = ""; }; + 4C3345B02371EEE70075ED92 /* TokenCredential.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TokenCredential.swift; sourceTree = ""; }; 4C3345B22371F10A0075ED92 /* TokenCredentialWritable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TokenCredentialWritable.swift; sourceTree = ""; }; - 4C3345B82371F9550075ED92 /* Atom+TokenCredential+Decodable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Atom+TokenCredential+Decodable.swift"; sourceTree = ""; }; - 4C3345BA237218670075ED92 /* Atom+Retryable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Atom+Retryable.swift"; sourceTree = ""; }; + 4C3345B82371F9550075ED92 /* TokenCredential+Decodable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TokenCredential+Decodable.swift"; sourceTree = ""; }; + 4C3345BA237218670075ED92 /* Retryable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Retryable.swift; sourceTree = ""; }; + 4C46EF87258C63CB00A34726 /* AtomResponse+Additions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AtomResponse+Additions.swift"; sourceTree = ""; }; + 4C4E42B9258AC0F2009AF14F /* AuthenticationManagerDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthenticationManagerDelegate.swift; sourceTree = ""; }; + 4C4E42C3258AC311009AF14F /* Service+Combine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Service+Combine.swift"; sourceTree = ""; }; + 4C4E42D1258AD50E009AF14F /* QueryItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QueryItem.swift; sourceTree = ""; }; 4C6A0D3823DBC28300A64975 /* Atom+Notifications.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Atom+Notifications.swift"; sourceTree = ""; }; 4C6A0D3B23DBC3C100A64975 /* Constants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Constants.swift; sourceTree = ""; }; - 4C7B85EF23721F7800FA85FC /* Atom+AuthenticationMethod.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Atom+AuthenticationMethod.swift"; sourceTree = ""; }; - 4C7B85F1237223C800FA85FC /* Atom+BasicCredential+Additions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Atom+BasicCredential+Additions.swift"; sourceTree = ""; }; + 4C7B85EF23721F7800FA85FC /* AuthenticationMethod.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthenticationMethod.swift; sourceTree = ""; }; + 4C7B85F1237223C800FA85FC /* BasicCredential+Additions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "BasicCredential+Additions.swift"; sourceTree = ""; }; 4C7B85F3237226EC00FA85FC /* Date+Additions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Date+Additions.swift"; sourceTree = ""; }; - 4C7B85F5237227B900FA85FC /* Atom+TokenCredential+Additions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Atom+TokenCredential+Additions.swift"; sourceTree = ""; }; - 4C7B85F9237229F300FA85FC /* Atom+AuthenticationManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Atom+AuthenticationManager.swift"; sourceTree = ""; }; - 4C7B85FB23722C5C00FA85FC /* Atom+AuthenticationManager+Status.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Atom+AuthenticationManager+Status.swift"; sourceTree = ""; }; - 4C7B85FF2372361F00FA85FC /* Atom+AuthorizationEndpoint.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Atom+AuthorizationEndpoint.swift"; sourceTree = ""; }; - 4C7B86012373353B00FA85FC /* Atom+Retryable+Additions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Atom+Retryable+Additions.swift"; sourceTree = ""; }; + 4C7B85F5237227B900FA85FC /* TokenCredential+Additions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TokenCredential+Additions.swift"; sourceTree = ""; }; + 4C7B85F9237229F300FA85FC /* AuthenticationManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthenticationManager.swift; sourceTree = ""; }; + 4C7B85FB23722C5C00FA85FC /* AuthenticationManager+Status.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AuthenticationManager+Status.swift"; sourceTree = ""; }; + 4C7B85FF2372361F00FA85FC /* AuthorizationEndpoint.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthorizationEndpoint.swift; sourceTree = ""; }; + 4C7B86012373353B00FA85FC /* Retryable+Additions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Retryable+Additions.swift"; sourceTree = ""; }; 4C92FD18224E6A6100D16767 /* Result+Additions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Result+Additions.swift"; sourceTree = ""; }; - 4C96B7132360B6CB0021EDB8 /* Atom+Response+Additions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Atom+Response+Additions.swift"; sourceTree = ""; }; - 4C973FD2237372EC006B2736 /* Atom+AuthenticationMethod+Additions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Atom+AuthenticationMethod+Additions.swift"; sourceTree = ""; }; + 4C96B7132360B6CB0021EDB8 /* Response+Additions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Response+Additions.swift"; sourceTree = ""; }; + 4C973FD2237372EC006B2736 /* AuthenticationMethod+Additions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AuthenticationMethod+Additions.swift"; sourceTree = ""; }; 4CA6564C242189E000E35D9F /* URLSessionTaskMetrics+Additions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "URLSessionTaskMetrics+Additions.swift"; sourceTree = ""; }; - 4CAB5A68242012E900E4FB97 /* Atom+Interceptor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Atom+Interceptor.swift"; sourceTree = ""; }; + 4CAB5A68242012E900E4FB97 /* Interceptor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Interceptor.swift; sourceTree = ""; }; 4CAB5A6B2420217E00E4FB97 /* OSLog+Additions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "OSLog+Additions.swift"; sourceTree = ""; }; - 4CAB5A6D2420223800E4FB97 /* Bool+Additions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Bool+Additions.swift"; sourceTree = ""; }; 4CAB5A6F2420226400E4FB97 /* URLSessionTask+Additions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "URLSessionTask+Additions.swift"; sourceTree = ""; }; /* End PBXFileReference section */ @@ -217,12 +221,12 @@ isa = PBXGroup; children = ( 1C4819B520D039C600CB6F31 /* Atom */, - 1CC3285420D8773A0099644D /* Common */, 1CC3280920D813AF0099644D /* Extensions */, 4C6A0D3A23DBC3AE00A64975 /* Global */, 4CAB5A67242012D600E4FB97 /* Interceptor */, 4C7B85F7237229D000FA85FC /* Managers */, 1CC3283D20D85A330099644D /* Models */, + 1CC3285720D877700099644D /* Protocols */, 1CC3280A20D813C90099644D /* Service */, 1C4819AC20D0383000CB6F31 /* Supporting Files */, ); @@ -280,9 +284,10 @@ 1CC3280A20D813C90099644D /* Service */ = { isa = PBXGroup; children = ( - 1CC3281D20D844610099644D /* Atom+Service.swift */, - 1CC3280B20D813E70099644D /* Atom+ServiceConfiguration.swift */, - 4C31600C221DE0BE00E853F5 /* Atom+ServiceConfiguration+Timeout.swift */, + 1CC3281D20D844610099644D /* Service.swift */, + 4C4E42C3258AC311009AF14F /* Service+Combine.swift */, + 1CC3280B20D813E70099644D /* ServiceConfiguration.swift */, + 4C31600C221DE0BE00E853F5 /* ServiceConfiguration+Timeout.swift */, ); path = Service; sourceTree = ""; @@ -290,14 +295,13 @@ 1CC3280F20D815420099644D /* Models */ = { isa = PBXGroup; children = ( + 4C31601A221E0DA500E853F5 /* AtomResponseTests.swift */, 1CC3281020D8158E0099644D /* BaseCase.swift */, - 1CC3286620D967BF0099644D /* BaseURLTests.swift */, 1CC3286820D969400099644D /* BaseURLSchemeTests.swift */, + 1CC3286620D967BF0099644D /* BaseURLTests.swift */, 1CC3285020D86FD40099644D /* HeaderItemTests.swift */, 1CC3285820D878480099644D /* MethodTests.swift */, - 1CC3284C20D868BE0099644D /* QueryItemTests.swift */, 1CC3286E20D96FCA0099644D /* RequestableTests.swift */, - 4C31601A221E0DA500E853F5 /* ResponseTests.swift */, 1CC3284020D85F3A0099644D /* ResultTests.swift */, 1CC3281B20D83E9E0099644D /* ServiceConfigurationTests.swift */, 1CC3286220D962A10099644D /* URLPathTests.swift */, @@ -308,27 +312,28 @@ 1CC3283D20D85A330099644D /* Models */ = { isa = PBXGroup; children = ( - 4C7B85EF23721F7800FA85FC /* Atom+AuthenticationMethod.swift */, - 4C973FD2237372EC006B2736 /* Atom+AuthenticationMethod+Additions.swift */, - 4C7B85FF2372361F00FA85FC /* Atom+AuthorizationEndpoint.swift */, - 1CC3286420D965F60099644D /* Atom+BaseURL.swift */, - 4C3345A42370D23C0075ED92 /* Atom+BaseURL+Scheme.swift */, - 4C3345AC2371E9BF0075ED92 /* Atom+BasicCredential.swift */, - 4C7B85F1237223C800FA85FC /* Atom+BasicCredential+Additions.swift */, - 4C3345A62371E6480075ED92 /* Atom+ClientCredential.swift */, - 4C3345A82371E6A90075ED92 /* Atom+ClientCredential+GrantType.swift */, - 1CC3288D20DA010C0099644D /* Atom+Endpoint.swift */, - 1CC3284E20D86F3D0099644D /* Atom+HeaderItem.swift */, - 1CC3285220D875490099644D /* Atom+Method.swift */, - 1CC3284A20D8685C0099644D /* Atom+QueryItem.swift */, - 4C316010221E0C8300E853F5 /* Atom+Response.swift */, - 4C96B7132360B6CB0021EDB8 /* Atom+Response+Additions.swift */, - 4C3345BA237218670075ED92 /* Atom+Retryable.swift */, - 4C7B86012373353B00FA85FC /* Atom+Retryable+Additions.swift */, - 4C3345B02371EEE70075ED92 /* Atom+TokenCredential.swift */, - 4C7B85F5237227B900FA85FC /* Atom+TokenCredential+Additions.swift */, - 4C3345B82371F9550075ED92 /* Atom+TokenCredential+Decodable.swift */, - 1CC3286020D9614C0099644D /* Atom+URLPath.swift */, + 4C316010221E0C8300E853F5 /* AtomResponse.swift */, + 4C46EF87258C63CB00A34726 /* AtomResponse+Additions.swift */, + 4C7B85EF23721F7800FA85FC /* AuthenticationMethod.swift */, + 4C973FD2237372EC006B2736 /* AuthenticationMethod+Additions.swift */, + 4C7B85FF2372361F00FA85FC /* AuthorizationEndpoint.swift */, + 1CC3286420D965F60099644D /* BaseURL.swift */, + 4C3345A42370D23C0075ED92 /* BaseURL+Scheme.swift */, + 4C3345AC2371E9BF0075ED92 /* BasicCredential.swift */, + 4C7B85F1237223C800FA85FC /* BasicCredential+Additions.swift */, + 4C3345A62371E6480075ED92 /* ClientCredential.swift */, + 4C3345A82371E6A90075ED92 /* ClientCredential+GrantType.swift */, + 1CC3288D20DA010C0099644D /* Endpoint.swift */, + 1CC3284A20D8685C0099644D /* HeaderItem.swift */, + 1CC3285220D875490099644D /* Method.swift */, + 4C4E42D1258AD50E009AF14F /* QueryItem.swift */, + 4C96B7132360B6CB0021EDB8 /* Response+Additions.swift */, + 4C3345BA237218670075ED92 /* Retryable.swift */, + 4C7B86012373353B00FA85FC /* Retryable+Additions.swift */, + 4C3345B02371EEE70075ED92 /* TokenCredential.swift */, + 4C7B85F5237227B900FA85FC /* TokenCredential+Additions.swift */, + 4C3345B82371F9550075ED92 /* TokenCredential+Decodable.swift */, + 1CC3286020D9614C0099644D /* URLPath.swift */, ); path = Models; sourceTree = ""; @@ -337,7 +342,6 @@ isa = PBXGroup; children = ( 1CC3285C20D8BBE80099644D /* Array+Additions.swift */, - 4CAB5A6D2420223800E4FB97 /* Bool+Additions.swift */, 4C316026221F0E5400E853F5 /* Data+Additions.swift */, 4C7B85F3237226EC00FA85FC /* Date+Additions.swift */, 1CC3284320D863540099644D /* NSRegularExpression+Additions.swift */, @@ -363,17 +367,10 @@ path = Extensions; sourceTree = ""; }; - 1CC3285420D8773A0099644D /* Common */ = { - isa = PBXGroup; - children = ( - 1CC3285720D877700099644D /* Protocols */, - ); - path = Common; - sourceTree = ""; - }; 1CC3285720D877700099644D /* Protocols */ = { isa = PBXGroup; children = ( + 4C4E42B8258AC0DD009AF14F /* Delegates */, 1CC3286D20D96A7D0099644D /* Convertibles */, 1CC3286A20D96A640099644D /* Types */, ); @@ -385,6 +382,7 @@ children = ( 4C316016221E0CFC00E853F5 /* Model.swift */, 1CC3286B20D96A730099644D /* Requestable.swift */, + 1CC3284E20D86F3D0099644D /* RequestableItem.swift */, 4C3345B22371F10A0075ED92 /* TokenCredentialWritable.swift */, ); path = Types; @@ -417,6 +415,14 @@ path = "Atom Error"; sourceTree = ""; }; + 4C4E42B8258AC0DD009AF14F /* Delegates */ = { + isa = PBXGroup; + children = ( + 4C4E42B9258AC0F2009AF14F /* AuthenticationManagerDelegate.swift */, + ); + path = Delegates; + sourceTree = ""; + }; 4C6A0D3723DBC26200A64975 /* Framework */ = { isa = PBXGroup; children = ( @@ -444,8 +450,8 @@ 4C7B85F8237229E600FA85FC /* Authentication Manager */ = { isa = PBXGroup; children = ( - 4C7B85F9237229F300FA85FC /* Atom+AuthenticationManager.swift */, - 4C7B85FB23722C5C00FA85FC /* Atom+AuthenticationManager+Status.swift */, + 4C7B85F9237229F300FA85FC /* AuthenticationManager.swift */, + 4C7B85FB23722C5C00FA85FC /* AuthenticationManager+Status.swift */, ); path = "Authentication Manager"; sourceTree = ""; @@ -453,7 +459,7 @@ 4CAB5A67242012D600E4FB97 /* Interceptor */ = { isa = PBXGroup; children = ( - 4CAB5A68242012E900E4FB97 /* Atom+Interceptor.swift */, + 4CAB5A68242012E900E4FB97 /* Interceptor.swift */, ); path = Interceptor; sourceTree = ""; @@ -524,7 +530,7 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 1000; - LastUpgradeCheck = 1000; + LastUpgradeCheck = 1220; ORGANIZATIONNAME = "Alaska Airlines, Inc"; TargetAttributes = { 1C48196720D0349600CB6F31 = { @@ -599,60 +605,63 @@ buildActionMask = 2147483647; files = ( 1CC3286C20D96A730099644D /* Requestable.swift in Sources */, - 4C973FD3237372EC006B2736 /* Atom+AuthenticationMethod+Additions.swift in Sources */, + 4C973FD3237372EC006B2736 /* AuthenticationMethod+Additions.swift in Sources */, + 4C4E42BA258AC0F2009AF14F /* AuthenticationManagerDelegate.swift in Sources */, 1CC3287D20D99D3F0099644D /* URLComponents+Additions.swift in Sources */, - 1CC3285320D875490099644D /* Atom+Method.swift in Sources */, + 1CC3285320D875490099644D /* Method.swift in Sources */, 1CC3287320D970560099644D /* Requestable+Implementation.swift in Sources */, - 1CC3281E20D844610099644D /* Atom+Service.swift in Sources */, + 1CC3281E20D844610099644D /* Service.swift in Sources */, 4CAB5A6C2420217E00E4FB97 /* OSLog+Additions.swift in Sources */, 1CC3284420D863540099644D /* NSRegularExpression+Additions.swift in Sources */, - 4C3345A52370D23C0075ED92 /* Atom+BaseURL+Scheme.swift in Sources */, - 1CC3288E20DA010C0099644D /* Atom+Endpoint.swift in Sources */, + 4C3345A52370D23C0075ED92 /* BaseURL+Scheme.swift in Sources */, + 1CC3288E20DA010C0099644D /* Endpoint.swift in Sources */, 4C316029221F130500E853F5 /* AtomError+Additions.swift in Sources */, 4C3345AF2371EAEC0075ED92 /* BasicCredentialConvertible.swift in Sources */, 4C3345B32371F10A0075ED92 /* TokenCredentialWritable.swift in Sources */, - 4C7B85F6237227B900FA85FC /* Atom+TokenCredential+Additions.swift in Sources */, - 4C7B85FA237229F300FA85FC /* Atom+AuthenticationManager.swift in Sources */, - 1CC3286120D9614C0099644D /* Atom+URLPath.swift in Sources */, - 4C7B85FC23722C5C00FA85FC /* Atom+AuthenticationManager+Status.swift in Sources */, + 4C7B85F6237227B900FA85FC /* TokenCredential+Additions.swift in Sources */, + 4C7B85FA237229F300FA85FC /* AuthenticationManager.swift in Sources */, + 1CC3286120D9614C0099644D /* URLPath.swift in Sources */, + 4C4E42C4258AC311009AF14F /* Service+Combine.swift in Sources */, + 4C7B85FC23722C5C00FA85FC /* AuthenticationManager+Status.swift in Sources */, 4CAB5A702420226400E4FB97 /* URLSessionTask+Additions.swift in Sources */, 1CC3284620D864210099644D /* String+Additions.swift in Sources */, - 4C7B86002372361F00FA85FC /* Atom+AuthorizationEndpoint.swift in Sources */, + 4C7B86002372361F00FA85FC /* AuthorizationEndpoint.swift in Sources */, 1C241795216687100032A994 /* RequestableError.swift in Sources */, 1CC3287B20D9990F0099644D /* URLRequest+Additions.swift in Sources */, - 4C316011221E0C8300E853F5 /* Atom+Response.swift in Sources */, + 4C316011221E0C8300E853F5 /* AtomResponse.swift in Sources */, 4C316027221F0E5400E853F5 /* Data+Additions.swift in Sources */, 4C6A0D3923DBC28300A64975 /* Atom+Notifications.swift in Sources */, - 4C7B85F2237223C800FA85FC /* Atom+BasicCredential+Additions.swift in Sources */, + 4C7B85F2237223C800FA85FC /* BasicCredential+Additions.swift in Sources */, 1CC3285620D8774E0099644D /* StringConvertible.swift in Sources */, 4C6A0D3C23DBC3C100A64975 /* Constants.swift in Sources */, - 1CC3280C20D813E70099644D /* Atom+ServiceConfiguration.swift in Sources */, + 1CC3280C20D813E70099644D /* ServiceConfiguration.swift in Sources */, 4C316017221E0CFC00E853F5 /* Model.swift in Sources */, 1CC3285B20D8BB360099644D /* AtomError.swift in Sources */, - 4C3345A92371E6A90075ED92 /* Atom+ClientCredential+GrantType.swift in Sources */, - 4CAB5A6E2420223800E4FB97 /* Bool+Additions.swift in Sources */, - 4C7B86022373353B00FA85FC /* Atom+Retryable+Additions.swift in Sources */, - 4C3345B12371EEE70075ED92 /* Atom+TokenCredential.swift in Sources */, - 4C3345AD2371E9BF0075ED92 /* Atom+BasicCredential.swift in Sources */, + 4C3345A92371E6A90075ED92 /* ClientCredential+GrantType.swift in Sources */, + 4C7B86022373353B00FA85FC /* Retryable+Additions.swift in Sources */, + 4C3345B12371EEE70075ED92 /* TokenCredential.swift in Sources */, + 4C3345AD2371E9BF0075ED92 /* BasicCredential.swift in Sources */, 1CFD5ACE213641710075EED1 /* Optional+Additions.swift in Sources */, - 1CC3284F20D86F3D0099644D /* Atom+HeaderItem.swift in Sources */, - 4C96B7142360B6CB0021EDB8 /* Atom+Response+Additions.swift in Sources */, + 1CC3284F20D86F3D0099644D /* RequestableItem.swift in Sources */, + 4C96B7142360B6CB0021EDB8 /* Response+Additions.swift in Sources */, 4C3345AB2371E8B20075ED92 /* ClientCredentialConvertible.swift in Sources */, 4C92FD19224E6A6100D16767 /* Result+Additions.swift in Sources */, 1C67F23120DB10CA00403C93 /* URLResponse+Additions.swift in Sources */, - 4C31600D221DE0BE00E853F5 /* Atom+ServiceConfiguration+Timeout.swift in Sources */, - 4CAB5A69242012E900E4FB97 /* Atom+Interceptor.swift in Sources */, - 4C3345BB237218670075ED92 /* Atom+Retryable.swift in Sources */, - 1CC3286520D965F60099644D /* Atom+BaseURL.swift in Sources */, - 1CC3284B20D8685C0099644D /* Atom+QueryItem.swift in Sources */, + 4C31600D221DE0BE00E853F5 /* ServiceConfiguration+Timeout.swift in Sources */, + 4CAB5A69242012E900E4FB97 /* Interceptor.swift in Sources */, + 4C3345BB237218670075ED92 /* Retryable.swift in Sources */, + 1CC3286520D965F60099644D /* BaseURL.swift in Sources */, + 1CC3284B20D8685C0099644D /* HeaderItem.swift in Sources */, 4C7B85F4237226EC00FA85FC /* Date+Additions.swift in Sources */, - 4C3345A72371E6480075ED92 /* Atom+ClientCredential.swift in Sources */, + 4C3345A72371E6480075ED92 /* ClientCredential.swift in Sources */, 1CC3285D20D8BBE80099644D /* Array+Additions.swift in Sources */, + 4C46EF88258C63CB00A34726 /* AtomResponse+Additions.swift in Sources */, + 4C4E42D2258AD50E009AF14F /* QueryItem.swift in Sources */, 1C4819B720D039D700CB6F31 /* Atom.swift in Sources */, 1CFD5ACC2135F8870075EED1 /* AtomError+StringConvertible.swift in Sources */, - 4C7B85F023721F7800FA85FC /* Atom+AuthenticationMethod.swift in Sources */, + 4C7B85F023721F7800FA85FC /* AuthenticationMethod.swift in Sources */, 4CA6564D242189E000E35D9F /* URLSessionTaskMetrics+Additions.swift in Sources */, - 4C3345B92371F9550075ED92 /* Atom+TokenCredential+Decodable.swift in Sources */, + 4C3345B92371F9550075ED92 /* TokenCredential+Decodable.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -669,9 +678,8 @@ 1CC3285920D878480099644D /* MethodTests.swift in Sources */, 1CC3281120D8158E0099644D /* BaseCase.swift in Sources */, 1CC3285F20D8BD730099644D /* ArrayTests.swift in Sources */, - 4C31601B221E0DA500E853F5 /* ResponseTests.swift in Sources */, + 4C31601B221E0DA500E853F5 /* AtomResponseTests.swift in Sources */, 1CC3286F20D96FCA0099644D /* RequestableTests.swift in Sources */, - 1CC3284D20D868BE0099644D /* QueryItemTests.swift in Sources */, 1CC3285120D86FD40099644D /* HeaderItemTests.swift in Sources */, 1CC3287F20D9A3700099644D /* URLRequestTests.swift in Sources */, ); @@ -714,6 +722,7 @@ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; @@ -740,7 +749,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -777,6 +786,7 @@ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; @@ -797,7 +807,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SWIFT_COMPILATION_MODE = wholemodule; diff --git a/Framework/Atom.xcodeproj/xcshareddata/xcschemes/Atom.xcscheme b/Framework/Atom.xcodeproj/xcshareddata/xcschemes/Atom.xcscheme index 054c911..0f88b28 100644 --- a/Framework/Atom.xcodeproj/xcshareddata/xcschemes/Atom.xcscheme +++ b/Framework/Atom.xcodeproj/xcshareddata/xcschemes/Atom.xcscheme @@ -1,6 +1,6 @@ + + + + @@ -39,17 +48,6 @@ - - - - - - - - Atom.Service { + /// - Returns: Updated `Service` instance initialized using `ServiceConfiguration`. + func enqueue(_ requestable: Requestable) -> Service { service.update(with: requestable) } } diff --git a/Framework/Atom/Atom/Errors/AtomError.swift b/Framework/Atom/Atom/Errors/AtomError.swift index 0b476ba..56b11f6 100644 --- a/Framework/Atom/Atom/Errors/AtomError.swift +++ b/Framework/Atom/Atom/Errors/AtomError.swift @@ -1,6 +1,6 @@ // Atom // -// Copyright (c) 2019 Alaska Airlines +// Copyright (c) 2020 Alaska Airlines // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -32,8 +32,8 @@ public enum AtomError: Error { /// An optional response `data` will be set for further processing of the `body`. In the /// context of ACE Group, `data` will contain the error message or the model object. /// - /// For more information, see `Atom.Response`. - case response(Atom.Response) + /// For more information, see `AtomResponse`. + case response(AtomResponse) /// URLSession failed with error. case session(Error) diff --git a/Framework/Atom/Atom/Errors/RequestableError.swift b/Framework/Atom/Atom/Errors/RequestableError.swift index 1a28b04..3e67242 100644 --- a/Framework/Atom/Atom/Errors/RequestableError.swift +++ b/Framework/Atom/Atom/Errors/RequestableError.swift @@ -1,6 +1,6 @@ // Atom // -// Copyright (c) 2019 Alaska Airlines +// Copyright (c) 2020 Alaska Airlines // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/Framework/Atom/Common/Protocols/Convertibles/StringConvertible.swift b/Framework/Atom/Common/Protocols/Convertibles/StringConvertible.swift deleted file mode 100644 index 1060113..0000000 --- a/Framework/Atom/Common/Protocols/Convertibles/StringConvertible.swift +++ /dev/null @@ -1,29 +0,0 @@ -// Atom -// -// Copyright (c) 2019 Alaska Airlines -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -import Foundation - -/// The `StringConvertible` protocol declares an interface used for representing conforming type as a string. -/// -/// `StringConvertible` protocol is defined and used despite having similar protocols available -/// in Standard Library (ex: `CustomStringConvertible`). This is intentional due to how these protocols -/// are defined and used. For example, documentation for `CustomStringConvertible` has this suggestion: -/// -/// "Accessing a type’s description property directly or using `CustomStringConvertible` as a generic constraint is discouraged." -internal protocol StringConvertible { - /// Returns conforming type as a **loosely** constructed string representation. - var stringValue: String { get } -} diff --git a/Framework/Atom/Extensions/Atom Error/AtomError+Additions.swift b/Framework/Atom/Extensions/Atom Error/AtomError+Additions.swift index 880e463..d624470 100644 --- a/Framework/Atom/Extensions/Atom Error/AtomError+Additions.swift +++ b/Framework/Atom/Extensions/Atom Error/AtomError+Additions.swift @@ -1,6 +1,6 @@ // Atom // -// Copyright (c) 2019 Alaska Airlines +// Copyright (c) 2020 Alaska Airlines // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/Framework/Atom/Extensions/Atom Error/AtomError+StringConvertible.swift b/Framework/Atom/Extensions/Atom Error/AtomError+StringConvertible.swift index 6d440b0..031b5be 100644 --- a/Framework/Atom/Extensions/Atom Error/AtomError+StringConvertible.swift +++ b/Framework/Atom/Extensions/Atom Error/AtomError+StringConvertible.swift @@ -1,6 +1,6 @@ // Atom // -// Copyright (c) 2019 Alaska Airlines +// Copyright (c) 2020 Alaska Airlines // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/Framework/Atom/Extensions/Foundation/Array+Additions.swift b/Framework/Atom/Extensions/Foundation/Array+Additions.swift index 347c90c..efa1542 100644 --- a/Framework/Atom/Extensions/Foundation/Array+Additions.swift +++ b/Framework/Atom/Extensions/Foundation/Array+Additions.swift @@ -1,6 +1,6 @@ // Atom // -// Copyright (c) 2019 Alaska Airlines +// Copyright (c) 2020 Alaska Airlines // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -21,10 +21,22 @@ import Foundation /// Each element must conform to `Model` protocol. extension Array: Model where Element: Model { } +// MARK: ExpressibleByDictionaryLiteral + +extension Array: ExpressibleByDictionaryLiteral where Element: RequestableItem { + public init(dictionaryLiteral elements: (String, String)...) { + self.init() + + for element in elements { + self.append(.init(name: element.0, value: element.1)) + } + } +} + // MARK: Internal -internal extension Array where Element == Atom.HeaderItem { - /// Returns an array of `Atom.HeaderItem` as a dictionary. +internal extension Array where Element: RequestableItem { + /// Returns an array of `HeaderItem` as a dictionary. var dictionary: [String: String] { return reduce([:]) { var result = $0 diff --git a/Framework/Atom/Extensions/Foundation/Data+Additions.swift b/Framework/Atom/Extensions/Foundation/Data+Additions.swift index 1e8162d..bf8f52b 100644 --- a/Framework/Atom/Extensions/Foundation/Data+Additions.swift +++ b/Framework/Atom/Extensions/Foundation/Data+Additions.swift @@ -1,6 +1,6 @@ // Atom // -// Copyright (c) 2019 Alaska Airlines +// Copyright (c) 2020 Alaska Airlines // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/Framework/Atom/Extensions/Foundation/Date+Additions.swift b/Framework/Atom/Extensions/Foundation/Date+Additions.swift index a5b8d4c..43cdd3c 100644 --- a/Framework/Atom/Extensions/Foundation/Date+Additions.swift +++ b/Framework/Atom/Extensions/Foundation/Date+Additions.swift @@ -1,6 +1,6 @@ // Atom // -// Copyright (c) 2019 Alaska Airlines +// Copyright (c) 2020 Alaska Airlines // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/Framework/Atom/Extensions/Foundation/NSRegularExpression+Additions.swift b/Framework/Atom/Extensions/Foundation/NSRegularExpression+Additions.swift index dfe5fc9..c03895c 100644 --- a/Framework/Atom/Extensions/Foundation/NSRegularExpression+Additions.swift +++ b/Framework/Atom/Extensions/Foundation/NSRegularExpression+Additions.swift @@ -1,6 +1,6 @@ // Atom // -// Copyright (c) 2019 Alaska Airlines +// Copyright (c) 2020 Alaska Airlines // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/Framework/Atom/Extensions/Foundation/Optional+Additions.swift b/Framework/Atom/Extensions/Foundation/Optional+Additions.swift index 395ae9c..e38aced 100644 --- a/Framework/Atom/Extensions/Foundation/Optional+Additions.swift +++ b/Framework/Atom/Extensions/Foundation/Optional+Additions.swift @@ -1,6 +1,6 @@ // Atom // -// Copyright (c) 2019 Alaska Airlines +// Copyright (c) 2020 Alaska Airlines // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -16,7 +16,7 @@ import Foundation -public extension Optional { +internal extension Optional { /// Unwraps an optional value. Terminates the process if the value is `nil`. /// /// - Warning: diff --git a/Framework/Atom/Extensions/Foundation/Result+Additions.swift b/Framework/Atom/Extensions/Foundation/Result+Additions.swift index c3607f8..89b9a6d 100644 --- a/Framework/Atom/Extensions/Foundation/Result+Additions.swift +++ b/Framework/Atom/Extensions/Foundation/Result+Additions.swift @@ -1,6 +1,6 @@ // Atom // -// Copyright (c) 2019 Alaska Airlines +// Copyright (c) 2020 Alaska Airlines // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/Framework/Atom/Extensions/Foundation/String+Additions.swift b/Framework/Atom/Extensions/Foundation/String+Additions.swift index bdf8da8..9f33f60 100644 --- a/Framework/Atom/Extensions/Foundation/String+Additions.swift +++ b/Framework/Atom/Extensions/Foundation/String+Additions.swift @@ -1,6 +1,6 @@ // Atom // -// Copyright (c) 2019 Alaska Airlines +// Copyright (c) 2020 Alaska Airlines // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/Framework/Atom/Extensions/Foundation/URLComponents+Additions.swift b/Framework/Atom/Extensions/Foundation/URLComponents+Additions.swift index 5d31ec4..7e0307f 100644 --- a/Framework/Atom/Extensions/Foundation/URLComponents+Additions.swift +++ b/Framework/Atom/Extensions/Foundation/URLComponents+Additions.swift @@ -1,6 +1,6 @@ // Atom // -// Copyright (c) 2019 Alaska Airlines +// Copyright (c) 2020 Alaska Airlines // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -23,9 +23,9 @@ internal extension URLComponents { /// - baseURLString: The `Requestable` base URL string value. /// - path: The `Requestable` path string value. /// - queryItems: The `Requestable` queryItems. - init?(_ baseURLString: String, path: String, queryItems: [Atom.QueryItem]?) { + init?(_ baseURLString: String, path: String, queryItems: [QueryItem]?) { self.init(string: baseURLString) self.path = path - self.queryItems = queryItems + self.queryItems = queryItems?.compactMap { URLQueryItem(name: $0.name, value: $0.value) } } } diff --git a/Framework/Atom/Extensions/Foundation/URLRequest+Additions.swift b/Framework/Atom/Extensions/Foundation/URLRequest+Additions.swift index 1a27659..05b769e 100644 --- a/Framework/Atom/Extensions/Foundation/URLRequest+Additions.swift +++ b/Framework/Atom/Extensions/Foundation/URLRequest+Additions.swift @@ -1,6 +1,6 @@ // Atom // -// Copyright (c) 2019 Alaska Airlines +// Copyright (c) 2020 Alaska Airlines // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/Framework/Atom/Extensions/Foundation/URLResponse+Additions.swift b/Framework/Atom/Extensions/Foundation/URLResponse+Additions.swift index 8fc1934..6b59360 100644 --- a/Framework/Atom/Extensions/Foundation/URLResponse+Additions.swift +++ b/Framework/Atom/Extensions/Foundation/URLResponse+Additions.swift @@ -1,6 +1,6 @@ // Atom // -// Copyright (c) 2019 Alaska Airlines +// Copyright (c) 2020 Alaska Airlines // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -35,9 +35,9 @@ public extension URLResponse { // MARK: Debug Description -extension URLResponse { +public extension URLResponse { /// Returns a textual representation of this instance, suitable for debugging. - override public var debugDescription: String { + override var debugDescription: String { guard let response = self as? HTTPURLResponse else { return description } return """ diff --git a/Framework/Atom/Extensions/Requestable/Requestable+Implementation.swift b/Framework/Atom/Extensions/Requestable/Requestable+Implementation.swift index 7d87ee7..c542b25 100644 --- a/Framework/Atom/Extensions/Requestable/Requestable+Implementation.swift +++ b/Framework/Atom/Extensions/Requestable/Requestable+Implementation.swift @@ -1,6 +1,6 @@ // Atom // -// Copyright (c) 2019 Alaska Airlines +// Copyright (c) 2020 Alaska Airlines // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -19,17 +19,17 @@ import Foundation /// Default implementation for `Requestable` protocol. public extension Requestable { /// The default value is `nil`. - var headerItems: [Atom.HeaderItem]? { nil } + var headerItems: [HeaderItem]? { nil } /// The default value is `.get`. - var method: Atom.Method { .get } + var method: HTTPMethod { .get } /// The default valus is `nil`. - var queryItems: [Atom.QueryItem]? { nil } + var queryItems: [QueryItem]? { nil } /// The default valus is `false`. var requiresAuthentication: Bool { true } - /// The default valus is `Atom.URLPath.default`. - func path() throws -> Atom.URLPath { Atom.URLPath.default } + /// The default valus is `URLPath.default`. + func path() throws -> URLPath { URLPath.default } } diff --git a/Framework/Atom/Global/Constants.swift b/Framework/Atom/Global/Constants.swift index 47026c6..cb4b8c1 100644 --- a/Framework/Atom/Global/Constants.swift +++ b/Framework/Atom/Global/Constants.swift @@ -21,4 +21,4 @@ internal let center = NotificationCenter.default /// A `Bool` indicating whether or not all service requests should be /// logged to the console. This property is set in `Atom.swift` only. -internal var consoleLog: Bool = .off +internal var consoleLog: Bool = false diff --git a/Framework/Atom/Interceptor/Atom+Interceptor.swift b/Framework/Atom/Interceptor/Interceptor.swift similarity index 67% rename from Framework/Atom/Interceptor/Atom+Interceptor.swift rename to Framework/Atom/Interceptor/Interceptor.swift index 4556911..d2349d1 100644 --- a/Framework/Atom/Interceptor/Atom+Interceptor.swift +++ b/Framework/Atom/Interceptor/Interceptor.swift @@ -17,25 +17,23 @@ import Foundation import os.log -internal extension Atom { - /// An object for handling task-level events & logging for `URLSession` requests. - final class Interceptor: NSObject { - /// The OSLog instance to use - private let log: OSLog - - /// Creates a `Interceptor` instance given the provided parameter(s). - /// - /// - Parameters: - /// - log: The service configuration data used for initializing `Atom.Service` instance. - internal init(for log: OSLog) { - self.log = log - } +/// An object for handling task-level events & logging for `URLSession` requests. +internal final class Interceptor: NSObject { + /// The OSLog instance to use + private let log: OSLog + + /// Creates a `Interceptor` instance given the provided parameter(s). + /// + /// - Parameters: + /// - log: The service configuration data used for initializing `Service` instance. + internal init(for log: OSLog) { + self.log = log } } // MARK: URLSessionTaskDelegate -extension Atom.Interceptor: URLSessionTaskDelegate { +extension Interceptor: URLSessionTaskDelegate { func urlSession(_ session: URLSession, task: URLSessionTask, didFinishCollecting metrics: URLSessionTaskMetrics) { guard consoleLog else { return } diff --git a/Framework/Atom/Managers/Authentication Manager/Atom+AuthenticationManager+Status.swift b/Framework/Atom/Managers/Authentication Manager/AuthenticationManager+Status.swift similarity index 84% rename from Framework/Atom/Managers/Authentication Manager/Atom+AuthenticationManager+Status.swift rename to Framework/Atom/Managers/Authentication Manager/AuthenticationManager+Status.swift index 73d0bf4..90ce02e 100644 --- a/Framework/Atom/Managers/Authentication Manager/Atom+AuthenticationManager+Status.swift +++ b/Framework/Atom/Managers/Authentication Manager/AuthenticationManager+Status.swift @@ -1,6 +1,6 @@ // Atom // -// Copyright (c) 2019 Alaska Airlines +// Copyright (c) 2020 Alaska Airlines // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -16,18 +16,18 @@ import Foundation -internal extension Atom.AuthenticationManager { - /// List of supported status cases by the `Atom.AuthenticationManager`. +internal extension AuthenticationManager { + /// List of supported status cases by the `AuthenticationManager`. enum Status { /// Authorization header was applied successfully. Set in the following scenarios: /// /// * Atom applies basic authorization header on behalf of the client. /// * Atom applies bearer authorization header on behalf of the client - token is not expired. /// * Atom applies bearer authorization header on behalf of the client - token is expired but successfully applied after a refresh. - case applied(Atom.Retryable) + case applied(Retryable) /// Application manages its own authorization header. - case na(Atom.Retryable) + case na(Retryable) /// AuthenticationManager is in the process of refreshing an access token. case refreshingAccessToken diff --git a/Framework/Atom/Managers/Authentication Manager/Atom+AuthenticationManager.swift b/Framework/Atom/Managers/Authentication Manager/AuthenticationManager.swift similarity index 68% rename from Framework/Atom/Managers/Authentication Manager/Atom+AuthenticationManager.swift rename to Framework/Atom/Managers/Authentication Manager/AuthenticationManager.swift index cdca742..bb934b8 100644 --- a/Framework/Atom/Managers/Authentication Manager/Atom+AuthenticationManager.swift +++ b/Framework/Atom/Managers/Authentication Manager/AuthenticationManager.swift @@ -1,6 +1,6 @@ // Atom // -// Copyright (c) 2019 Alaska Airlines +// Copyright (c) 2020 Alaska Airlines // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -16,51 +16,40 @@ import Foundation -/// The `AuthenticationManagerDelegate` protocol provides an interface for responding to `AuthenticationManager` events. -internal protocol AuthenticationManagerDelegate: class { - /// Notifies the delegate when the `AuthenticationManager` successfully refreshed the access token. - func authenticationManagerDidRefreshAccessToken() - - /// Notifies the delegate when the `AuthenticationManager` failed to refresh the access token. - func authenticationManagerDidFailToRefreshAccessTokenWithError(_ error: AtomError) -} - -internal extension Atom { - /// The `AuthenticationManager` object used by Atom for automated refreshing of the access token. - final class AuthenticationManager { - /// The delegate to notify of `AuthenticationManager` events. - private unowned let delegate: AuthenticationManagerDelegate - - /// Indicates whether the `AuthenticationManager` is in the process of refreshing access token. - private var isRefreshing = false - - /// The `URLSession` instance used for token refresh. - private let session: URLSession - - /// The authentication method to apply to a request. - private let method: Atom.AuthenticationMethod - - /// Creates a `AuthenticationManager` instance given the provided parameter(s). - /// - /// - Parameters: - /// - method: The authentication method to apply to a request. - /// - delegate: The delegate to notify of `AuthenticationManager` events. - internal init(_ method: Atom.AuthenticationMethod, delegate: AuthenticationManagerDelegate) { - self.method = method - self.delegate = delegate - self.session = URLSession(configuration: .default, delegate: Interceptor(for: .authentication), delegateQueue: .main) - } +/// The `AuthenticationManager` object used by Atom for automated refreshing of the access token. +internal final class AuthenticationManager { + /// The delegate to notify of `AuthenticationManager` events. + private unowned let delegate: AuthenticationManagerDelegate + + /// Indicates whether the `AuthenticationManager` is in the process of refreshing access token. + private var isRefreshing = false + + /// The `URLSession` instance used for token refresh. + private let session: URLSession + + /// The authentication method to apply to a request. + private let method: AuthenticationMethod + + /// Creates a `AuthenticationManager` instance given the provided parameter(s). + /// + /// - Parameters: + /// - method: The authentication method to apply to a request. + /// - delegate: The delegate to notify of `AuthenticationManager` events. + internal init(_ method: AuthenticationMethod, delegate: AuthenticationManagerDelegate) { + self.method = method + self.delegate = delegate + self.session = URLSession(configuration: .default, delegate: Interceptor(for: .authentication), delegateQueue: .main) } } -internal extension Atom.AuthenticationManager { +internal extension AuthenticationManager { /// Applies authorization header to a `Retryable` instance. /// /// - Parameters: /// - retryable: The `Retryable` instance to apply authorization header to. /// /// - Returns: A `Status` instance indicating whether authorization header was applied. - func applyAuthorizationHeader(to retryable: Atom.Retryable, on queue: DispatchQueue) -> Status { + func applyAuthorizationHeader(to retryable: Retryable, on queue: DispatchQueue) -> Status { switch method { case .basic: // Client does not need authorization header applied for this request. @@ -102,7 +91,7 @@ internal extension Atom.AuthenticationManager { // MARK: Token Refresh -private extension Atom.AuthenticationManager { +private extension AuthenticationManager { /// Will refresh existing access token using defined endpoint. func refreshAccessToken(_ writable: TokenCredentialWritable, queue: DispatchQueue) { unowned let unownedSelf = self @@ -127,14 +116,14 @@ private extension Atom.AuthenticationManager { // Process error response returned by the service. else if response?.isFailure == true { - queue.async { unownedSelf.delegate.authenticationManagerDidFailToRefreshAccessTokenWithError(.response(Atom.Response(data, response))) } + queue.async { unownedSelf.delegate.authenticationManagerDidFailToRefreshAccessTokenWithError(.response(AtomResponse(data, response))) } } // Process data returned by the service. else if let data = data { do { // Decode token from data on the background queue and update the client with new token credentials. - writable.tokenCredential = try JSONDecoder().decode(Atom.TokenCredential.self, from: data) + writable.tokenCredential = try JSONDecoder().decode(TokenCredential.self, from: data) // Notify the delegate of successful token refresh. queue.async { unownedSelf.delegate.authenticationManagerDidRefreshAccessToken() } diff --git a/Framework/Atom/Models/Atom+AuthenticationMethod.swift b/Framework/Atom/Models/Atom+AuthenticationMethod.swift deleted file mode 100644 index f68ddbd..0000000 --- a/Framework/Atom/Models/Atom+AuthenticationMethod.swift +++ /dev/null @@ -1,37 +0,0 @@ -// Atom -// -// Copyright (c) 2019 Alaska Airlines -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -import Foundation - -public extension Atom { - /// List of authentication methods a client can choose from for `Atom` configuration. - enum AuthenticationMethod { - /// Atom will apply basic authorization header to a request on behalf of the client. - /// - /// To apply authorization header, Atom needs access to user's credentials required as `BasicCredential` (associated value). - case basic(BasicCredential) - - /// Atom will manage access token expiration and apply authorization header to a request on behalf of the client. - /// - /// To apply authorization header, Atom needs access to client's credentials required as `ClientCredential` (associated value) - /// and the location where to save / read from / updated credentials required as `TokenCredentialWritable` (associated value). In addition, a - /// valid `AuthorizationEndpoint` - the location of the authorization server must be provided (associated value). - case bearer(AuthorizationEndpoint, ClientCredential, TokenCredentialWritable) - - /// Application will manage its own authorization headers. - case none - } -} diff --git a/Framework/Atom/Models/Atom+AuthorizationEndpoint.swift b/Framework/Atom/Models/Atom+AuthorizationEndpoint.swift deleted file mode 100644 index 2b0b9dd..0000000 --- a/Framework/Atom/Models/Atom+AuthorizationEndpoint.swift +++ /dev/null @@ -1,51 +0,0 @@ -// Atom -// -// Copyright (c) 2019 Alaska Airlines -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -import Foundation - -public extension Atom { - /// Model object representing the location of the authorization server. - struct AuthorizationEndpoint { - /// The base url of the authorization server. - internal let baseURL: Atom.BaseURL - - /// The url path of the authorization server. - internal let path: Atom.URLPath - - /// Creates a `AuthorizationEndpoint` instance given the provided parameter(s). - /// - /// Before an instance of the `AuthorizationEndpoint` can be created, host and path will be - /// validated using regex patters defined in `NSRegularExpression+Additions`. If validation - /// fails for any reason, an exception will be raised by Atom - this is intentional to ensure - /// a valid authorization endpoint is provided during Atom configuration. - /// - /// - Parameters: - /// - host: The URL host as defined in RFC 1738. - /// - path: The URL path as defined in RFC 1738. - public init(host: String, path: String) { - guard let baseURL = try? Atom.BaseURL(host: host) else { - fatalError("Failed to validate URL host parameter.") - } - - guard let path = try? Atom.URLPath(path) else { - fatalError("Failed to validate URL path parameter.") - } - - self.baseURL = baseURL - self.path = path - } - } -} diff --git a/Framework/Atom/Models/Atom+BaseURL.swift b/Framework/Atom/Models/Atom+BaseURL.swift deleted file mode 100644 index 4d890f9..0000000 --- a/Framework/Atom/Models/Atom+BaseURL.swift +++ /dev/null @@ -1,61 +0,0 @@ -// Atom -// -// Copyright (c) 2019 Alaska Airlines -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -import Foundation - -public extension Atom { - /// Model object representing base URL composed from URL scheme and host. - struct BaseURL { - /// The URL scheme as defined in RFC 2718. - internal let scheme: Atom.BaseURL.Scheme - - /// The URL host as defined in RFC 1738. - internal let host: String - - /// Creates a `BaseURL` instance given the provided parameter(s). - /// - /// - Parameters: - /// - scheme: The URL scheme as defined in RFC 2718. - /// - host: The URL host as defined in RFC 1738. - /// - /// - Throws: `RequestableError.invalidBaseURL` when URL host validation fails. - public init(scheme: Atom.BaseURL.Scheme = .https, host: String) throws { - guard host.isValidURLHost else { - throw RequestableError.invalidBaseURL - } - - self.scheme = scheme - self.host = host - } - } -} - -// MARK: StringConvertible - -extension Atom.BaseURL: StringConvertible { - var stringValue: String { scheme.stringValue + host } -} - -extension Atom.BaseURL.Scheme: StringConvertible { - var stringValue: String { - switch self { - case .http: - return "http://" - case .https: - return "https://" - } - } -} diff --git a/Framework/Atom/Models/Atom+BasicCredential.swift b/Framework/Atom/Models/Atom+BasicCredential.swift deleted file mode 100644 index cfa36c6..0000000 --- a/Framework/Atom/Models/Atom+BasicCredential.swift +++ /dev/null @@ -1,40 +0,0 @@ -// Atom -// -// Copyright (c) 2019 Alaska Airlines -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -import Foundation - -public extension Atom { - /// The `BasicCredential` type declares an object used by Atom in network requests that require basic authentication. Before - /// basic authentication is applied as Authorization header value, username and password will be combined into a single - /// string using `:` and base 64 encoded. - struct BasicCredential { - /// The password to encode and use when applying basic authentication to a request. - internal let password: String - - /// The username to encode and use when applying basic authentication to a request. - internal let username: String - - /// Creates a `BasicCredential` instance given the provided parameter(s). - /// - /// - Parameters: - /// - password: The password to encode and use when applying basic authentication to a request. - /// - username: The username to encode and use when applying basic authentication to a request. - public init(password: String, username: String) { - self.password = password - self.username = username - } - } -} diff --git a/Framework/Atom/Models/Atom+ClientCredential.swift b/Framework/Atom/Models/Atom+ClientCredential.swift deleted file mode 100644 index 893093e..0000000 --- a/Framework/Atom/Models/Atom+ClientCredential.swift +++ /dev/null @@ -1,45 +0,0 @@ -// Atom -// -// Copyright (c) 2019 Alaska Airlines -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -import Foundation - -public extension Atom { - /// The `ClientCredential` type declares an object used by Atom for automated refreshing of the access token. - /// See https://tools.ietf.org/html/RFC6749 - struct ClientCredential { - /// The authorization grant type as described in Sections 4.1.3, 4.3.2, 4.4.2, RFC 6749. Starting with - /// version 4.0, Atom supports automated token refresh using `refresh_token` grant type as defined in RFC 6749. - internal let grantType: GrantType - - /// The client identifier issued to the client during the registration process described in Section 2.2, RFC 6749. - internal let id: String - - /// The client secret. The client MAY omit the parameter if the client secret is an empty string. See RFC 6749. - internal let secret: String - - /// Creates a `ClientCredential` instance given the provided parameter(s). - /// - /// - Parameters: - /// - grantType: The authorization grant type as described in Sections 4.1.3, 4.3.2, 4.4.2, RFC 6749. - /// - id: The client identifier issued to the client during the registration process described by Section 2.2, RFC 6749. - /// - secret: The client secret. The client MAY omit the parameter if the client secret is an empty string. See RFC 6749. - public init(grantType: GrantType = .refreshToken, id: String, secret: String) { - self.id = id - self.grantType = grantType - self.secret = secret - } - } -} diff --git a/Framework/Atom/Models/Atom+HeaderItem.swift b/Framework/Atom/Models/Atom+HeaderItem.swift deleted file mode 100644 index 4085596..0000000 --- a/Framework/Atom/Models/Atom+HeaderItem.swift +++ /dev/null @@ -1,38 +0,0 @@ -// Atom -// -// Copyright (c) 2019 Alaska Airlines -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -import Foundation - -public extension Atom { - /// A single name-value pair for specifying HTTP header value modeled after `URLQueryItem`. - struct HeaderItem { - /// The name of the header item. - internal let name: String - - /// The value of the header item. - internal let value: String - - /// Creates a `HeaderItem` instance given the provided parameter(s). - /// - /// - Parameters: - /// - name: The name of the header item. - /// - value: The value of the header item. - public init(name: String, value: String) { - self.name = name - self.value = value - } - } -} diff --git a/Framework/Atom/Models/Atom+Retryable.swift b/Framework/Atom/Models/Atom+Retryable.swift deleted file mode 100644 index c5f082e..0000000 --- a/Framework/Atom/Models/Atom+Retryable.swift +++ /dev/null @@ -1,55 +0,0 @@ -// Atom -// -// Copyright (c) 2019 Alaska Airlines -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -import Foundation - -internal extension Atom { - /// A model type representing a network request type that can be retried. - /// - /// Each `URLRequest` instance, before being executed, will be converted to `Retryable` - /// instance and enqueued for network call execution. This is done to provide a manageable - /// way for Atom to inspect and retry each request ensuring valid Authorization header value(s) - /// are applied where needed. See `Atom.AuthenticationPreference` and `Requestable` for more information. - /// - /// Atom implementation ensures valid access token is applied to a request before executing it. If Atom - /// determines that a token refresh is required, all calls will be collected and suspended without execution - /// until new token is obtained using defined endpoint. Once a new token is obtained, all suspended requests - /// will be resumed at once. - struct Retryable { - internal typealias Completion = (Data?, URLResponse?, Error?) -> Void - - /// The `URLRequest` instance to retry. - internal let request: URLRequest - - /// The `Bool` indicating whether or not authorization header should be applied. - internal let requiresAuthorization: Bool - - /// The completion block for retried requests. - internal let completion: Completion - - /// Creates a `Retryable` instance given the provided parameter(s). - /// - /// - Parameters: - /// - request: The `URLRequest` instance to retry. - /// - requiresAuthorization: The `Bool` indicating whether or not authorization header should be applied. - /// - completion: The completion block for retried requests. - internal init(request: URLRequest, requiresAuthorization: Bool, completion: @escaping Completion) { - self.request = request - self.requiresAuthorization = requiresAuthorization - self.completion = completion - } - } -} diff --git a/Framework/Atom/Models/Atom+TokenCredential.swift b/Framework/Atom/Models/Atom+TokenCredential.swift deleted file mode 100644 index 4d48af8..0000000 --- a/Framework/Atom/Models/Atom+TokenCredential.swift +++ /dev/null @@ -1,48 +0,0 @@ -// Atom -// -// Copyright (c) 2019 Alaska Airlines -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -import Foundation - -public extension Atom { - /// The `TokenCredential` type declares an object used by Atom in network requests that require bearer authentication. - struct TokenCredential { - /// The access token as defined in OAuth 2.0 spec. - public let accessToken: String - - /// The number of seconds access token is valid for. - public let expiresIn: Int - - /// The expiration date of the access token. - public let expiresAt: Date - - /// The refresh token as defined in OAuth 2.0 spec. - public let refreshToken: String - - /// Creates a `TokenCredential` instance given the provided parameter(s). - /// - /// - Parameters: - /// - accessToken: The access token as defined in OAuth 2.0 spec. - /// - expiresIn: The number of seconds access token is valid for. - /// - expiresAt: The expiration date of the access token. - /// - refreshToken: The refresh token as defined in OAuth 2.0 spec. - public init(accessToken: String, expiresIn: Int, expiresAt: Date, refreshToken: String) { - self.accessToken = accessToken - self.expiresIn = expiresIn - self.expiresAt = expiresAt - self.refreshToken = refreshToken - } - } -} diff --git a/Framework/Atom/Models/Atom+Endpoint.swift b/Framework/Atom/Models/AtomResponse+Additions.swift similarity index 54% rename from Framework/Atom/Models/Atom+Endpoint.swift rename to Framework/Atom/Models/AtomResponse+Additions.swift index b07cd86..964784e 100644 --- a/Framework/Atom/Models/Atom+Endpoint.swift +++ b/Framework/Atom/Models/AtomResponse+Additions.swift @@ -1,6 +1,6 @@ // Atom // -// Copyright (c) 2019 Alaska Airlines +// Copyright (c) 2020 Alaska Airlines // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -16,11 +16,19 @@ import Foundation -internal extension Atom { - /// Model object representing default `Endpoint` requestable used for initializing `Atom.Service` only. - struct Endpoint: Requestable { - func baseURL() throws -> Atom.BaseURL { - try Atom.BaseURL(host: String()) +public extension AtomResponse { + /// Returns `true` if the status code of the `AtomResponse` is not in `200...299` range. + var isFailure: Bool { !isSuccessful } + + /// Returns `true` if the status code of the `AtomResponse` is in `200...299` range. + var isSuccessful: Bool { + guard let statusCode = statusCode else { return false } + + switch statusCode { + case 200...299: + return true + default: + return false } } } diff --git a/Framework/Atom/Models/Atom+Response.swift b/Framework/Atom/Models/AtomResponse.swift similarity index 59% rename from Framework/Atom/Models/Atom+Response.swift rename to Framework/Atom/Models/AtomResponse.swift index 1c58f61..aaddf67 100644 --- a/Framework/Atom/Models/Atom+Response.swift +++ b/Framework/Atom/Models/AtomResponse.swift @@ -1,6 +1,6 @@ // Atom // -// Copyright (c) 2019 Alaska Airlines +// Copyright (c) 2020 Alaska Airlines // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -16,41 +16,39 @@ import Foundation -public extension Atom { - /// The metadata associated with the response to a URL load request, independent of protocol and URL scheme. - struct Response { - public typealias HeaderFields = NSDictionary +/// The metadata associated with the response to a URL load request, independent of protocol and URL scheme. +public struct AtomResponse { + public typealias HeaderFields = NSDictionary - /// All HTTP header fields of the response. - public let allHeaderFields: HeaderFields? + /// All HTTP header fields of the response. + public let allHeaderFields: HeaderFields? - /// The expected length of the response’s content. - public let expectedContentLength: Int64? + /// The expected length of the response’s content. + public let expectedContentLength: Int64? - /// The data returned by the server. - public let data: Data? + /// The data returned by the server. + public let data: Data? - /// The MIME type of the response. - public let mimeType: String? + /// The MIME type of the response. + public let mimeType: String? - /// The response’s HTTP status code. - public let statusCode: Int? + /// The response’s HTTP status code. + public let statusCode: Int? - /// A suggested filename for the response data. - public let suggestedFilename: String? + /// A suggested filename for the response data. + public let suggestedFilename: String? - /// The name of the text encoding provided by the response’s originating source. - public let textEncodingName: String? + /// The name of the text encoding provided by the response’s originating source. + public let textEncodingName: String? - /// The URL for the response. - public let url: URL? - } + /// The URL for the response. + public let url: URL? } // MARK: Convenience Initializers -internal extension Atom.Response { - /// Creates a `Response` instance given the provided parameter(s). +internal extension AtomResponse { + /// Creates a `AtomResponse` instance given the provided parameter(s). /// /// - Parameters: /// - data: The Data returned by URLSession completion. @@ -68,7 +66,7 @@ internal extension Atom.Response { self.url = response?.url } - /// Creates a `Response` instance given the provided parameter(s). + /// Creates a `AtomResponse` instance given the provided parameter(s). /// /// - Parameters: /// - statusCode: The response’s HTTP status code. diff --git a/Framework/Atom/Models/Atom+AuthenticationMethod+Additions.swift b/Framework/Atom/Models/AuthenticationMethod+Additions.swift similarity index 95% rename from Framework/Atom/Models/Atom+AuthenticationMethod+Additions.swift rename to Framework/Atom/Models/AuthenticationMethod+Additions.swift index 514f2b3..bf0f00e 100644 --- a/Framework/Atom/Models/Atom+AuthenticationMethod+Additions.swift +++ b/Framework/Atom/Models/AuthenticationMethod+Additions.swift @@ -1,6 +1,6 @@ // Atom // -// Copyright (c) 2019 Alaska Airlines +// Copyright (c) 2020 Alaska Airlines // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -18,7 +18,7 @@ import Foundation // MARK: Authorization Values -internal extension Atom.AuthenticationMethod { +internal extension AuthenticationMethod { /// Returns "Authorization" as the header field name. var headerField: String { "Authorization" } @@ -37,7 +37,7 @@ internal extension Atom.AuthenticationMethod { // MARK: Network Request -internal extension Atom.AuthenticationMethod { +internal extension AuthenticationMethod { /// Returns `URLRequest` instance used for refreshing a token. var tokenRefreshRequest: URLRequest? { guard diff --git a/Framework/Atom/Models/AuthenticationMethod.swift b/Framework/Atom/Models/AuthenticationMethod.swift new file mode 100644 index 0000000..91f7c07 --- /dev/null +++ b/Framework/Atom/Models/AuthenticationMethod.swift @@ -0,0 +1,35 @@ +// Atom +// +// Copyright (c) 2020 Alaska Airlines +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import Foundation + +/// List of authentication methods a client can choose from for `Atom` configuration. +public enum AuthenticationMethod { + /// Atom will apply basic authorization header to a request on behalf of the client. + /// + /// To apply authorization header, Atom needs access to user's credentials required as `BasicCredential` (associated value). + case basic(BasicCredential) + + /// Atom will manage access token expiration and apply authorization header to a request on behalf of the client. + /// + /// To apply authorization header, Atom needs access to client's credentials required as `ClientCredential` (associated value) + /// and the location where to save / read from / updated credentials required as `TokenCredentialWritable` (associated value). In addition, a + /// valid `AuthorizationEndpoint` - the location of the authorization server must be provided (associated value). + case bearer(AuthorizationEndpoint, ClientCredential, TokenCredentialWritable) + + /// Application will manage its own authorization headers. + case none +} diff --git a/Framework/Atom/Models/AuthorizationEndpoint.swift b/Framework/Atom/Models/AuthorizationEndpoint.swift new file mode 100644 index 0000000..f2b7729 --- /dev/null +++ b/Framework/Atom/Models/AuthorizationEndpoint.swift @@ -0,0 +1,49 @@ +// Atom +// +// Copyright (c) 2020 Alaska Airlines +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import Foundation + +/// Model object representing the location of the authorization server. +public struct AuthorizationEndpoint { + /// The base url of the authorization server. + internal let baseURL: BaseURL + + /// The url path of the authorization server. + internal let path: URLPath + + /// Creates a `AuthorizationEndpoint` instance given the provided parameter(s). + /// + /// Before an instance of the `AuthorizationEndpoint` can be created, host and path will be + /// validated using regex patters defined in `NSRegularExpression+Additions`. If validation + /// fails for any reason, an exception will be raised by Atom - this is intentional to ensure + /// a valid authorization endpoint is provided during Atom configuration. + /// + /// - Parameters: + /// - host: The URL host as defined in RFC 1738. + /// - path: The URL path as defined in RFC 1738. + public init(host: String, path: String) { + guard let baseURL = try? BaseURL(host: host) else { + fatalError("Failed to validate URL host parameter.") + } + + guard let path = try? URLPath(path) else { + fatalError("Failed to validate URL path parameter.") + } + + self.baseURL = baseURL + self.path = path + } +} diff --git a/Framework/Atom/Models/Atom+BaseURL+Scheme.swift b/Framework/Atom/Models/BaseURL+Scheme.swift similarity index 91% rename from Framework/Atom/Models/Atom+BaseURL+Scheme.swift rename to Framework/Atom/Models/BaseURL+Scheme.swift index 2688d10..bbf52b6 100644 --- a/Framework/Atom/Models/Atom+BaseURL+Scheme.swift +++ b/Framework/Atom/Models/BaseURL+Scheme.swift @@ -1,6 +1,6 @@ // Atom // -// Copyright (c) 2019 Alaska Airlines +// Copyright (c) 2020 Alaska Airlines // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -16,7 +16,7 @@ import Foundation -public extension Atom.BaseURL { +public extension BaseURL { /// List of supported scheme types. enum Scheme { /// The hyper text transfer protocol. diff --git a/Framework/Atom/Models/BaseURL.swift b/Framework/Atom/Models/BaseURL.swift new file mode 100644 index 0000000..111bcb3 --- /dev/null +++ b/Framework/Atom/Models/BaseURL.swift @@ -0,0 +1,59 @@ +// Atom +// +// Copyright (c) 2020 Alaska Airlines +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import Foundation + +/// Model object representing base URL composed from URL scheme and host. +public struct BaseURL { + /// The URL scheme as defined in RFC 2718. + internal let scheme: BaseURL.Scheme + + /// The URL host as defined in RFC 1738. + internal let host: String + + /// Creates a `BaseURL` instance given the provided parameter(s). + /// + /// - Parameters: + /// - scheme: The URL scheme as defined in RFC 2718. + /// - host: The URL host as defined in RFC 1738. + /// + /// - Throws: `RequestableError.invalidBaseURL` when URL host validation fails. + public init(scheme: BaseURL.Scheme = .https, host: String) throws { + guard host.isValidURLHost else { + throw RequestableError.invalidBaseURL + } + + self.scheme = scheme + self.host = host + } +} + +// MARK: StringConvertible + +extension BaseURL: StringConvertible { + var stringValue: String { scheme.stringValue + host } +} + +extension BaseURL.Scheme: StringConvertible { + var stringValue: String { + switch self { + case .http: + return "http://" + case .https: + return "https://" + } + } +} diff --git a/Framework/Atom/Models/Atom+BasicCredential+Additions.swift b/Framework/Atom/Models/BasicCredential+Additions.swift similarity index 90% rename from Framework/Atom/Models/Atom+BasicCredential+Additions.swift rename to Framework/Atom/Models/BasicCredential+Additions.swift index 911cc56..bfc8dcd 100644 --- a/Framework/Atom/Models/Atom+BasicCredential+Additions.swift +++ b/Framework/Atom/Models/BasicCredential+Additions.swift @@ -1,6 +1,6 @@ // Atom // -// Copyright (c) 2019 Alaska Airlines +// Copyright (c) 2020 Alaska Airlines // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -16,7 +16,7 @@ import Foundation -internal extension Atom.BasicCredential { +internal extension BasicCredential { /// Returns `username` and `password` combined together with `:` in-between. var combined: String { username.appending(":").appending(password) diff --git a/Framework/Atom/Models/BasicCredential.swift b/Framework/Atom/Models/BasicCredential.swift new file mode 100644 index 0000000..c941201 --- /dev/null +++ b/Framework/Atom/Models/BasicCredential.swift @@ -0,0 +1,38 @@ +// Atom +// +// Copyright (c) 2020 Alaska Airlines +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import Foundation + +/// The `BasicCredential` type declares an object used by Atom in network requests that require basic authentication. Before +/// basic authentication is applied as Authorization header value, username and password will be combined into a single +/// string using `:` and base 64 encoded. +public struct BasicCredential { + /// The password to encode and use when applying basic authentication to a request. + internal let password: String + + /// The username to encode and use when applying basic authentication to a request. + internal let username: String + + /// Creates a `BasicCredential` instance given the provided parameter(s). + /// + /// - Parameters: + /// - password: The password to encode and use when applying basic authentication to a request. + /// - username: The username to encode and use when applying basic authentication to a request. + public init(password: String, username: String) { + self.password = password + self.username = username + } +} diff --git a/Framework/Atom/Models/Atom+ClientCredential+GrantType.swift b/Framework/Atom/Models/ClientCredential+GrantType.swift similarity index 90% rename from Framework/Atom/Models/Atom+ClientCredential+GrantType.swift rename to Framework/Atom/Models/ClientCredential+GrantType.swift index 8de5d0d..c7bc376 100644 --- a/Framework/Atom/Models/Atom+ClientCredential+GrantType.swift +++ b/Framework/Atom/Models/ClientCredential+GrantType.swift @@ -1,6 +1,6 @@ // Atom // -// Copyright (c) 2019 Alaska Airlines +// Copyright (c) 2020 Alaska Airlines // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -16,7 +16,7 @@ import Foundation -public extension Atom.ClientCredential { +public extension ClientCredential { /// List of supported grant types by Atom. enum GrantType: String { /// The `refresh_token` grant type as defined in Sections 6.0, RFC 6749. diff --git a/Framework/Atom/Models/ClientCredential.swift b/Framework/Atom/Models/ClientCredential.swift new file mode 100644 index 0000000..1b35fb2 --- /dev/null +++ b/Framework/Atom/Models/ClientCredential.swift @@ -0,0 +1,43 @@ +// Atom +// +// Copyright (c) 2020 Alaska Airlines +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import Foundation + +/// The `ClientCredential` type declares an object used by Atom for automated refreshing of the access token. +/// See https://tools.ietf.org/html/RFC6749 +public struct ClientCredential { + /// The authorization grant type as described in Sections 4.1.3, 4.3.2, 4.4.2, RFC 6749. Starting with + /// version 4.0, Atom supports automated token refresh using `refresh_token` grant type as defined in RFC 6749. + internal let grantType: GrantType + + /// The client identifier issued to the client during the registration process described in Section 2.2, RFC 6749. + internal let id: String + + /// The client secret. The client MAY omit the parameter if the client secret is an empty string. See RFC 6749. + internal let secret: String + + /// Creates a `ClientCredential` instance given the provided parameter(s). + /// + /// - Parameters: + /// - grantType: The authorization grant type as described in Sections 4.1.3, 4.3.2, 4.4.2, RFC 6749. + /// - id: The client identifier issued to the client during the registration process described by Section 2.2, RFC 6749. + /// - secret: The client secret. The client MAY omit the parameter if the client secret is an empty string. See RFC 6749. + public init(grantType: GrantType = .refreshToken, id: String, secret: String) { + self.id = id + self.grantType = grantType + self.secret = secret + } +} diff --git a/Framework/Atom/Models/Endpoint.swift b/Framework/Atom/Models/Endpoint.swift new file mode 100644 index 0000000..87f7d02 --- /dev/null +++ b/Framework/Atom/Models/Endpoint.swift @@ -0,0 +1,24 @@ +// Atom +// +// Copyright (c) 2020 Alaska Airlines +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import Foundation + +/// Model object representing default `Endpoint` requestable used for initializing `Service` only. +internal struct Endpoint: Requestable { + func baseURL() throws -> BaseURL { + try BaseURL(host: String()) + } +} diff --git a/Framework/Atom/Models/HeaderItem.swift b/Framework/Atom/Models/HeaderItem.swift new file mode 100644 index 0000000..c462277 --- /dev/null +++ b/Framework/Atom/Models/HeaderItem.swift @@ -0,0 +1,36 @@ +// Atom +// +// Copyright (c) 2020 Alaska Airlines +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import Foundation + +/// A single name-value pair from the header portion of a request. +public struct HeaderItem: RequestableItem { + /// The name of the header item. + public let name: String + + /// The value of the header item. + public let value: String + + /// Creates a `HeaderItem` instance given the provided parameter(s). + /// + /// - Parameters: + /// - name: The name of the header item. + /// - value: The value of the header item. + public init(name: String, value: String) { + self.name = name + self.value = value + } +} diff --git a/Framework/Atom/Models/Atom+Method.swift b/Framework/Atom/Models/Method.swift similarity index 66% rename from Framework/Atom/Models/Atom+Method.swift rename to Framework/Atom/Models/Method.swift index 2eb18fb..d89fce6 100644 --- a/Framework/Atom/Models/Atom+Method.swift +++ b/Framework/Atom/Models/Method.swift @@ -1,6 +1,6 @@ // Atom // -// Copyright (c) 2019 Alaska Airlines +// Copyright (c) 2020 Alaska Airlines // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -16,29 +16,27 @@ import Foundation -public extension Atom { - /// List of primary HTTP methods. - enum Method: Equatable { - /// Use for deleting a resource identified by a URI. - case delete +/// List of primary HTTP methods. +public enum HTTPMethod: Equatable { + /// Use for deleting a resource identified by a URI. + case delete - /// Use for reading (or retrieving) a representation of a resource. - case get + /// Use for reading (or retrieving) a representation of a resource. + case get - /// Use for modifying capabilities. - case patch(Data) + /// Use for modifying capabilities. + case patch(Data) - /// Use for creating new resources. - case post(Data) + /// Use for creating new resources. + case post(Data) - /// Use for replacing a resource. - case put(Data) - } + /// Use for replacing a resource. + case put(Data) } // MARK: StringConvertible -extension Atom.Method: StringConvertible { +extension HTTPMethod: StringConvertible { internal var stringValue: String { switch self { case .delete: @@ -57,7 +55,7 @@ extension Atom.Method: StringConvertible { // MARK: Data -internal extension Atom.Method { +internal extension HTTPMethod { var body: Data? { switch self { case .delete, .get: diff --git a/Framework/Atom/Models/QueryItem.swift b/Framework/Atom/Models/QueryItem.swift new file mode 100644 index 0000000..e70d816 --- /dev/null +++ b/Framework/Atom/Models/QueryItem.swift @@ -0,0 +1,36 @@ +// Atom +// +// Copyright (c) 2020 Alaska Airlines +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import Foundation + +/// A single name-value pair from the query portion of a URL. +public struct QueryItem: RequestableItem { + /// The name of the query item. + public let name: String + + /// The value of the query item. + public let value: String + + /// Creates a `QueryItem` instance given the provided parameter(s). + /// + /// - Parameters: + /// - name: The name of the query item. + /// - value: The value of the query item. + public init(name: String, value: String) { + self.name = name + self.value = value + } +} diff --git a/Framework/Atom/Models/Atom+Response+Additions.swift b/Framework/Atom/Models/Response+Additions.swift similarity index 83% rename from Framework/Atom/Models/Atom+Response+Additions.swift rename to Framework/Atom/Models/Response+Additions.swift index e2bd5c4..bd9d64d 100644 --- a/Framework/Atom/Models/Atom+Response+Additions.swift +++ b/Framework/Atom/Models/Response+Additions.swift @@ -1,6 +1,6 @@ // Atom // -// Copyright (c) 2019 Alaska Airlines +// Copyright (c) 2020 Alaska Airlines // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -16,7 +16,7 @@ import Foundation -public extension Atom.Response { +public extension AtomResponse { /// Returns default, success response where status code is 200. - static let success = Atom.Response(statusCode: 200) + static let success = AtomResponse(statusCode: 200) } diff --git a/Framework/Atom/Models/Atom+Retryable+Additions.swift b/Framework/Atom/Models/Retryable+Additions.swift similarity index 78% rename from Framework/Atom/Models/Atom+Retryable+Additions.swift rename to Framework/Atom/Models/Retryable+Additions.swift index 450ac3b..05d9c6d 100644 --- a/Framework/Atom/Models/Atom+Retryable+Additions.swift +++ b/Framework/Atom/Models/Retryable+Additions.swift @@ -1,6 +1,6 @@ // Atom // -// Copyright (c) 2019 Alaska Airlines +// Copyright (c) 2020 Alaska Airlines // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -16,17 +16,17 @@ import Foundation -internal extension Atom.Retryable { +internal extension Retryable { /// Applies authorization header to a `Retryable` request instance. /// /// - Parameters: /// - method: The authentication method to apply to a `Retryable` request instance. /// /// Returns: A new `Retryable` instance with applied authorization header. - func appliedAuthorizationHeader(_ method: Atom.AuthenticationMethod) -> Self { + func appliedAuthorizationHeader(_ method: AuthenticationMethod) -> Self { var request = self.request request.addValue(method.headerValue, forHTTPHeaderField: method.headerField) - return Atom.Retryable(request: request, requiresAuthorization: requiresAuthorization, completion: completion) + return Retryable(request: request, requiresAuthorization: requiresAuthorization, completion: completion) } } diff --git a/Framework/Atom/Models/Retryable.swift b/Framework/Atom/Models/Retryable.swift new file mode 100644 index 0000000..0e235b1 --- /dev/null +++ b/Framework/Atom/Models/Retryable.swift @@ -0,0 +1,53 @@ +// Atom +// +// Copyright (c) 2020 Alaska Airlines +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import Foundation + +/// A model type representing a network request type that can be retried. +/// +/// Each `URLRequest` instance, before being resumed, will be converted to `Retryable` +/// instance and enqueued for network call execution. This is done to provide a manageable +/// way for Atom to inspect and retry each request ensuring valid Authorization header value(s) +/// are applied where needed. See `AuthenticationPreference` and `Requestable` for more information. +/// +/// Atom implementation ensures valid access token is applied to a request before executing it. If Atom +/// determines that a token refresh is required, all calls will be collected and suspended without execution +/// until new token is obtained using defined endpoint. Once a new token is obtained, all suspended requests +/// will be resumed at once. +internal struct Retryable { + internal typealias Completion = (Data?, URLResponse?, Error?) -> Void + + /// The `URLRequest` instance to retry. + internal let request: URLRequest + + /// The `Bool` indicating whether or not authorization header should be applied. + internal let requiresAuthorization: Bool + + /// The completion block for retried requests. + internal let completion: Completion + + /// Creates a `Retryable` instance given the provided parameter(s). + /// + /// - Parameters: + /// - request: The `URLRequest` instance to retry. + /// - requiresAuthorization: The `Bool` indicating whether or not authorization header should be applied. + /// - completion: The completion block for retried requests. + internal init(request: URLRequest, requiresAuthorization: Bool, completion: @escaping Completion) { + self.request = request + self.requiresAuthorization = requiresAuthorization + self.completion = completion + } +} diff --git a/Framework/Atom/Models/Atom+TokenCredential+Additions.swift b/Framework/Atom/Models/TokenCredential+Additions.swift similarity index 89% rename from Framework/Atom/Models/Atom+TokenCredential+Additions.swift rename to Framework/Atom/Models/TokenCredential+Additions.swift index c04da7d..eaed764 100644 --- a/Framework/Atom/Models/Atom+TokenCredential+Additions.swift +++ b/Framework/Atom/Models/TokenCredential+Additions.swift @@ -1,6 +1,6 @@ // Atom // -// Copyright (c) 2019 Alaska Airlines +// Copyright (c) 2020 Alaska Airlines // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -16,7 +16,7 @@ import Foundation -internal extension Atom.TokenCredential { +internal extension TokenCredential { /// Returns `Bool` indicating whether the credential needs refreshing. var requiresRefresh: Bool { expiresAt <= .now } } diff --git a/Framework/Atom/Models/Atom+TokenCredential+Decodable.swift b/Framework/Atom/Models/TokenCredential+Decodable.swift similarity index 93% rename from Framework/Atom/Models/Atom+TokenCredential+Decodable.swift rename to Framework/Atom/Models/TokenCredential+Decodable.swift index bdbf02a..04d2c61 100644 --- a/Framework/Atom/Models/Atom+TokenCredential+Decodable.swift +++ b/Framework/Atom/Models/TokenCredential+Decodable.swift @@ -1,6 +1,6 @@ // Atom // -// Copyright (c) 2019 Alaska Airlines +// Copyright (c) 2020 Alaska Airlines // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -16,7 +16,7 @@ import Foundation -extension Atom.TokenCredential: Decodable { +extension TokenCredential: Decodable { private enum CodingKeys: String, CodingKey { case accessToken = "access_token" case expiresIn = "expires_in" diff --git a/Framework/Atom/Models/TokenCredential.swift b/Framework/Atom/Models/TokenCredential.swift new file mode 100644 index 0000000..5846706 --- /dev/null +++ b/Framework/Atom/Models/TokenCredential.swift @@ -0,0 +1,46 @@ +// Atom +// +// Copyright (c) 2020 Alaska Airlines +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import Foundation + +/// The `TokenCredential` type declares an object used by Atom in network requests that require bearer authentication. +public struct TokenCredential { + /// The access token as defined in OAuth 2.0 spec. + public let accessToken: String + + /// The number of seconds access token is valid for. + public let expiresIn: Int + + /// The expiration date of the access token. + public let expiresAt: Date + + /// The refresh token as defined in OAuth 2.0 spec. + public let refreshToken: String + + /// Creates a `TokenCredential` instance given the provided parameter(s). + /// + /// - Parameters: + /// - accessToken: The access token as defined in OAuth 2.0 spec. + /// - expiresIn: The number of seconds access token is valid for. + /// - expiresAt: The expiration date of the access token. + /// - refreshToken: The refresh token as defined in OAuth 2.0 spec. + public init(accessToken: String, expiresIn: Int, expiresAt: Date, refreshToken: String) { + self.accessToken = accessToken + self.expiresIn = expiresIn + self.expiresAt = expiresAt + self.refreshToken = refreshToken + } +} diff --git a/Framework/Atom/Models/Atom+URLPath.swift b/Framework/Atom/Models/URLPath.swift similarity index 57% rename from Framework/Atom/Models/Atom+URLPath.swift rename to Framework/Atom/Models/URLPath.swift index 8c2da4b..6d04feb 100644 --- a/Framework/Atom/Models/Atom+URLPath.swift +++ b/Framework/Atom/Models/URLPath.swift @@ -1,6 +1,6 @@ // Atom // -// Copyright (c) 2019 Alaska Airlines +// Copyright (c) 2020 Alaska Airlines // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -16,42 +16,40 @@ import Foundation -public extension Atom { - /// Model object representing URL path. - struct URLPath { - /// The URL path as defined in RFC 3986. - private let path: String +/// Model object representing URL path. +public struct URLPath { + /// The URL path as defined in RFC 3986. + private let path: String - /// Creates a `URLPath` instance given the provided parameter(s). - /// - /// - Parameters: - /// - path: The URL path as defined in RFC 3986. - /// - /// - Throws: `RequestableError.invalidURLPath` when URL path validation fails. - public init(_ path: String) throws { - guard path.isValidURLPath else { - throw RequestableError.invalidURLPath - } - - self.path = path + /// Creates a `URLPath` instance given the provided parameter(s). + /// + /// - Parameters: + /// - path: The URL path as defined in RFC 3986. + /// + /// - Throws: `RequestableError.invalidURLPath` when URL path validation fails. + public init(_ path: String) throws { + guard path.isValidURLPath else { + throw RequestableError.invalidURLPath } + + self.path = path } } // MARK: StringConvertible -extension Atom.URLPath: StringConvertible { +extension URLPath: StringConvertible { var stringValue: String { path } } -private extension Atom.URLPath { +private extension URLPath { /// Creates a `URLPath` instance where path is an empty string. /// /// This implementation is used by internal static constant `default` to /// provide default implementation for the `Requestable.path()` method. /// ```` - /// func path() throws -> Atom.URLPath { - /// return Atom.URLPath.default + /// func path() throws -> URLPath { + /// return URLPath.default /// } /// ```` /// This approach allows url path method implementation to remain as an optional @@ -62,9 +60,9 @@ private extension Atom.URLPath { } } -internal extension Atom.URLPath { +internal extension URLPath { /// Provides default implementation value for the `Requestable` protocol. /// - /// For documentation see `Atom.URLPath.init` declaration. - static let `default` = Atom.URLPath() + /// For documentation see `URLPath.init` declaration. + static let `default` = URLPath() } diff --git a/Framework/Atom/Common/Protocols/Convertibles/BasicCredentialConvertible.swift b/Framework/Atom/Protocols/Convertibles/BasicCredentialConvertible.swift similarity index 79% rename from Framework/Atom/Common/Protocols/Convertibles/BasicCredentialConvertible.swift rename to Framework/Atom/Protocols/Convertibles/BasicCredentialConvertible.swift index 2f2048d..d3db72c 100644 --- a/Framework/Atom/Common/Protocols/Convertibles/BasicCredentialConvertible.swift +++ b/Framework/Atom/Protocols/Convertibles/BasicCredentialConvertible.swift @@ -1,6 +1,6 @@ // Atom // -// Copyright (c) 2019 Alaska Airlines +// Copyright (c) 2020 Alaska Airlines // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -16,14 +16,14 @@ import Foundation -/// The `BasicCredentialConvertible` protocol declares an interface used for converting conforming type to `Atom.BasicCredential`. +/// The `BasicCredentialConvertible` protocol declares an interface used for converting conforming type to `BasicCredential`. /// /// Atom can be configured to automatically apply authorization header to any `Requestable` instance. Once properly configured, Atom will read /// credentials from the storage specified by the client and apply them to `Requestable` instance if `requiresAuthentication` property /// is set to `true`. Values will be set as `Authorization: Basic base64-encoded-credential` header value. /// -/// For more information see `Atom.Configuration` documentation. +/// For more information see `Configuration` documentation. public protocol BasicCredentialConvertible { - /// Returns conforming type as `Atom.BasicCredential`. - var basicCredential: Atom.BasicCredential { get } + /// Returns conforming type as `BasicCredential`. + var basicCredential: BasicCredential { get } } diff --git a/Framework/Atom/Common/Protocols/Convertibles/ClientCredentialConvertible.swift b/Framework/Atom/Protocols/Convertibles/ClientCredentialConvertible.swift similarity index 75% rename from Framework/Atom/Common/Protocols/Convertibles/ClientCredentialConvertible.swift rename to Framework/Atom/Protocols/Convertibles/ClientCredentialConvertible.swift index f25cc5f..4c368a8 100644 --- a/Framework/Atom/Common/Protocols/Convertibles/ClientCredentialConvertible.swift +++ b/Framework/Atom/Protocols/Convertibles/ClientCredentialConvertible.swift @@ -1,6 +1,6 @@ // Atom // -// Copyright (c) 2019 Alaska Airlines +// Copyright (c) 2020 Alaska Airlines // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -16,8 +16,8 @@ import Foundation -/// The `ClientCredentialConvertible` protocol declares an interface used for converting conforming type to `Atom.ClientCredential`. +/// The `ClientCredentialConvertible` protocol declares an interface used for converting conforming type to `ClientCredential`. public protocol ClientCredentialConvertible { - /// Returns conforming type as `Atom.ClientCredential`. - var clientCredential: Atom.ClientCredential { get } + /// Returns conforming type as `ClientCredential`. + var clientCredential: ClientCredential { get } } diff --git a/Framework/Atom/Protocols/Convertibles/StringConvertible.swift b/Framework/Atom/Protocols/Convertibles/StringConvertible.swift new file mode 100644 index 0000000..d166c19 --- /dev/null +++ b/Framework/Atom/Protocols/Convertibles/StringConvertible.swift @@ -0,0 +1,23 @@ +// Atom +// +// Copyright (c) 2020 Alaska Airlines +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import Foundation + +/// The `StringConvertible` protocol declares an interface used for representing conforming type as a string. +internal protocol StringConvertible { + /// Returns conforming type as a **loosely** constructed string representation. + var stringValue: String { get } +} diff --git a/Framework/Atom/Protocols/Delegates/AuthenticationManagerDelegate.swift b/Framework/Atom/Protocols/Delegates/AuthenticationManagerDelegate.swift new file mode 100644 index 0000000..bb0421c --- /dev/null +++ b/Framework/Atom/Protocols/Delegates/AuthenticationManagerDelegate.swift @@ -0,0 +1,26 @@ +// Atom +// +// Copyright (c) 2020 Alaska Airlines +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import Foundation + +/// The `AuthenticationManagerDelegate` protocol provides an interface for responding to `AuthenticationManager` events. +internal protocol AuthenticationManagerDelegate: class { + /// Notifies the delegate when the `AuthenticationManager` successfully refreshed the access token. + func authenticationManagerDidRefreshAccessToken() + + /// Notifies the delegate when the `AuthenticationManager` failed to refresh the access token. + func authenticationManagerDidFailToRefreshAccessTokenWithError(_ error: AtomError) +} diff --git a/Framework/Atom/Common/Protocols/Types/Model.swift b/Framework/Atom/Protocols/Types/Model.swift similarity index 89% rename from Framework/Atom/Common/Protocols/Types/Model.swift rename to Framework/Atom/Protocols/Types/Model.swift index 5ad1767..b4ca372 100644 --- a/Framework/Atom/Common/Protocols/Types/Model.swift +++ b/Framework/Atom/Protocols/Types/Model.swift @@ -1,6 +1,6 @@ // Atom // -// Copyright (c) 2019 Alaska Airlines +// Copyright (c) 2020 Alaska Airlines // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -16,5 +16,5 @@ import Foundation -/// The `Model` protocol declares an interface used as a generic constraint on `Atom.Service` methods. +/// The `Model` protocol declares an interface used as a generic constraint on `Service` methods. public protocol Model: Codable { } diff --git a/Framework/Atom/Common/Protocols/Types/Requestable.swift b/Framework/Atom/Protocols/Types/Requestable.swift similarity index 80% rename from Framework/Atom/Common/Protocols/Types/Requestable.swift rename to Framework/Atom/Protocols/Types/Requestable.swift index 95aa71f..30a6910 100644 --- a/Framework/Atom/Common/Protocols/Types/Requestable.swift +++ b/Framework/Atom/Protocols/Types/Requestable.swift @@ -1,6 +1,6 @@ // Atom // -// Copyright (c) 2019 Alaska Airlines +// Copyright (c) 2020 Alaska Airlines // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -19,13 +19,13 @@ import Foundation /// The `Requestable` protocol declares an interface used for initializing network request object. public protocol Requestable { /// The array of header items to apply to a `URLRequest`. - var headerItems: [Atom.HeaderItem]? { get } + var headerItems: [HeaderItem]? { get } /// The HTTP method to apply to a `URLRequest`. - var method: Atom.Method { get } + var method: HTTPMethod { get } /// The array of query items to apply to a URL. - var queryItems: [Atom.QueryItem]? { get } + var queryItems: [QueryItem]? { get } /// The `Bool` indicating whether or not authorization header should be applied /// automatically by Atom to a `URLRequest` instance created from `Requestable`. @@ -36,24 +36,24 @@ public protocol Requestable { /// The URL host must begin and end with a word. /// /// ```` - /// func baseURL() throws -> Atom.BaseURL { - /// try Atom.BaseURL(host: "api.alaskaair.net") + /// func baseURL() throws -> BaseURL { + /// try BaseURL(host: "api.alaskaair.net") /// } /// ```` /// In the event that provided URL host fails validation, the client will be notified /// at the time of a network call by receiving `RequestableError.invalidBaseURL` error. - func baseURL() throws -> Atom.BaseURL + func baseURL() throws -> BaseURL /// The URL path to append to a base URL. /// /// The path should begin with a forward slash `/` and end with a word. /// /// ```` - /// func path() throws -> Atom.URLPath { - /// try Atom.URLPath("/path/to/resource") + /// func path() throws -> URLPath { + /// try URLPath("/path/to/resource") /// } /// ```` /// In the event when provided URL path fails validation, the client will be notified /// at the time of a network call by receiving `RequestableError.invalidURLPath` error. - func path() throws -> Atom.URLPath + func path() throws -> URLPath } diff --git a/Framework/Atom/Models/Atom+QueryItem.swift b/Framework/Atom/Protocols/Types/RequestableItem.swift similarity index 53% rename from Framework/Atom/Models/Atom+QueryItem.swift rename to Framework/Atom/Protocols/Types/RequestableItem.swift index 928728c..0db2482 100644 --- a/Framework/Atom/Models/Atom+QueryItem.swift +++ b/Framework/Atom/Protocols/Types/RequestableItem.swift @@ -1,6 +1,6 @@ // Atom // -// Copyright (c) 2019 Alaska Airlines +// Copyright (c) 2020 Alaska Airlines // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -16,11 +16,18 @@ import Foundation -public extension Atom { - /// A single name-value pair from the query portion of a URL. +/// The `RequestableItem` protocol declares an interface used for specifying HTTP header values & request queries. +public protocol RequestableItem { + /// The name of the requestable item. + var name: String { get } + + /// The value of the requestable item. + var value: String { get } + + /// /// - /// Foundation offers `URLQueryItem` type but not a similar type for creating - /// HTTP header item. To stay consistent, Atom framework introduced `Atom.HeaderItem` - /// and type aliased `URLQueryItem` to `Atom.QueryItem`. - typealias QueryItem = URLQueryItem + /// - Parameters: + /// - name: The name of the requestable item. + /// - value: The value of the requestable item. + init(name: String, value: String) } diff --git a/Framework/Atom/Common/Protocols/Types/TokenCredentialWritable.swift b/Framework/Atom/Protocols/Types/TokenCredentialWritable.swift similarity index 80% rename from Framework/Atom/Common/Protocols/Types/TokenCredentialWritable.swift rename to Framework/Atom/Protocols/Types/TokenCredentialWritable.swift index 45bbba8..e3e654f 100644 --- a/Framework/Atom/Common/Protocols/Types/TokenCredentialWritable.swift +++ b/Framework/Atom/Protocols/Types/TokenCredentialWritable.swift @@ -1,6 +1,6 @@ // Atom // -// Copyright (c) 2019 Alaska Airlines +// Copyright (c) 2020 Alaska Airlines // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -16,7 +16,7 @@ import Foundation -/// The `TokenCredentialWritable` protocol declares an interface used for reading from / writing to `Atom.TokenCredential`. +/// The `TokenCredentialWritable` protocol declares an interface used for reading from / writing to `TokenCredential`. /// /// Atom can be configured to automatically apply authorization header to any `Requestable` instance. Once properly configured, Atom will read /// credentials from the storage specified by the client and apply them to `Requestable` instance if `requiresAuthentication` property @@ -26,15 +26,15 @@ import Foundation /// /// ``` /// class SSOCredential: TokenCredentialWritable { -/// var tokenCredential: Atom.TokenCredential { +/// var tokenCredential: TokenCredential { /// get { keychain.value() } /// set { keychain.save(newValue) } /// } /// } /// ``` /// -/// For more information see `Atom.Configuration` documentation. +/// For more information see `Configuration` documentation. public protocol TokenCredentialWritable: class { - /// Returns conforming type as `Atom.TokenCredential`. - var tokenCredential: Atom.TokenCredential { get set } + /// Returns conforming type as `TokenCredential`. + var tokenCredential: TokenCredential { get set } } diff --git a/Framework/Atom/Service/Atom+ServiceConfiguration.swift b/Framework/Atom/Service/Atom+ServiceConfiguration.swift deleted file mode 100644 index 9d5e8f9..0000000 --- a/Framework/Atom/Service/Atom+ServiceConfiguration.swift +++ /dev/null @@ -1,132 +0,0 @@ -// Atom -// -// Copyright (c) 2019 Alaska Airlines -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -import Foundation - -public extension Atom { - /// Model object representing Service configuration. - class ServiceConfiguration { - /// The authentication method indicating how authorization header will be handled in Atom. - internal let authenticationMethod: Atom.AuthenticationMethod - - /// The `Atom.ServiceConfiguration.Configuration` - default value is `.ephemeral`. - internal let configuration: Atom.ServiceConfiguration.Configuration - - /// The JSONDecoder for decoding data into models. - internal let decoder: JSONDecoder - - /// The queue to dispatch `Result` object on. - internal let dispatchQueue: DispatchQueue - - /// The standardized timeout interval for request and resource. - internal let timeout: Atom.ServiceConfiguration.Timeout - - /// List of supported session configurations. - /// - /// Configuration enum is a reflection of available options offered - /// by Foundation as class properties on `URLSessionConfiguration`. The - /// main reason for this abstraction is testability - see `ServiceConfigurationTests`. - public enum Configuration: Equatable { - /// The background session configuration is suitable for transferring data files while the app runs in the background. - case background(String) - - /// The default session configuration that uses a persistent disk-based cache. - case `default` - - /// Ephemeral configuration doesn’t store caches, credential stores, or any session-related data on disk (RAM only). - case ephemeral - } - - /// Constants that specify the type of service that Multipath TCP uses. - /// - /// The multipath service type determines whether multipath TCP should be attempted and the conditions - /// for creating and switching between subflows. Using these service types requires the appropriate entitlement. Any - /// connection attempt will fail if the process does not have the required entitlement. - /// - /// Available options are: - /// - `.none` - The default service type indicating that Multipath TCP should not be used. - /// - `.handover` - A Multipath TCP service that provides seamless handover between Wi-Fi and cellular in order to preserve the connection. - /// - `.interactive` - A service whereby Multipath TCP attempts to use the lowest-latency interface. - /// - `.aggregate` - A service that aggregates the capacities of other Multipath options in an attempt to increase throughput and minimize latency. - #if os(iOS) - public typealias MultipathServiceType = URLSessionConfiguration.MultipathServiceType - - /// The service type that specifies the Multipath TCP connection policy for transmitting data over Wi-Fi and cellular interfaces. - internal var multipathServiceType: MultipathServiceType = .none - - /// Creates a `ServiceConfiguration` instance given the provided parameter(s). - /// - /// - Parameters: - /// - authenticationMethod: The authentication method indicating how authorization header will be handled in Atom. - /// - configuration: The `Atom.ServiceConfiguration.Configuration` - default value is `.ephemeral`. - /// - decoder: The `JSONDecoder` for decoding data into models. - /// - dispatchQueue: The queue to dispatch `Result` object on. - /// - multipathServiceType: The service type that specifies the Multipath TCP connection policy for transmitting data over Wi-Fi and cellular interfaces. - public init(authenticationMethod: AuthenticationMethod = .none, configuration: Configuration = .ephemeral, decoder: JSONDecoder = JSONDecoder(), dispatchQueue: DispatchQueue = .main, multipathServiceType: MultipathServiceType = .none) { - self.authenticationMethod = authenticationMethod - self.configuration = configuration - self.decoder = decoder - self.dispatchQueue = dispatchQueue - self.multipathServiceType = multipathServiceType - self.timeout = Timeout() - } - - #else - - /// Creates a `ServiceConfiguration` instance given the provided parameter(s). - /// - /// - Parameters: - /// - authenticationMethod: The authentication method indicating how authorization header will be handled in Atom. - /// - configuration: The `Atom.ServiceConfiguration.Configuration` - default value is `.ephemeral`. - /// - decoder: The `JSONDecoder` for decoding data into models. - /// - dispatchQueue: The queue to dispatch `Result` object on. - public init(authenticationMethod: AuthenticationMethod = .none, configuration: Configuration = .ephemeral, decoder: JSONDecoder = JSONDecoder(), dispatchQueue: DispatchQueue = .main) { - self.authenticationMethod = authenticationMethod - self.configuration = configuration - self.decoder = decoder - self.dispatchQueue = dispatchQueue - self.timeout = Timeout() - } - #endif - } -} - -// MARK: Configuration - -internal extension Atom.ServiceConfiguration { - /// Returns `URLSessionConfiguration` for each `Atom.ServiceConfiguration.Configuration` case. - var sessionConfiguration: URLSessionConfiguration { - let sessionConfiguration: URLSessionConfiguration - - switch configuration { - case .background(let identifier): - sessionConfiguration = .background(withIdentifier: identifier) - case .ephemeral: - sessionConfiguration = .ephemeral - case .default: - sessionConfiguration = .default - } - - sessionConfiguration.timeoutIntervalForRequest = timeout.request - sessionConfiguration.timeoutIntervalForResource = timeout.resource - - #if os(iOS) - sessionConfiguration.multipathServiceType = multipathServiceType - #endif - - return sessionConfiguration - } -} diff --git a/Framework/Atom/Service/Service+Combine.swift b/Framework/Atom/Service/Service+Combine.swift new file mode 100644 index 0000000..d9aa5e0 --- /dev/null +++ b/Framework/Atom/Service/Service+Combine.swift @@ -0,0 +1,88 @@ +// Atom +// +// Copyright (c) 2020 Alaska Airlines +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import Combine +import Foundation + +@available(iOS 13.0, macOS 10.15, *) +public extension Service { + /// Creates and resumes `URLRequest` initialized from `Requestable`. + /// + /// Use this method to make network requests where you expect data returned by the + /// service and require that data to be decoded into internal representations - models. + /// + /// Network request and decoding will be performed on a background thread after + /// which the client will be notified on a queue `Atom` was configured to use. + /// + /// A typical usage pattern for this method could look like this: + /// + /// ```` + /// atom + /// .enqueue(endpoint) + /// .resume(expecting: User.self) + /// .sink { completion in + /// // Handle `AtomError`. + /// } receiveValue: { user in + /// // Handle decoded `User` instance. + /// } + /// .store(in: &cancelables) + /// ```` + /// + /// In the above example, data will be decoded into a `User` instance. + /// + /// - Parameters: + /// - type: The type to decode. + /// + /// - Returns: `AnyPublisher` where `Output` is the decoded `Model` and `Failure` is `AtomError`. + func resume(expecting type: T.Type) -> AnyPublisher where T: Model { + Future { promise in + self.resume(expecting: type) { + promise($0) + } + }.eraseToAnyPublisher() + } + + /// Creates and resumes `URLRequest` initialized from `Requestable`. + /// + /// Use this method to make network requests where you don't expect any data returned + /// and are only interested in knowing if the network call succeeded or failed. + /// + /// `Atom` framework uses a convenience computed variable on `AtomResponse` - `isSuccessful` + /// to determine success or a failure of a response based on a status code returned by the service. + /// + /// A typical usage pattern for this method after getting a `result` could look like this: + /// + /// ```` + /// atom + /// .enqueue(Endpoint.random) + /// .resume() + /// .sink { + /// // Handle `AtomError`. + /// } receiveValue: { + /// // Handle `AtomResponse`. + /// } + /// .store(in: &cancelables) + /// ```` + /// + /// - Returns: `AnyPublisher` where `Output` is the `AtomResponse` and `Failure` is `AtomError`. + func resume() -> AnyPublisher { + Future { promise in + self.resume { + promise($0) + } + }.eraseToAnyPublisher() + } +} diff --git a/Framework/Atom/Service/Atom+Service.swift b/Framework/Atom/Service/Service.swift similarity index 68% rename from Framework/Atom/Service/Atom+Service.swift rename to Framework/Atom/Service/Service.swift index 84df2ce..6662252 100644 --- a/Framework/Atom/Service/Atom+Service.swift +++ b/Framework/Atom/Service/Service.swift @@ -1,6 +1,6 @@ // Atom // -// Copyright (c) 2019 Alaska Airlines +// Copyright (c) 2020 Alaska Airlines // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -16,47 +16,45 @@ import Foundation -public extension Atom { - /// `Service` is a public facing class responsible for managing - /// `URLSession` configuration, network calls, and decoding instances of a - /// data type into internal models. +/// `Service` is a public facing class responsible for managing +/// `URLSession` configuration, network calls, and decoding instances of a +/// data type into internal models. +/// +/// `Service` is available through the `Atom` instance only and cannot be +/// initialized dirrectly. This behavior is intentional to allow for better separation +/// of responsibilities such as creating a request, network call, and data decoding. +public class Service { + /// The `AuthenticationManager` instance. + private lazy var authenticationManager: AuthenticationManager = { + AuthenticationManager(serviceConfiguration.authenticationMethod, delegate: self) + }() + + /// The service configuration data. + private let serviceConfiguration: ServiceConfiguration + + /// The `URLSession` instance configured from `ServiceConfiguration`. + private let session: URLSession + + /// The requestable item to initialize `URLRequest` with. + private var requestable: Requestable + + /// An array of retryables. + private var retryables: [Retryable] + + /// Creates a `Service` instance given the provided parameter(s). /// - /// `Service` is available through the `Atom` instance only and cannot be - /// initialized dirrectly. This behavior is intentional to allow for better separation - /// of responsibilities such as creating a request, network call, and data decoding. - class Service { - /// The `AuthenticationManager` instance. - private lazy var authenticationManager: Atom.AuthenticationManager = { - Atom.AuthenticationManager(serviceConfiguration.authenticationMethod, delegate: self) - }() - - /// The service configuration data. - private let serviceConfiguration: Atom.ServiceConfiguration - - /// The `URLSession` instance configured from `Atom.ServiceConfiguration`. - private let session: URLSession - - /// The requestable item to initialize `URLRequest` with. - private var requestable: Requestable - - /// An array of retryables. - private var retryables: [Retryable] - - /// Creates a `Service` instance given the provided parameter(s). - /// - /// - Parameters: - /// - serviceConfiguration: The service configuration data. - internal init(serviceConfiguration: Atom.ServiceConfiguration) { - self.requestable = Atom.Endpoint() - self.retryables = [Retryable]() - self.serviceConfiguration = serviceConfiguration - self.session = URLSession(configuration: serviceConfiguration.sessionConfiguration, delegate: Interceptor(for: .network), delegateQueue: .main) - } + /// - Parameters: + /// - serviceConfiguration: The service configuration data. + internal init(serviceConfiguration: ServiceConfiguration) { + self.requestable = Endpoint() + self.retryables = [Retryable]() + self.serviceConfiguration = serviceConfiguration + self.session = URLSession(configuration: serviceConfiguration.sessionConfiguration, delegate: Interceptor(for: .network), delegateQueue: .main) } } -internal extension Atom.Service { - /// For documentation see `Atom.cancelAllSessionTasks` declaration. +internal extension Service { + /// For documentation see `cancelAllSessionTasks` declaration. func cancelAllSessionTasks() { session.getAllTasks { $0.forEach { $0.cancel() } @@ -64,15 +62,15 @@ internal extension Atom.Service { } /// Update requestable instance property with new data. - func update(with requestable: Requestable) -> Atom.Service { + func update(with requestable: Requestable) -> Service { self.requestable = requestable return self } } -public extension Atom.Service { - /// Creates and executes `URLRequest` initialized from `Requestable`. +public extension Service { + /// Creates and resumes `URLRequest` initialized from `Requestable`. /// /// Use this method to make network requests where you expect data returned by the /// service and require that data to be decoded into internal representations - models. @@ -81,8 +79,9 @@ public extension Atom.Service { /// which the client will be notified of a `result` on a queue `Atom` was configured to use. /// /// A typical usage pattern for this method could look like this: + /// /// ```` - /// atom.load(endpoint).execute(expecting: User.self) { result in + /// atom.enqueue(endpoint).resume(expecting: User.self) { result in /// switch result { /// case .failure(let error): /// // Handle `AtomError`. @@ -97,7 +96,7 @@ public extension Atom.Service { /// - Parameters: /// - type: The type to decode. /// - completion: The completion containing `Result` where the associated value is either an `AtomError` or decoded model instance. - func execute(expecting type: T.Type, completion: @escaping (Result) -> Void) where T: Model { + func resume(expecting type: T.Type, completion: @escaping (Result) -> Void) where T: Model { // Get decoder from `ServiceConfiguration`. let decoder = serviceConfiguration.decoder @@ -109,7 +108,7 @@ public extension Atom.Service { let request = try URLRequest(requestable: requestable) // Initialize `Retryable` with `URLRequest` instance and completion. - let retryable = Atom.Retryable(request: request, requiresAuthorization: requestable.requiresAuthentication) { data, response, error in + let retryable = Retryable(request: request, requiresAuthorization: requestable.requiresAuthentication) { data, response, error in // Process error returned by the service. if let error = error { queue.async { completion(Result(AtomError.session(error))) } @@ -117,7 +116,7 @@ public extension Atom.Service { // Process error response returned by the service. else if response?.isFailure == true { - queue.async { completion(Result(AtomError.response(Atom.Response(data, response)))) } + queue.async { completion(Result(AtomError.response(AtomResponse(data, response)))) } } // Process data returned by the service. @@ -127,7 +126,7 @@ public extension Atom.Service { // Initialize a result instance on the background queue. let result = Result(value) - // Call completion on the queue `Atom.Service` was configured to use. + // Call completion on the queue `Service` was configured to use. queue.async { completion(result) } } @@ -140,7 +139,7 @@ public extension Atom.Service { // Initialize a result instance on the background queue. let result = Result(value) - // Call completion on the queue `Atom.Service` was configured to use. + // Call completion on the queue `Service` was configured to use. queue.async { completion(result) } } catch { @@ -154,8 +153,8 @@ public extension Atom.Service { else { queue.async { completion(Result(AtomError.unknown)) } } } - // Execute retryable. - execute(retryable) + // Resume retryable. + resume(retryable) } catch let error as RequestableError { // Error initializing `URLRequest` from requestable instance. @@ -167,31 +166,32 @@ public extension Atom.Service { } } - /// Creates and executes `URLRequest` initialized from `Requestable`. + /// Creates and resumes `URLRequest` initialized from `Requestable`. /// /// Use this method to make network requests where you don't expect any data returned /// and are only interested in knowing if the network call succeeded or failed. /// - /// `Atom` framework uses a convenience computed variable on `URLResponse` - `isSuccessful` + /// `Atom` framework uses a convenience computed variable on `AtomResponse` - `isSuccessful` /// to determine success or a failure of a response based on a status code returned by the service. /// /// A typical usage pattern for this method after getting a `result` could look like this: + /// /// ```` - /// atom.load(endpoint).execute { result in + /// atom.enqueue(endpoint).resume { result in /// switch result { /// case .failure(let error): /// // Handle `AtomError`. /// /// case .success(let response): - /// // Handle `URLResponse`. + /// // Handle `AtomResponse`. /// } /// } /// } /// ```` /// /// - Parameters: - /// - completion: The completion containing `Result` where the associated value is either an `AtomError` or `URLResponse`. - func execute(_ completion: @escaping (Result) -> Void) { + /// - completion: The completion containing `Result` where the associated value is either an `AtomError` or `AtomResponse`. + func resume(_ completion: @escaping (Result) -> Void) { // Get dispatch queue from `ServiceConfiguration`. let queue = serviceConfiguration.dispatchQueue @@ -200,7 +200,7 @@ public extension Atom.Service { let request = try URLRequest(requestable: requestable) // Initialize `Retryable` with `URLRequest` instance and completion. - let retryable = Atom.Retryable(request: request, requiresAuthorization: requestable.requiresAuthentication) { data, response, error in + let retryable = Retryable(request: request, requiresAuthorization: requestable.requiresAuthentication) { data, response, error in // Process error returned by the service. if let error = error { queue.async { completion(Result(AtomError.session(error))) } @@ -209,17 +209,17 @@ public extension Atom.Service { // Process response returned by the service. else if response?.isSuccessful == true { // Initialize `success` case with response object. - queue.async { completion(Result(Atom.Response(data, response))) } + queue.async { completion(Result(AtomResponse(data, response))) } } // Service returned invalid response (based on `statusCode`). Initialize `failure` case with response and optional `data` object. else { queue.async { - completion(Result(AtomError.response(Atom.Response(data, response)))) } + completion(Result(AtomError.response(AtomResponse(data, response)))) } } } - // Execute retryable. - execute(retryable) + // Resume retryable. + resume(retryable) } catch let error as RequestableError { // Error initializing `URLRequest` from requestable instance. @@ -234,8 +234,8 @@ public extension Atom.Service { // MARK: Private Implementation -private extension Atom.Service { - func execute(_ retryable: Atom.Retryable) { +private extension Service { + func resume(_ retryable: Retryable) { let queue = serviceConfiguration.dispatchQueue let status = authenticationManager.applyAuthorizationHeader(to: retryable, on: queue) @@ -252,13 +252,13 @@ private extension Atom.Service { // MARK: AuthenticationManagerDelegate -extension Atom.Service: AuthenticationManagerDelegate { +extension Service: AuthenticationManagerDelegate { func authenticationManagerDidRefreshAccessToken() { for retryable in retryables { - // Execute retryable. - execute(retryable) + // Resume retryable. + resume(retryable) - // Remove executed retryable. + // Remove resumed retryable. retryables.removeFirst() } } @@ -272,7 +272,7 @@ extension Atom.Service: AuthenticationManagerDelegate { // Notify the client of errors for each request that required authorization - token refresh failed. retryable.completion(nil, nil, error) - // Remove executed retryable. + // Remove resumed retryable. retryables.removeFirst() } } diff --git a/Framework/Atom/Service/Atom+ServiceConfiguration+Timeout.swift b/Framework/Atom/Service/ServiceConfiguration+Timeout.swift similarity index 91% rename from Framework/Atom/Service/Atom+ServiceConfiguration+Timeout.swift rename to Framework/Atom/Service/ServiceConfiguration+Timeout.swift index c25e5a3..4c6dec9 100644 --- a/Framework/Atom/Service/Atom+ServiceConfiguration+Timeout.swift +++ b/Framework/Atom/Service/ServiceConfiguration+Timeout.swift @@ -1,6 +1,6 @@ // Atom // -// Copyright (c) 2019 Alaska Airlines +// Copyright (c) 2020 Alaska Airlines // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -16,7 +16,7 @@ import Foundation -internal extension Atom.ServiceConfiguration { +internal extension ServiceConfiguration { /// Model object representing `URLSessionConfiguration` timeout intervals. struct Timeout { /// The timeout interval to use when waiting for additional data. diff --git a/Framework/Atom/Service/ServiceConfiguration.swift b/Framework/Atom/Service/ServiceConfiguration.swift new file mode 100644 index 0000000..b387ab2 --- /dev/null +++ b/Framework/Atom/Service/ServiceConfiguration.swift @@ -0,0 +1,130 @@ +// Atom +// +// Copyright (c) 2020 Alaska Airlines +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import Foundation + +/// Model object representing Service configuration. +public final class ServiceConfiguration { + /// The authentication method indicating how authorization header will be handled in + internal let authenticationMethod: AuthenticationMethod + + /// The `ServiceConfiguration.Configuration` - default value is `.ephemeral`. + internal let configuration: ServiceConfiguration.Configuration + + /// The JSONDecoder for decoding data into models. + internal let decoder: JSONDecoder + + /// The queue to dispatch `Result` object on. + internal let dispatchQueue: DispatchQueue + + /// The standardized timeout interval for request and resource. + internal let timeout: ServiceConfiguration.Timeout + + /// List of supported session configurations. + /// + /// Configuration enum is a reflection of available options offered + /// by Foundation as class properties on `URLSessionConfiguration`. The + /// main reason for this abstraction is testability - see `ServiceConfigurationTests`. + public enum Configuration: Equatable { + /// The background session configuration is suitable for transferring data files while the app runs in the background. + case background(String) + + /// The default session configuration that uses a persistent disk-based cache. + case `default` + + /// Ephemeral configuration doesn’t store caches, credential stores, or any session-related data on disk (RAM only). + case ephemeral + } + + /// Constants that specify the type of service that Multipath TCP uses. + /// + /// The multipath service type determines whether multipath TCP should be attempted and the conditions + /// for creating and switching between subflows. Using these service types requires the appropriate entitlement. Any + /// connection attempt will fail if the process does not have the required entitlement. + /// + /// Available options are: + /// - `.none` - The default service type indicating that Multipath TCP should not be used. + /// - `.handover` - A Multipath TCP service that provides seamless handover between Wi-Fi and cellular in order to preserve the connection. + /// - `.interactive` - A service whereby Multipath TCP attempts to use the lowest-latency interface. + /// - `.aggregate` - A service that aggregates the capacities of other Multipath options in an attempt to increase throughput and minimize latency. + #if os(iOS) + public typealias MultipathServiceType = URLSessionConfiguration.MultipathServiceType + + /// The service type that specifies the Multipath TCP connection policy for transmitting data over Wi-Fi and cellular interfaces. + internal var multipathServiceType: MultipathServiceType = .none + + /// Creates a `ServiceConfiguration` instance given the provided parameter(s). + /// + /// - Parameters: + /// - authenticationMethod: The authentication method indicating how authorization header will be handled in Atom. + /// - configuration: The `ServiceConfiguration.Configuration` - default value is `.ephemeral`. + /// - decoder: The `JSONDecoder` for decoding data into models. + /// - dispatchQueue: The queue to dispatch `Result` object on. + /// - multipathServiceType: The service type that specifies the Multipath TCP connection policy for transmitting data over Wi-Fi and cellular interfaces. + public init(authenticationMethod: AuthenticationMethod = .none, configuration: Configuration = .ephemeral, decoder: JSONDecoder = JSONDecoder(), dispatchQueue: DispatchQueue = .main, multipathServiceType: MultipathServiceType = .none) { + self.authenticationMethod = authenticationMethod + self.configuration = configuration + self.decoder = decoder + self.dispatchQueue = dispatchQueue + self.multipathServiceType = multipathServiceType + self.timeout = Timeout() + } + + #else + + /// Creates a `ServiceConfiguration` instance given the provided parameter(s). + /// + /// - Parameters: + /// - authenticationMethod: The authentication method indicating how authorization header will be handled in Atom. + /// - configuration: The `ServiceConfiguration.Configuration` - default value is `.ephemeral`. + /// - decoder: The `JSONDecoder` for decoding data into models. + /// - dispatchQueue: The queue to dispatch `Result` object on. + public init(authenticationMethod: AuthenticationMethod = .none, configuration: Configuration = .ephemeral, decoder: JSONDecoder = JSONDecoder(), dispatchQueue: DispatchQueue = .main) { + self.authenticationMethod = authenticationMethod + self.configuration = configuration + self.decoder = decoder + self.dispatchQueue = dispatchQueue + self.timeout = Timeout() + } + #endif +} + +// MARK: Configuration + +internal extension ServiceConfiguration { + /// Returns `URLSessionConfiguration` for each `ServiceConfiguration.Configuration` case. + var sessionConfiguration: URLSessionConfiguration { + let sessionConfiguration: URLSessionConfiguration + + switch configuration { + case .background(let identifier): + sessionConfiguration = .background(withIdentifier: identifier) + case .ephemeral: + sessionConfiguration = .ephemeral + case .default: + sessionConfiguration = .default + } + + sessionConfiguration.timeoutIntervalForRequest = timeout.request + sessionConfiguration.timeoutIntervalForResource = timeout.resource + + #if os(iOS) + sessionConfiguration.multipathServiceType = multipathServiceType + #endif + + return sessionConfiguration + } +} diff --git a/Framework/AtomTests/Extensions/ArrayTests.swift b/Framework/AtomTests/Extensions/ArrayTests.swift index 58d7d03..c3c8830 100644 --- a/Framework/AtomTests/Extensions/ArrayTests.swift +++ b/Framework/AtomTests/Extensions/ArrayTests.swift @@ -1,6 +1,6 @@ // Atom // -// Copyright (c) 2019 Alaska Airlines +// Copyright (c) 2020 Alaska Airlines // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -23,7 +23,7 @@ internal class ArrayTests: BaseCase { let dictionary = ["name": "value"] // When - let headerItems = [Atom.HeaderItem(name: "name", value: "value")] + let headerItems = [HeaderItem(name: "name", value: "value")] // Then XCTAssertEqual(headerItems.dictionary, dictionary) diff --git a/Framework/AtomTests/Extensions/StringTests.swift b/Framework/AtomTests/Extensions/StringTests.swift index 3d22e0c..1867b8a 100644 --- a/Framework/AtomTests/Extensions/StringTests.swift +++ b/Framework/AtomTests/Extensions/StringTests.swift @@ -1,6 +1,6 @@ // Atom // -// Copyright (c) 2019 Alaska Airlines +// Copyright (c) 2020 Alaska Airlines // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/Framework/AtomTests/Extensions/URLRequestTests.swift b/Framework/AtomTests/Extensions/URLRequestTests.swift index e308083..620ddb1 100644 --- a/Framework/AtomTests/Extensions/URLRequestTests.swift +++ b/Framework/AtomTests/Extensions/URLRequestTests.swift @@ -1,6 +1,6 @@ // Atom // -// Copyright (c) 2019 Alaska Airlines +// Copyright (c) 2020 Alaska Airlines // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -105,7 +105,7 @@ internal class URLRequestTests: BaseCase { // Then XCTAssertNil(requestableError) - XCTAssertEqual(request?.httpMethod, Atom.Method.get.stringValue) + XCTAssertEqual(request?.httpMethod, HTTPMethod.get.stringValue) } } @@ -113,7 +113,7 @@ internal class URLRequestTests: BaseCase { private extension URLRequestTests { /// Test header values. - private static let headers = [Atom.HeaderItem(name: "name", value: "value")] + private static let headers = [HeaderItem(name: "name", value: "value")] /// Test body data. private static let body = Data() @@ -128,9 +128,9 @@ private extension URLRequestTests { case validHTTPBody case validMethod - var headerItems: [Atom.HeaderItem]? { URLRequestTests.headers } + var headerItems: [HeaderItem]? { URLRequestTests.headers } - var method: Atom.Method { + var method: HTTPMethod { switch self { case .validHTTPBody: return .post(URLRequestTests.body) @@ -139,21 +139,21 @@ private extension URLRequestTests { } } - func baseURL() throws -> Atom.BaseURL { + func baseURL() throws -> BaseURL { switch self { case .invalidBaseURL: - return try Atom.BaseURL(host: "/alaskaair/") + return try BaseURL(host: "/alaskaair/") default: - return try Atom.BaseURL(host: "api.alaskaair.net") + return try BaseURL(host: "api.alaskaair.net") } } - func path() throws -> Atom.URLPath { + func path() throws -> URLPath { switch self { case .invalidURLPath: - return try Atom.URLPath("path") + return try URLPath("path") default: - return try Atom.URLPath("/path/to/resource") + return try URLPath("/path/to/resource") } } } diff --git a/Framework/AtomTests/Models/ResponseTests.swift b/Framework/AtomTests/Models/AtomResponseTests.swift similarity index 79% rename from Framework/AtomTests/Models/ResponseTests.swift rename to Framework/AtomTests/Models/AtomResponseTests.swift index e0bebb2..0675b6d 100644 --- a/Framework/AtomTests/Models/ResponseTests.swift +++ b/Framework/AtomTests/Models/AtomResponseTests.swift @@ -1,6 +1,6 @@ // Atom // -// Copyright (c) 2019 Alaska Airlines +// Copyright (c) 2020 Alaska Airlines // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -17,10 +17,10 @@ @testable import Atom import XCTest -internal class ResponseTests: BaseCase { - internal func testResponseInitializationWithNilValuesSuccess() { +internal class AtomResponseTests: BaseCase { + internal func testAtomResponseInitializationWithNilValuesSuccess() { // Given, When - let response = Atom.Response(nil, nil) + let response = AtomResponse(nil, nil) // Then XCTAssertNotNil(response) @@ -34,14 +34,14 @@ internal class ResponseTests: BaseCase { XCTAssertNil(response.url) } - internal func testResponseInitializationWithDataNilValueSuccess() { + internal func testAtomResponseInitializationWithDataNilValueSuccess() { // Given - var response: Atom.Response? + var response: AtomResponse? let expectation = self.expectation(description: "Expecting URLResponse.") // When URLSession.shared.dataTask(with: url) { _, res, _ in - response = Atom.Response(nil, res) + response = AtomResponse(nil, res) expectation.fulfill() }.resume() @@ -51,9 +51,9 @@ internal class ResponseTests: BaseCase { } } - internal func testResponseInitializationWithURLResponseNilValueSuccess() { + internal func testAtomResponseInitializationWithURLResponseNilValueSuccess() { // Given, When - let response = Atom.Response(Data(), nil) + let response = AtomResponse(Data(), nil) // Then XCTAssertNotNil(response) @@ -70,7 +70,7 @@ internal class ResponseTests: BaseCase { // MARK: Test Data -private extension ResponseTests { +private extension AtomResponseTests { private var url: URL { guard let url = URL(string: "https://www.alaskaair.com") else { fatalError("Initializing URL instance with a valid URL string should never fail.") diff --git a/Framework/AtomTests/Models/BaseCase.swift b/Framework/AtomTests/Models/BaseCase.swift index 9ed3a52..d6616da 100644 --- a/Framework/AtomTests/Models/BaseCase.swift +++ b/Framework/AtomTests/Models/BaseCase.swift @@ -1,6 +1,6 @@ // Atom // -// Copyright (c) 2019 Alaska Airlines +// Copyright (c) 2020 Alaska Airlines // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/Framework/AtomTests/Models/BaseURLSchemeTests.swift b/Framework/AtomTests/Models/BaseURLSchemeTests.swift index 4165632..66af0ce 100644 --- a/Framework/AtomTests/Models/BaseURLSchemeTests.swift +++ b/Framework/AtomTests/Models/BaseURLSchemeTests.swift @@ -1,6 +1,6 @@ // Atom // -// Copyright (c) 2019 Alaska Airlines +// Copyright (c) 2020 Alaska Airlines // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -24,7 +24,7 @@ internal class BaseURLSchemeTests: BaseCase { let https = "https://" // Then - XCTAssertEqual(Atom.BaseURL.Scheme.http.stringValue, http) - XCTAssertEqual(Atom.BaseURL.Scheme.https.stringValue, https) + XCTAssertEqual(BaseURL.Scheme.http.stringValue, http) + XCTAssertEqual(BaseURL.Scheme.https.stringValue, https) } } diff --git a/Framework/AtomTests/Models/BaseURLTests.swift b/Framework/AtomTests/Models/BaseURLTests.swift index 4e1968e..f5f8dda 100644 --- a/Framework/AtomTests/Models/BaseURLTests.swift +++ b/Framework/AtomTests/Models/BaseURLTests.swift @@ -1,6 +1,6 @@ // Atom // -// Copyright (c) 2019 Alaska Airlines +// Copyright (c) 2020 Alaska Airlines // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -21,7 +21,7 @@ internal class BaseURLTests: BaseCase { internal func testBaseURLInitializationFailure() { // Given let host = ".api.alaskaair.net" - let atomBaseURL = try? Atom.BaseURL(host: host) + let atomBaseURL = try? BaseURL(host: host) // Then XCTAssertNil(atomBaseURL) @@ -31,12 +31,12 @@ internal class BaseURLTests: BaseCase { // Given let host = "api.alaskaair.net" let baseURL = "https://api.alaskaair.net" - var atomBaseURL: Atom.BaseURL? + var atomBaseURL: BaseURL? var requestableError: RequestableError? // When do { - atomBaseURL = try Atom.BaseURL(host: host) + atomBaseURL = try BaseURL(host: host) } catch let error as RequestableError { requestableError = error } catch { XCTFail("Unexpected error thrown.") } diff --git a/Framework/AtomTests/Models/HeaderItemTests.swift b/Framework/AtomTests/Models/HeaderItemTests.swift index 5eda82c..8ee9274 100644 --- a/Framework/AtomTests/Models/HeaderItemTests.swift +++ b/Framework/AtomTests/Models/HeaderItemTests.swift @@ -1,6 +1,6 @@ // Atom // -// Copyright (c) 2019 Alaska Airlines +// Copyright (c) 2020 Alaska Airlines // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -24,7 +24,7 @@ internal class HeaderItemTests: BaseCase { let value = "value" // When - let headerItem = Atom.HeaderItem(name: name, value: value) + let headerItem = HeaderItem(name: name, value: value) // Then XCTAssertEqual(headerItem.name, name) diff --git a/Framework/AtomTests/Models/MethodTests.swift b/Framework/AtomTests/Models/MethodTests.swift index 8ec1ac2..16435d7 100644 --- a/Framework/AtomTests/Models/MethodTests.swift +++ b/Framework/AtomTests/Models/MethodTests.swift @@ -1,6 +1,6 @@ // Atom // -// Copyright (c) 2019 Alaska Airlines +// Copyright (c) 2020 Alaska Airlines // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -17,7 +17,7 @@ @testable import Atom import XCTest -internal class MethodTests: BaseCase { +internal class HTTPMethodTests: BaseCase { internal func testMethodCaseReturnsExpectedStringValue() { // Give, When let delete = "DELETE" @@ -27,10 +27,10 @@ internal class MethodTests: BaseCase { let put = "PUT" // Then - XCTAssertEqual(Atom.Method.delete.stringValue, delete) - XCTAssertEqual(Atom.Method.get.stringValue, get) - XCTAssertEqual(Atom.Method.patch(Data()).stringValue, patch) - XCTAssertEqual(Atom.Method.post(Data()).stringValue, post) - XCTAssertEqual(Atom.Method.put(Data()).stringValue, put) + XCTAssertEqual(HTTPMethod.delete.stringValue, delete) + XCTAssertEqual(HTTPMethod.get.stringValue, get) + XCTAssertEqual(HTTPMethod.patch(Data()).stringValue, patch) + XCTAssertEqual(HTTPMethod.post(Data()).stringValue, post) + XCTAssertEqual(HTTPMethod.put(Data()).stringValue, put) } } diff --git a/Framework/AtomTests/Models/QueryItemTests.swift b/Framework/AtomTests/Models/QueryItemTests.swift deleted file mode 100644 index ca44088..0000000 --- a/Framework/AtomTests/Models/QueryItemTests.swift +++ /dev/null @@ -1,25 +0,0 @@ -// Atom -// -// Copyright (c) 2019 Alaska Airlines -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -@testable import Atom -import XCTest - -internal class QueryItemTests: BaseCase { - internal func testQueryDefinitionTypeAssignedExpectedType() { - // Given, When, Then - XCTAssertTrue(type(of: Atom.QueryItem.self) == type(of: URLQueryItem.self)) - } -} diff --git a/Framework/AtomTests/Models/RequestableTests.swift b/Framework/AtomTests/Models/RequestableTests.swift index f720b35..db4b19e 100644 --- a/Framework/AtomTests/Models/RequestableTests.swift +++ b/Framework/AtomTests/Models/RequestableTests.swift @@ -1,6 +1,6 @@ // Atom // -// Copyright (c) 2019 Alaska Airlines +// Copyright (c) 2020 Alaska Airlines // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -24,7 +24,7 @@ internal class RequestableTests: BaseCase { // Then XCTAssertEqual(endpoint.method, .get) - XCTAssertEqual(try? endpoint.path().stringValue, Atom.URLPath.default.stringValue) + XCTAssertEqual(try? endpoint.path().stringValue, URLPath.default.stringValue) XCTAssertNil(endpoint.headerItems) XCTAssertNil(endpoint.queryItems) } @@ -34,8 +34,8 @@ internal class RequestableTests: BaseCase { private extension RequestableTests { private struct Endpoint: Requestable { - func baseURL() throws -> Atom.BaseURL { - try Atom.BaseURL(host: "api.alaskaair.com") + func baseURL() throws -> BaseURL { + try BaseURL(host: "api.alaskaair.com") } } } diff --git a/Framework/AtomTests/Models/ResultTests.swift b/Framework/AtomTests/Models/ResultTests.swift index df12c71..b661d2d 100644 --- a/Framework/AtomTests/Models/ResultTests.swift +++ b/Framework/AtomTests/Models/ResultTests.swift @@ -1,6 +1,6 @@ // Atom // -// Copyright (c) 2019 Alaska Airlines +// Copyright (c) 2020 Alaska Airlines // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/Framework/AtomTests/Models/ServiceConfigurationTests.swift b/Framework/AtomTests/Models/ServiceConfigurationTests.swift index d0ed4d0..774bfe2 100644 --- a/Framework/AtomTests/Models/ServiceConfigurationTests.swift +++ b/Framework/AtomTests/Models/ServiceConfigurationTests.swift @@ -1,6 +1,6 @@ // Atom // -// Copyright (c) 2019 Alaska Airlines +// Copyright (c) 2020 Alaska Airlines // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -20,7 +20,7 @@ import XCTest internal class ServiceConfigurationTests: BaseCase { internal func testServiceConfigurationInitializationWithDefaultParameters() { // Given, When - let serviceConfiguration = Atom.ServiceConfiguration() + let serviceConfiguration = ServiceConfiguration() // Then XCTAssertEqual(serviceConfiguration.dispatchQueue, .main) diff --git a/Framework/AtomTests/Models/URLPathTests.swift b/Framework/AtomTests/Models/URLPathTests.swift index d502d3a..1626fa8 100644 --- a/Framework/AtomTests/Models/URLPathTests.swift +++ b/Framework/AtomTests/Models/URLPathTests.swift @@ -1,6 +1,6 @@ // Atom // -// Copyright (c) 2019 Alaska Airlines +// Copyright (c) 2020 Alaska Airlines // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -21,7 +21,7 @@ internal class URLPathTests: BaseCase { internal func testURLPathInitializationFailure() { // Given, When let path = "path" - let atomPath = try? Atom.URLPath(path) + let atomPath = try? URLPath(path) // Then XCTAssertNil(atomPath) @@ -30,12 +30,12 @@ internal class URLPathTests: BaseCase { internal func testURLPathInitializationSuccess() { // Given let path = "/path" - var atomPath: Atom.URLPath? + var atomPath: URLPath? var requestableError: RequestableError? // When do { - atomPath = try Atom.URLPath(path) + atomPath = try URLPath(path) } catch let error as RequestableError { requestableError = error } catch { XCTFail("Unexpected error thrown.") } diff --git a/Framework/README.md b/Framework/README.md index 5cfcd5e..4c60a43 100644 --- a/Framework/README.md +++ b/Framework/README.md @@ -2,56 +2,54 @@ The lightweight & delightful networking library. -Atom is a wrapper library built around a subset of features offered by `URLSession` with added ability to decode data into models, handle access token refresh and authorization headers on behalf of the client, and more. It takes advantage of Swift features such as default implementation for protocols, generics and `Decodable` to make it extremely easy to integrate and use in an existing project. Atom offers support for any endpoint, a much stricter URL host and path validation, comprehensive documentation and an example application to eliminate any guesswork. +Atom is a wrapper library built around a subset of features offered by `URLSession` with added ability to decode data into models, handle access token refresh and authorization headers on behalf of the client, and more. It takes advantage of Swift features such as default implementation for protocols, generics and `Decodable` to make it extremely easy to integrate and use in an existing project. Atom offers support for any endpoint, a much stricter URL host and path validation, comprehensive [documentation](https://htmlpreview.github.com/?https://github.com/AlaskaAirlines/atom/blob/master/Documentation/index.html) and an example application to eliminate any guesswork. ## Features - [x] Simple to setup, easy to use & efficient - [x] Supports any endpoint +- [x] Supports Combine publishers +- [x] Supports Multipath TCP configuration - [x] Handles object decoding from data returned by the service - [x] Handles token refresh - [x] Handles and applies authorization headers on behalf of the client - [x] Handles URL host validation - [x] Handles URL path validation -- [x] Complete Documentation +- [x] Complete [Documentation](https://htmlpreview.github.com/?https://github.com/AlaskaAirlines/atom/blob/master/Documentation/index.html) ## Requirements -* iOS 11.0+ -* Xcode 11.0+ +* iOS 12.0+ +* Xcode 12.0+ * Swift 5.0+ ## Installation -### Carthage -[Carthage](https://github.com/Carthage/Carthage) is a decentralized dependency manager that builds your dependencies and provides you with binary frameworks. To integrate Atom into your Xcode project using Carthage, specify it in your `Cartfile`: - -``` -git "https://github.com/AlaskaAirlines/atom" ~> 1.0.0 -``` - -For more information on getting started with Carthage, visit the [repo](https://github.com/Carthage/Carthage). - ### Swift Package Manager The [Swift Package Manager](https://swift.org/package-manager/) is a tool for automating the distribution of Swift code and is integrated into the `swift` compiler. Once you have your Swift package set up, adding Atom as a dependency is as easy as adding it to the `dependencies` value of your `Package.swift`. +If you are using Xcode, adding Atom as a dependency is even easier. First, select your application, then your application project. Once you see **Swift Packages** tab at the top of the Project Editor, click on it. Click `+` button and add the following URL: + +`https://github.com/alaskaairlines/atom/` + +At this point you can setup your project to either use a branch or tagged version of the package. ## Usage Getting started is easy. First, create an instance of Atom. -``` +```swift let atom = Atom() ``` In the above example, default configuration will be used. Default configuration will setup `URLSession`to use ephemeral configuration as well as ensure that the data returned by the service is available on the main thread. -Any network request needs to conform and implement `Requestable` protocol. The `Requestable ` protocol provides default implementation for all of its properties - except for the `func baseURL() throws -> Atom.BaseURL`. See documentation for more information. +Any endpoint needs to conform and implement `Requestable` protocol. The `Requestable ` protocol provides default implementation for all of its properties - except for the `func baseURL() throws -> BaseURL`. See [documentation](https://htmlpreview.github.com/?https://github.com/AlaskaAirlines/atom/blob/master/Documentation/index.html) for more information. -``` +```swift extension Seatmap { enum Endpoint: Requestable { case refresh @@ -65,10 +63,12 @@ extension Seatmap { Atom offers a handful of methods with support for fully decoded model objects, raw data, or status indicating success / failure of a request. -``` +```swift +// Completion based. + typealias Endpoint = Seatmap.Endpoint -service.load(Endpoint.refresh).execute(expecting: Seatmap.self) { [weak self] result in +atom.enqueue(Endpoint.refresh).resume(expecting: Seatmap.self) { result in switch result { case .failure(let error): // Handle error. @@ -77,17 +77,29 @@ service.load(Endpoint.refresh).execute(expecting: Seatmap.self) { [weak self] re // Handle seatmap model. } } + +// Publisher based. + +atom + .enqueue(Endpoint.refresh) + .resume(expecting: Seatmap.self) + .sink { completion in + // Handle `AtomError`. + } receiveValue: { seatmap in + // Handle decoded `Seatmap` instance. + } + .store(in: &cancelables) ``` -The above example demonstrates how to use `execute()` method to get a fully decoded `Seatmap` model object. +The above example demonstrates how to use `resume(expecting:)` function to get a fully decoded `Seatmap` model object. -For more information, please see documentation. +For more information, please see [documentation](https://htmlpreview.github.com/?https://github.com/AlaskaAirlines/atom/blob/master/Documentation/index.html). ### Authentication Atom can be configured to apply authorization headers on behalf of the client. -Atom supports `Basic` and `Bearer` authentication methods. When configured properly, Atom will perform automatic token refresh on behalf of the client if it determines that the access token being used has expired. Any in-flight calls will be enqueued and executed once a new token is obtained. +Atom supports `Basic` and `Bearer` authentication methods. When configured properly, Atom will perform automatic token refresh on behalf of the client if it determines that the access token being used has expired. Any in-flight calls will be enqueued and resumed once a new token is obtained. If the token refresh call fails, all enqueued network calls will be executed at once with completions set to `AtomError` failure. @@ -95,7 +107,7 @@ If the token refresh call fails, all enqueued network calls will be executed at You can configure Atom to apply `Basic` authorization header like this: -``` +```swift let atom: Atom = { let credential = Atom.BasicCredential(password: "password", username: "username") let basic = Atom.AuthenticationMethod.basic(credential) @@ -108,7 +120,7 @@ let atom: Atom = { An existing implementation can be extended by conforming and implementing `BasicCredentialConvertible` protocol. A hypothetical configuration can look something like this: -``` +```swift final class CredentialManager { private(set) var username = String() private(set) var password = String() @@ -145,7 +157,7 @@ Once configured, Atom will combine username and password into a single string `u ### Bearer You can configure Atom to apply `Bearer ` authorization header. Here is an example: -``` +```swift class TokenManager: TokenCredentialWritable { var tokenCredential: Atom.TokenCredential { // Read values from the keychain. @@ -178,7 +190,7 @@ Once configured, Atom will apply authorization header to a request as `Authoriza Please note, Atom will only decode token credential from a JSON objecting returned in this form: -``` +```json { "access_token": "2YotnFZFEjr1zCsicMWpAA", "expires_in": 3600, @@ -188,7 +200,7 @@ Please note, Atom will only decode token credential from a JSON objecting return The above response is in accordance with [RFC 6749, section 1.5](https://tools.ietf.org/html/rfc6749#section-1.5). -For more information and Atom usage example, please see documentation and the provided Example application. +For more information and Atom usage example, please see [documentation](https://htmlpreview.github.com/?https://github.com/AlaskaAirlines/atom/blob/master/Documentation/index.html) and the provided Example application. ## Communication * If you found a bug, open an issue. diff --git a/Package.swift b/Package.swift index 861e731..72ba4a7 100644 --- a/Package.swift +++ b/Package.swift @@ -1,4 +1,4 @@ -// swift-tools-version:5.0 +// swift-tools-version:5.3 // // Package.swift // Atom @@ -23,7 +23,8 @@ let package = Package( targets: [ .target( name: "Atom", - path: "Framework/Atom") + path: "Framework/Atom", + exclude:["Info.plist"]) ], swiftLanguageVersions: [.v5] ) diff --git a/README.md b/README.md index 678d6ec..1a5037b 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,8 @@ Atom is a wrapper library built around a subset of features offered by `URLSessi ## Features - [x] Simple to setup, easy to use & efficient - [x] Supports any endpoint +- [x] Supports Combine publishers +- [x] Supports Multipath TCP configuration - [x] Handles object decoding from data returned by the service - [x] Handles token refresh - [x] Handles and applies authorization headers on behalf of the client @@ -17,28 +19,24 @@ Atom is a wrapper library built around a subset of features offered by `URLSessi ## Requirements -* iOS 11.0+ -* Xcode 11.0+ +* iOS 12.0+ +* Xcode 12.0+ * Swift 5.0+ ## Installation -### Carthage -[Carthage](https://github.com/Carthage/Carthage) is a decentralized dependency manager that builds your dependencies and provides you with binary frameworks. To integrate Atom into your Xcode project using Carthage, specify it in your `Cartfile`: - -``` -git "https://github.com/AlaskaAirlines/atom" ~> 1.0.0 -``` - -For more information on getting started with Carthage, visit the [repo](https://github.com/Carthage/Carthage). - ### Swift Package Manager The [Swift Package Manager](https://swift.org/package-manager/) is a tool for automating the distribution of Swift code and is integrated into the `swift` compiler. Once you have your Swift package set up, adding Atom as a dependency is as easy as adding it to the `dependencies` value of your `Package.swift`. +If you are using Xcode, adding Atom as a dependency is even easier. First, select your application, then your application project. Once you see **Swift Packages** tab at the top of the Project Editor, click on it. Click `+` button and add the following URL: + +`https://github.com/alaskaairlines/atom/` + +At this point you can setup your project to either use a branch or tagged version of the package. ## Usage Getting started is easy. First, create an instance of Atom. @@ -49,7 +47,7 @@ let atom = Atom() In the above example, default configuration will be used. Default configuration will setup `URLSession`to use ephemeral configuration as well as ensure that the data returned by the service is available on the main thread. -Any network request needs to conform and implement `Requestable` protocol. The `Requestable ` protocol provides default implementation for all of its properties - except for the `func baseURL() throws -> Atom.BaseURL`. See [documentation](https://htmlpreview.github.com/?https://github.com/AlaskaAirlines/atom/blob/master/Documentation/index.html) for more information. +Any endpoint needs to conform and implement `Requestable` protocol. The `Requestable ` protocol provides default implementation for all of its properties - except for the `func baseURL() throws -> BaseURL`. See [documentation](https://htmlpreview.github.com/?https://github.com/AlaskaAirlines/atom/blob/master/Documentation/index.html) for more information. ```swift extension Seatmap { @@ -66,9 +64,11 @@ extension Seatmap { Atom offers a handful of methods with support for fully decoded model objects, raw data, or status indicating success / failure of a request. ```swift +// Completion based. + typealias Endpoint = Seatmap.Endpoint -service.load(Endpoint.refresh).execute(expecting: Seatmap.self) { [weak self] result in +atom.enqueue(Endpoint.refresh).resume(expecting: Seatmap.self) { result in switch result { case .failure(let error): // Handle error. @@ -77,9 +77,21 @@ service.load(Endpoint.refresh).execute(expecting: Seatmap.self) { [weak self] re // Handle seatmap model. } } + +// Publisher based. + +atom + .enqueue(Endpoint.refresh) + .resume(expecting: Seatmap.self) + .sink { completion in + // Handle `AtomError`. + } receiveValue: { seatmap in + // Handle decoded `Seatmap` instance. + } + .store(in: &cancelables) ``` -The above example demonstrates how to use `execute()` method to get a fully decoded `Seatmap` model object. +The above example demonstrates how to use `resume(expecting:)` function to get a fully decoded `Seatmap` model object. For more information, please see [documentation](https://htmlpreview.github.com/?https://github.com/AlaskaAirlines/atom/blob/master/Documentation/index.html). @@ -87,7 +99,7 @@ For more information, please see [documentation](https://htmlpreview.github.com/ Atom can be configured to apply authorization headers on behalf of the client. -Atom supports `Basic` and `Bearer` authentication methods. When configured properly, Atom will perform automatic token refresh on behalf of the client if it determines that the access token being used has expired. Any in-flight calls will be enqueued and executed once a new token is obtained. +Atom supports `Basic` and `Bearer` authentication methods. When configured properly, Atom will perform automatic token refresh on behalf of the client if it determines that the access token being used has expired. Any in-flight calls will be enqueued and resumed once a new token is obtained. If the token refresh call fails, all enqueued network calls will be executed at once with completions set to `AtomError` failure. @@ -196,4 +208,4 @@ For more information and Atom usage example, please see [documentation](https:// * If you want to contribute, submit a pull request. ## Authors -* [Michael Babiy](https://github.com/michaelbabiy) \ No newline at end of file +* [Michael Babiy](https://github.com/michaelbabiy)